2011-04-23 17:31:31 +02:00
|
|
|
/*
|
2013-02-24 18:40:43 +01:00
|
|
|
Minetest
|
2013-02-24 19:38:45 +01:00
|
|
|
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
2011-04-23 17:31:31 +02:00
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
2012-06-05 16:56:56 +02:00
|
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
2011-04-23 17:31:31 +02:00
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2012-06-05 16:56:56 +02:00
|
|
|
GNU Lesser General Public License for more details.
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2012-06-05 16:56:56 +02:00
|
|
|
You should have received a copy of the GNU Lesser General Public License along
|
2011-04-23 17:31:31 +02:00
|
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "game.h"
|
2012-06-17 03:00:31 +02:00
|
|
|
#include "irrlichttypes_extrabloated.h"
|
2011-10-12 12:53:38 +02:00
|
|
|
#include <IGUICheckBox.h>
|
|
|
|
#include <IGUIEditBox.h>
|
|
|
|
#include <IGUIButton.h>
|
|
|
|
#include <IGUIStaticText.h>
|
|
|
|
#include <IGUIFont.h>
|
2012-12-01 02:02:16 +01:00
|
|
|
#include <IMaterialRendererServices.h>
|
2013-04-07 20:22:06 +02:00
|
|
|
#include "IMeshCache.h"
|
2011-04-23 17:31:31 +02:00
|
|
|
#include "client.h"
|
|
|
|
#include "server.h"
|
|
|
|
#include "guiPauseMenu.h"
|
2011-05-22 22:09:12 +02:00
|
|
|
#include "guiPasswordChange.h"
|
2013-02-23 16:01:35 +01:00
|
|
|
#include "guiVolumeChange.h"
|
2012-07-15 18:19:38 +02:00
|
|
|
#include "guiFormSpecMenu.h"
|
2011-04-23 17:31:31 +02:00
|
|
|
#include "guiTextInputMenu.h"
|
2011-10-15 13:46:59 +02:00
|
|
|
#include "guiDeathScreen.h"
|
2012-02-28 18:45:23 +01:00
|
|
|
#include "tool.h"
|
2011-12-03 09:01:14 +01:00
|
|
|
#include "guiChatConsole.h"
|
2011-04-24 10:41:33 +02:00
|
|
|
#include "config.h"
|
2013-09-25 04:29:07 +02:00
|
|
|
#include "version.h"
|
2011-04-29 14:34:26 +02:00
|
|
|
#include "clouds.h"
|
2012-12-31 19:33:36 +01:00
|
|
|
#include "particles.h"
|
2011-09-08 01:08:47 +02:00
|
|
|
#include "camera.h"
|
2011-06-26 01:34:36 +02:00
|
|
|
#include "mapblock.h"
|
2011-10-12 12:53:38 +02:00
|
|
|
#include "settings.h"
|
|
|
|
#include "profiler.h"
|
|
|
|
#include "mainmenumanager.h"
|
2011-10-15 13:46:59 +02:00
|
|
|
#include "gettext.h"
|
2011-10-16 13:57:53 +02:00
|
|
|
#include "log.h"
|
2011-10-16 15:16:47 +02:00
|
|
|
#include "filesys.h"
|
2011-11-13 09:57:55 +01:00
|
|
|
// Needed for determining pointing to nodes
|
2011-11-14 20:41:30 +01:00
|
|
|
#include "nodedef.h"
|
2011-11-13 11:54:33 +01:00
|
|
|
#include "nodemetadata.h"
|
2011-11-13 23:19:48 +01:00
|
|
|
#include "main.h" // For g_settings
|
2012-01-12 06:10:39 +01:00
|
|
|
#include "itemdef.h"
|
2011-11-15 12:13:18 +01:00
|
|
|
#include "tile.h" // For TextureSource
|
2012-03-19 02:59:12 +01:00
|
|
|
#include "shader.h" // For ShaderSource
|
2011-11-27 13:29:48 +01:00
|
|
|
#include "logoutputbuffer.h"
|
2012-03-11 13:54:23 +01:00
|
|
|
#include "subgame.h"
|
2012-03-12 20:27:29 +01:00
|
|
|
#include "quicktune_shortcutter.h"
|
2012-03-15 23:25:18 +01:00
|
|
|
#include "clientmap.h"
|
2013-04-14 00:20:22 +02:00
|
|
|
#include "hud.h"
|
2012-03-16 15:34:30 +01:00
|
|
|
#include "sky.h"
|
2012-03-23 11:05:17 +01:00
|
|
|
#include "sound.h"
|
2012-03-25 10:50:29 +02:00
|
|
|
#if USE_SOUND
|
2012-03-23 14:29:30 +01:00
|
|
|
#include "sound_openal.h"
|
|
|
|
#endif
|
2012-03-23 19:23:03 +01:00
|
|
|
#include "event_manager.h"
|
2013-06-01 01:49:59 +02:00
|
|
|
#include <iomanip>
|
2012-03-21 02:33:02 +01:00
|
|
|
#include <list>
|
2012-03-19 04:25:09 +01:00
|
|
|
#include "util/directiontables.h"
|
Rewrite client media download and support hash-based remote download
Move most of the media-related code in client.cpp into a new class
ClientMediaDownloader (clientmedia.cpp, clientmedia.h). Among other
things, this class does the following things:
- Download [remote_server][sha1] instead of [remote_server][name]. This
is to support servers that provide the same file name with different
contents.
- Initially fetch [remote_server]index.mth. This file should follow the
Minetest Hashset format (currently version 1) and contain a list of SHA1
hashes that exist on the server.
- The list of needed SHA1s is uploaded (via HTTP POST) when index.mth is
requested, so servers can optionally narrow down the list to the needs
of the client.
- If index.mth is missing (HTTP response code 404), we enter compat mode,
fetching [remote_server][name] as before this commit.
- remote_server can now contain multiple servers, separated by commas.
The downloader code attempts to split requests between the different
servers, as permitted by each server's index.mth. If one server claims
to have a file but actually doesn't (or something fails), we ask a
different server that also claims to have it.
- As before, when none of the remote servers provide a particular
file, we download it via the conventional method, i.e. using
the minetest protocol: TOSERVER_REQUEST_MEDIA / TOCLIENT_MEDIA.
- Bugfix: Every downloaded file's SHA1 is now verified against the SHA1
announced by the minetest server (before loading it and inserting it
into the file cache).
- Bugfix: Only send TOSERVER_RECEIVED_MEDIA when we actually have all
media. This should fix #863.
2013-08-29 05:22:18 +02:00
|
|
|
#include "util/pointedthing.h"
|
2011-06-17 21:20:15 +02:00
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
|
|
|
Text input system
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct TextDestChat : public TextDest
|
|
|
|
{
|
|
|
|
TextDestChat(Client *client)
|
|
|
|
{
|
|
|
|
m_client = client;
|
|
|
|
}
|
|
|
|
void gotText(std::wstring text)
|
|
|
|
{
|
2011-12-03 09:01:14 +01:00
|
|
|
m_client->typeChatMessage(text);
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
2012-07-15 18:19:38 +02:00
|
|
|
void gotText(std::map<std::string, std::string> fields)
|
|
|
|
{
|
|
|
|
m_client->typeChatMessage(narrow_to_wide(fields["text"]));
|
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
|
|
|
|
Client *m_client;
|
|
|
|
};
|
|
|
|
|
2011-11-13 11:48:05 +01:00
|
|
|
struct TextDestNodeMetadata : public TextDest
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2011-11-13 11:48:05 +01:00
|
|
|
TextDestNodeMetadata(v3s16 p, Client *client)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
|
|
|
m_p = p;
|
|
|
|
m_client = client;
|
|
|
|
}
|
2012-07-15 18:19:38 +02:00
|
|
|
// This is deprecated I guess? -celeron55
|
2011-04-23 17:31:31 +02:00
|
|
|
void gotText(std::wstring text)
|
|
|
|
{
|
|
|
|
std::string ntext = wide_to_narrow(text);
|
2012-07-15 18:19:38 +02:00
|
|
|
infostream<<"Submitting 'text' field of node at ("<<m_p.X<<","
|
|
|
|
<<m_p.Y<<","<<m_p.Z<<"): "<<ntext<<std::endl;
|
2012-06-01 19:51:15 +02:00
|
|
|
std::map<std::string, std::string> fields;
|
|
|
|
fields["text"] = ntext;
|
|
|
|
m_client->sendNodemetaFields(m_p, "", fields);
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
2012-07-15 18:19:38 +02:00
|
|
|
void gotText(std::map<std::string, std::string> fields)
|
|
|
|
{
|
|
|
|
m_client->sendNodemetaFields(m_p, "", fields);
|
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
|
|
|
|
v3s16 m_p;
|
|
|
|
Client *m_client;
|
|
|
|
};
|
|
|
|
|
2012-07-22 16:10:58 +02:00
|
|
|
struct TextDestPlayerInventory : public TextDest
|
|
|
|
{
|
|
|
|
TextDestPlayerInventory(Client *client)
|
|
|
|
{
|
|
|
|
m_client = client;
|
2013-01-03 18:59:28 +01:00
|
|
|
m_formname = "";
|
|
|
|
}
|
|
|
|
TextDestPlayerInventory(Client *client, std::string formname)
|
|
|
|
{
|
|
|
|
m_client = client;
|
|
|
|
m_formname = formname;
|
2012-07-22 16:10:58 +02:00
|
|
|
}
|
|
|
|
void gotText(std::map<std::string, std::string> fields)
|
|
|
|
{
|
2013-01-03 18:59:28 +01:00
|
|
|
m_client->sendInventoryFields(m_formname, fields);
|
2012-07-22 16:10:58 +02:00
|
|
|
}
|
|
|
|
|
2013-04-07 16:34:35 +02:00
|
|
|
void setFormName(std::string formname) {
|
|
|
|
m_formname = formname;
|
|
|
|
}
|
|
|
|
|
2012-07-22 16:10:58 +02:00
|
|
|
Client *m_client;
|
2013-01-03 18:59:28 +01:00
|
|
|
std::string m_formname;
|
2012-07-22 16:10:58 +02:00
|
|
|
};
|
|
|
|
|
2011-10-15 13:46:59 +02:00
|
|
|
/* Respawn menu callback */
|
|
|
|
|
|
|
|
class MainRespawnInitiator: public IRespawnInitiator
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
MainRespawnInitiator(bool *active, Client *client):
|
|
|
|
m_active(active), m_client(client)
|
|
|
|
{
|
|
|
|
*m_active = true;
|
|
|
|
}
|
|
|
|
void respawn()
|
|
|
|
{
|
|
|
|
*m_active = false;
|
|
|
|
m_client->sendRespawn();
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
bool *m_active;
|
|
|
|
Client *m_client;
|
|
|
|
};
|
|
|
|
|
2012-06-03 17:30:34 +02:00
|
|
|
/* Form update callback */
|
|
|
|
|
|
|
|
class NodeMetadataFormSource: public IFormSource
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NodeMetadataFormSource(ClientMap *map, v3s16 p):
|
|
|
|
m_map(map),
|
|
|
|
m_p(p)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
std::string getForm()
|
|
|
|
{
|
|
|
|
NodeMetadata *meta = m_map->getNodeMetadata(m_p);
|
|
|
|
if(!meta)
|
|
|
|
return "";
|
|
|
|
return meta->getString("formspec");
|
|
|
|
}
|
2012-07-15 18:19:38 +02:00
|
|
|
std::string resolveText(std::string str)
|
|
|
|
{
|
|
|
|
NodeMetadata *meta = m_map->getNodeMetadata(m_p);
|
|
|
|
if(!meta)
|
|
|
|
return str;
|
|
|
|
return meta->resolveString(str);
|
|
|
|
}
|
2012-06-03 17:30:34 +02:00
|
|
|
|
|
|
|
ClientMap *m_map;
|
|
|
|
v3s16 m_p;
|
|
|
|
};
|
|
|
|
|
2012-07-19 13:09:16 +02:00
|
|
|
class PlayerInventoryFormSource: public IFormSource
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
PlayerInventoryFormSource(Client *client):
|
|
|
|
m_client(client)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
std::string getForm()
|
|
|
|
{
|
|
|
|
LocalPlayer* player = m_client->getEnv().getLocalPlayer();
|
|
|
|
return player->inventory_formspec;
|
|
|
|
}
|
|
|
|
|
|
|
|
Client *m_client;
|
|
|
|
};
|
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
/*
|
|
|
|
Check if a node is pointable
|
|
|
|
*/
|
|
|
|
inline bool isPointableNode(const MapNode& n,
|
|
|
|
Client *client, bool liquids_pointable)
|
|
|
|
{
|
|
|
|
const ContentFeatures &features = client->getNodeDefManager()->get(n);
|
|
|
|
return features.pointable ||
|
|
|
|
(liquids_pointable && features.isLiquid());
|
|
|
|
}
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
|
|
|
Find what the player is pointing at
|
|
|
|
*/
|
2011-11-29 16:15:18 +01:00
|
|
|
PointedThing getPointedThing(Client *client, v3f player_position,
|
2011-04-23 17:31:31 +02:00
|
|
|
v3f camera_direction, v3f camera_position,
|
2011-11-29 16:15:18 +01:00
|
|
|
core::line3d<f32> shootline, f32 d,
|
|
|
|
bool liquids_pointable,
|
|
|
|
bool look_for_object,
|
2012-03-19 04:25:09 +01:00
|
|
|
std::vector<aabb3f> &hilightboxes,
|
2011-11-29 16:15:18 +01:00
|
|
|
ClientActiveObject *&selected_object)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2011-11-29 16:15:18 +01:00
|
|
|
PointedThing result;
|
|
|
|
|
2012-03-19 04:25:09 +01:00
|
|
|
hilightboxes.clear();
|
2011-11-29 16:15:18 +01:00
|
|
|
selected_object = NULL;
|
|
|
|
|
2012-01-21 00:11:44 +01:00
|
|
|
INodeDefManager *nodedef = client->getNodeDefManager();
|
2012-03-15 22:54:10 +01:00
|
|
|
ClientMap &map = client->getEnv().getClientMap();
|
2012-01-21 00:11:44 +01:00
|
|
|
|
2014-01-02 14:26:21 +01:00
|
|
|
f32 mindistance = BS * 1001;
|
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
// First try to find a pointed at active object
|
|
|
|
if(look_for_object)
|
|
|
|
{
|
|
|
|
selected_object = client->getSelectedActiveObject(d*BS,
|
|
|
|
camera_position, shootline);
|
|
|
|
|
2012-03-19 04:25:09 +01:00
|
|
|
if(selected_object != NULL)
|
|
|
|
{
|
|
|
|
if(selected_object->doShowSelectionBox())
|
|
|
|
{
|
|
|
|
aabb3f *selection_box = selected_object->getSelectionBox();
|
|
|
|
// Box should exist because object was
|
|
|
|
// returned in the first place
|
|
|
|
assert(selection_box);
|
|
|
|
|
|
|
|
v3f pos = selected_object->getPosition();
|
|
|
|
hilightboxes.push_back(aabb3f(
|
|
|
|
selection_box->MinEdge + pos,
|
|
|
|
selection_box->MaxEdge + pos));
|
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
|
2014-01-02 14:26:21 +01:00
|
|
|
mindistance = (selected_object->getPosition() - camera_position).getLength();
|
2011-11-29 16:15:18 +01:00
|
|
|
|
2012-03-19 04:25:09 +01:00
|
|
|
result.type = POINTEDTHING_OBJECT;
|
|
|
|
result.object_id = selected_object->getId();
|
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// That didn't work, try to find a pointed at node
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
|
|
|
|
v3s16 pos_i = floatToInt(player_position, BS);
|
|
|
|
|
2011-10-16 13:57:53 +02:00
|
|
|
/*infostream<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
|
2011-04-23 17:31:31 +02:00
|
|
|
<<std::endl;*/
|
|
|
|
|
|
|
|
s16 a = d;
|
|
|
|
s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);
|
|
|
|
s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);
|
|
|
|
s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);
|
|
|
|
s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);
|
|
|
|
s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);
|
|
|
|
s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);
|
|
|
|
|
2012-07-04 21:06:19 +02:00
|
|
|
// Prevent signed number overflow
|
|
|
|
if(yend==32767)
|
|
|
|
yend=32766;
|
|
|
|
if(zend==32767)
|
|
|
|
zend=32766;
|
|
|
|
if(xend==32767)
|
|
|
|
xend=32766;
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
for(s16 y = ystart; y <= yend; y++)
|
|
|
|
for(s16 z = zstart; z <= zend; z++)
|
|
|
|
for(s16 x = xstart; x <= xend; x++)
|
|
|
|
{
|
|
|
|
MapNode n;
|
|
|
|
try
|
|
|
|
{
|
2012-03-15 22:54:10 +01:00
|
|
|
n = map.getNode(v3s16(x,y,z));
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
catch(InvalidPositionException &e)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
if(!isPointableNode(n, client, liquids_pointable))
|
|
|
|
continue;
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2012-03-19 04:25:09 +01:00
|
|
|
std::vector<aabb3f> boxes = n.getSelectionBoxes(nodedef);
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
v3s16 np(x,y,z);
|
|
|
|
v3f npf = intToFloat(np, BS);
|
2012-03-19 04:25:09 +01:00
|
|
|
|
|
|
|
for(std::vector<aabb3f>::const_iterator
|
|
|
|
i = boxes.begin();
|
|
|
|
i != boxes.end(); i++)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2012-03-19 04:25:09 +01:00
|
|
|
aabb3f box = *i;
|
2011-11-13 11:31:05 +01:00
|
|
|
box.MinEdge += npf;
|
|
|
|
box.MaxEdge += npf;
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2012-03-19 04:25:09 +01:00
|
|
|
for(u16 j=0; j<6; j++)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2012-03-19 04:25:09 +01:00
|
|
|
v3s16 facedir = g_6dirs[j];
|
|
|
|
aabb3f facebox = box;
|
|
|
|
|
|
|
|
f32 d = 0.001*BS;
|
|
|
|
if(facedir.X > 0)
|
|
|
|
facebox.MinEdge.X = facebox.MaxEdge.X-d;
|
|
|
|
else if(facedir.X < 0)
|
|
|
|
facebox.MaxEdge.X = facebox.MinEdge.X+d;
|
|
|
|
else if(facedir.Y > 0)
|
|
|
|
facebox.MinEdge.Y = facebox.MaxEdge.Y-d;
|
|
|
|
else if(facedir.Y < 0)
|
|
|
|
facebox.MaxEdge.Y = facebox.MinEdge.Y+d;
|
|
|
|
else if(facedir.Z > 0)
|
|
|
|
facebox.MinEdge.Z = facebox.MaxEdge.Z-d;
|
|
|
|
else if(facedir.Z < 0)
|
|
|
|
facebox.MaxEdge.Z = facebox.MinEdge.Z+d;
|
|
|
|
|
|
|
|
v3f centerpoint = facebox.getCenter();
|
2011-11-14 21:57:58 +01:00
|
|
|
f32 distance = (centerpoint - camera_position).getLength();
|
|
|
|
if(distance >= mindistance)
|
|
|
|
continue;
|
2012-03-19 04:25:09 +01:00
|
|
|
if(!facebox.intersectsWithLine(shootline))
|
2011-11-14 21:57:58 +01:00
|
|
|
continue;
|
2012-03-19 04:25:09 +01:00
|
|
|
|
|
|
|
v3s16 np_above = np + facedir;
|
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
result.type = POINTEDTHING_NODE;
|
|
|
|
result.node_undersurface = np;
|
2012-03-19 04:25:09 +01:00
|
|
|
result.node_abovesurface = np_above;
|
2011-11-14 21:57:58 +01:00
|
|
|
mindistance = distance;
|
2011-06-08 05:27:51 +02:00
|
|
|
|
2012-03-19 04:25:09 +01:00
|
|
|
hilightboxes.clear();
|
|
|
|
for(std::vector<aabb3f>::const_iterator
|
|
|
|
i2 = boxes.begin();
|
|
|
|
i2 != boxes.end(); i2++)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2012-03-19 04:25:09 +01:00
|
|
|
aabb3f box = *i2;
|
|
|
|
box.MinEdge += npf + v3f(-d,-d,-d);
|
|
|
|
box.MaxEdge += npf + v3f(d,d,d);
|
|
|
|
hilightboxes.push_back(box);
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // for coords
|
2011-11-29 16:15:18 +01:00
|
|
|
|
|
|
|
return result;
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
|
2011-06-26 19:00:04 +02:00
|
|
|
/*
|
|
|
|
Draws a screen with a single text on it.
|
|
|
|
Text will be removed when the screen is drawn the next time.
|
2013-05-08 15:03:42 +02:00
|
|
|
Additionally, a progressbar can be drawn when percent is set between 0 and 100.
|
2011-06-26 19:00:04 +02:00
|
|
|
*/
|
|
|
|
/*gui::IGUIStaticText **/
|
|
|
|
void draw_load_screen(const std::wstring &text,
|
2013-05-08 15:03:42 +02:00
|
|
|
IrrlichtDevice* device, gui::IGUIFont* font,
|
2013-05-09 18:23:48 +02:00
|
|
|
float dtime=0 ,int percent=0, bool clouds=true)
|
2011-06-26 19:00:04 +02:00
|
|
|
{
|
2013-05-08 15:03:42 +02:00
|
|
|
video::IVideoDriver* driver = device->getVideoDriver();
|
2011-06-26 19:00:04 +02:00
|
|
|
v2u32 screensize = driver->getScreenSize();
|
|
|
|
const wchar_t *loadingtext = text.c_str();
|
|
|
|
core::vector2d<u32> textsize_u = font->getDimension(loadingtext);
|
|
|
|
core::vector2d<s32> textsize(textsize_u.X,textsize_u.Y);
|
|
|
|
core::vector2d<s32> center(screensize.X/2, screensize.Y/2);
|
|
|
|
core::rect<s32> textrect(center - textsize/2, center + textsize/2);
|
|
|
|
|
|
|
|
gui::IGUIStaticText *guitext = guienv->addStaticText(
|
|
|
|
loadingtext, textrect, false, false);
|
|
|
|
guitext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
|
|
|
|
2013-05-09 18:23:48 +02:00
|
|
|
bool cloud_menu_background = clouds && g_settings->getBool("menu_clouds");
|
|
|
|
if (cloud_menu_background)
|
2013-05-08 15:03:42 +02:00
|
|
|
{
|
2013-05-09 18:23:48 +02:00
|
|
|
g_menuclouds->step(dtime*3);
|
|
|
|
g_menuclouds->render();
|
2013-05-08 15:03:42 +02:00
|
|
|
driver->beginScene(true, true, video::SColor(255,140,186,250));
|
2013-05-09 18:23:48 +02:00
|
|
|
g_menucloudsmgr->drawAll();
|
2013-05-08 15:03:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
driver->beginScene(true, true, video::SColor(255,0,0,0));
|
|
|
|
if (percent >= 0 && percent <= 100) // draw progress bar
|
|
|
|
{
|
|
|
|
core::vector2d<s32> barsize(256,32);
|
|
|
|
core::rect<s32> barrect(center-barsize/2, center+barsize/2);
|
|
|
|
driver->draw2DRectangle(video::SColor(255,255,255,255),barrect, NULL); // border
|
2013-05-09 18:23:48 +02:00
|
|
|
driver->draw2DRectangle(video::SColor(255,64,64,64), core::rect<s32> (
|
2013-05-08 15:03:42 +02:00
|
|
|
barrect.UpperLeftCorner+1,
|
|
|
|
barrect.LowerRightCorner-1), NULL); // black inside the bar
|
|
|
|
driver->draw2DRectangle(video::SColor(255,128,128,128), core::rect<s32> (
|
|
|
|
barrect.UpperLeftCorner+1,
|
|
|
|
core::vector2d<s32>(
|
|
|
|
barrect.LowerRightCorner.X-(barsize.X-1)+percent*(barsize.X-2)/100,
|
|
|
|
barrect.LowerRightCorner.Y-1)), NULL); // the actual progress
|
|
|
|
}
|
2011-06-26 19:00:04 +02:00
|
|
|
guienv->drawAll();
|
|
|
|
driver->endScene();
|
|
|
|
|
|
|
|
guitext->remove();
|
|
|
|
|
|
|
|
//return guitext;
|
|
|
|
}
|
|
|
|
|
2012-02-01 00:56:30 +01:00
|
|
|
/* Profiler display */
|
|
|
|
|
|
|
|
void update_profiler_gui(gui::IGUIStaticText *guitext_profiler,
|
|
|
|
gui::IGUIFont *font, u32 text_height,
|
|
|
|
u32 show_profiler, u32 show_profiler_max)
|
|
|
|
{
|
|
|
|
if(show_profiler == 0)
|
|
|
|
{
|
|
|
|
guitext_profiler->setVisible(false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
std::ostringstream os(std::ios_base::binary);
|
|
|
|
g_profiler->printPage(os, show_profiler, show_profiler_max);
|
|
|
|
std::wstring text = narrow_to_wide(os.str());
|
|
|
|
guitext_profiler->setText(text.c_str());
|
|
|
|
guitext_profiler->setVisible(true);
|
|
|
|
|
|
|
|
s32 w = font->getDimension(text.c_str()).Width;
|
|
|
|
if(w < 400)
|
|
|
|
w = 400;
|
|
|
|
core::rect<s32> rect(6, 4+(text_height+5)*2, 12+w,
|
|
|
|
8+(text_height+5)*2 +
|
|
|
|
font->getDimension(text.c_str()).Height);
|
|
|
|
guitext_profiler->setRelativePosition(rect);
|
|
|
|
guitext_profiler->setVisible(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-21 02:33:02 +01:00
|
|
|
class ProfilerGraph
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
struct Piece{
|
|
|
|
Profiler::GraphValues values;
|
|
|
|
};
|
|
|
|
struct Meta{
|
|
|
|
float min;
|
|
|
|
float max;
|
|
|
|
video::SColor color;
|
|
|
|
Meta(float initial=0, video::SColor color=
|
|
|
|
video::SColor(255,255,255,255)):
|
|
|
|
min(initial),
|
|
|
|
max(initial),
|
|
|
|
color(color)
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
std::list<Piece> m_log;
|
|
|
|
public:
|
|
|
|
u32 m_log_max_size;
|
|
|
|
|
|
|
|
ProfilerGraph():
|
|
|
|
m_log_max_size(200)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void put(const Profiler::GraphValues &values)
|
|
|
|
{
|
|
|
|
Piece piece;
|
|
|
|
piece.values = values;
|
|
|
|
m_log.push_back(piece);
|
|
|
|
while(m_log.size() > m_log_max_size)
|
|
|
|
m_log.erase(m_log.begin());
|
|
|
|
}
|
|
|
|
|
|
|
|
void draw(s32 x_left, s32 y_bottom, video::IVideoDriver *driver,
|
|
|
|
gui::IGUIFont* font) const
|
|
|
|
{
|
|
|
|
std::map<std::string, Meta> m_meta;
|
|
|
|
for(std::list<Piece>::const_iterator k = m_log.begin();
|
|
|
|
k != m_log.end(); k++)
|
|
|
|
{
|
|
|
|
const Piece &piece = *k;
|
|
|
|
for(Profiler::GraphValues::const_iterator i = piece.values.begin();
|
|
|
|
i != piece.values.end(); i++){
|
|
|
|
const std::string &id = i->first;
|
|
|
|
const float &value = i->second;
|
|
|
|
std::map<std::string, Meta>::iterator j =
|
|
|
|
m_meta.find(id);
|
|
|
|
if(j == m_meta.end()){
|
|
|
|
m_meta[id] = Meta(value);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(value < j->second.min)
|
|
|
|
j->second.min = value;
|
|
|
|
if(value > j->second.max)
|
|
|
|
j->second.max = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Assign colors
|
|
|
|
static const video::SColor usable_colors[] = {
|
|
|
|
video::SColor(255,255,100,100),
|
|
|
|
video::SColor(255,90,225,90),
|
2012-03-21 13:09:32 +01:00
|
|
|
video::SColor(255,100,100,255),
|
|
|
|
video::SColor(255,255,150,50),
|
|
|
|
video::SColor(255,220,220,100)
|
2012-03-21 02:33:02 +01:00
|
|
|
};
|
|
|
|
static const u32 usable_colors_count =
|
|
|
|
sizeof(usable_colors) / sizeof(*usable_colors);
|
|
|
|
u32 next_color_i = 0;
|
|
|
|
for(std::map<std::string, Meta>::iterator i = m_meta.begin();
|
|
|
|
i != m_meta.end(); i++){
|
|
|
|
Meta &meta = i->second;
|
|
|
|
video::SColor color(255,200,200,200);
|
|
|
|
if(next_color_i < usable_colors_count)
|
|
|
|
color = usable_colors[next_color_i++];
|
|
|
|
meta.color = color;
|
|
|
|
}
|
|
|
|
|
|
|
|
s32 graphh = 50;
|
|
|
|
s32 textx = x_left + m_log_max_size + 15;
|
|
|
|
s32 textx2 = textx + 200 - 15;
|
|
|
|
|
|
|
|
// Draw background
|
|
|
|
/*{
|
|
|
|
u32 num_graphs = m_meta.size();
|
|
|
|
core::rect<s32> rect(x_left, y_bottom - num_graphs*graphh,
|
|
|
|
textx2, y_bottom);
|
|
|
|
video::SColor bgcolor(120,0,0,0);
|
|
|
|
driver->draw2DRectangle(bgcolor, rect, NULL);
|
|
|
|
}*/
|
|
|
|
|
|
|
|
s32 meta_i = 0;
|
|
|
|
for(std::map<std::string, Meta>::const_iterator i = m_meta.begin();
|
|
|
|
i != m_meta.end(); i++){
|
|
|
|
const std::string &id = i->first;
|
|
|
|
const Meta &meta = i->second;
|
|
|
|
s32 x = x_left;
|
|
|
|
s32 y = y_bottom - meta_i * 50;
|
|
|
|
float show_min = meta.min;
|
|
|
|
float show_max = meta.max;
|
2012-03-21 13:09:32 +01:00
|
|
|
if(show_min >= -0.0001 && show_max >= -0.0001){
|
2012-03-21 02:33:02 +01:00
|
|
|
if(show_min <= show_max * 0.5)
|
|
|
|
show_min = 0;
|
|
|
|
}
|
|
|
|
s32 texth = 15;
|
|
|
|
char buf[10];
|
|
|
|
snprintf(buf, 10, "%.3g", show_max);
|
|
|
|
font->draw(narrow_to_wide(buf).c_str(),
|
|
|
|
core::rect<s32>(textx, y - graphh,
|
|
|
|
textx2, y - graphh + texth),
|
|
|
|
meta.color);
|
|
|
|
snprintf(buf, 10, "%.3g", show_min);
|
|
|
|
font->draw(narrow_to_wide(buf).c_str(),
|
|
|
|
core::rect<s32>(textx, y - texth,
|
|
|
|
textx2, y),
|
|
|
|
meta.color);
|
|
|
|
font->draw(narrow_to_wide(id).c_str(),
|
|
|
|
core::rect<s32>(textx, y - graphh/2 - texth/2,
|
|
|
|
textx2, y - graphh/2 + texth/2),
|
|
|
|
meta.color);
|
2012-03-21 14:05:51 +01:00
|
|
|
s32 graph1y = y;
|
|
|
|
s32 graph1h = graphh;
|
|
|
|
bool relativegraph = (show_min != 0 && show_min != show_max);
|
|
|
|
float lastscaledvalue = 0.0;
|
|
|
|
bool lastscaledvalue_exists = false;
|
2012-03-21 02:33:02 +01:00
|
|
|
for(std::list<Piece>::const_iterator j = m_log.begin();
|
|
|
|
j != m_log.end(); j++)
|
|
|
|
{
|
|
|
|
const Piece &piece = *j;
|
|
|
|
float value = 0;
|
|
|
|
bool value_exists = false;
|
|
|
|
Profiler::GraphValues::const_iterator k =
|
|
|
|
piece.values.find(id);
|
|
|
|
if(k != piece.values.end()){
|
|
|
|
value = k->second;
|
|
|
|
value_exists = true;
|
|
|
|
}
|
|
|
|
if(!value_exists){
|
|
|
|
x++;
|
2012-03-21 14:05:51 +01:00
|
|
|
lastscaledvalue_exists = false;
|
2012-03-21 02:33:02 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
float scaledvalue = 1.0;
|
|
|
|
if(show_max != show_min)
|
|
|
|
scaledvalue = (value - show_min) / (show_max - show_min);
|
|
|
|
if(scaledvalue == 1.0 && value == 0){
|
|
|
|
x++;
|
2012-03-21 14:05:51 +01:00
|
|
|
lastscaledvalue_exists = false;
|
2012-03-21 02:33:02 +01:00
|
|
|
continue;
|
|
|
|
}
|
2012-03-21 14:05:51 +01:00
|
|
|
if(relativegraph){
|
|
|
|
if(lastscaledvalue_exists){
|
|
|
|
s32 ivalue1 = lastscaledvalue * graph1h;
|
|
|
|
s32 ivalue2 = scaledvalue * graph1h;
|
|
|
|
driver->draw2DLine(v2s32(x-1, graph1y - ivalue1),
|
|
|
|
v2s32(x, graph1y - ivalue2), meta.color);
|
|
|
|
}
|
|
|
|
lastscaledvalue = scaledvalue;
|
|
|
|
lastscaledvalue_exists = true;
|
|
|
|
} else{
|
|
|
|
s32 ivalue = scaledvalue * graph1h;
|
|
|
|
driver->draw2DLine(v2s32(x, graph1y),
|
|
|
|
v2s32(x, graph1y - ivalue), meta.color);
|
|
|
|
}
|
2012-03-21 02:33:02 +01:00
|
|
|
x++;
|
|
|
|
}
|
|
|
|
meta_i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-03-24 02:28:08 +01:00
|
|
|
class NodeDugEvent: public MtEvent
|
2012-03-23 19:23:03 +01:00
|
|
|
{
|
|
|
|
public:
|
2012-03-24 02:28:08 +01:00
|
|
|
v3s16 p;
|
|
|
|
MapNode n;
|
2012-03-23 23:33:58 +01:00
|
|
|
|
2012-03-24 02:28:08 +01:00
|
|
|
NodeDugEvent(v3s16 p, MapNode n):
|
|
|
|
p(p),
|
|
|
|
n(n)
|
|
|
|
{}
|
|
|
|
const char* getType() const
|
|
|
|
{return "NodeDug";}
|
|
|
|
};
|
|
|
|
|
|
|
|
class SoundMaker
|
|
|
|
{
|
|
|
|
ISoundManager *m_sound;
|
|
|
|
INodeDefManager *m_ndef;
|
|
|
|
public:
|
2012-03-23 23:33:58 +01:00
|
|
|
float m_player_step_timer;
|
2012-03-23 19:23:03 +01:00
|
|
|
|
|
|
|
SimpleSoundSpec m_player_step_sound;
|
2012-03-23 23:33:58 +01:00
|
|
|
SimpleSoundSpec m_player_leftpunch_sound;
|
|
|
|
SimpleSoundSpec m_player_rightpunch_sound;
|
2012-03-23 19:23:03 +01:00
|
|
|
|
2012-03-24 02:28:08 +01:00
|
|
|
SoundMaker(ISoundManager *sound, INodeDefManager *ndef):
|
2012-03-23 19:23:03 +01:00
|
|
|
m_sound(sound),
|
2012-03-24 02:28:08 +01:00
|
|
|
m_ndef(ndef),
|
2012-03-23 19:23:03 +01:00
|
|
|
m_player_step_timer(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void playPlayerStep()
|
|
|
|
{
|
|
|
|
if(m_player_step_timer <= 0 && m_player_step_sound.exists()){
|
|
|
|
m_player_step_timer = 0.03;
|
|
|
|
m_sound->playSound(m_player_step_sound, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void viewBobbingStep(MtEvent *e, void *data)
|
|
|
|
{
|
|
|
|
SoundMaker *sm = (SoundMaker*)data;
|
|
|
|
sm->playPlayerStep();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void playerRegainGround(MtEvent *e, void *data)
|
|
|
|
{
|
|
|
|
SoundMaker *sm = (SoundMaker*)data;
|
|
|
|
sm->playPlayerStep();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void playerJump(MtEvent *e, void *data)
|
|
|
|
{
|
2012-03-23 23:33:58 +01:00
|
|
|
//SoundMaker *sm = (SoundMaker*)data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cameraPunchLeft(MtEvent *e, void *data)
|
|
|
|
{
|
|
|
|
SoundMaker *sm = (SoundMaker*)data;
|
2012-03-24 02:28:08 +01:00
|
|
|
sm->m_sound->playSound(sm->m_player_leftpunch_sound, false);
|
2012-03-23 23:33:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void cameraPunchRight(MtEvent *e, void *data)
|
|
|
|
{
|
|
|
|
SoundMaker *sm = (SoundMaker*)data;
|
2012-03-24 02:28:08 +01:00
|
|
|
sm->m_sound->playSound(sm->m_player_rightpunch_sound, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void nodeDug(MtEvent *e, void *data)
|
|
|
|
{
|
|
|
|
SoundMaker *sm = (SoundMaker*)data;
|
|
|
|
NodeDugEvent *nde = (NodeDugEvent*)e;
|
|
|
|
sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false);
|
2012-03-23 19:23:03 +01:00
|
|
|
}
|
|
|
|
|
2013-04-17 20:13:47 +02:00
|
|
|
static void playerDamage(MtEvent *e, void *data)
|
|
|
|
{
|
|
|
|
SoundMaker *sm = (SoundMaker*)data;
|
|
|
|
sm->m_sound->playSound(SimpleSoundSpec("player_damage", 0.5), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void playerFallingDamage(MtEvent *e, void *data)
|
|
|
|
{
|
|
|
|
SoundMaker *sm = (SoundMaker*)data;
|
|
|
|
sm->m_sound->playSound(SimpleSoundSpec("player_falling_damage", 0.5), false);
|
|
|
|
}
|
|
|
|
|
2012-03-23 19:23:03 +01:00
|
|
|
void registerReceiver(MtEventManager *mgr)
|
|
|
|
{
|
|
|
|
mgr->reg("ViewBobbingStep", SoundMaker::viewBobbingStep, this);
|
|
|
|
mgr->reg("PlayerRegainGround", SoundMaker::playerRegainGround, this);
|
|
|
|
mgr->reg("PlayerJump", SoundMaker::playerJump, this);
|
2012-03-23 23:33:58 +01:00
|
|
|
mgr->reg("CameraPunchLeft", SoundMaker::cameraPunchLeft, this);
|
|
|
|
mgr->reg("CameraPunchRight", SoundMaker::cameraPunchRight, this);
|
2012-03-24 02:28:08 +01:00
|
|
|
mgr->reg("NodeDug", SoundMaker::nodeDug, this);
|
2013-04-17 20:13:47 +02:00
|
|
|
mgr->reg("PlayerDamage", SoundMaker::playerDamage, this);
|
|
|
|
mgr->reg("PlayerFallingDamage", SoundMaker::playerFallingDamage, this);
|
2012-03-23 19:23:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void step(float dtime)
|
|
|
|
{
|
|
|
|
m_player_step_timer -= dtime;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-03-24 02:28:08 +01:00
|
|
|
// Locally stored sounds don't need to be preloaded because of this
|
|
|
|
class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
|
|
|
|
{
|
|
|
|
std::set<std::string> m_fetched;
|
|
|
|
public:
|
|
|
|
|
|
|
|
void fetchSounds(const std::string &name,
|
|
|
|
std::set<std::string> &dst_paths,
|
2012-03-25 13:47:51 +02:00
|
|
|
std::set<std::string> &dst_datas)
|
2012-03-24 02:28:08 +01:00
|
|
|
{
|
|
|
|
if(m_fetched.count(name))
|
|
|
|
return;
|
|
|
|
m_fetched.insert(name);
|
|
|
|
std::string base = porting::path_share + DIR_DELIM + "testsounds";
|
|
|
|
dst_paths.insert(base + DIR_DELIM + name + ".ogg");
|
2012-03-25 17:51:05 +02:00
|
|
|
dst_paths.insert(base + DIR_DELIM + name + ".0.ogg");
|
|
|
|
dst_paths.insert(base + DIR_DELIM + name + ".1.ogg");
|
|
|
|
dst_paths.insert(base + DIR_DELIM + name + ".2.ogg");
|
|
|
|
dst_paths.insert(base + DIR_DELIM + name + ".3.ogg");
|
|
|
|
dst_paths.insert(base + DIR_DELIM + name + ".4.ogg");
|
|
|
|
dst_paths.insert(base + DIR_DELIM + name + ".5.ogg");
|
|
|
|
dst_paths.insert(base + DIR_DELIM + name + ".6.ogg");
|
|
|
|
dst_paths.insert(base + DIR_DELIM + name + ".7.ogg");
|
|
|
|
dst_paths.insert(base + DIR_DELIM + name + ".8.ogg");
|
|
|
|
dst_paths.insert(base + DIR_DELIM + name + ".9.ogg");
|
2012-03-24 02:28:08 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-12-01 02:02:16 +01:00
|
|
|
class GameGlobalShaderConstantSetter : public IShaderConstantSetter
|
|
|
|
{
|
|
|
|
Sky *m_sky;
|
|
|
|
bool *m_force_fog_off;
|
|
|
|
f32 *m_fog_range;
|
2012-12-02 13:24:58 +01:00
|
|
|
Client *m_client;
|
2012-12-01 02:02:16 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
|
2012-12-02 13:24:58 +01:00
|
|
|
f32 *fog_range, Client *client):
|
2012-12-01 02:02:16 +01:00
|
|
|
m_sky(sky),
|
|
|
|
m_force_fog_off(force_fog_off),
|
2012-12-02 13:24:58 +01:00
|
|
|
m_fog_range(fog_range),
|
|
|
|
m_client(client)
|
2012-12-01 02:02:16 +01:00
|
|
|
{}
|
|
|
|
~GameGlobalShaderConstantSetter() {}
|
|
|
|
|
|
|
|
virtual void onSetConstants(video::IMaterialRendererServices *services,
|
|
|
|
bool is_highlevel)
|
|
|
|
{
|
|
|
|
if(!is_highlevel)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Background color
|
|
|
|
video::SColor bgcolor = m_sky->getBgColor();
|
|
|
|
video::SColorf bgcolorf(bgcolor);
|
|
|
|
float bgcolorfa[4] = {
|
|
|
|
bgcolorf.r,
|
|
|
|
bgcolorf.g,
|
|
|
|
bgcolorf.b,
|
|
|
|
bgcolorf.a,
|
|
|
|
};
|
|
|
|
services->setPixelShaderConstant("skyBgColor", bgcolorfa, 4);
|
|
|
|
|
|
|
|
// Fog distance
|
2013-09-03 13:21:04 +02:00
|
|
|
float fog_distance = 10000*BS;
|
|
|
|
if(g_settings->getBool("enable_fog") && !*m_force_fog_off)
|
|
|
|
fog_distance = *m_fog_range;
|
2012-12-01 02:02:16 +01:00
|
|
|
services->setPixelShaderConstant("fogDistance", &fog_distance, 1);
|
|
|
|
|
2012-12-02 13:24:58 +01:00
|
|
|
// 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);
|
2013-07-04 02:36:32 +02:00
|
|
|
|
2013-12-03 17:21:40 +01:00
|
|
|
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();
|
2014-01-06 12:45:42 +01:00
|
|
|
v3f eye_position = player->getEyePosition();
|
2013-12-03 17:21:40 +01:00
|
|
|
services->setPixelShaderConstant("eyePosition", (irr::f32*)&eye_position, 3);
|
|
|
|
services->setVertexShaderConstant("eyePosition", (irr::f32*)&eye_position, 3);
|
|
|
|
|
2013-07-04 02:36:32 +02:00
|
|
|
// Normal map texture layer
|
2013-12-03 17:21:40 +01:00
|
|
|
int layer1 = 1;
|
|
|
|
int layer2 = 2;
|
2013-07-30 04:18:11 +02:00
|
|
|
// before 1.8 there isn't a "integer interface", only float
|
|
|
|
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
|
2013-12-03 17:21:40 +01:00
|
|
|
services->setPixelShaderConstant("normalTexture" , (irr::f32*)&layer1, 1);
|
|
|
|
services->setPixelShaderConstant("useNormalmap" , (irr::f32*)&layer2, 1);
|
2013-07-30 04:18:11 +02:00
|
|
|
#else
|
2013-12-03 17:21:40 +01:00
|
|
|
services->setPixelShaderConstant("normalTexture" , (irr::s32*)&layer1, 1);
|
|
|
|
services->setPixelShaderConstant("useNormalmap" , (irr::s32*)&layer2, 1);
|
2013-07-30 04:18:11 +02:00
|
|
|
#endif
|
2012-12-02 13:24:58 +01:00
|
|
|
}
|
2012-12-01 02:02:16 +01:00
|
|
|
};
|
|
|
|
|
2013-06-19 23:09:18 +02:00
|
|
|
bool nodePlacementPrediction(Client &client,
|
2013-04-27 03:47:52 +02:00
|
|
|
const ItemDefinition &playeritem_def,
|
|
|
|
v3s16 nodepos, v3s16 neighbourpos)
|
|
|
|
{
|
|
|
|
std::string prediction = playeritem_def.node_placement_prediction;
|
|
|
|
INodeDefManager *nodedef = client.ndef();
|
|
|
|
ClientMap &map = client.getEnv().getClientMap();
|
|
|
|
|
|
|
|
if(prediction != "" && !nodedef->get(map.getNode(nodepos)).rightclickable)
|
|
|
|
{
|
|
|
|
verbosestream<<"Node placement prediction for "
|
|
|
|
<<playeritem_def.name<<" is "
|
|
|
|
<<prediction<<std::endl;
|
|
|
|
v3s16 p = neighbourpos;
|
|
|
|
// Place inside node itself if buildable_to
|
|
|
|
try{
|
|
|
|
MapNode n_under = map.getNode(nodepos);
|
|
|
|
if(nodedef->get(n_under).buildable_to)
|
|
|
|
p = nodepos;
|
2013-04-20 23:01:02 +02:00
|
|
|
else if (!nodedef->get(map.getNode(p)).buildable_to)
|
2013-06-19 23:09:18 +02:00
|
|
|
return false;
|
2013-04-27 03:47:52 +02:00
|
|
|
}catch(InvalidPositionException &e){}
|
|
|
|
// Find id of predicted node
|
|
|
|
content_t id;
|
|
|
|
bool found = nodedef->getId(prediction, id);
|
|
|
|
if(!found){
|
|
|
|
errorstream<<"Node placement prediction failed for "
|
|
|
|
<<playeritem_def.name<<" (places "
|
|
|
|
<<prediction
|
|
|
|
<<") - Name not known"<<std::endl;
|
2013-06-19 23:09:18 +02:00
|
|
|
return false;
|
2013-04-27 03:47:52 +02:00
|
|
|
}
|
2013-05-24 01:38:57 +02:00
|
|
|
// Predict param2 for facedir and wallmounted nodes
|
2013-04-27 03:47:52 +02:00
|
|
|
u8 param2 = 0;
|
|
|
|
if(nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED){
|
|
|
|
v3s16 dir = nodepos - neighbourpos;
|
|
|
|
if(abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))){
|
|
|
|
param2 = dir.Y < 0 ? 1 : 0;
|
|
|
|
} else if(abs(dir.X) > abs(dir.Z)){
|
|
|
|
param2 = dir.X < 0 ? 3 : 2;
|
|
|
|
} else {
|
|
|
|
param2 = dir.Z < 0 ? 5 : 4;
|
|
|
|
}
|
|
|
|
}
|
2013-05-24 01:38:57 +02:00
|
|
|
if(nodedef->get(id).param_type_2 == CPT2_FACEDIR){
|
|
|
|
v3s16 dir = nodepos - floatToInt(client.getEnv().getLocalPlayer()->getPosition(), BS);
|
|
|
|
if(abs(dir.X) > abs(dir.Z)){
|
|
|
|
param2 = dir.X < 0 ? 3 : 1;
|
|
|
|
} else {
|
|
|
|
param2 = dir.Z < 0 ? 2 : 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(param2 >= 0 && param2 <= 5);
|
|
|
|
//Check attachment if node is in group attached_node
|
|
|
|
if(((ItemGroupList) nodedef->get(id).groups)["attached_node"] != 0){
|
|
|
|
static v3s16 wallmounted_dirs[8] = {
|
|
|
|
v3s16(0,1,0),
|
|
|
|
v3s16(0,-1,0),
|
|
|
|
v3s16(1,0,0),
|
|
|
|
v3s16(-1,0,0),
|
|
|
|
v3s16(0,0,1),
|
|
|
|
v3s16(0,0,-1),
|
|
|
|
};
|
|
|
|
v3s16 pp;
|
|
|
|
if(nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED)
|
|
|
|
pp = p + wallmounted_dirs[param2];
|
|
|
|
else
|
|
|
|
pp = p + v3s16(0,-1,0);
|
|
|
|
if(!nodedef->get(map.getNode(pp)).walkable)
|
2013-06-19 23:09:18 +02:00
|
|
|
return false;
|
2013-05-24 01:38:57 +02:00
|
|
|
}
|
2013-04-27 03:47:52 +02:00
|
|
|
// Add node to client map
|
|
|
|
MapNode n(id, 0, param2);
|
|
|
|
try{
|
2014-01-15 21:26:54 +01:00
|
|
|
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;
|
|
|
|
}
|
2013-04-27 03:47:52 +02:00
|
|
|
}catch(InvalidPositionException &e){
|
|
|
|
errorstream<<"Node placement prediction failed for "
|
|
|
|
<<playeritem_def.name<<" (places "
|
|
|
|
<<prediction
|
|
|
|
<<") - Position not loaded"<<std::endl;
|
|
|
|
}
|
|
|
|
}
|
2013-06-19 23:09:18 +02:00
|
|
|
return false;
|
2013-04-27 03:47:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
void the_game(
|
|
|
|
bool &kill,
|
|
|
|
bool random_input,
|
|
|
|
InputHandler *input,
|
|
|
|
IrrlichtDevice *device,
|
|
|
|
gui::IGUIFont* font,
|
|
|
|
std::string map_dir,
|
|
|
|
std::string playername,
|
2011-05-20 21:28:03 +02:00
|
|
|
std::string password,
|
2012-03-11 13:54:23 +01:00
|
|
|
std::string address, // If "", local server is used
|
2011-04-23 17:31:31 +02:00
|
|
|
u16 port,
|
2011-07-30 18:49:42 +02:00
|
|
|
std::wstring &error_message,
|
2012-03-11 13:54:23 +01:00
|
|
|
ChatBackend &chat_backend,
|
2012-03-15 14:20:20 +01:00
|
|
|
const SubgameSpec &gamespec, // Used for local game,
|
|
|
|
bool simple_singleplayer_mode
|
2011-04-23 17:31:31 +02:00
|
|
|
)
|
|
|
|
{
|
2013-01-02 20:45:04 +01:00
|
|
|
FormspecFormSource* current_formspec = 0;
|
2013-04-07 16:34:35 +02:00
|
|
|
TextDestPlayerInventory* current_textdest = 0;
|
2011-04-23 17:31:31 +02:00
|
|
|
video::IVideoDriver* driver = device->getVideoDriver();
|
|
|
|
scene::ISceneManager* smgr = device->getSceneManager();
|
2011-06-26 19:00:04 +02:00
|
|
|
|
|
|
|
// Calculate text height using the font
|
|
|
|
u32 text_height = font->getDimension(L"Random test string").Height;
|
2011-04-23 17:31:31 +02:00
|
|
|
|
|
|
|
v2u32 last_screensize(0,0);
|
2013-04-14 00:20:22 +02:00
|
|
|
v2u32 screensize = driver->getScreenSize();
|
2011-04-23 17:31:31 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Draw "Loading" screen
|
|
|
|
*/
|
|
|
|
|
2013-05-09 18:23:48 +02:00
|
|
|
{
|
|
|
|
wchar_t* text = wgettext("Loading...");
|
|
|
|
draw_load_screen(text, device, font,0,0);
|
|
|
|
delete[] text;
|
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2011-11-13 23:19:48 +01:00
|
|
|
// Create texture source
|
2011-11-14 20:41:30 +01:00
|
|
|
IWritableTextureSource *tsrc = createTextureSource(device);
|
2011-11-15 22:58:56 +01:00
|
|
|
|
2012-03-19 02:59:12 +01:00
|
|
|
// Create shader source
|
|
|
|
IWritableShaderSource *shsrc = createShaderSource(device);
|
|
|
|
|
2011-11-15 22:58:56 +01:00
|
|
|
// These will be filled by data received from the server
|
2012-01-12 06:10:39 +01:00
|
|
|
// Create item definition manager
|
|
|
|
IWritableItemDefManager *itemdef = createItemDefManager();
|
2011-11-14 20:41:30 +01:00
|
|
|
// Create node definition manager
|
2011-11-15 13:43:15 +01:00
|
|
|
IWritableNodeDefManager *nodedef = createNodeDefManager();
|
2012-03-23 14:29:30 +01:00
|
|
|
|
2012-03-24 02:28:08 +01:00
|
|
|
// Sound fetcher (useful when testing)
|
|
|
|
GameOnDemandSoundFetcher soundfetcher;
|
|
|
|
|
2012-03-23 14:29:30 +01:00
|
|
|
// Sound manager
|
|
|
|
ISoundManager *sound = NULL;
|
|
|
|
bool sound_is_dummy = false;
|
2012-03-25 10:50:29 +02:00
|
|
|
#if USE_SOUND
|
2012-04-06 14:30:36 +02:00
|
|
|
if(g_settings->getBool("enable_sound")){
|
|
|
|
infostream<<"Attempting to use OpenAL audio"<<std::endl;
|
|
|
|
sound = createOpenALSoundManager(&soundfetcher);
|
|
|
|
if(!sound)
|
|
|
|
infostream<<"Failed to initialize OpenAL audio"<<std::endl;
|
|
|
|
} else {
|
|
|
|
infostream<<"Sound disabled."<<std::endl;
|
|
|
|
}
|
2012-03-23 14:29:30 +01:00
|
|
|
#endif
|
|
|
|
if(!sound){
|
|
|
|
infostream<<"Using dummy audio."<<std::endl;
|
|
|
|
sound = &dummySoundManager;
|
|
|
|
sound_is_dummy = true;
|
|
|
|
}
|
2012-03-23 19:23:03 +01:00
|
|
|
|
2013-04-07 19:41:12 +02:00
|
|
|
Server *server = NULL;
|
|
|
|
|
|
|
|
try{
|
2012-03-23 19:23:03 +01:00
|
|
|
// Event manager
|
|
|
|
EventManager eventmgr;
|
|
|
|
|
|
|
|
// Sound maker
|
2012-03-24 02:28:08 +01:00
|
|
|
SoundMaker soundmaker(sound, nodedef);
|
2012-03-23 19:23:03 +01:00
|
|
|
soundmaker.registerReceiver(&eventmgr);
|
2012-03-23 14:29:30 +01:00
|
|
|
|
2011-11-27 13:29:48 +01:00
|
|
|
// Add chat log output for errors to be shown in chat
|
|
|
|
LogOutputBuffer chat_log_error_buf(LMT_ERROR);
|
|
|
|
|
2012-03-12 20:27:29 +01:00
|
|
|
// Create UI for modifying quicktune values
|
|
|
|
QuicktuneShortcutter quicktune;
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
|
|
|
Create server.
|
|
|
|
*/
|
2013-04-07 19:41:12 +02:00
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
if(address == ""){
|
2013-05-09 18:23:48 +02:00
|
|
|
wchar_t* text = wgettext("Creating server....");
|
|
|
|
draw_load_screen(text, device, font,0,25);
|
|
|
|
delete[] text;
|
2011-10-16 13:57:53 +02:00
|
|
|
infostream<<"Creating server"<<std::endl;
|
2013-08-11 04:09:45 +02:00
|
|
|
server = new Server(map_dir, gamespec,
|
2012-03-15 14:20:20 +01:00
|
|
|
simple_singleplayer_mode);
|
2011-04-23 17:31:31 +02:00
|
|
|
server->start(port);
|
|
|
|
}
|
2011-11-15 00:00:16 +01:00
|
|
|
|
2012-03-10 22:28:51 +01:00
|
|
|
do{ // Client scope (breakable do-while(0))
|
2011-04-23 17:31:31 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Create client
|
|
|
|
*/
|
|
|
|
|
2013-05-09 18:23:48 +02:00
|
|
|
{
|
|
|
|
wchar_t* text = wgettext("Creating client...");
|
|
|
|
draw_load_screen(text, device, font,0,50);
|
|
|
|
delete[] text;
|
|
|
|
}
|
2011-10-16 13:57:53 +02:00
|
|
|
infostream<<"Creating client"<<std::endl;
|
2011-11-14 20:41:30 +01:00
|
|
|
|
2011-09-08 01:08:47 +02:00
|
|
|
MapDrawControl draw_control;
|
2013-05-09 18:23:48 +02:00
|
|
|
|
|
|
|
{
|
|
|
|
wchar_t* text = wgettext("Resolving address...");
|
|
|
|
draw_load_screen(text, device, font,0,75);
|
|
|
|
delete[] text;
|
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
Address connect_address(0,0,0,0, port);
|
|
|
|
try{
|
|
|
|
if(address == "")
|
2013-06-23 09:31:22 +02:00
|
|
|
{
|
2011-04-23 17:31:31 +02:00
|
|
|
//connect_address.Resolve("localhost");
|
2013-06-23 09:31:22 +02:00
|
|
|
if(g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"))
|
|
|
|
{
|
|
|
|
IPv6AddressBytes addr_bytes;
|
|
|
|
addr_bytes.bytes[15] = 1;
|
|
|
|
connect_address.setAddress(&addr_bytes);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
connect_address.setAddress(127,0,0,1);
|
|
|
|
}
|
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
else
|
|
|
|
connect_address.Resolve(address.c_str());
|
|
|
|
}
|
|
|
|
catch(ResolveError &e)
|
|
|
|
{
|
2013-06-23 09:31:22 +02:00
|
|
|
error_message = L"Couldn't resolve address: " + narrow_to_wide(e.what());
|
2012-03-11 11:06:59 +01:00
|
|
|
errorstream<<wide_to_narrow(error_message)<<std::endl;
|
2012-03-10 22:28:51 +01:00
|
|
|
// Break out of client scope
|
|
|
|
break;
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
2013-06-23 09:31:22 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
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;
|
2011-04-23 23:11:23 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Attempt to connect to the server
|
|
|
|
*/
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2011-10-16 13:57:53 +02:00
|
|
|
infostream<<"Connecting to server at ";
|
|
|
|
connect_address.print(&infostream);
|
|
|
|
infostream<<std::endl;
|
2011-04-23 17:31:31 +02:00
|
|
|
client.connect(connect_address);
|
|
|
|
|
2011-11-15 22:58:56 +01:00
|
|
|
/*
|
|
|
|
Wait for server to accept connection
|
|
|
|
*/
|
|
|
|
bool could_connect = false;
|
2012-03-10 22:28:51 +01:00
|
|
|
bool connect_aborted = false;
|
2011-04-23 17:31:31 +02:00
|
|
|
try{
|
2011-04-23 23:11:23 +02:00
|
|
|
float time_counter = 0.0;
|
2012-03-10 22:28:51 +01:00
|
|
|
input->clear();
|
2013-05-09 18:23:48 +02:00
|
|
|
float fps_max = g_settings->getFloat("fps_max");
|
|
|
|
bool cloud_menu_background = g_settings->getBool("menu_clouds");
|
|
|
|
u32 lasttime = device->getTimer()->getTime();
|
2012-03-10 22:28:51 +01:00
|
|
|
while(device->run())
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2013-05-19 18:07:00 +02:00
|
|
|
f32 dtime = 0.033; // in seconds
|
2013-05-09 18:23:48 +02:00
|
|
|
if (cloud_menu_background) {
|
|
|
|
u32 time = device->getTimer()->getTime();
|
|
|
|
if(time > lasttime)
|
|
|
|
dtime = (time - lasttime) / 1000.0;
|
|
|
|
else
|
|
|
|
dtime = 0;
|
|
|
|
lasttime = time;
|
|
|
|
}
|
2011-11-15 22:58:56 +01:00
|
|
|
// Update client and server
|
2013-05-09 18:23:48 +02:00
|
|
|
client.step(dtime);
|
2011-11-15 22:58:56 +01:00
|
|
|
if(server != NULL)
|
2013-05-09 18:23:48 +02:00
|
|
|
server->step(dtime);
|
2011-11-15 22:58:56 +01:00
|
|
|
|
|
|
|
// End condition
|
|
|
|
if(client.connectedAndInitialized()){
|
2011-04-23 23:11:23 +02:00
|
|
|
could_connect = true;
|
|
|
|
break;
|
|
|
|
}
|
2011-11-15 22:58:56 +01:00
|
|
|
// Break conditions
|
2012-03-10 22:28:51 +01:00
|
|
|
if(client.accessDenied()){
|
|
|
|
error_message = L"Access denied. Reason: "
|
|
|
|
+client.accessDeniedReason();
|
2012-03-11 11:06:59 +01:00
|
|
|
errorstream<<wide_to_narrow(error_message)<<std::endl;
|
2011-05-20 21:28:03 +02:00
|
|
|
break;
|
2012-03-10 22:28:51 +01:00
|
|
|
}
|
|
|
|
if(input->wasKeyDown(EscapeKey)){
|
|
|
|
connect_aborted = true;
|
2012-03-11 11:06:59 +01:00
|
|
|
infostream<<"Connect aborted [Escape]"<<std::endl;
|
2011-04-23 23:11:23 +02:00
|
|
|
break;
|
2012-03-10 22:28:51 +01:00
|
|
|
}
|
2011-06-26 19:00:04 +02:00
|
|
|
|
2011-11-15 22:58:56 +01:00
|
|
|
// Display status
|
2013-05-09 18:23:48 +02:00
|
|
|
{
|
|
|
|
wchar_t* text = wgettext("Connecting to server...");
|
|
|
|
draw_load_screen(text, device, font, dtime, 100);
|
|
|
|
delete[] text;
|
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2013-05-09 18:23:48 +02:00
|
|
|
// On some computers framerate doesn't seem to be
|
|
|
|
// automatically limited
|
|
|
|
if (cloud_menu_background) {
|
|
|
|
// Time of frame without fps limit
|
|
|
|
float busytime;
|
|
|
|
u32 busytime_u32;
|
|
|
|
// not using getRealTime is necessary for wine
|
|
|
|
u32 time = device->getTimer()->getTime();
|
|
|
|
if(time > lasttime)
|
|
|
|
busytime_u32 = time - lasttime;
|
|
|
|
else
|
|
|
|
busytime_u32 = 0;
|
|
|
|
busytime = busytime_u32 / 1000.0;
|
|
|
|
|
|
|
|
// FPS limiter
|
|
|
|
u32 frametime_min = 1000./fps_max;
|
|
|
|
|
|
|
|
if(busytime_u32 < frametime_min) {
|
|
|
|
u32 sleeptime = frametime_min - busytime_u32;
|
|
|
|
device->sleep(sleeptime);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sleep_ms(25);
|
|
|
|
}
|
|
|
|
time_counter += dtime;
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(con::PeerNotFoundException &e)
|
2011-04-23 23:11:23 +02:00
|
|
|
{}
|
2011-11-15 22:58:56 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Handle failure to connect
|
|
|
|
*/
|
2012-03-10 22:28:51 +01:00
|
|
|
if(!could_connect){
|
2012-03-11 11:06:59 +01:00
|
|
|
if(error_message == L"" && !connect_aborted){
|
2012-03-10 22:28:51 +01:00
|
|
|
error_message = L"Connection failed";
|
2012-03-11 11:06:59 +01:00
|
|
|
errorstream<<wide_to_narrow(error_message)<<std::endl;
|
|
|
|
}
|
2012-03-10 22:28:51 +01:00
|
|
|
// Break out of client scope
|
|
|
|
break;
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
2011-11-15 22:58:56 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Wait until content has been received
|
|
|
|
*/
|
|
|
|
bool got_content = false;
|
2012-03-10 22:28:51 +01:00
|
|
|
bool content_aborted = false;
|
2011-11-15 22:58:56 +01:00
|
|
|
{
|
|
|
|
float time_counter = 0.0;
|
2012-03-10 22:28:51 +01:00
|
|
|
input->clear();
|
2013-05-09 18:23:48 +02:00
|
|
|
float fps_max = g_settings->getFloat("fps_max");
|
|
|
|
bool cloud_menu_background = g_settings->getBool("menu_clouds");
|
|
|
|
u32 lasttime = device->getTimer()->getTime();
|
2012-03-10 22:28:51 +01:00
|
|
|
while(device->run())
|
2011-11-15 22:58:56 +01:00
|
|
|
{
|
2013-05-19 18:07:00 +02:00
|
|
|
f32 dtime = 0.033; // in seconds
|
2013-05-09 18:23:48 +02:00
|
|
|
if (cloud_menu_background) {
|
|
|
|
u32 time = device->getTimer()->getTime();
|
|
|
|
if(time > lasttime)
|
|
|
|
dtime = (time - lasttime) / 1000.0;
|
|
|
|
else
|
|
|
|
dtime = 0;
|
|
|
|
lasttime = time;
|
|
|
|
}
|
2011-11-15 22:58:56 +01:00
|
|
|
// Update client and server
|
2013-05-09 18:23:48 +02:00
|
|
|
client.step(dtime);
|
2011-11-15 22:58:56 +01:00
|
|
|
if(server != NULL)
|
2013-05-09 18:23:48 +02:00
|
|
|
server->step(dtime);
|
2011-11-15 22:58:56 +01:00
|
|
|
|
|
|
|
// End condition
|
Rewrite client media download and support hash-based remote download
Move most of the media-related code in client.cpp into a new class
ClientMediaDownloader (clientmedia.cpp, clientmedia.h). Among other
things, this class does the following things:
- Download [remote_server][sha1] instead of [remote_server][name]. This
is to support servers that provide the same file name with different
contents.
- Initially fetch [remote_server]index.mth. This file should follow the
Minetest Hashset format (currently version 1) and contain a list of SHA1
hashes that exist on the server.
- The list of needed SHA1s is uploaded (via HTTP POST) when index.mth is
requested, so servers can optionally narrow down the list to the needs
of the client.
- If index.mth is missing (HTTP response code 404), we enter compat mode,
fetching [remote_server][name] as before this commit.
- remote_server can now contain multiple servers, separated by commas.
The downloader code attempts to split requests between the different
servers, as permitted by each server's index.mth. If one server claims
to have a file but actually doesn't (or something fails), we ask a
different server that also claims to have it.
- As before, when none of the remote servers provide a particular
file, we download it via the conventional method, i.e. using
the minetest protocol: TOSERVER_REQUEST_MEDIA / TOCLIENT_MEDIA.
- Bugfix: Every downloaded file's SHA1 is now verified against the SHA1
announced by the minetest server (before loading it and inserting it
into the file cache).
- Bugfix: Only send TOSERVER_RECEIVED_MEDIA when we actually have all
media. This should fix #863.
2013-08-29 05:22:18 +02:00
|
|
|
if(client.mediaReceived() &&
|
2012-01-12 06:10:39 +01:00
|
|
|
client.itemdefReceived() &&
|
|
|
|
client.nodedefReceived()){
|
2011-11-15 22:58:56 +01:00
|
|
|
got_content = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Break conditions
|
2013-12-19 21:47:08 +01:00
|
|
|
if(client.accessDenied()){
|
|
|
|
error_message = L"Access denied. Reason: "
|
|
|
|
+client.accessDeniedReason();
|
|
|
|
errorstream<<wide_to_narrow(error_message)<<std::endl;
|
|
|
|
break;
|
|
|
|
}
|
2012-03-10 22:28:51 +01:00
|
|
|
if(!client.connectedAndInitialized()){
|
|
|
|
error_message = L"Client disconnected";
|
2012-03-11 11:06:59 +01:00
|
|
|
errorstream<<wide_to_narrow(error_message)<<std::endl;
|
2011-11-15 22:58:56 +01:00
|
|
|
break;
|
2012-03-10 22:28:51 +01:00
|
|
|
}
|
|
|
|
if(input->wasKeyDown(EscapeKey)){
|
|
|
|
content_aborted = true;
|
2012-03-11 11:06:59 +01:00
|
|
|
infostream<<"Connect aborted [Escape]"<<std::endl;
|
2011-11-15 22:58:56 +01:00
|
|
|
break;
|
2012-03-10 22:28:51 +01:00
|
|
|
}
|
2011-11-15 22:58:56 +01:00
|
|
|
|
|
|
|
// Display status
|
2013-05-09 18:23:48 +02:00
|
|
|
int progress=0;
|
2013-05-08 15:03:42 +02:00
|
|
|
if (!client.itemdefReceived())
|
2013-05-09 18:23:48 +02:00
|
|
|
{
|
2013-06-24 02:07:45 +02:00
|
|
|
wchar_t* text = wgettext("Item definitions...");
|
2013-05-09 18:23:48 +02:00
|
|
|
progress = 0;
|
2013-06-24 02:07:45 +02:00
|
|
|
draw_load_screen(text, device, font, dtime, progress);
|
|
|
|
delete[] text;
|
2013-05-09 18:23:48 +02:00
|
|
|
}
|
2013-05-08 15:03:42 +02:00
|
|
|
else if (!client.nodedefReceived())
|
2013-05-09 18:23:48 +02:00
|
|
|
{
|
2013-06-24 02:07:45 +02:00
|
|
|
wchar_t* text = wgettext("Node definitions...");
|
2013-05-09 18:23:48 +02:00
|
|
|
progress = 25;
|
2013-06-24 02:07:45 +02:00
|
|
|
draw_load_screen(text, device, font, dtime, progress);
|
|
|
|
delete[] text;
|
2013-05-09 18:23:48 +02:00
|
|
|
}
|
2013-05-08 15:03:42 +02:00
|
|
|
else
|
|
|
|
{
|
2013-06-24 02:07:45 +02:00
|
|
|
wchar_t* text = wgettext("Media...");
|
2013-05-09 18:23:48 +02:00
|
|
|
progress = 50+client.mediaReceiveProgress()*50+0.5;
|
2013-06-24 02:07:45 +02:00
|
|
|
draw_load_screen(text, device, font, dtime, progress);
|
|
|
|
delete[] text;
|
2013-05-08 15:03:42 +02:00
|
|
|
}
|
|
|
|
|
2013-05-09 18:23:48 +02:00
|
|
|
// On some computers framerate doesn't seem to be
|
|
|
|
// automatically limited
|
|
|
|
if (cloud_menu_background) {
|
|
|
|
// Time of frame without fps limit
|
|
|
|
float busytime;
|
|
|
|
u32 busytime_u32;
|
|
|
|
// not using getRealTime is necessary for wine
|
|
|
|
u32 time = device->getTimer()->getTime();
|
|
|
|
if(time > lasttime)
|
|
|
|
busytime_u32 = time - lasttime;
|
|
|
|
else
|
|
|
|
busytime_u32 = 0;
|
|
|
|
busytime = busytime_u32 / 1000.0;
|
|
|
|
|
|
|
|
// FPS limiter
|
|
|
|
u32 frametime_min = 1000./fps_max;
|
|
|
|
|
|
|
|
if(busytime_u32 < frametime_min) {
|
|
|
|
u32 sleeptime = frametime_min - busytime_u32;
|
|
|
|
device->sleep(sleeptime);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sleep_ms(25);
|
|
|
|
}
|
|
|
|
time_counter += dtime;
|
2013-05-08 15:03:42 +02:00
|
|
|
}
|
2011-11-15 22:58:56 +01:00
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2012-03-10 22:28:51 +01:00
|
|
|
if(!got_content){
|
2012-03-11 11:06:59 +01:00
|
|
|
if(error_message == L"" && !content_aborted){
|
2012-03-10 22:28:51 +01:00
|
|
|
error_message = L"Something failed";
|
2012-03-11 11:06:59 +01:00
|
|
|
errorstream<<wide_to_narrow(error_message)<<std::endl;
|
|
|
|
}
|
2012-03-10 22:28:51 +01:00
|
|
|
// Break out of client scope
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
/*
|
|
|
|
After all content has been received:
|
|
|
|
Update cached textures, meshes and materials
|
|
|
|
*/
|
2013-05-11 16:02:41 +02:00
|
|
|
client.afterContentReceived(device,font);
|
2012-01-12 06:10:39 +01:00
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
|
|
|
Create the camera node
|
|
|
|
*/
|
2012-03-23 14:29:30 +01:00
|
|
|
Camera camera(smgr, draw_control, gamedef);
|
2011-09-15 00:32:11 +02:00
|
|
|
if (!camera.successfullyCreated(error_message))
|
2011-09-08 01:08:47 +02:00
|
|
|
return;
|
2011-04-23 17:31:31 +02:00
|
|
|
|
|
|
|
f32 camera_yaw = 0; // "right/left"
|
|
|
|
f32 camera_pitch = 0; // "up/down"
|
|
|
|
|
2011-04-29 14:34:26 +02:00
|
|
|
/*
|
|
|
|
Clouds
|
|
|
|
*/
|
|
|
|
|
2011-05-06 15:58:06 +02:00
|
|
|
Clouds *clouds = NULL;
|
2011-10-12 12:53:38 +02:00
|
|
|
if(g_settings->getBool("enable_clouds"))
|
2011-06-07 21:08:16 +02:00
|
|
|
{
|
2012-03-16 15:34:30 +01:00
|
|
|
clouds = new Clouds(smgr->getRootSceneNode(), smgr, -1, time(0));
|
2011-06-07 21:08:16 +02:00
|
|
|
}
|
2012-03-16 15:34:30 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Skybox thingy
|
|
|
|
*/
|
|
|
|
|
|
|
|
Sky *sky = NULL;
|
2013-06-30 17:17:14 +02:00
|
|
|
sky = new Sky(smgr->getRootSceneNode(), smgr, -1, client.getEnv().getLocalPlayer());
|
2013-05-02 22:52:50 +02:00
|
|
|
|
|
|
|
scene::ISceneNode* skybox = NULL;
|
2011-06-07 21:08:16 +02:00
|
|
|
|
2012-01-12 06:10:39 +01:00
|
|
|
/*
|
|
|
|
A copy of the local inventory
|
|
|
|
*/
|
|
|
|
Inventory local_inventory(itemdef);
|
|
|
|
|
2012-06-16 17:02:56 +02:00
|
|
|
/*
|
|
|
|
Find out size of crack animation
|
|
|
|
*/
|
|
|
|
int crack_animation_length = 5;
|
|
|
|
{
|
2013-06-24 04:17:50 +02:00
|
|
|
video::ITexture *t = tsrc->getTexture("crack_anylength.png");
|
2012-06-16 17:02:56 +02:00
|
|
|
v2u32 size = t->getOriginalSize();
|
|
|
|
crack_animation_length = size.Y / size.X;
|
|
|
|
}
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
|
|
|
Add some gui stuff
|
|
|
|
*/
|
|
|
|
|
|
|
|
// First line of debug text
|
|
|
|
gui::IGUIStaticText *guitext = guienv->addStaticText(
|
2012-12-06 20:01:45 +01:00
|
|
|
L"Minetest",
|
2011-04-23 17:31:31 +02:00
|
|
|
core::rect<s32>(5, 5, 795, 5+text_height),
|
|
|
|
false, false);
|
|
|
|
// Second line of debug text
|
|
|
|
gui::IGUIStaticText *guitext2 = guienv->addStaticText(
|
|
|
|
L"",
|
|
|
|
core::rect<s32>(5, 5+(text_height+5)*1, 795, (5+text_height)*2),
|
|
|
|
false, false);
|
|
|
|
// At the middle of the screen
|
|
|
|
// Object infos are shown in this
|
|
|
|
gui::IGUIStaticText *guitext_info = guienv->addStaticText(
|
|
|
|
L"",
|
2012-03-09 19:28:55 +01:00
|
|
|
core::rect<s32>(0,0,400,text_height*5+5) + v2s32(100,200),
|
2013-02-12 19:37:25 +01:00
|
|
|
false, true);
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2012-02-01 00:56:30 +01:00
|
|
|
// Status text (displays info when showing and hiding GUI stuff, etc.)
|
|
|
|
gui::IGUIStaticText *guitext_status = guienv->addStaticText(
|
|
|
|
L"<Status>",
|
|
|
|
core::rect<s32>(0,0,0,0),
|
|
|
|
false, false);
|
|
|
|
guitext_status->setVisible(false);
|
|
|
|
|
|
|
|
std::wstring statustext;
|
|
|
|
float statustext_time = 0;
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
// Chat text
|
|
|
|
gui::IGUIStaticText *guitext_chat = guienv->addStaticText(
|
|
|
|
L"",
|
|
|
|
core::rect<s32>(0,0,0,0),
|
2011-06-18 07:50:14 +02:00
|
|
|
//false, false); // Disable word wrap as of now
|
|
|
|
false, true);
|
2011-12-03 09:01:14 +01:00
|
|
|
// Remove stale "recent" chat messages from previous connections
|
|
|
|
chat_backend.clearRecentChat();
|
|
|
|
// Chat backend and console
|
|
|
|
GUIChatConsole *gui_chat_console = new GUIChatConsole(guienv, guienv->getRootGUIElement(), -1, &chat_backend, &client);
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2011-11-02 17:13:56 +01:00
|
|
|
// Profiler text (size is updated when text is updated)
|
2011-10-17 19:40:55 +02:00
|
|
|
gui::IGUIStaticText *guitext_profiler = guienv->addStaticText(
|
|
|
|
L"<Profiler>",
|
2012-02-01 00:56:30 +01:00
|
|
|
core::rect<s32>(0,0,0,0),
|
2011-10-17 19:40:55 +02:00
|
|
|
false, false);
|
2012-03-21 02:33:02 +01:00
|
|
|
guitext_profiler->setBackgroundColor(video::SColor(120,0,0,0));
|
2011-10-17 19:40:55 +02:00
|
|
|
guitext_profiler->setVisible(false);
|
2013-06-13 14:32:53 +02:00
|
|
|
guitext_profiler->setWordWrap(true);
|
2011-10-17 19:40:55 +02:00
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
|
|
|
Some statistics are collected in these
|
|
|
|
*/
|
|
|
|
u32 drawtime = 0;
|
|
|
|
u32 beginscenetime = 0;
|
|
|
|
u32 scenetime = 0;
|
|
|
|
u32 endscenetime = 0;
|
|
|
|
|
2012-03-16 15:34:30 +01:00
|
|
|
float recent_turn_speed = 0.0;
|
2012-03-21 02:33:02 +01:00
|
|
|
|
|
|
|
ProfilerGraph graph;
|
2012-03-21 14:05:51 +01:00
|
|
|
// Initially clear the profiler
|
|
|
|
Profiler::GraphValues dummyvalues;
|
|
|
|
g_profiler->graphGet(dummyvalues);
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
float nodig_delay_timer = 0.0;
|
2011-10-15 01:28:57 +02:00
|
|
|
float dig_time = 0.0;
|
|
|
|
u16 dig_index = 0;
|
2011-11-29 16:15:18 +01:00
|
|
|
PointedThing pointed_old;
|
|
|
|
bool digging = false;
|
2011-11-21 13:34:43 +01:00
|
|
|
bool ldown_for_dig = false;
|
2011-10-15 01:28:57 +02:00
|
|
|
|
2013-01-02 21:57:04 +01:00
|
|
|
float damage_flash = 0;
|
2011-10-15 01:28:57 +02:00
|
|
|
|
2013-01-03 19:51:52 +01:00
|
|
|
float jump_timer = 0;
|
|
|
|
bool reset_jump_timer = false;
|
|
|
|
|
2011-11-21 13:40:16 +01:00
|
|
|
const float object_hit_delay = 0.2;
|
2011-10-15 01:28:57 +02:00
|
|
|
float object_hit_delay_timer = 0.0;
|
2012-03-09 22:53:25 +01:00
|
|
|
float time_from_last_punch = 10;
|
2012-03-11 11:28:41 +01:00
|
|
|
|
2012-09-04 08:48:26 +02:00
|
|
|
float update_draw_list_timer = 0.0;
|
|
|
|
v3f update_draw_list_last_cam_dir;
|
|
|
|
|
2011-10-12 12:53:38 +02:00
|
|
|
bool invert_mouse = g_settings->getBool("invert_mouse");
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2011-10-15 13:46:59 +02:00
|
|
|
bool respawn_menu_active = false;
|
Rewrite client media download and support hash-based remote download
Move most of the media-related code in client.cpp into a new class
ClientMediaDownloader (clientmedia.cpp, clientmedia.h). Among other
things, this class does the following things:
- Download [remote_server][sha1] instead of [remote_server][name]. This
is to support servers that provide the same file name with different
contents.
- Initially fetch [remote_server]index.mth. This file should follow the
Minetest Hashset format (currently version 1) and contain a list of SHA1
hashes that exist on the server.
- The list of needed SHA1s is uploaded (via HTTP POST) when index.mth is
requested, so servers can optionally narrow down the list to the needs
of the client.
- If index.mth is missing (HTTP response code 404), we enter compat mode,
fetching [remote_server][name] as before this commit.
- remote_server can now contain multiple servers, separated by commas.
The downloader code attempts to split requests between the different
servers, as permitted by each server's index.mth. If one server claims
to have a file but actually doesn't (or something fails), we ask a
different server that also claims to have it.
- As before, when none of the remote servers provide a particular
file, we download it via the conventional method, i.e. using
the minetest protocol: TOSERVER_REQUEST_MEDIA / TOCLIENT_MEDIA.
- Bugfix: Every downloaded file's SHA1 is now verified against the SHA1
announced by the minetest server (before loading it and inserting it
into the file cache).
- Bugfix: Only send TOSERVER_RECEIVED_MEDIA when we actually have all
media. This should fix #863.
2013-08-29 05:22:18 +02:00
|
|
|
bool update_wielded_item_trigger = true;
|
2011-10-15 13:46:59 +02:00
|
|
|
|
2012-02-01 00:56:30 +01:00
|
|
|
bool show_hud = true;
|
|
|
|
bool show_chat = true;
|
2011-10-18 20:08:31 +02:00
|
|
|
bool force_fog_off = false;
|
2012-12-01 02:02:16 +01:00
|
|
|
f32 fog_range = 100*BS;
|
2011-11-02 17:13:56 +01:00
|
|
|
bool disable_camera_update = false;
|
2012-02-01 00:56:30 +01:00
|
|
|
bool show_debug = g_settings->getBool("show_debug");
|
2012-03-21 02:33:02 +01:00
|
|
|
bool show_profiler_graph = false;
|
2012-02-01 00:56:30 +01:00
|
|
|
u32 show_profiler = 0;
|
|
|
|
u32 show_profiler_max = 3; // Number of pages
|
2011-10-18 20:08:31 +02:00
|
|
|
|
2012-03-16 15:34:30 +01:00
|
|
|
float time_of_day = 0;
|
|
|
|
float time_of_day_smooth = 0;
|
|
|
|
|
2013-01-04 15:19:16 +01:00
|
|
|
float repeat_rightclick_timer = 0;
|
|
|
|
|
2012-12-01 02:02:16 +01:00
|
|
|
/*
|
|
|
|
Shader constants
|
|
|
|
*/
|
2012-12-02 13:24:58 +01:00
|
|
|
shsrc->addGlobalConstantSetter(new GameGlobalShaderConstantSetter(
|
|
|
|
sky, &force_fog_off, &fog_range, &client));
|
2012-12-01 02:02:16 +01:00
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
|
|
|
Main loop
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool first_loop_after_window_activation = true;
|
|
|
|
|
2011-05-30 23:15:43 +02:00
|
|
|
// TODO: Convert the static interval timers to these
|
|
|
|
// Interval limiter for profiler
|
|
|
|
IntervalLimiter m_profiler_interval;
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
// Time is in milliseconds
|
|
|
|
// NOTE: getRealTime() causes strange problems in wine (imprecision?)
|
|
|
|
// NOTE: So we have to use getTime() and call run()s between them
|
|
|
|
u32 lasttime = device->getTimer()->getTime();
|
|
|
|
|
2012-04-28 02:06:25 +02:00
|
|
|
LocalPlayer* player = client.getEnv().getLocalPlayer();
|
|
|
|
player->hurt_tilt_timer = 0;
|
|
|
|
player->hurt_tilt_strength = 0;
|
2013-04-14 00:20:22 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
HUD object
|
|
|
|
*/
|
2014-01-26 21:31:59 +01:00
|
|
|
Hud hud(driver, smgr, guienv, font, text_height,
|
2013-04-14 00:20:22 +02:00
|
|
|
gamedef, player, &local_inventory);
|
2012-04-28 02:06:25 +02:00
|
|
|
|
2013-09-17 00:56:15 +02:00
|
|
|
bool use_weather = g_settings->getBool("weather");
|
|
|
|
|
2013-12-25 03:52:42 +01:00
|
|
|
core::stringw str = L"Minetest [";
|
|
|
|
str += driver->getName();
|
|
|
|
str += "]";
|
|
|
|
device->setWindowCaption(str.c_str());
|
|
|
|
|
2012-03-21 02:33:02 +01:00
|
|
|
for(;;)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2012-03-21 02:33:02 +01:00
|
|
|
if(device->run() == false || kill == true)
|
|
|
|
break;
|
2011-06-26 02:14:52 +02:00
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
// Time of frame without fps limit
|
|
|
|
float busytime;
|
|
|
|
u32 busytime_u32;
|
|
|
|
{
|
|
|
|
// not using getRealTime is necessary for wine
|
|
|
|
u32 time = device->getTimer()->getTime();
|
|
|
|
if(time > lasttime)
|
|
|
|
busytime_u32 = time - lasttime;
|
|
|
|
else
|
|
|
|
busytime_u32 = 0;
|
|
|
|
busytime = busytime_u32 / 1000.0;
|
|
|
|
}
|
2012-03-21 12:31:47 +01:00
|
|
|
|
|
|
|
g_profiler->graphAdd("mainloop_other", busytime - (float)drawtime/1000.0f);
|
2011-04-23 17:31:31 +02:00
|
|
|
|
|
|
|
// Necessary for device->getTimer()->getTime()
|
|
|
|
device->run();
|
|
|
|
|
|
|
|
/*
|
|
|
|
FPS limiter
|
|
|
|
*/
|
|
|
|
|
|
|
|
{
|
2014-01-06 16:37:23 +01:00
|
|
|
float fps_max = g_menumgr.pausesGame() ?
|
|
|
|
g_settings->getFloat("pause_fps_max") :
|
|
|
|
g_settings->getFloat("fps_max");
|
2011-04-23 17:31:31 +02:00
|
|
|
u32 frametime_min = 1000./fps_max;
|
|
|
|
|
|
|
|
if(busytime_u32 < frametime_min)
|
|
|
|
{
|
|
|
|
u32 sleeptime = frametime_min - busytime_u32;
|
|
|
|
device->sleep(sleeptime);
|
2012-03-21 12:31:47 +01:00
|
|
|
g_profiler->graphAdd("mainloop_sleep", (float)sleeptime/1000.0f);
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Necessary for device->getTimer()->getTime()
|
|
|
|
device->run();
|
|
|
|
|
|
|
|
/*
|
|
|
|
Time difference calculation
|
|
|
|
*/
|
|
|
|
f32 dtime; // in seconds
|
|
|
|
|
|
|
|
u32 time = device->getTimer()->getTime();
|
|
|
|
if(time > lasttime)
|
|
|
|
dtime = (time - lasttime) / 1000.0;
|
|
|
|
else
|
|
|
|
dtime = 0;
|
|
|
|
lasttime = time;
|
|
|
|
|
2012-03-21 13:09:32 +01:00
|
|
|
g_profiler->graphAdd("mainloop_dtime", dtime);
|
|
|
|
|
2011-10-15 01:28:57 +02:00
|
|
|
/* Run timers */
|
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
if(nodig_delay_timer >= 0)
|
|
|
|
nodig_delay_timer -= dtime;
|
|
|
|
if(object_hit_delay_timer >= 0)
|
|
|
|
object_hit_delay_timer -= dtime;
|
2012-03-09 22:53:25 +01:00
|
|
|
time_from_last_punch += dtime;
|
2012-03-23 19:23:03 +01:00
|
|
|
|
2011-10-16 21:39:35 +02:00
|
|
|
g_profiler->add("Elapsed time", dtime);
|
2011-10-17 16:06:28 +02:00
|
|
|
g_profiler->avg("FPS", 1./dtime);
|
2011-10-16 20:16:44 +02:00
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
|
|
|
Time average and jitter calculation
|
|
|
|
*/
|
|
|
|
|
|
|
|
static f32 dtime_avg1 = 0.0;
|
2011-06-26 23:29:17 +02:00
|
|
|
dtime_avg1 = dtime_avg1 * 0.96 + dtime * 0.04;
|
2011-04-23 17:31:31 +02:00
|
|
|
f32 dtime_jitter1 = dtime - dtime_avg1;
|
|
|
|
|
|
|
|
static f32 dtime_jitter1_max_sample = 0.0;
|
|
|
|
static f32 dtime_jitter1_max_fraction = 0.0;
|
|
|
|
{
|
|
|
|
static f32 jitter1_max = 0.0;
|
|
|
|
static f32 counter = 0.0;
|
|
|
|
if(dtime_jitter1 > jitter1_max)
|
|
|
|
jitter1_max = dtime_jitter1;
|
|
|
|
counter += dtime;
|
|
|
|
if(counter > 0.0)
|
|
|
|
{
|
|
|
|
counter -= 3.0;
|
|
|
|
dtime_jitter1_max_sample = jitter1_max;
|
|
|
|
dtime_jitter1_max_fraction
|
|
|
|
= dtime_jitter1_max_sample / (dtime_avg1+0.001);
|
|
|
|
jitter1_max = 0.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Busytime average and jitter calculation
|
|
|
|
*/
|
|
|
|
|
|
|
|
static f32 busytime_avg1 = 0.0;
|
|
|
|
busytime_avg1 = busytime_avg1 * 0.98 + busytime * 0.02;
|
|
|
|
f32 busytime_jitter1 = busytime - busytime_avg1;
|
|
|
|
|
|
|
|
static f32 busytime_jitter1_max_sample = 0.0;
|
|
|
|
static f32 busytime_jitter1_min_sample = 0.0;
|
|
|
|
{
|
|
|
|
static f32 jitter1_max = 0.0;
|
|
|
|
static f32 jitter1_min = 0.0;
|
|
|
|
static f32 counter = 0.0;
|
|
|
|
if(busytime_jitter1 > jitter1_max)
|
|
|
|
jitter1_max = busytime_jitter1;
|
|
|
|
if(busytime_jitter1 < jitter1_min)
|
|
|
|
jitter1_min = busytime_jitter1;
|
|
|
|
counter += dtime;
|
|
|
|
if(counter > 0.0){
|
|
|
|
counter -= 3.0;
|
|
|
|
busytime_jitter1_max_sample = jitter1_max;
|
|
|
|
busytime_jitter1_min_sample = jitter1_min;
|
|
|
|
jitter1_max = 0.0;
|
|
|
|
jitter1_min = 0.0;
|
|
|
|
}
|
|
|
|
}
|
2012-03-21 12:31:47 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Handle miscellaneous stuff
|
|
|
|
*/
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2012-03-21 12:31:47 +01:00
|
|
|
if(client.accessDenied())
|
|
|
|
{
|
|
|
|
error_message = L"Access denied. Reason: "
|
|
|
|
+client.accessDeniedReason();
|
|
|
|
errorstream<<wide_to_narrow(error_message)<<std::endl;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(g_gamecallback->disconnect_requested)
|
|
|
|
{
|
|
|
|
g_gamecallback->disconnect_requested = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(g_gamecallback->changepassword_requested)
|
|
|
|
{
|
|
|
|
(new GUIPasswordChange(guienv, guiroot, -1,
|
|
|
|
&g_menumgr, &client))->drop();
|
|
|
|
g_gamecallback->changepassword_requested = false;
|
|
|
|
}
|
|
|
|
|
2013-02-23 16:01:35 +01:00
|
|
|
if(g_gamecallback->changevolume_requested)
|
|
|
|
{
|
|
|
|
(new GUIVolumeChange(guienv, guiroot, -1,
|
|
|
|
&g_menumgr, &client))->drop();
|
|
|
|
g_gamecallback->changevolume_requested = false;
|
|
|
|
}
|
|
|
|
|
2012-11-30 17:12:32 +01:00
|
|
|
/* Process TextureSource's queue */
|
2012-03-21 12:31:47 +01:00
|
|
|
tsrc->processQueue();
|
|
|
|
|
2012-11-30 17:12:32 +01:00
|
|
|
/* Process ItemDefManager's queue */
|
|
|
|
itemdef->processQueue(gamedef);
|
|
|
|
|
2012-03-19 02:59:12 +01:00
|
|
|
/*
|
|
|
|
Process ShaderSource's queue
|
|
|
|
*/
|
|
|
|
shsrc->processQueue();
|
|
|
|
|
2012-03-21 12:31:47 +01:00
|
|
|
/*
|
|
|
|
Random calculations
|
|
|
|
*/
|
|
|
|
last_screensize = screensize;
|
|
|
|
screensize = driver->getScreenSize();
|
|
|
|
v2s32 displaycenter(screensize.X/2,screensize.Y/2);
|
|
|
|
//bool screensize_changed = screensize != last_screensize;
|
|
|
|
|
2013-04-14 00:20:22 +02:00
|
|
|
|
|
|
|
// Update HUD values
|
|
|
|
hud.screensize = screensize;
|
|
|
|
hud.displaycenter = displaycenter;
|
|
|
|
hud.resizeHotbar();
|
2012-03-21 12:31:47 +01:00
|
|
|
|
|
|
|
// Hilight boxes collected during the loop and displayed
|
2012-03-19 04:25:09 +01:00
|
|
|
std::vector<aabb3f> hilightboxes;
|
2012-03-21 12:31:47 +01:00
|
|
|
|
|
|
|
// Info text
|
|
|
|
std::wstring infotext;
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
|
|
|
Debug info for client
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
static float counter = 0.0;
|
|
|
|
counter -= dtime;
|
|
|
|
if(counter < 0)
|
|
|
|
{
|
|
|
|
counter = 30.0;
|
2011-10-16 13:57:53 +02:00
|
|
|
client.printDebugInfo(infostream);
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-30 23:15:43 +02:00
|
|
|
/*
|
|
|
|
Profiler
|
|
|
|
*/
|
|
|
|
float profiler_print_interval =
|
2011-10-12 12:53:38 +02:00
|
|
|
g_settings->getFloat("profiler_print_interval");
|
2011-10-17 19:40:55 +02:00
|
|
|
bool print_to_log = true;
|
|
|
|
if(profiler_print_interval == 0){
|
|
|
|
print_to_log = false;
|
|
|
|
profiler_print_interval = 5;
|
|
|
|
}
|
2011-10-18 09:36:52 +02:00
|
|
|
if(m_profiler_interval.step(dtime, profiler_print_interval))
|
2011-05-30 23:15:43 +02:00
|
|
|
{
|
2011-10-17 19:40:55 +02:00
|
|
|
if(print_to_log){
|
2011-10-16 13:57:53 +02:00
|
|
|
infostream<<"Profiler:"<<std::endl;
|
|
|
|
g_profiler->print(infostream);
|
2011-05-30 23:15:43 +02:00
|
|
|
}
|
2011-10-17 19:40:55 +02:00
|
|
|
|
2012-02-01 00:56:30 +01:00
|
|
|
update_profiler_gui(guitext_profiler, font, text_height,
|
|
|
|
show_profiler, show_profiler_max);
|
2011-10-17 19:40:55 +02:00
|
|
|
|
|
|
|
g_profiler->clear();
|
2011-05-30 23:15:43 +02:00
|
|
|
}
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
|
|
|
Direct handling of user input
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Reset input if window not active or some menu is active
|
2011-12-03 09:01:14 +01:00
|
|
|
if(device->isWindowActive() == false
|
|
|
|
|| noMenuActive() == false
|
|
|
|
|| guienv->hasFocus(gui_chat_console))
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
|
|
|
input->clear();
|
|
|
|
}
|
2013-06-05 04:26:52 +02:00
|
|
|
if (!guienv->hasFocus(gui_chat_console) && gui_chat_console->isOpen())
|
|
|
|
{
|
|
|
|
gui_chat_console->closeConsoleAtOnce();
|
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
|
|
|
|
// Input handler step() (used by the random input generator)
|
|
|
|
input->step(dtime);
|
|
|
|
|
2013-01-03 19:51:52 +01:00
|
|
|
// Increase timer for doubleclick of "jump"
|
2013-01-04 20:00:49 +01:00
|
|
|
if(g_settings->getBool("doubletap_jump") && jump_timer <= 0.2)
|
2013-01-03 19:51:52 +01:00
|
|
|
jump_timer += dtime;
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
2011-11-27 04:01:38 +01:00
|
|
|
Launch menus and trigger stuff according to keys
|
2011-04-23 17:31:31 +02:00
|
|
|
*/
|
2011-11-27 04:01:38 +01:00
|
|
|
if(input->wasKeyDown(getKeySetting("keymap_drop")))
|
|
|
|
{
|
|
|
|
// drop selected item
|
|
|
|
IDropAction *a = new IDropAction();
|
|
|
|
a->count = 0;
|
2012-01-12 06:10:39 +01:00
|
|
|
a->from_inv.setCurrentPlayer();
|
2011-11-27 04:01:38 +01:00
|
|
|
a->from_list = "main";
|
2011-11-29 16:15:18 +01:00
|
|
|
a->from_i = client.getPlayerItem();
|
2011-11-27 04:01:38 +01:00
|
|
|
client.inventoryAction(a);
|
|
|
|
}
|
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_inventory")))
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2011-10-16 13:57:53 +02:00
|
|
|
infostream<<"the_game: "
|
2011-04-23 17:31:31 +02:00
|
|
|
<<"Launching inventory"<<std::endl;
|
|
|
|
|
2012-07-15 18:19:38 +02:00
|
|
|
GUIFormSpecMenu *menu =
|
2012-11-28 18:39:58 +01:00
|
|
|
new GUIFormSpecMenu(device, guiroot, -1,
|
2012-06-03 15:03:19 +02:00
|
|
|
&g_menumgr,
|
2013-08-20 22:38:14 +02:00
|
|
|
&client, gamedef, tsrc);
|
2012-01-12 06:10:39 +01:00
|
|
|
|
|
|
|
InventoryLocation inventoryloc;
|
|
|
|
inventoryloc.setCurrentPlayer();
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2012-07-19 13:09:16 +02:00
|
|
|
PlayerInventoryFormSource *src = new PlayerInventoryFormSource(&client);
|
|
|
|
assert(src);
|
|
|
|
menu->setFormSpec(src->getForm(), inventoryloc);
|
2012-07-15 18:19:38 +02:00
|
|
|
menu->setFormSource(src);
|
2012-07-22 16:10:58 +02:00
|
|
|
menu->setTextDest(new TextDestPlayerInventory(&client));
|
2011-04-23 17:31:31 +02:00
|
|
|
menu->drop();
|
|
|
|
}
|
2011-08-13 22:44:31 +02:00
|
|
|
else if(input->wasKeyDown(EscapeKey))
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2011-10-16 13:57:53 +02:00
|
|
|
infostream<<"the_game: "
|
2011-04-23 17:31:31 +02:00
|
|
|
<<"Launching pause menu"<<std::endl;
|
|
|
|
// It will delete itself by itself
|
|
|
|
(new GUIPauseMenu(guienv, guiroot, -1, g_gamecallback,
|
2012-03-15 14:20:20 +01:00
|
|
|
&g_menumgr, simple_singleplayer_mode))->drop();
|
2011-05-24 20:04:22 +02:00
|
|
|
|
|
|
|
// Move mouse cursor on top of the disconnect button
|
2012-03-15 14:57:31 +01:00
|
|
|
if(simple_singleplayer_mode)
|
|
|
|
input->setMousePos(displaycenter.X, displaycenter.Y+0);
|
|
|
|
else
|
|
|
|
input->setMousePos(displaycenter.X, displaycenter.Y+25);
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
2011-05-14 14:43:26 +02:00
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_chat")))
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
|
|
|
TextDest *dest = new TextDestChat(&client);
|
|
|
|
|
|
|
|
(new GUITextInputMenu(guienv, guiroot, -1,
|
|
|
|
&g_menumgr, dest,
|
|
|
|
L""))->drop();
|
|
|
|
}
|
2011-08-13 18:16:49 +02:00
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_cmd")))
|
|
|
|
{
|
|
|
|
TextDest *dest = new TextDestChat(&client);
|
|
|
|
|
|
|
|
(new GUITextInputMenu(guienv, guiroot, -1,
|
|
|
|
&g_menumgr, dest,
|
|
|
|
L"/"))->drop();
|
|
|
|
}
|
2011-12-03 09:01:14 +01:00
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_console")))
|
|
|
|
{
|
|
|
|
if (!gui_chat_console->isOpenInhibited())
|
|
|
|
{
|
|
|
|
// Open up to over half of the screen
|
|
|
|
gui_chat_console->openConsole(0.6);
|
|
|
|
guienv->setFocus(gui_chat_console);
|
|
|
|
}
|
|
|
|
}
|
2011-06-17 22:55:21 +02:00
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_freemove")))
|
|
|
|
{
|
2011-10-12 12:53:38 +02:00
|
|
|
if(g_settings->getBool("free_move"))
|
2011-06-17 22:55:21 +02:00
|
|
|
{
|
2011-10-12 12:53:38 +02:00
|
|
|
g_settings->set("free_move","false");
|
2012-02-01 00:56:30 +01:00
|
|
|
statustext = L"free_move disabled";
|
|
|
|
statustext_time = 0;
|
2011-06-17 22:55:21 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-10-12 12:53:38 +02:00
|
|
|
g_settings->set("free_move","true");
|
2012-02-01 00:56:30 +01:00
|
|
|
statustext = L"free_move enabled";
|
|
|
|
statustext_time = 0;
|
2012-03-31 15:23:26 +02:00
|
|
|
if(!client.checkPrivilege("fly"))
|
|
|
|
statustext += L" (note: no 'fly' privilege)";
|
2011-06-17 22:55:21 +02:00
|
|
|
}
|
|
|
|
}
|
2013-01-03 19:51:52 +01:00
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_jump")))
|
|
|
|
{
|
2013-01-04 20:00:49 +01:00
|
|
|
if(g_settings->getBool("doubletap_jump") && jump_timer < 0.2)
|
2013-01-03 19:51:52 +01:00
|
|
|
{
|
|
|
|
if(g_settings->getBool("free_move"))
|
|
|
|
{
|
|
|
|
g_settings->set("free_move","false");
|
|
|
|
statustext = L"free_move disabled";
|
|
|
|
statustext_time = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_settings->set("free_move","true");
|
|
|
|
statustext = L"free_move enabled";
|
|
|
|
statustext_time = 0;
|
|
|
|
if(!client.checkPrivilege("fly"))
|
|
|
|
statustext += L" (note: no 'fly' privilege)";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
reset_jump_timer = true;
|
|
|
|
}
|
2011-06-17 22:55:21 +02:00
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_fastmove")))
|
|
|
|
{
|
2011-10-12 12:53:38 +02:00
|
|
|
if(g_settings->getBool("fast_move"))
|
2011-06-17 22:55:21 +02:00
|
|
|
{
|
2011-10-12 12:53:38 +02:00
|
|
|
g_settings->set("fast_move","false");
|
2012-02-01 00:56:30 +01:00
|
|
|
statustext = L"fast_move disabled";
|
|
|
|
statustext_time = 0;
|
2011-06-17 22:55:21 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-10-12 12:53:38 +02:00
|
|
|
g_settings->set("fast_move","true");
|
2012-02-01 00:56:30 +01:00
|
|
|
statustext = L"fast_move enabled";
|
|
|
|
statustext_time = 0;
|
2012-03-31 15:23:26 +02:00
|
|
|
if(!client.checkPrivilege("fast"))
|
|
|
|
statustext += L" (note: no 'fast' privilege)";
|
2011-06-26 02:14:52 +02:00
|
|
|
}
|
|
|
|
}
|
2012-12-09 13:34:16 +01:00
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_noclip")))
|
|
|
|
{
|
|
|
|
if(g_settings->getBool("noclip"))
|
|
|
|
{
|
|
|
|
g_settings->set("noclip","false");
|
|
|
|
statustext = L"noclip disabled";
|
|
|
|
statustext_time = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_settings->set("noclip","true");
|
|
|
|
statustext = L"noclip enabled";
|
|
|
|
statustext_time = 0;
|
|
|
|
if(!client.checkPrivilege("noclip"))
|
|
|
|
statustext += L" (note: no 'noclip' privilege)";
|
|
|
|
}
|
|
|
|
}
|
2011-06-26 18:33:40 +02:00
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_screenshot")))
|
|
|
|
{
|
2014-01-06 12:45:42 +01:00
|
|
|
irr::video::IImage* const image = driver->createScreenShot();
|
|
|
|
if (image) {
|
|
|
|
irr::c8 filename[256];
|
|
|
|
snprintf(filename, 256, "%s" DIR_DELIM "screenshot_%u.png",
|
2011-10-12 12:53:38 +02:00
|
|
|
g_settings->get("screenshot_path").c_str(),
|
2014-01-06 12:45:42 +01:00
|
|
|
device->getTimer()->getRealTime());
|
2011-06-26 18:33:40 +02:00
|
|
|
if (driver->writeImageToFile(image, filename)) {
|
|
|
|
std::wstringstream sstr;
|
|
|
|
sstr<<"Saved screenshot to '"<<filename<<"'";
|
2011-10-16 13:57:53 +02:00
|
|
|
infostream<<"Saved screenshot to '"<<filename<<"'"<<std::endl;
|
2012-02-01 00:56:30 +01:00
|
|
|
statustext = sstr.str();
|
|
|
|
statustext_time = 0;
|
2011-06-26 18:33:40 +02:00
|
|
|
} else{
|
2011-10-16 13:57:53 +02:00
|
|
|
infostream<<"Failed to save screenshot '"<<filename<<"'"<<std::endl;
|
2011-06-26 18:33:40 +02:00
|
|
|
}
|
2014-01-06 12:45:42 +01:00
|
|
|
image->drop();
|
|
|
|
}
|
2011-06-26 18:33:40 +02:00
|
|
|
}
|
2012-02-01 00:56:30 +01:00
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_toggle_hud")))
|
2011-10-17 19:40:55 +02:00
|
|
|
{
|
2012-02-01 00:56:30 +01:00
|
|
|
show_hud = !show_hud;
|
|
|
|
if(show_hud)
|
|
|
|
statustext = L"HUD shown";
|
2011-11-02 17:13:56 +01:00
|
|
|
else
|
2012-02-01 00:56:30 +01:00
|
|
|
statustext = L"HUD hidden";
|
|
|
|
statustext_time = 0;
|
|
|
|
}
|
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_toggle_chat")))
|
|
|
|
{
|
|
|
|
show_chat = !show_chat;
|
|
|
|
if(show_chat)
|
|
|
|
statustext = L"Chat shown";
|
|
|
|
else
|
|
|
|
statustext = L"Chat hidden";
|
|
|
|
statustext_time = 0;
|
2011-10-17 19:40:55 +02:00
|
|
|
}
|
2011-10-18 20:08:31 +02:00
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_toggle_force_fog_off")))
|
|
|
|
{
|
|
|
|
force_fog_off = !force_fog_off;
|
2011-11-02 17:13:56 +01:00
|
|
|
if(force_fog_off)
|
2012-02-01 00:56:30 +01:00
|
|
|
statustext = L"Fog disabled";
|
2011-11-02 17:13:56 +01:00
|
|
|
else
|
2012-02-01 00:56:30 +01:00
|
|
|
statustext = L"Fog enabled";
|
|
|
|
statustext_time = 0;
|
2011-11-02 17:13:56 +01:00
|
|
|
}
|
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_toggle_update_camera")))
|
|
|
|
{
|
|
|
|
disable_camera_update = !disable_camera_update;
|
|
|
|
if(disable_camera_update)
|
2012-02-01 00:56:30 +01:00
|
|
|
statustext = L"Camera update disabled";
|
2011-11-02 17:13:56 +01:00
|
|
|
else
|
2012-02-01 00:56:30 +01:00
|
|
|
statustext = L"Camera update enabled";
|
|
|
|
statustext_time = 0;
|
|
|
|
}
|
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_toggle_debug")))
|
|
|
|
{
|
|
|
|
// Initial / 3x toggle: Chat only
|
|
|
|
// 1x toggle: Debug text with chat
|
2012-03-21 02:33:02 +01:00
|
|
|
// 2x toggle: Debug text with profiler graph
|
2012-02-01 00:56:30 +01:00
|
|
|
if(!show_debug)
|
|
|
|
{
|
|
|
|
show_debug = true;
|
2012-03-21 02:33:02 +01:00
|
|
|
show_profiler_graph = false;
|
2012-02-01 00:56:30 +01:00
|
|
|
statustext = L"Debug info shown";
|
|
|
|
statustext_time = 0;
|
|
|
|
}
|
2012-03-21 02:33:02 +01:00
|
|
|
else if(show_profiler_graph)
|
2012-02-01 00:56:30 +01:00
|
|
|
{
|
|
|
|
show_debug = false;
|
2012-03-21 02:33:02 +01:00
|
|
|
show_profiler_graph = false;
|
|
|
|
statustext = L"Debug info and profiler graph hidden";
|
2012-02-01 00:56:30 +01:00
|
|
|
statustext_time = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-03-21 02:33:02 +01:00
|
|
|
show_profiler_graph = true;
|
|
|
|
statustext = L"Profiler graph shown";
|
2012-02-01 00:56:30 +01:00
|
|
|
statustext_time = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_toggle_profiler")))
|
|
|
|
{
|
|
|
|
show_profiler = (show_profiler + 1) % (show_profiler_max + 1);
|
|
|
|
|
|
|
|
// FIXME: This updates the profiler with incomplete values
|
|
|
|
update_profiler_gui(guitext_profiler, font, text_height,
|
|
|
|
show_profiler, show_profiler_max);
|
|
|
|
|
|
|
|
if(show_profiler != 0)
|
|
|
|
{
|
|
|
|
std::wstringstream sstr;
|
|
|
|
sstr<<"Profiler shown (page "<<show_profiler
|
|
|
|
<<" of "<<show_profiler_max<<")";
|
|
|
|
statustext = sstr.str();
|
|
|
|
statustext_time = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
statustext = L"Profiler hidden";
|
|
|
|
statustext_time = 0;
|
|
|
|
}
|
2011-10-18 20:08:31 +02:00
|
|
|
}
|
2012-02-01 02:24:55 +01:00
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_increase_viewing_range_min")))
|
|
|
|
{
|
|
|
|
s16 range = g_settings->getS16("viewing_range_nodes_min");
|
|
|
|
s16 range_new = range + 10;
|
|
|
|
g_settings->set("viewing_range_nodes_min", itos(range_new));
|
|
|
|
statustext = narrow_to_wide(
|
2012-02-01 02:37:01 +01:00
|
|
|
"Minimum viewing range changed to "
|
|
|
|
+ itos(range_new));
|
2012-02-01 02:24:55 +01:00
|
|
|
statustext_time = 0;
|
|
|
|
}
|
|
|
|
else if(input->wasKeyDown(getKeySetting("keymap_decrease_viewing_range_min")))
|
|
|
|
{
|
|
|
|
s16 range = g_settings->getS16("viewing_range_nodes_min");
|
|
|
|
s16 range_new = range - 10;
|
2012-02-01 02:37:01 +01:00
|
|
|
if(range_new < 0)
|
|
|
|
range_new = range;
|
|
|
|
g_settings->set("viewing_range_nodes_min",
|
|
|
|
itos(range_new));
|
|
|
|
statustext = narrow_to_wide(
|
|
|
|
"Minimum viewing range changed to "
|
|
|
|
+ itos(range_new));
|
|
|
|
statustext_time = 0;
|
2012-02-01 02:24:55 +01:00
|
|
|
}
|
2012-03-12 20:27:29 +01:00
|
|
|
|
2013-01-03 19:51:52 +01:00
|
|
|
// Reset jump_timer
|
|
|
|
if(!input->isKeyDown(getKeySetting("keymap_jump")) && reset_jump_timer)
|
|
|
|
{
|
|
|
|
reset_jump_timer = false;
|
|
|
|
jump_timer = 0.0;
|
|
|
|
}
|
|
|
|
|
2012-03-12 20:27:29 +01:00
|
|
|
// Handle QuicktuneShortcutter
|
|
|
|
if(input->wasKeyDown(getKeySetting("keymap_quicktune_next")))
|
|
|
|
quicktune.next();
|
|
|
|
if(input->wasKeyDown(getKeySetting("keymap_quicktune_prev")))
|
|
|
|
quicktune.prev();
|
|
|
|
if(input->wasKeyDown(getKeySetting("keymap_quicktune_inc")))
|
|
|
|
quicktune.inc();
|
|
|
|
if(input->wasKeyDown(getKeySetting("keymap_quicktune_dec")))
|
|
|
|
quicktune.dec();
|
|
|
|
{
|
|
|
|
std::string msg = quicktune.getMessage();
|
|
|
|
if(msg != ""){
|
|
|
|
statustext = narrow_to_wide(msg);
|
|
|
|
statustext_time = 0;
|
|
|
|
}
|
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
|
|
|
|
// Item selection with mouse wheel
|
2011-11-29 16:15:18 +01:00
|
|
|
u16 new_playeritem = client.getPlayerItem();
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
|
|
|
s32 wheel = input->getMouseWheel();
|
|
|
|
u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE-1,
|
2013-05-04 02:08:52 +02:00
|
|
|
player->hud_hotbar_itemcount-1);
|
2011-04-23 17:31:31 +02:00
|
|
|
|
|
|
|
if(wheel < 0)
|
|
|
|
{
|
2011-11-29 16:15:18 +01:00
|
|
|
if(new_playeritem < max_item)
|
|
|
|
new_playeritem++;
|
2011-04-23 17:31:31 +02:00
|
|
|
else
|
2011-11-29 16:15:18 +01:00
|
|
|
new_playeritem = 0;
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
else if(wheel > 0)
|
|
|
|
{
|
2011-11-29 16:15:18 +01:00
|
|
|
if(new_playeritem > 0)
|
|
|
|
new_playeritem--;
|
2011-04-23 17:31:31 +02:00
|
|
|
else
|
2011-11-29 16:15:18 +01:00
|
|
|
new_playeritem = max_item;
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Item selection
|
|
|
|
for(u16 i=0; i<10; i++)
|
|
|
|
{
|
2011-08-13 22:44:31 +02:00
|
|
|
const KeyPress *kp = NumberKey + (i + 1) % 10;
|
|
|
|
if(input->wasKeyDown(*kp))
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2013-05-04 02:08:52 +02:00
|
|
|
if(i < PLAYER_INVENTORY_SIZE && i < player->hud_hotbar_itemcount)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2011-11-29 16:15:18 +01:00
|
|
|
new_playeritem = i;
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2011-10-16 13:57:53 +02:00
|
|
|
infostream<<"Selected item: "
|
2011-11-29 16:15:18 +01:00
|
|
|
<<new_playeritem<<std::endl;
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Viewing range selection
|
2011-05-14 14:43:26 +02:00
|
|
|
if(input->wasKeyDown(getKeySetting("keymap_rangeselect")))
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2012-02-01 00:56:30 +01:00
|
|
|
draw_control.range_all = !draw_control.range_all;
|
2011-04-23 17:31:31 +02:00
|
|
|
if(draw_control.range_all)
|
|
|
|
{
|
2012-02-01 00:56:30 +01:00
|
|
|
infostream<<"Enabled full viewing range"<<std::endl;
|
|
|
|
statustext = L"Enabled full viewing range";
|
|
|
|
statustext_time = 0;
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-02-01 00:56:30 +01:00
|
|
|
infostream<<"Disabled full viewing range"<<std::endl;
|
|
|
|
statustext = L"Disabled full viewing range";
|
|
|
|
statustext_time = 0;
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print debug stacks
|
2011-05-14 14:43:26 +02:00
|
|
|
if(input->wasKeyDown(getKeySetting("keymap_print_debug_stacks")))
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
|
|
|
dstream<<"-----------------------------------------"
|
|
|
|
<<std::endl;
|
|
|
|
dstream<<DTIME<<"Printing debug stacks:"<<std::endl;
|
|
|
|
dstream<<"-----------------------------------------"
|
|
|
|
<<std::endl;
|
|
|
|
debug_stacks_print();
|
|
|
|
}
|
|
|
|
|
2011-09-26 14:09:04 +02:00
|
|
|
/*
|
|
|
|
Mouse and camera control
|
|
|
|
NOTE: Do this before client.setPlayerControl() to not cause a camera lag of one frame
|
|
|
|
*/
|
|
|
|
|
2012-03-16 15:34:30 +01:00
|
|
|
float turn_amount = 0;
|
2011-09-26 14:09:04 +02:00
|
|
|
if((device->isWindowActive() && noMenuActive()) || random_input)
|
|
|
|
{
|
|
|
|
if(!random_input)
|
|
|
|
{
|
|
|
|
// Mac OSX gets upset if this is set every frame
|
|
|
|
if(device->getCursorControl()->isVisible())
|
|
|
|
device->getCursorControl()->setVisible(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(first_loop_after_window_activation){
|
2011-10-16 13:57:53 +02:00
|
|
|
//infostream<<"window active, first loop"<<std::endl;
|
2011-09-26 14:09:04 +02:00
|
|
|
first_loop_after_window_activation = false;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
s32 dx = input->getMousePos().X - displaycenter.X;
|
|
|
|
s32 dy = input->getMousePos().Y - displaycenter.Y;
|
|
|
|
if(invert_mouse)
|
|
|
|
dy = -dy;
|
2011-10-16 13:57:53 +02:00
|
|
|
//infostream<<"window active, pos difference "<<dx<<","<<dy<<std::endl;
|
2011-09-26 14:09:04 +02:00
|
|
|
|
|
|
|
/*const float keyspeed = 500;
|
|
|
|
if(input->isKeyDown(irr::KEY_UP))
|
|
|
|
dy -= dtime * keyspeed;
|
|
|
|
if(input->isKeyDown(irr::KEY_DOWN))
|
|
|
|
dy += dtime * keyspeed;
|
|
|
|
if(input->isKeyDown(irr::KEY_LEFT))
|
|
|
|
dx -= dtime * keyspeed;
|
|
|
|
if(input->isKeyDown(irr::KEY_RIGHT))
|
|
|
|
dx += dtime * keyspeed;*/
|
2012-03-16 15:34:30 +01:00
|
|
|
|
2013-04-14 19:53:00 +02:00
|
|
|
float d = g_settings->getFloat("mouse_sensitivity");
|
|
|
|
d = rangelim(d, 0.01, 100.0);
|
2012-03-16 15:34:30 +01:00
|
|
|
camera_yaw -= dx*d;
|
|
|
|
camera_pitch += dy*d;
|
2011-09-26 14:09:04 +02:00
|
|
|
if(camera_pitch < -89.5) camera_pitch = -89.5;
|
|
|
|
if(camera_pitch > 89.5) camera_pitch = 89.5;
|
2012-03-16 15:34:30 +01:00
|
|
|
|
|
|
|
turn_amount = v2f(dx, dy).getLength() * d;
|
2011-09-26 14:09:04 +02:00
|
|
|
}
|
|
|
|
input->setMousePos(displaycenter.X, displaycenter.Y);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
// Mac OSX gets upset if this is set every frame
|
|
|
|
if(device->getCursorControl()->isVisible() == false)
|
|
|
|
device->getCursorControl()->setVisible(true);
|
|
|
|
|
2011-10-16 13:57:53 +02:00
|
|
|
//infostream<<"window inactive"<<std::endl;
|
2011-09-26 14:09:04 +02:00
|
|
|
first_loop_after_window_activation = true;
|
|
|
|
}
|
2012-03-16 15:34:30 +01:00
|
|
|
recent_turn_speed = recent_turn_speed * 0.9 + turn_amount * 0.1;
|
|
|
|
//std::cerr<<"recent_turn_speed = "<<recent_turn_speed<<std::endl;
|
2011-09-26 14:09:04 +02:00
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
|
|
|
Player speed control
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
/*bool a_up,
|
|
|
|
bool a_down,
|
|
|
|
bool a_left,
|
|
|
|
bool a_right,
|
|
|
|
bool a_jump,
|
|
|
|
bool a_superspeed,
|
|
|
|
bool a_sneak,
|
2012-11-22 20:01:31 +01:00
|
|
|
bool a_LMB,
|
|
|
|
bool a_RMB,
|
2011-04-23 17:31:31 +02:00
|
|
|
float a_pitch,
|
|
|
|
float a_yaw*/
|
|
|
|
PlayerControl control(
|
2011-05-14 14:43:26 +02:00
|
|
|
input->isKeyDown(getKeySetting("keymap_forward")),
|
|
|
|
input->isKeyDown(getKeySetting("keymap_backward")),
|
|
|
|
input->isKeyDown(getKeySetting("keymap_left")),
|
|
|
|
input->isKeyDown(getKeySetting("keymap_right")),
|
|
|
|
input->isKeyDown(getKeySetting("keymap_jump")),
|
|
|
|
input->isKeyDown(getKeySetting("keymap_special1")),
|
|
|
|
input->isKeyDown(getKeySetting("keymap_sneak")),
|
2012-11-22 20:01:31 +01:00
|
|
|
input->getLeftState(),
|
|
|
|
input->getRightState(),
|
2011-04-23 17:31:31 +02:00
|
|
|
camera_pitch,
|
|
|
|
camera_yaw
|
|
|
|
);
|
|
|
|
client.setPlayerControl(control);
|
2012-11-22 20:01:31 +01:00
|
|
|
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;
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
2014-01-06 16:37:23 +01:00
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
2014-01-06 16:37:23 +01:00
|
|
|
Run server, client (and process environments)
|
2011-04-23 17:31:31 +02:00
|
|
|
*/
|
2014-01-06 16:37:23 +01:00
|
|
|
bool can_be_and_is_paused =
|
|
|
|
(simple_singleplayer_mode && g_menumgr.pausesGame());
|
|
|
|
if(can_be_and_is_paused)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2014-01-06 16:37:23 +01:00
|
|
|
// No time passes
|
|
|
|
dtime = 0;
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
2014-01-06 16:37:23 +01:00
|
|
|
else
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2014-01-06 16:37:23 +01:00
|
|
|
if(server != NULL)
|
|
|
|
{
|
|
|
|
//TimeTaker timer("server->step(dtime)");
|
|
|
|
server->step(dtime);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
//TimeTaker timer("client.step(dtime)");
|
|
|
|
client.step(dtime);
|
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2011-10-15 13:46:59 +02:00
|
|
|
// Read client events
|
|
|
|
for(;;)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2011-10-15 13:46:59 +02:00
|
|
|
ClientEvent event = client.getClientEvent();
|
|
|
|
if(event.type == CE_NONE)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2013-01-06 15:32:23 +01:00
|
|
|
else if(event.type == CE_PLAYER_DAMAGE &&
|
|
|
|
client.getHP() != 0)
|
2011-10-15 13:46:59 +02:00
|
|
|
{
|
|
|
|
//u16 damage = event.player_damage.amount;
|
2011-10-16 13:57:53 +02:00
|
|
|
//infostream<<"Player damage: "<<damage<<std::endl;
|
2012-04-28 02:06:25 +02:00
|
|
|
|
2013-01-02 21:57:04 +01:00
|
|
|
damage_flash += 100.0;
|
|
|
|
damage_flash += 8.0 * event.player_damage.amount;
|
2012-04-28 02:06:25 +02:00
|
|
|
|
|
|
|
player->hurt_tilt_timer = 1.5;
|
|
|
|
player->hurt_tilt_strength = event.player_damage.amount/2;
|
|
|
|
player->hurt_tilt_strength = rangelim(player->hurt_tilt_strength, 2.0, 10.0);
|
2013-04-17 20:13:47 +02:00
|
|
|
|
|
|
|
MtEvent *e = new SimpleTriggerEvent("PlayerDamage");
|
|
|
|
gamedef->event()->put(e);
|
2011-10-15 13:46:59 +02:00
|
|
|
}
|
|
|
|
else if(event.type == CE_PLAYER_FORCE_MOVE)
|
|
|
|
{
|
|
|
|
camera_yaw = event.player_force_move.yaw;
|
|
|
|
camera_pitch = event.player_force_move.pitch;
|
|
|
|
}
|
|
|
|
else if(event.type == CE_DEATHSCREEN)
|
|
|
|
{
|
|
|
|
if(respawn_menu_active)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*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 =
|
2014-01-06 12:45:42 +01:00
|
|
|
new GUIDeathScreen(guienv, guiroot, -1,
|
2011-10-15 13:46:59 +02:00
|
|
|
&g_menumgr, respawner);
|
|
|
|
menu->drop();
|
|
|
|
|
2011-12-03 09:01:14 +01:00
|
|
|
chat_backend.addMessage(L"", L"You died.");
|
|
|
|
|
2011-10-15 13:46:59 +02:00
|
|
|
/* Handle visualization */
|
|
|
|
|
2013-01-02 21:57:04 +01:00
|
|
|
damage_flash = 0;
|
2011-10-15 13:46:59 +02:00
|
|
|
|
2012-04-28 02:06:25 +02:00
|
|
|
LocalPlayer* player = client.getEnv().getLocalPlayer();
|
|
|
|
player->hurt_tilt_timer = 0;
|
|
|
|
player->hurt_tilt_strength = 0;
|
|
|
|
|
2011-10-15 13:46:59 +02:00
|
|
|
/*LocalPlayer* player = client.getLocalPlayer();
|
|
|
|
player->setPosition(player->getPosition() + v3f(0,-BS,0));
|
|
|
|
camera.update(player, busytime, screensize);*/
|
|
|
|
}
|
2013-01-02 20:45:04 +01:00
|
|
|
else if (event.type == CE_SHOW_FORMSPEC)
|
|
|
|
{
|
|
|
|
if (current_formspec == 0)
|
|
|
|
{
|
|
|
|
/* Create menu */
|
2013-04-07 16:34:35 +02:00
|
|
|
/* Note: FormspecFormSource and TextDestPlayerInventory
|
|
|
|
* are deleted by guiFormSpecMenu */
|
2013-01-02 20:45:04 +01:00
|
|
|
current_formspec = new FormspecFormSource(*(event.show_formspec.formspec),¤t_formspec);
|
2013-04-07 16:34:35 +02:00
|
|
|
current_textdest = new TextDestPlayerInventory(&client,*(event.show_formspec.formname));
|
2013-01-02 20:45:04 +01:00
|
|
|
GUIFormSpecMenu *menu =
|
|
|
|
new GUIFormSpecMenu(device, guiroot, -1,
|
|
|
|
&g_menumgr,
|
2013-08-20 22:38:14 +02:00
|
|
|
&client, gamedef, tsrc);
|
2013-01-02 20:45:04 +01:00
|
|
|
menu->setFormSource(current_formspec);
|
2013-04-07 16:34:35 +02:00
|
|
|
menu->setTextDest(current_textdest);
|
2013-01-02 20:45:04 +01:00
|
|
|
menu->drop();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-04-07 16:34:35 +02:00
|
|
|
assert(current_textdest != 0);
|
2013-01-02 20:45:04 +01:00
|
|
|
/* update menu */
|
2013-04-07 16:34:35 +02:00
|
|
|
current_textdest->setFormName(*(event.show_formspec.formname));
|
2013-01-02 20:45:04 +01:00
|
|
|
current_formspec->setForm(*(event.show_formspec.formspec));
|
|
|
|
}
|
|
|
|
delete(event.show_formspec.formspec);
|
2013-01-03 18:59:28 +01:00
|
|
|
delete(event.show_formspec.formname);
|
2013-01-02 20:45:04 +01:00
|
|
|
}
|
2013-01-23 18:32:02 +01:00
|
|
|
else if(event.type == CE_SPAWN_PARTICLE)
|
|
|
|
{
|
|
|
|
LocalPlayer* player = client.getEnv().getLocalPlayer();
|
2013-06-24 04:17:50 +02:00
|
|
|
video::ITexture *texture =
|
2013-01-23 18:32:02 +01:00
|
|
|
gamedef->tsrc()->getTexture(*(event.spawn_particle.texture));
|
|
|
|
|
|
|
|
new Particle(gamedef, smgr, player, client.getEnv(),
|
|
|
|
*event.spawn_particle.pos,
|
|
|
|
*event.spawn_particle.vel,
|
|
|
|
*event.spawn_particle.acc,
|
|
|
|
event.spawn_particle.expirationtime,
|
|
|
|
event.spawn_particle.size,
|
2013-06-24 04:17:50 +02:00
|
|
|
event.spawn_particle.collisiondetection,
|
2013-04-22 20:35:10 +02:00
|
|
|
event.spawn_particle.vertical,
|
2013-06-24 04:17:50 +02:00
|
|
|
texture,
|
|
|
|
v2f(0.0, 0.0),
|
|
|
|
v2f(1.0, 1.0));
|
2013-01-23 18:32:02 +01:00
|
|
|
}
|
|
|
|
else if(event.type == CE_ADD_PARTICLESPAWNER)
|
|
|
|
{
|
|
|
|
LocalPlayer* player = client.getEnv().getLocalPlayer();
|
2013-06-24 04:17:50 +02:00
|
|
|
video::ITexture *texture =
|
2013-01-23 18:32:02 +01:00
|
|
|
gamedef->tsrc()->getTexture(*(event.add_particlespawner.texture));
|
|
|
|
|
|
|
|
new ParticleSpawner(gamedef, smgr, player,
|
|
|
|
event.add_particlespawner.amount,
|
|
|
|
event.add_particlespawner.spawntime,
|
|
|
|
*event.add_particlespawner.minpos,
|
|
|
|
*event.add_particlespawner.maxpos,
|
|
|
|
*event.add_particlespawner.minvel,
|
|
|
|
*event.add_particlespawner.maxvel,
|
|
|
|
*event.add_particlespawner.minacc,
|
|
|
|
*event.add_particlespawner.maxacc,
|
|
|
|
event.add_particlespawner.minexptime,
|
|
|
|
event.add_particlespawner.maxexptime,
|
|
|
|
event.add_particlespawner.minsize,
|
|
|
|
event.add_particlespawner.maxsize,
|
|
|
|
event.add_particlespawner.collisiondetection,
|
2013-04-22 20:35:10 +02:00
|
|
|
event.add_particlespawner.vertical,
|
2013-06-24 04:17:50 +02:00
|
|
|
texture,
|
2013-01-23 18:32:02 +01:00
|
|
|
event.add_particlespawner.id);
|
|
|
|
}
|
|
|
|
else if(event.type == CE_DELETE_PARTICLESPAWNER)
|
|
|
|
{
|
|
|
|
delete_particlespawner (event.delete_particlespawner.id);
|
|
|
|
}
|
2013-04-11 20:23:38 +02:00
|
|
|
else if (event.type == CE_HUDADD)
|
|
|
|
{
|
2013-04-14 00:20:22 +02:00
|
|
|
u32 id = event.hudadd.id;
|
|
|
|
size_t nhudelem = player->hud.size();
|
|
|
|
if (id > nhudelem || (id < nhudelem && player->hud[id])) {
|
|
|
|
delete event.hudadd.pos;
|
|
|
|
delete event.hudadd.name;
|
|
|
|
delete event.hudadd.scale;
|
|
|
|
delete event.hudadd.text;
|
2013-04-22 11:53:55 +02:00
|
|
|
delete event.hudadd.align;
|
2013-04-23 01:47:59 +02:00
|
|
|
delete event.hudadd.offset;
|
2014-01-26 21:31:59 +01:00
|
|
|
delete event.hudadd.world_pos;
|
2013-04-14 00:20:22 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
HudElement *e = new HudElement;
|
|
|
|
e->type = (HudElementType)event.hudadd.type;
|
2013-04-11 20:23:38 +02:00
|
|
|
e->pos = *event.hudadd.pos;
|
|
|
|
e->name = *event.hudadd.name;
|
|
|
|
e->scale = *event.hudadd.scale;
|
|
|
|
e->text = *event.hudadd.text;
|
|
|
|
e->number = event.hudadd.number;
|
|
|
|
e->item = event.hudadd.item;
|
|
|
|
e->dir = event.hudadd.dir;
|
2013-04-22 11:53:55 +02:00
|
|
|
e->align = *event.hudadd.align;
|
2013-04-23 01:47:59 +02:00
|
|
|
e->offset = *event.hudadd.offset;
|
2014-01-26 21:31:59 +01:00
|
|
|
e->world_pos = *event.hudadd.world_pos;
|
2013-04-14 00:20:22 +02:00
|
|
|
|
|
|
|
if (id == nhudelem)
|
|
|
|
player->hud.push_back(e);
|
|
|
|
else
|
|
|
|
player->hud[id] = e;
|
|
|
|
|
|
|
|
delete event.hudadd.pos;
|
|
|
|
delete event.hudadd.name;
|
|
|
|
delete event.hudadd.scale;
|
|
|
|
delete event.hudadd.text;
|
2013-04-22 11:53:55 +02:00
|
|
|
delete event.hudadd.align;
|
2013-04-23 01:47:59 +02:00
|
|
|
delete event.hudadd.offset;
|
2014-01-26 21:31:59 +01:00
|
|
|
delete event.hudadd.world_pos;
|
2013-04-11 20:23:38 +02:00
|
|
|
}
|
|
|
|
else if (event.type == CE_HUDRM)
|
|
|
|
{
|
2013-04-14 00:20:22 +02:00
|
|
|
u32 id = event.hudrm.id;
|
|
|
|
if (id < player->hud.size() && player->hud[id]) {
|
|
|
|
delete player->hud[id];
|
|
|
|
player->hud[id] = NULL;
|
|
|
|
}
|
2013-04-11 20:23:38 +02:00
|
|
|
}
|
|
|
|
else if (event.type == CE_HUDCHANGE)
|
|
|
|
{
|
2013-04-14 00:20:22 +02:00
|
|
|
u32 id = event.hudchange.id;
|
|
|
|
if (id >= player->hud.size() || !player->hud[id]) {
|
2014-01-26 21:31:59 +01:00
|
|
|
delete event.hudchange.v3fdata;
|
2013-04-14 00:20:22 +02:00
|
|
|
delete event.hudchange.v2fdata;
|
|
|
|
delete event.hudchange.sdata;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
HudElement* e = player->hud[id];
|
|
|
|
switch (event.hudchange.stat) {
|
|
|
|
case HUD_STAT_POS:
|
|
|
|
e->pos = *event.hudchange.v2fdata;
|
|
|
|
break;
|
|
|
|
case HUD_STAT_NAME:
|
|
|
|
e->name = *event.hudchange.sdata;
|
|
|
|
break;
|
|
|
|
case HUD_STAT_SCALE:
|
|
|
|
e->scale = *event.hudchange.v2fdata;
|
|
|
|
break;
|
|
|
|
case HUD_STAT_TEXT:
|
|
|
|
e->text = *event.hudchange.sdata;
|
|
|
|
break;
|
|
|
|
case HUD_STAT_NUMBER:
|
|
|
|
e->number = event.hudchange.data;
|
|
|
|
break;
|
|
|
|
case HUD_STAT_ITEM:
|
|
|
|
e->item = event.hudchange.data;
|
|
|
|
break;
|
|
|
|
case HUD_STAT_DIR:
|
|
|
|
e->dir = event.hudchange.data;
|
|
|
|
break;
|
2013-04-22 11:53:55 +02:00
|
|
|
case HUD_STAT_ALIGN:
|
|
|
|
e->align = *event.hudchange.v2fdata;
|
|
|
|
break;
|
2013-04-23 01:47:59 +02:00
|
|
|
case HUD_STAT_OFFSET:
|
|
|
|
e->offset = *event.hudchange.v2fdata;
|
|
|
|
break;
|
2014-01-26 21:31:59 +01:00
|
|
|
case HUD_STAT_WORLD_POS:
|
|
|
|
e->world_pos = *event.hudchange.v3fdata;
|
|
|
|
break;
|
2013-04-14 00:20:22 +02:00
|
|
|
}
|
|
|
|
|
2014-01-26 21:31:59 +01:00
|
|
|
delete event.hudchange.v3fdata;
|
2013-04-14 00:20:22 +02:00
|
|
|
delete event.hudchange.v2fdata;
|
|
|
|
delete event.hudchange.sdata;
|
2013-04-11 20:23:38 +02:00
|
|
|
}
|
2013-05-02 22:52:50 +02:00
|
|
|
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;
|
|
|
|
}
|
2013-10-18 10:53:19 +02:00
|
|
|
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);
|
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//TimeTaker //timer2("//timer2");
|
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
/*
|
|
|
|
For interaction purposes, get info about the held item
|
2012-01-12 06:10:39 +01:00
|
|
|
- What item is it?
|
2011-11-29 16:15:18 +01:00
|
|
|
- Is it a usable item?
|
|
|
|
- Can it point to liquids?
|
|
|
|
*/
|
2012-01-12 06:10:39 +01:00
|
|
|
ItemStack playeritem;
|
2011-11-29 16:15:18 +01:00
|
|
|
{
|
|
|
|
InventoryList *mlist = local_inventory.getList("main");
|
|
|
|
if(mlist != NULL)
|
|
|
|
{
|
2012-01-12 06:10:39 +01:00
|
|
|
playeritem = mlist->getItem(client.getPlayerItem());
|
2011-11-29 16:15:18 +01:00
|
|
|
}
|
|
|
|
}
|
2013-04-27 03:47:52 +02:00
|
|
|
const ItemDefinition &playeritem_def =
|
|
|
|
playeritem.getDefinition(itemdef);
|
2012-03-09 22:53:25 +01:00
|
|
|
ToolCapabilities playeritem_toolcap =
|
|
|
|
playeritem.getToolCapabilities(itemdef);
|
|
|
|
|
|
|
|
/*
|
|
|
|
Update camera
|
|
|
|
*/
|
|
|
|
|
2012-03-15 22:54:10 +01:00
|
|
|
LocalPlayer* player = client.getEnv().getLocalPlayer();
|
2012-03-09 22:53:25 +01:00
|
|
|
float full_punch_interval = playeritem_toolcap.full_punch_interval;
|
|
|
|
float tool_reload_ratio = time_from_last_punch / full_punch_interval;
|
|
|
|
tool_reload_ratio = MYMIN(tool_reload_ratio, 1.0);
|
2013-08-03 17:46:18 +02:00
|
|
|
camera.update(player, dtime, busytime, screensize,
|
|
|
|
tool_reload_ratio);
|
2012-03-09 22:53:25 +01:00
|
|
|
camera.step(dtime);
|
|
|
|
|
|
|
|
v3f player_position = player->getPosition();
|
2013-07-27 20:34:30 +02:00
|
|
|
v3s16 pos_i = floatToInt(player_position, BS);
|
2012-03-09 22:53:25 +01:00
|
|
|
v3f camera_position = camera.getPosition();
|
|
|
|
v3f camera_direction = camera.getDirection();
|
|
|
|
f32 camera_fov = camera.getFovMax();
|
|
|
|
|
|
|
|
if(!disable_camera_update){
|
2012-03-15 22:54:10 +01:00
|
|
|
client.getEnv().getClientMap().updateCamera(camera_position,
|
2012-03-09 22:53:25 +01:00
|
|
|
camera_direction, camera_fov);
|
|
|
|
}
|
2012-03-23 14:29:30 +01:00
|
|
|
|
|
|
|
// Update sound listener
|
|
|
|
sound->updateListener(camera.getCameraNode()->getPosition(),
|
|
|
|
v3f(0,0,0), // velocity
|
2012-04-04 12:32:08 +02:00
|
|
|
camera.getDirection(),
|
2012-03-23 14:29:30 +01:00
|
|
|
camera.getCameraNode()->getUpVector());
|
2012-04-06 14:30:36 +02:00
|
|
|
sound->setListenerGain(g_settings->getFloat("sound_volume"));
|
2011-11-29 16:15:18 +01:00
|
|
|
|
2012-03-23 19:23:03 +01:00
|
|
|
/*
|
|
|
|
Update sound maker
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
soundmaker.step(dtime);
|
|
|
|
|
|
|
|
ClientMap &map = client.getEnv().getClientMap();
|
|
|
|
MapNode n = map.getNodeNoEx(player->getStandingNodePos());
|
|
|
|
soundmaker.m_player_step_sound = nodedef->get(n).sound_footstep;
|
|
|
|
}
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
|
|
|
Calculate what block is the crosshair pointing to
|
|
|
|
*/
|
|
|
|
|
|
|
|
//u32 t1 = device->getTimer()->getRealTime();
|
|
|
|
|
2013-07-20 14:50:19 +02:00
|
|
|
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;
|
2011-04-23 17:31:31 +02:00
|
|
|
core::line3d<f32> shootline(camera_position,
|
|
|
|
camera_position + camera_direction * BS * (d+1));
|
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
ClientActiveObject *selected_object = NULL;
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
PointedThing pointed = getPointedThing(
|
|
|
|
// input
|
|
|
|
&client, player_position, camera_direction,
|
|
|
|
camera_position, shootline, d,
|
2013-04-27 03:47:52 +02:00
|
|
|
playeritem_def.liquids_pointable, !ldown_for_dig,
|
2011-11-29 16:15:18 +01:00
|
|
|
// output
|
2012-03-19 04:25:09 +01:00
|
|
|
hilightboxes,
|
2011-11-29 16:15:18 +01:00
|
|
|
selected_object);
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
if(pointed != pointed_old)
|
|
|
|
{
|
|
|
|
infostream<<"Pointing at "<<pointed.dump()<<std::endl;
|
|
|
|
//dstream<<"Pointing at "<<pointed.dump()<<std::endl;
|
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
/*
|
|
|
|
Stop digging when
|
|
|
|
- releasing left mouse button
|
|
|
|
- pointing away from node
|
|
|
|
*/
|
|
|
|
if(digging)
|
|
|
|
{
|
|
|
|
if(input->getLeftReleased())
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2011-11-29 16:15:18 +01:00
|
|
|
infostream<<"Left button released"
|
|
|
|
<<" (stopped digging)"<<std::endl;
|
|
|
|
digging = false;
|
|
|
|
}
|
|
|
|
else if(pointed != pointed_old)
|
|
|
|
{
|
|
|
|
if (pointed.type == POINTEDTHING_NODE
|
|
|
|
&& pointed_old.type == POINTEDTHING_NODE
|
|
|
|
&& pointed.node_undersurface == pointed_old.node_undersurface)
|
|
|
|
{
|
|
|
|
// Still pointing to the same node,
|
|
|
|
// but a different face. Don't reset.
|
2011-10-15 11:17:21 +02:00
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
infostream<<"Pointing away from node"
|
|
|
|
<<" (stopped digging)"<<std::endl;
|
|
|
|
digging = false;
|
2011-10-15 01:28:57 +02:00
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
if(!digging)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2011-11-29 16:15:18 +01:00
|
|
|
client.interact(1, pointed_old);
|
2012-03-13 18:56:12 +01:00
|
|
|
client.setCrack(-1, v3s16(0,0,0));
|
2011-11-29 16:15:18 +01:00
|
|
|
dig_time = 0.0;
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
if(!digging && ldown_for_dig && !input->getLeftState())
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2011-11-29 16:15:18 +01:00
|
|
|
ldown_for_dig = false;
|
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
bool left_punch = false;
|
2012-03-24 02:28:08 +01:00
|
|
|
soundmaker.m_player_leftpunch_sound.name = "";
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2013-01-04 15:19:16 +01:00
|
|
|
if(input->getRightState())
|
|
|
|
repeat_rightclick_timer += dtime;
|
2013-01-14 21:30:36 +01:00
|
|
|
else
|
|
|
|
repeat_rightclick_timer = 0;
|
2013-01-04 15:19:16 +01:00
|
|
|
|
2013-04-27 03:47:52 +02:00
|
|
|
if(playeritem_def.usable && input->getLeftState())
|
2011-11-29 16:15:18 +01:00
|
|
|
{
|
|
|
|
if(input->getLeftClicked())
|
|
|
|
client.interact(4, pointed);
|
|
|
|
}
|
|
|
|
else if(pointed.type == POINTEDTHING_NODE)
|
|
|
|
{
|
|
|
|
v3s16 nodepos = pointed.node_undersurface;
|
|
|
|
v3s16 neighbourpos = pointed.node_abovesurface;
|
2011-04-23 17:31:31 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Check information text of node
|
|
|
|
*/
|
2012-03-15 22:54:10 +01:00
|
|
|
|
|
|
|
ClientMap &map = client.getEnv().getClientMap();
|
|
|
|
NodeMetadata *meta = map.getNodeMetadata(nodepos);
|
|
|
|
if(meta){
|
2012-06-01 15:10:53 +02:00
|
|
|
infotext = narrow_to_wide(meta->getString("infotext"));
|
2012-03-15 22:54:10 +01:00
|
|
|
} else {
|
|
|
|
MapNode n = map.getNode(nodepos);
|
2013-03-19 19:05:32 +01:00
|
|
|
if(nodedef->get(n).tiledef[0].name == "unknown_node.png"){
|
2011-12-03 12:51:16 +01:00
|
|
|
infotext = L"Unknown node: ";
|
|
|
|
infotext += narrow_to_wide(nodedef->get(n).name);
|
|
|
|
}
|
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Handle digging
|
|
|
|
*/
|
|
|
|
|
2013-06-19 23:00:14 +02:00
|
|
|
if(nodig_delay_timer <= 0.0 && input->getLeftState()
|
|
|
|
&& client.checkPrivilege("interact"))
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2011-11-29 16:15:18 +01:00
|
|
|
if(!digging)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2011-11-29 16:15:18 +01:00
|
|
|
infostream<<"Started digging"<<std::endl;
|
|
|
|
client.interact(0, pointed);
|
|
|
|
digging = true;
|
|
|
|
ldown_for_dig = true;
|
|
|
|
}
|
2012-03-15 22:54:10 +01:00
|
|
|
MapNode n = client.getEnv().getClientMap().getNode(nodepos);
|
2012-07-21 13:38:49 +02:00
|
|
|
|
|
|
|
// NOTE: Similar piece of code exists on the server side for
|
|
|
|
// cheat detection.
|
2012-03-09 22:53:25 +01:00
|
|
|
// Get digging parameters
|
|
|
|
DigParams params = getDigParams(nodedef->get(n).groups,
|
|
|
|
&playeritem_toolcap);
|
2012-02-28 18:45:23 +01:00
|
|
|
// If can't dig, try hand
|
|
|
|
if(!params.diggable){
|
|
|
|
const ItemDefinition &hand = itemdef->get("");
|
|
|
|
const ToolCapabilities *tp = hand.tool_capabilities;
|
|
|
|
if(tp)
|
|
|
|
params = getDigParams(nodedef->get(n).groups, tp);
|
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
|
|
|
|
float dig_time_complete = 0.0;
|
|
|
|
|
2012-02-28 18:45:23 +01:00
|
|
|
if(params.diggable == false)
|
2011-11-29 16:15:18 +01:00
|
|
|
{
|
|
|
|
// I guess nobody will wait for this long
|
|
|
|
dig_time_complete = 10000000.0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-02-28 18:45:23 +01:00
|
|
|
dig_time_complete = params.time;
|
2012-12-31 19:33:36 +01:00
|
|
|
if (g_settings->getBool("enable_particles"))
|
|
|
|
{
|
|
|
|
const ContentFeatures &features =
|
|
|
|
client.getNodeDefManager()->get(n);
|
|
|
|
addPunchingParticles
|
2013-01-23 18:32:02 +01:00
|
|
|
(gamedef, smgr, player, client.getEnv(),
|
|
|
|
nodepos, features.tiles);
|
2012-12-31 19:33:36 +01:00
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
if(dig_time_complete >= 0.001)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2012-06-16 17:02:56 +02:00
|
|
|
dig_index = (u16)((float)crack_animation_length
|
2011-11-29 16:15:18 +01:00
|
|
|
* dig_time/dig_time_complete);
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
// This is for torches
|
|
|
|
else
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2012-06-16 17:02:56 +02:00
|
|
|
dig_index = crack_animation_length;
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
2012-07-21 13:38:49 +02:00
|
|
|
|
2013-07-09 02:38:53 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-04 15:21:35 +01:00
|
|
|
// Don't show cracks if not diggable
|
|
|
|
if(dig_time_complete >= 100000.0)
|
|
|
|
{
|
|
|
|
}
|
2012-06-16 17:02:56 +02:00
|
|
|
else if(dig_index < crack_animation_length)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2012-03-13 18:56:12 +01:00
|
|
|
//TimeTaker timer("client.setTempMod");
|
|
|
|
//infostream<<"dig_index="<<dig_index<<std::endl;
|
|
|
|
client.setCrack(dig_index, nodepos);
|
2011-11-29 16:15:18 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
infostream<<"Digging completed"<<std::endl;
|
|
|
|
client.interact(2, pointed);
|
2012-03-13 18:56:12 +01:00
|
|
|
client.setCrack(-1, v3s16(0,0,0));
|
2012-03-24 02:28:08 +01:00
|
|
|
MapNode wasnode = map.getNode(nodepos);
|
2011-11-29 16:15:18 +01:00
|
|
|
client.removeNode(nodepos);
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2012-12-31 19:33:36 +01:00
|
|
|
if (g_settings->getBool("enable_particles"))
|
|
|
|
{
|
|
|
|
const ContentFeatures &features =
|
|
|
|
client.getNodeDefManager()->get(wasnode);
|
|
|
|
addDiggingParticles
|
2013-01-23 18:32:02 +01:00
|
|
|
(gamedef, smgr, player, client.getEnv(),
|
|
|
|
nodepos, features.tiles);
|
2012-12-31 19:33:36 +01:00
|
|
|
}
|
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
dig_time = 0;
|
|
|
|
digging = false;
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
nodig_delay_timer = dig_time_complete
|
2012-06-16 17:02:56 +02:00
|
|
|
/ (float)crack_animation_length;
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
// We don't want a corresponding delay to
|
|
|
|
// very time consuming nodes
|
2012-03-24 02:28:08 +01:00
|
|
|
if(nodig_delay_timer > 0.3)
|
|
|
|
nodig_delay_timer = 0.3;
|
2011-11-29 16:15:18 +01:00
|
|
|
// We want a slight delay to very little
|
|
|
|
// time consuming nodes
|
|
|
|
float mindelay = 0.15;
|
|
|
|
if(nodig_delay_timer < mindelay)
|
|
|
|
nodig_delay_timer = mindelay;
|
2012-03-24 02:28:08 +01:00
|
|
|
|
|
|
|
// Send event to trigger sound
|
|
|
|
MtEvent *e = new NodeDugEvent(nodepos, wasnode);
|
|
|
|
gamedef->event()->put(e);
|
2011-11-29 16:15:18 +01:00
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2013-06-13 14:41:23 +02:00
|
|
|
if(dig_time_complete < 100000.0)
|
|
|
|
dig_time += dtime;
|
|
|
|
else {
|
|
|
|
dig_time = 0;
|
|
|
|
client.setCrack(-1, nodepos);
|
|
|
|
}
|
2011-09-19 03:01:11 +02:00
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
camera.setDigging(0); // left click animation
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
|
2013-06-19 23:00:14 +02:00
|
|
|
if((input->getRightClicked() ||
|
|
|
|
repeat_rightclick_timer >=
|
|
|
|
g_settings->getFloat("repeat_rightclick_time")) &&
|
|
|
|
client.checkPrivilege("interact"))
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2013-01-04 15:19:16 +01:00
|
|
|
repeat_rightclick_timer = 0;
|
2011-10-16 13:57:53 +02:00
|
|
|
infostream<<"Ground right-clicked"<<std::endl;
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2012-07-15 18:19:38 +02:00
|
|
|
// Sign special case, at least until formspec is properly implemented.
|
|
|
|
// Deprecated?
|
2014-01-06 12:45:42 +01:00
|
|
|
if(meta && meta->getString("formspec") == "hack:sign_text_input"
|
2013-01-26 23:15:23 +01:00
|
|
|
&& !random_input
|
|
|
|
&& !input->isKeyDown(getKeySetting("keymap_sneak")))
|
2012-06-01 15:10:53 +02:00
|
|
|
{
|
|
|
|
infostream<<"Launching metadata text input"<<std::endl;
|
|
|
|
|
|
|
|
// Get a new text for it
|
|
|
|
|
|
|
|
TextDest *dest = new TextDestNodeMetadata(nodepos, &client);
|
|
|
|
|
|
|
|
std::wstring wtext = narrow_to_wide(meta->getString("text"));
|
|
|
|
|
|
|
|
(new GUITextInputMenu(guienv, guiroot, -1,
|
|
|
|
&g_menumgr, dest,
|
|
|
|
wtext))->drop();
|
|
|
|
}
|
2011-06-18 01:00:01 +02:00
|
|
|
// If metadata provides an inventory view, activate it
|
2013-01-26 23:15:23 +01:00
|
|
|
else if(meta && meta->getString("formspec") != "" && !random_input
|
|
|
|
&& !input->isKeyDown(getKeySetting("keymap_sneak")))
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2011-10-16 13:57:53 +02:00
|
|
|
infostream<<"Launching custom inventory view"<<std::endl;
|
2012-01-12 06:10:39 +01:00
|
|
|
|
|
|
|
InventoryLocation inventoryloc;
|
|
|
|
inventoryloc.setNodeMeta(nodepos);
|
2011-06-18 01:00:01 +02:00
|
|
|
|
2012-06-03 15:03:19 +02:00
|
|
|
/* Create menu */
|
2011-06-18 01:00:01 +02:00
|
|
|
|
2012-07-15 18:19:38 +02:00
|
|
|
GUIFormSpecMenu *menu =
|
2012-11-28 18:39:58 +01:00
|
|
|
new GUIFormSpecMenu(device, guiroot, -1,
|
2012-06-03 15:03:19 +02:00
|
|
|
&g_menumgr,
|
2013-08-20 22:38:14 +02:00
|
|
|
&client, gamedef, tsrc);
|
2012-06-03 15:03:19 +02:00
|
|
|
menu->setFormSpec(meta->getString("formspec"),
|
|
|
|
inventoryloc);
|
2012-06-03 17:30:34 +02:00
|
|
|
menu->setFormSource(new NodeMetadataFormSource(
|
|
|
|
&client.getEnv().getClientMap(), nodepos));
|
2012-07-15 18:19:38 +02:00
|
|
|
menu->setTextDest(new TextDestNodeMetadata(nodepos, &client));
|
2011-04-23 17:31:31 +02:00
|
|
|
menu->drop();
|
|
|
|
}
|
2011-11-13 11:48:05 +01:00
|
|
|
// Otherwise report right click to server
|
2011-04-23 17:31:31 +02:00
|
|
|
else
|
|
|
|
{
|
2014-01-15 21:26:54 +01:00
|
|
|
camera.setDigging(1); // right click animation (always shown for feedback)
|
|
|
|
|
2012-06-10 11:46:48 +02:00
|
|
|
// If the wielded item has node placement prediction,
|
|
|
|
// make that happen
|
2013-06-19 23:09:18 +02:00
|
|
|
bool placed = nodePlacementPrediction(client,
|
2014-01-15 21:26:54 +01:00
|
|
|
playeritem_def,
|
|
|
|
nodepos, neighbourpos);
|
|
|
|
|
|
|
|
if(placed) {
|
|
|
|
// Report to server
|
|
|
|
client.interact(3, pointed);
|
|
|
|
// Read the sound
|
2013-06-19 23:09:18 +02:00
|
|
|
soundmaker.m_player_rightpunch_sound =
|
2014-01-15 21:26:54 +01:00
|
|
|
playeritem_def.sound_place;
|
|
|
|
} else {
|
2013-06-19 23:09:18 +02:00
|
|
|
soundmaker.m_player_rightpunch_sound =
|
2014-01-15 21:26:54 +01:00
|
|
|
SimpleSoundSpec();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (playeritem_def.node_placement_prediction == "" ||
|
|
|
|
nodedef->get(map.getNode(nodepos)).rightclickable)
|
|
|
|
client.interact(3, pointed); // Report to server
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
}
|
2011-11-29 16:15:18 +01:00
|
|
|
}
|
|
|
|
else if(pointed.type == POINTEDTHING_OBJECT)
|
|
|
|
{
|
|
|
|
infotext = narrow_to_wide(selected_object->infoText());
|
|
|
|
|
2012-03-09 19:28:55 +01:00
|
|
|
if(infotext == L"" && show_debug){
|
|
|
|
infotext = narrow_to_wide(selected_object->debugInfoText());
|
|
|
|
}
|
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
//if(input->getLeftClicked())
|
|
|
|
if(input->getLeftState())
|
|
|
|
{
|
|
|
|
bool do_punch = false;
|
|
|
|
bool do_punch_damage = false;
|
|
|
|
if(object_hit_delay_timer <= 0.0){
|
|
|
|
do_punch = true;
|
|
|
|
do_punch_damage = true;
|
|
|
|
object_hit_delay_timer = object_hit_delay;
|
|
|
|
}
|
|
|
|
if(input->getLeftClicked()){
|
|
|
|
do_punch = true;
|
|
|
|
}
|
|
|
|
if(do_punch){
|
|
|
|
infostream<<"Left-clicked object"<<std::endl;
|
|
|
|
left_punch = true;
|
|
|
|
}
|
|
|
|
if(do_punch_damage){
|
|
|
|
// Report direct punch
|
2012-03-05 00:30:55 +01:00
|
|
|
v3f objpos = selected_object->getPosition();
|
|
|
|
v3f dir = (objpos - player_position).normalize();
|
|
|
|
|
|
|
|
bool disable_send = selected_object->directReportPunch(
|
|
|
|
dir, &playeritem, time_from_last_punch);
|
2012-03-09 22:53:25 +01:00
|
|
|
time_from_last_punch = 0;
|
2011-11-29 16:15:18 +01:00
|
|
|
if(!disable_send)
|
|
|
|
client.interact(0, pointed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(input->getRightClicked())
|
|
|
|
{
|
|
|
|
infostream<<"Right-clicked object"<<std::endl;
|
|
|
|
client.interact(3, pointed); // place
|
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
2012-03-11 11:22:37 +01:00
|
|
|
else if(input->getLeftState())
|
|
|
|
{
|
|
|
|
// When button is held down in air, show continuous animation
|
|
|
|
left_punch = true;
|
|
|
|
}
|
2011-09-07 16:56:04 +02:00
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
pointed_old = pointed;
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2012-03-11 11:22:37 +01:00
|
|
|
if(left_punch || input->getLeftClicked())
|
2011-09-20 11:06:16 +02:00
|
|
|
{
|
|
|
|
camera.setDigging(0); // left click animation
|
|
|
|
}
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
input->resetLeftClicked();
|
|
|
|
input->resetRightClicked();
|
2011-11-29 16:15:18 +01:00
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
input->resetLeftReleased();
|
|
|
|
input->resetRightReleased();
|
|
|
|
|
|
|
|
/*
|
|
|
|
Calculate stuff for drawing
|
|
|
|
*/
|
2012-03-16 15:34:30 +01:00
|
|
|
|
2011-11-15 12:13:18 +01:00
|
|
|
/*
|
2012-03-16 15:34:30 +01:00
|
|
|
Fog range
|
2011-11-15 12:13:18 +01:00
|
|
|
*/
|
2012-03-16 15:34:30 +01:00
|
|
|
|
2013-08-12 08:18:38 +02:00
|
|
|
if(draw_control.range_all)
|
|
|
|
fog_range = 100000*BS;
|
|
|
|
else {
|
2012-03-16 15:34:30 +01:00
|
|
|
fog_range = draw_control.wanted_range*BS + 0.0*MAP_BLOCKSIZE*BS;
|
2013-09-17 00:56:15 +02:00
|
|
|
if(use_weather)
|
2013-08-30 19:20:07 +02:00
|
|
|
fog_range *= (1.5 - 1.4*(float)client.getEnv().getClientMap().getHumidity(pos_i)/100);
|
2013-08-03 17:46:18 +02:00
|
|
|
fog_range = MYMIN(fog_range, (draw_control.farthest_drawn+20)*BS);
|
2012-03-16 15:34:30 +01:00
|
|
|
fog_range *= 0.9;
|
|
|
|
}
|
2011-04-29 16:53:07 +02:00
|
|
|
|
|
|
|
/*
|
2012-03-16 15:34:30 +01:00
|
|
|
Calculate general brightness
|
2011-04-29 16:53:07 +02:00
|
|
|
*/
|
2012-03-16 15:34:30 +01:00
|
|
|
u32 daynight_ratio = client.getEnv().getDayNightRatio();
|
2012-12-02 17:02:04 +01:00
|
|
|
float time_brightness = decode_light_f((float)daynight_ratio/1000.0);
|
2012-03-16 15:34:30 +01:00
|
|
|
float direct_brightness = 0;
|
|
|
|
bool sunlight_seen = false;
|
|
|
|
if(g_settings->getBool("free_move")){
|
|
|
|
direct_brightness = time_brightness;
|
|
|
|
sunlight_seen = true;
|
|
|
|
} else {
|
|
|
|
ScopeProfiler sp(g_profiler, "Detecting background light", SPT_AVG);
|
|
|
|
float old_brightness = sky->getBrightness();
|
|
|
|
direct_brightness = (float)client.getEnv().getClientMap()
|
|
|
|
.getBackgroundBrightness(MYMIN(fog_range*1.2, 60*BS),
|
|
|
|
daynight_ratio, (int)(old_brightness*255.5), &sunlight_seen)
|
|
|
|
/ 255.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
time_of_day = client.getEnv().getTimeOfDayF();
|
|
|
|
float maxsm = 0.05;
|
|
|
|
if(fabs(time_of_day - time_of_day_smooth) > maxsm &&
|
|
|
|
fabs(time_of_day - time_of_day_smooth + 1.0) > maxsm &&
|
|
|
|
fabs(time_of_day - time_of_day_smooth - 1.0) > maxsm)
|
|
|
|
time_of_day_smooth = time_of_day;
|
|
|
|
float todsm = 0.05;
|
|
|
|
if(time_of_day_smooth > 0.8 && time_of_day < 0.2)
|
|
|
|
time_of_day_smooth = time_of_day_smooth * (1.0-todsm)
|
|
|
|
+ (time_of_day+1.0) * todsm;
|
|
|
|
else
|
|
|
|
time_of_day_smooth = time_of_day_smooth * (1.0-todsm)
|
|
|
|
+ time_of_day * todsm;
|
|
|
|
|
|
|
|
sky->update(time_of_day_smooth, time_brightness, direct_brightness,
|
|
|
|
sunlight_seen);
|
|
|
|
|
|
|
|
video::SColor bgcolor = sky->getBgColor();
|
|
|
|
video::SColor skycolor = sky->getSkyColor();
|
2011-04-29 16:53:07 +02:00
|
|
|
|
2011-04-29 14:34:26 +02:00
|
|
|
/*
|
2011-09-07 19:21:28 +02:00
|
|
|
Update clouds
|
2011-04-29 14:34:26 +02:00
|
|
|
*/
|
2012-03-16 15:34:30 +01:00
|
|
|
if(clouds){
|
|
|
|
if(sky->getCloudsVisible()){
|
|
|
|
clouds->setVisible(true);
|
|
|
|
clouds->step(dtime);
|
|
|
|
clouds->update(v2f(player_position.X, player_position.Z),
|
|
|
|
sky->getCloudColor());
|
|
|
|
} else{
|
|
|
|
clouds->setVisible(false);
|
|
|
|
}
|
2011-05-06 15:58:06 +02:00
|
|
|
}
|
2011-04-29 14:34:26 +02:00
|
|
|
|
2012-12-31 19:33:36 +01:00
|
|
|
/*
|
|
|
|
Update particles
|
|
|
|
*/
|
|
|
|
|
|
|
|
allparticles_step(dtime, client.getEnv());
|
2013-01-23 18:32:02 +01:00
|
|
|
allparticlespawners_step(dtime, client.getEnv());
|
2011-06-07 21:08:16 +02:00
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
|
|
|
Fog
|
|
|
|
*/
|
|
|
|
|
2013-09-03 13:21:04 +02:00
|
|
|
if(g_settings->getBool("enable_fog") && !force_fog_off)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
|
|
|
driver->setFog(
|
|
|
|
bgcolor,
|
|
|
|
video::EFT_FOG_LINEAR,
|
2012-03-16 15:34:30 +01:00
|
|
|
fog_range*0.4,
|
|
|
|
fog_range*1.0,
|
2011-04-23 17:31:31 +02:00
|
|
|
0.01,
|
|
|
|
false, // pixel fog
|
|
|
|
false // range fog
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
driver->setFog(
|
|
|
|
bgcolor,
|
|
|
|
video::EFT_FOG_LINEAR,
|
|
|
|
100000*BS,
|
|
|
|
110000*BS,
|
|
|
|
0.01,
|
|
|
|
false, // pixel fog
|
|
|
|
false // range fog
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Update gui stuff (0ms)
|
|
|
|
*/
|
|
|
|
|
|
|
|
//TimeTaker guiupdatetimer("Gui updating");
|
|
|
|
|
2012-02-01 00:56:30 +01:00
|
|
|
if(show_debug)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
|
|
|
static float drawtime_avg = 0;
|
|
|
|
drawtime_avg = drawtime_avg * 0.95 + (float)drawtime*0.05;
|
2012-02-01 00:56:30 +01:00
|
|
|
/*static float beginscenetime_avg = 0;
|
2011-04-23 17:31:31 +02:00
|
|
|
beginscenetime_avg = beginscenetime_avg * 0.95 + (float)beginscenetime*0.05;
|
|
|
|
static float scenetime_avg = 0;
|
|
|
|
scenetime_avg = scenetime_avg * 0.95 + (float)scenetime*0.05;
|
|
|
|
static float endscenetime_avg = 0;
|
2012-02-01 00:56:30 +01:00
|
|
|
endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;*/
|
2013-12-25 03:52:42 +01:00
|
|
|
|
|
|
|
u16 fps = (1.0/dtime_avg1);
|
|
|
|
|
2013-06-01 01:49:59 +02:00
|
|
|
std::ostringstream os(std::ios_base::binary);
|
|
|
|
os<<std::fixed
|
2013-09-25 04:29:07 +02:00
|
|
|
<<"Minetest "<<minetest_version_hash
|
2013-12-25 03:52:42 +01:00
|
|
|
<<" FPS = "<<fps
|
2013-06-01 01:49:59 +02:00
|
|
|
<<" (R: range_all="<<draw_control.range_all<<")"
|
|
|
|
<<std::setprecision(0)
|
|
|
|
<<" drawtime = "<<drawtime_avg
|
|
|
|
<<std::setprecision(1)
|
|
|
|
<<", dtime_jitter = "
|
|
|
|
<<(dtime_jitter1_max_fraction * 100.0)<<" %"
|
|
|
|
<<std::setprecision(1)
|
|
|
|
<<", v_range = "<<draw_control.wanted_range
|
|
|
|
<<std::setprecision(3)
|
|
|
|
<<", RTT = "<<client.getRTT();
|
|
|
|
guitext->setText(narrow_to_wide(os.str()).c_str());
|
2012-02-01 00:56:30 +01:00
|
|
|
guitext->setVisible(true);
|
|
|
|
}
|
2012-02-01 01:36:59 +01:00
|
|
|
else if(show_hud || show_chat)
|
2012-02-01 00:56:30 +01:00
|
|
|
{
|
2013-09-25 04:29:07 +02:00
|
|
|
std::ostringstream os(std::ios_base::binary);
|
|
|
|
os<<"Minetest "<<minetest_version_hash;
|
|
|
|
guitext->setText(narrow_to_wide(os.str()).c_str());
|
2012-02-01 00:56:30 +01:00
|
|
|
guitext->setVisible(true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
guitext->setVisible(false);
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
|
2012-02-01 00:56:30 +01:00
|
|
|
if(show_debug)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2013-06-01 01:49:59 +02:00
|
|
|
std::ostringstream os(std::ios_base::binary);
|
|
|
|
os<<std::setprecision(1)<<std::fixed
|
|
|
|
<<"(" <<(player_position.X/BS)
|
|
|
|
<<", "<<(player_position.Y/BS)
|
|
|
|
<<", "<<(player_position.Z/BS)
|
|
|
|
<<") (yaw="<<(wrapDegrees_0_360(camera_yaw))
|
2013-07-27 20:34:30 +02:00
|
|
|
<<") (t="<<client.getEnv().getClientMap().getHeat(pos_i)
|
|
|
|
<<"C, h="<<client.getEnv().getClientMap().getHumidity(pos_i)
|
|
|
|
<<"%) (seed = "<<((unsigned long long)client.getMapSeed())
|
2013-06-01 01:49:59 +02:00
|
|
|
<<")";
|
|
|
|
guitext2->setText(narrow_to_wide(os.str()).c_str());
|
2012-02-01 00:56:30 +01:00
|
|
|
guitext2->setVisible(true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
guitext2->setVisible(false);
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
guitext_info->setText(infotext.c_str());
|
2012-03-09 19:28:55 +01:00
|
|
|
guitext_info->setVisible(show_hud && g_menumgr.menuCount() == 0);
|
2012-02-01 00:56:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2012-03-21 13:09:32 +01:00
|
|
|
float statustext_time_max = 1.5;
|
2012-02-01 00:56:30 +01:00
|
|
|
if(!statustext.empty())
|
|
|
|
{
|
|
|
|
statustext_time += dtime;
|
|
|
|
if(statustext_time >= statustext_time_max)
|
|
|
|
{
|
|
|
|
statustext = L"";
|
|
|
|
statustext_time = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
guitext_status->setText(statustext.c_str());
|
|
|
|
guitext_status->setVisible(!statustext.empty());
|
|
|
|
|
|
|
|
if(!statustext.empty())
|
|
|
|
{
|
|
|
|
s32 status_y = screensize.Y - 130;
|
|
|
|
core::rect<s32> rect(
|
|
|
|
10,
|
|
|
|
status_y - guitext_status->getTextHeight(),
|
|
|
|
screensize.X - 10,
|
|
|
|
status_y
|
|
|
|
);
|
|
|
|
guitext_status->setRelativePosition(rect);
|
|
|
|
|
|
|
|
// Fade out
|
|
|
|
video::SColor initial_color(255,0,0,0);
|
|
|
|
if(guienv->getSkin())
|
|
|
|
initial_color = guienv->getSkin()->getColor(gui::EGDC_BUTTON_TEXT);
|
|
|
|
video::SColor final_color = initial_color;
|
|
|
|
final_color.setAlpha(0);
|
|
|
|
video::SColor fade_color =
|
|
|
|
initial_color.getInterpolated_quadratic(
|
|
|
|
initial_color,
|
|
|
|
final_color,
|
2012-03-21 21:11:15 +01:00
|
|
|
pow(statustext_time / (float)statustext_time_max, 2.0f));
|
2012-02-01 00:56:30 +01:00
|
|
|
guitext_status->setOverrideColor(fade_color);
|
|
|
|
guitext_status->enableOverrideColor(true);
|
|
|
|
}
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Get chat messages from client
|
|
|
|
*/
|
|
|
|
{
|
2011-11-27 13:29:48 +01:00
|
|
|
// Get new messages from error log buffer
|
|
|
|
while(!chat_log_error_buf.empty())
|
|
|
|
{
|
2011-12-03 09:01:14 +01:00
|
|
|
chat_backend.addMessage(L"", narrow_to_wide(
|
|
|
|
chat_log_error_buf.get()));
|
2011-11-27 13:29:48 +01:00
|
|
|
}
|
|
|
|
// Get new messages from client
|
2011-04-23 17:31:31 +02:00
|
|
|
std::wstring message;
|
|
|
|
while(client.getChatMessage(message))
|
|
|
|
{
|
2011-12-03 09:01:14 +01:00
|
|
|
chat_backend.addUnparsedMessage(message);
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
2011-12-03 09:01:14 +01:00
|
|
|
// Remove old messages
|
|
|
|
chat_backend.step(dtime);
|
2011-04-23 17:31:31 +02:00
|
|
|
|
2011-12-03 09:01:14 +01:00
|
|
|
// Display all messages in a static text element
|
|
|
|
u32 recent_chat_count = chat_backend.getRecentBuffer().getLineCount();
|
|
|
|
std::wstring recent_chat = chat_backend.getRecentChat();
|
|
|
|
guitext_chat->setText(recent_chat.c_str());
|
2012-02-01 00:56:30 +01:00
|
|
|
|
2011-12-03 09:01:14 +01:00
|
|
|
// Update gui element size and position
|
2012-02-01 00:56:30 +01:00
|
|
|
s32 chat_y = 5+(text_height+5);
|
|
|
|
if(show_debug)
|
|
|
|
chat_y += (text_height+5);
|
2011-04-23 17:31:31 +02:00
|
|
|
core::rect<s32> rect(
|
2011-12-03 09:01:14 +01:00
|
|
|
10,
|
|
|
|
chat_y,
|
|
|
|
screensize.X - 10,
|
|
|
|
chat_y + guitext_chat->getTextHeight()
|
2011-04-23 17:31:31 +02:00
|
|
|
);
|
|
|
|
guitext_chat->setRelativePosition(rect);
|
|
|
|
|
2011-12-03 09:01:14 +01:00
|
|
|
// Don't show chat if disabled or empty or profiler is enabled
|
|
|
|
guitext_chat->setVisible(show_chat && recent_chat_count != 0
|
|
|
|
&& !show_profiler);
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Inventory
|
|
|
|
*/
|
|
|
|
|
2011-11-29 16:15:18 +01:00
|
|
|
if(client.getPlayerItem() != new_playeritem)
|
|
|
|
{
|
|
|
|
client.selectPlayerItem(new_playeritem);
|
|
|
|
}
|
|
|
|
if(client.getLocalInventoryUpdated())
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2011-10-16 13:57:53 +02:00
|
|
|
//infostream<<"Updating local inventory"<<std::endl;
|
2011-04-23 17:31:31 +02:00
|
|
|
client.getLocalInventory(local_inventory);
|
2012-01-02 16:44:00 +01:00
|
|
|
|
|
|
|
update_wielded_item_trigger = true;
|
|
|
|
}
|
|
|
|
if(update_wielded_item_trigger)
|
|
|
|
{
|
|
|
|
update_wielded_item_trigger = false;
|
2011-09-19 03:01:11 +02:00
|
|
|
// Update wielded tool
|
|
|
|
InventoryList *mlist = local_inventory.getList("main");
|
2012-01-12 06:10:39 +01:00
|
|
|
ItemStack item;
|
2011-09-19 03:01:11 +02:00
|
|
|
if(mlist != NULL)
|
2011-11-29 16:15:18 +01:00
|
|
|
item = mlist->getItem(client.getPlayerItem());
|
2013-05-20 00:20:42 +02:00
|
|
|
camera.wield(item, client.getPlayerItem());
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
2012-09-04 08:48:26 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Update block draw list every 200ms or when camera direction has
|
|
|
|
changed much
|
|
|
|
*/
|
|
|
|
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_timer = 0;
|
|
|
|
client.getEnv().getClientMap().updateDrawList(driver);
|
|
|
|
update_draw_list_last_cam_dir = camera_direction;
|
|
|
|
}
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
|
|
|
Drawing begins
|
|
|
|
*/
|
|
|
|
|
2012-03-21 02:33:02 +01:00
|
|
|
TimeTaker tt_draw("mainloop: draw");
|
2011-04-23 17:31:31 +02:00
|
|
|
|
|
|
|
{
|
|
|
|
TimeTaker timer("beginScene");
|
|
|
|
//driver->beginScene(false, true, bgcolor);
|
2012-03-16 15:34:30 +01:00
|
|
|
//driver->beginScene(true, true, bgcolor);
|
|
|
|
driver->beginScene(true, true, skycolor);
|
2011-04-23 17:31:31 +02:00
|
|
|
beginscenetime = timer.stop(true);
|
|
|
|
}
|
2011-06-07 21:08:16 +02:00
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
//timer3.stop();
|
2012-03-16 15:34:30 +01:00
|
|
|
|
2011-10-16 13:57:53 +02:00
|
|
|
//infostream<<"smgr->drawAll()"<<std::endl;
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
|
|
|
TimeTaker timer("smgr");
|
|
|
|
smgr->drawAll();
|
2012-02-18 17:51:19 +01:00
|
|
|
|
|
|
|
if(g_settings->getBool("anaglyph"))
|
|
|
|
{
|
|
|
|
irr::core::vector3df oldPosition = camera.getCameraNode()->getPosition();
|
|
|
|
irr::core::vector3df oldTarget = camera.getCameraNode()->getTarget();
|
|
|
|
|
|
|
|
irr::core::matrix4 startMatrix = camera.getCameraNode()->getAbsoluteTransformation();
|
|
|
|
|
|
|
|
irr::core::vector3df focusPoint = (camera.getCameraNode()->getTarget() -
|
|
|
|
camera.getCameraNode()->getAbsolutePosition()).setLength(1) +
|
|
|
|
camera.getCameraNode()->getAbsolutePosition() ;
|
|
|
|
|
|
|
|
//Left eye...
|
|
|
|
irr::core::vector3df leftEye;
|
|
|
|
irr::core::matrix4 leftMove;
|
|
|
|
|
|
|
|
leftMove.setTranslation( irr::core::vector3df(-g_settings->getFloat("anaglyph_strength"),0.0f,0.0f) );
|
|
|
|
leftEye=(startMatrix*leftMove).getTranslation();
|
|
|
|
|
|
|
|
//clear the depth buffer, and color
|
|
|
|
driver->beginScene( true, true, irr::video::SColor(0,200,200,255) );
|
|
|
|
|
|
|
|
driver->getOverrideMaterial().Material.ColorMask = irr::video::ECP_RED;
|
|
|
|
driver->getOverrideMaterial().EnableFlags = irr::video::EMF_COLOR_MASK;
|
2014-01-06 12:45:42 +01:00
|
|
|
driver->getOverrideMaterial().EnablePasses = irr::scene::ESNRP_SKY_BOX +
|
2012-02-18 17:51:19 +01:00
|
|
|
irr::scene::ESNRP_SOLID +
|
|
|
|
irr::scene::ESNRP_TRANSPARENT +
|
|
|
|
irr::scene::ESNRP_TRANSPARENT_EFFECT +
|
|
|
|
irr::scene::ESNRP_SHADOW;
|
|
|
|
|
|
|
|
camera.getCameraNode()->setPosition( leftEye );
|
|
|
|
camera.getCameraNode()->setTarget( focusPoint );
|
|
|
|
|
|
|
|
smgr->drawAll(); // 'smgr->drawAll();' may go here
|
|
|
|
|
2013-08-25 15:41:16 +02:00
|
|
|
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
|
|
|
|
|
|
|
|
if (show_hud)
|
|
|
|
hud.drawSelectionBoxes(hilightboxes);
|
|
|
|
|
2012-02-18 17:51:19 +01:00
|
|
|
|
|
|
|
//Right eye...
|
|
|
|
irr::core::vector3df rightEye;
|
|
|
|
irr::core::matrix4 rightMove;
|
|
|
|
|
|
|
|
rightMove.setTranslation( irr::core::vector3df(g_settings->getFloat("anaglyph_strength"),0.0f,0.0f) );
|
|
|
|
rightEye=(startMatrix*rightMove).getTranslation();
|
|
|
|
|
|
|
|
//clear the depth buffer
|
|
|
|
driver->clearZBuffer();
|
|
|
|
|
|
|
|
driver->getOverrideMaterial().Material.ColorMask = irr::video::ECP_GREEN + irr::video::ECP_BLUE;
|
|
|
|
driver->getOverrideMaterial().EnableFlags = irr::video::EMF_COLOR_MASK;
|
|
|
|
driver->getOverrideMaterial().EnablePasses = irr::scene::ESNRP_SKY_BOX +
|
|
|
|
irr::scene::ESNRP_SOLID +
|
|
|
|
irr::scene::ESNRP_TRANSPARENT +
|
|
|
|
irr::scene::ESNRP_TRANSPARENT_EFFECT +
|
|
|
|
irr::scene::ESNRP_SHADOW;
|
|
|
|
|
|
|
|
camera.getCameraNode()->setPosition( rightEye );
|
|
|
|
camera.getCameraNode()->setTarget( focusPoint );
|
|
|
|
|
|
|
|
smgr->drawAll(); // 'smgr->drawAll();' may go here
|
|
|
|
|
2013-08-25 15:41:16 +02:00
|
|
|
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
|
|
|
|
|
|
|
|
if (show_hud)
|
|
|
|
hud.drawSelectionBoxes(hilightboxes);
|
|
|
|
|
2012-02-18 17:51:19 +01:00
|
|
|
|
|
|
|
//driver->endScene();
|
|
|
|
|
|
|
|
driver->getOverrideMaterial().Material.ColorMask=irr::video::ECP_ALL;
|
|
|
|
driver->getOverrideMaterial().EnableFlags=0;
|
|
|
|
driver->getOverrideMaterial().EnablePasses=0;
|
|
|
|
|
|
|
|
camera.getCameraNode()->setPosition( oldPosition );
|
|
|
|
camera.getCameraNode()->setTarget( oldTarget );
|
|
|
|
}
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
scenetime = timer.stop(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
//TimeTaker timer9("auxiliary drawings");
|
|
|
|
// 0ms
|
|
|
|
|
|
|
|
//timer9.stop();
|
|
|
|
//TimeTaker //timer10("//timer10");
|
|
|
|
|
|
|
|
video::SMaterial m;
|
|
|
|
//m.Thickness = 10;
|
|
|
|
m.Thickness = 3;
|
|
|
|
m.Lighting = false;
|
|
|
|
driver->setMaterial(m);
|
|
|
|
|
|
|
|
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
|
2013-08-25 15:41:16 +02:00
|
|
|
if((!g_settings->getBool("anaglyph")) && (show_hud))
|
|
|
|
{
|
2013-04-14 00:20:22 +02:00
|
|
|
hud.drawSelectionBoxes(hilightboxes);
|
2013-08-25 15:41:16 +02:00
|
|
|
}
|
|
|
|
|
2011-09-21 01:42:52 +02:00
|
|
|
/*
|
|
|
|
Wielded tool
|
|
|
|
*/
|
2013-04-26 01:27:22 +02:00
|
|
|
if(show_hud && (player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE))
|
2011-09-21 01:42:52 +02:00
|
|
|
{
|
|
|
|
// Warning: This clears the Z buffer.
|
|
|
|
camera.drawWieldedTool();
|
|
|
|
}
|
|
|
|
|
2011-09-07 19:21:28 +02:00
|
|
|
/*
|
|
|
|
Post effects
|
|
|
|
*/
|
|
|
|
{
|
2012-03-15 22:54:10 +01:00
|
|
|
client.getEnv().getClientMap().renderPostFx();
|
2011-09-07 19:21:28 +02:00
|
|
|
}
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
2012-03-21 02:33:02 +01:00
|
|
|
Profiler graph
|
2011-04-23 17:31:31 +02:00
|
|
|
*/
|
2012-03-21 02:33:02 +01:00
|
|
|
if(show_profiler_graph)
|
|
|
|
{
|
|
|
|
graph.draw(10, screensize.Y - 10, driver, font);
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Draw crosshair
|
|
|
|
*/
|
2013-04-26 01:27:22 +02:00
|
|
|
if (show_hud)
|
2013-04-14 00:20:22 +02:00
|
|
|
hud.drawCrosshair();
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
} // timer
|
|
|
|
|
|
|
|
//timer10.stop();
|
|
|
|
//TimeTaker //timer11("//timer11");
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Draw hotbar
|
|
|
|
*/
|
2013-04-14 00:20:22 +02:00
|
|
|
if (show_hud)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2013-04-14 00:20:22 +02:00
|
|
|
hud.drawHotbar(v2s32(displaycenter.X, screensize.Y),
|
2013-06-19 16:30:22 +02:00
|
|
|
client.getHP(), client.getPlayerItem(), client.getBreath());
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Damage flash
|
|
|
|
*/
|
2013-01-02 21:57:04 +01:00
|
|
|
if(damage_flash > 0.0)
|
2011-04-23 17:31:31 +02:00
|
|
|
{
|
2013-01-03 16:15:46 +01:00
|
|
|
video::SColor color(std::min(damage_flash, 180.0f),180,0,0);
|
2011-04-23 17:31:31 +02:00
|
|
|
driver->draw2DRectangle(color,
|
|
|
|
core::rect<s32>(0,0,screensize.X,screensize.Y),
|
|
|
|
NULL);
|
2013-01-02 21:57:04 +01:00
|
|
|
|
|
|
|
damage_flash -= 100.0*dtime;
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
2011-07-01 20:25:31 +02:00
|
|
|
|
2012-04-28 02:06:25 +02:00
|
|
|
/*
|
|
|
|
Damage camera tilt
|
|
|
|
*/
|
|
|
|
if(player->hurt_tilt_timer > 0.0)
|
|
|
|
{
|
|
|
|
player->hurt_tilt_timer -= dtime*5;
|
|
|
|
if(player->hurt_tilt_timer < 0)
|
|
|
|
player->hurt_tilt_strength = 0;
|
|
|
|
}
|
|
|
|
|
2013-04-11 20:23:38 +02:00
|
|
|
/*
|
|
|
|
Draw lua hud items
|
|
|
|
*/
|
2013-04-14 00:20:22 +02:00
|
|
|
if (show_hud)
|
|
|
|
hud.drawLuaElements();
|
2013-04-11 20:23:38 +02:00
|
|
|
|
2012-12-06 17:33:11 +01:00
|
|
|
/*
|
|
|
|
Draw gui
|
|
|
|
*/
|
|
|
|
// 0-1ms
|
|
|
|
guienv->drawAll();
|
|
|
|
|
2011-04-23 17:31:31 +02:00
|
|
|
/*
|
|
|
|
End scene
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
TimeTaker timer("endScene");
|
2013-08-11 04:09:45 +02:00
|
|
|
driver->endScene();
|
2011-04-23 17:31:31 +02:00
|
|
|
endscenetime = timer.stop(true);
|
|
|
|
}
|
|
|
|
|
2012-03-21 02:33:02 +01:00
|
|
|
drawtime = tt_draw.stop(true);
|
|
|
|
g_profiler->graphAdd("mainloop_draw", (float)drawtime/1000.0f);
|
2011-04-23 17:31:31 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
End of drawing
|
|
|
|
*/
|
|
|
|
|
2012-03-21 02:33:02 +01:00
|
|
|
/*
|
|
|
|
Log times and stuff for visualization
|
|
|
|
*/
|
|
|
|
Profiler::GraphValues values;
|
|
|
|
g_profiler->graphGet(values);
|
|
|
|
graph.put(values);
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
2011-05-21 13:28:28 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Drop stuff
|
|
|
|
*/
|
2013-04-14 00:20:22 +02:00
|
|
|
if (clouds)
|
2011-06-07 21:08:16 +02:00
|
|
|
clouds->drop();
|
2013-04-14 00:20:22 +02:00
|
|
|
if (gui_chat_console)
|
2011-12-03 09:01:14 +01:00
|
|
|
gui_chat_console->drop();
|
2013-05-10 19:12:02 +02:00
|
|
|
if (sky)
|
|
|
|
sky->drop();
|
2013-04-14 00:20:22 +02:00
|
|
|
clear_particles();
|
2011-05-06 15:58:06 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Draw a "shutting down" screen, which will be shown while the map
|
|
|
|
generator and other stuff quits
|
|
|
|
*/
|
|
|
|
{
|
2011-06-26 19:00:04 +02:00
|
|
|
/*gui::IGUIStaticText *gui_shuttingdowntext = */
|
2013-05-09 18:23:48 +02:00
|
|
|
wchar_t* text = wgettext("Shutting down stuff...");
|
|
|
|
draw_load_screen(text, device, font, 0, -1, false);
|
|
|
|
delete[] text;
|
2011-06-26 19:00:04 +02:00
|
|
|
/*driver->beginScene(true, true, video::SColor(255,0,0,0));
|
2011-05-06 15:58:06 +02:00
|
|
|
guienv->drawAll();
|
|
|
|
driver->endScene();
|
2011-06-26 19:00:04 +02:00
|
|
|
gui_shuttingdowntext->remove();*/
|
2011-05-06 15:58:06 +02:00
|
|
|
}
|
2011-11-13 23:19:48 +01:00
|
|
|
|
2011-12-03 09:01:14 +01:00
|
|
|
chat_backend.addMessage(L"", L"# Disconnected.");
|
|
|
|
chat_backend.addMessage(L"", L"");
|
|
|
|
|
2014-01-06 12:45:42 +01:00
|
|
|
client.Stop();
|
|
|
|
|
|
|
|
//force answer all texture and shader jobs (TODO return empty values)
|
|
|
|
|
|
|
|
while(!client.isShutdown()) {
|
|
|
|
tsrc->processQueue();
|
|
|
|
shsrc->processQueue();
|
|
|
|
sleep_ms(100);
|
|
|
|
}
|
|
|
|
|
2012-03-10 22:28:51 +01:00
|
|
|
// Client scope (client is destructed before destructing *def and tsrc)
|
|
|
|
}while(0);
|
2012-03-25 17:45:27 +02:00
|
|
|
} // try-catch
|
|
|
|
catch(SerializationError &e)
|
|
|
|
{
|
|
|
|
error_message = L"A serialization error occurred:\n"
|
|
|
|
+ narrow_to_wide(e.what()) + L"\n\nThe server is probably "
|
|
|
|
L" running a different version of Minetest.";
|
|
|
|
errorstream<<wide_to_narrow(error_message)<<std::endl;
|
|
|
|
}
|
2013-12-18 22:35:55 +01:00
|
|
|
catch(ServerError &e) {
|
2013-04-07 19:41:12 +02:00
|
|
|
error_message = narrow_to_wide(e.what());
|
2013-12-18 22:35:55 +01:00
|
|
|
errorstream << "ServerError: " << e.what() << std::endl;
|
2013-04-07 19:41:12 +02:00
|
|
|
}
|
2013-12-18 22:35:55 +01:00
|
|
|
catch(ModError &e) {
|
|
|
|
errorstream << "ModError: " << e.what() << std::endl;
|
2013-04-07 19:41:12 +02:00
|
|
|
error_message = narrow_to_wide(e.what()) + wgettext("\nCheck debug.txt for details.");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-23 14:29:30 +01:00
|
|
|
|
|
|
|
if(!sound_is_dummy)
|
|
|
|
delete sound;
|
2012-03-19 02:59:12 +01:00
|
|
|
|
2013-04-07 19:41:12 +02:00
|
|
|
//has to be deleted first to stop all server threads
|
|
|
|
delete server;
|
|
|
|
|
2012-03-19 02:59:12 +01:00
|
|
|
delete tsrc;
|
|
|
|
delete shsrc;
|
2011-11-15 00:00:16 +01:00
|
|
|
delete nodedef;
|
2012-01-12 06:10:39 +01:00
|
|
|
delete itemdef;
|
2013-04-07 20:22:06 +02:00
|
|
|
|
|
|
|
//extended resource accounting
|
|
|
|
infostream << "Irrlicht resources after cleanup:" << std::endl;
|
|
|
|
infostream << "\tRemaining meshes : "
|
|
|
|
<< device->getSceneManager()->getMeshCache()->getMeshCount() << std::endl;
|
|
|
|
infostream << "\tRemaining textures : "
|
|
|
|
<< driver->getTextureCount() << std::endl;
|
|
|
|
for (unsigned int i = 0; i < driver->getTextureCount(); i++ ) {
|
|
|
|
irr::video::ITexture* texture = driver->getTextureByIndex(i);
|
|
|
|
infostream << "\t\t" << i << ":" << texture->getName().getPath().c_str()
|
|
|
|
<< std::endl;
|
|
|
|
}
|
2013-08-02 15:18:48 +02:00
|
|
|
clearTextureNameCache();
|
2013-04-07 20:22:06 +02:00
|
|
|
infostream << "\tRemaining materials: "
|
|
|
|
<< driver-> getMaterialRendererCount ()
|
|
|
|
<< " (note: irrlicht doesn't support removing renderers)"<< std::endl;
|
2011-04-23 17:31:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|