Merge branch 'master' of git://github.com/celeron55/minetest
Also: Some changes, bigger teleportsmaster
commit
0d367550bc
|
@ -10,7 +10,7 @@ project(minetest)
|
|||
# Also remember to set PROTOCOL_VERSION in clientserver.h when releasing
|
||||
set(VERSION_MAJOR 0)
|
||||
set(VERSION_MINOR 3)
|
||||
set(VERSION_PATCH dev-20111016)
|
||||
set(VERSION_PATCH dev-20111021)
|
||||
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
|
||||
|
||||
MESSAGE(STATUS "*** Will build version ${VERSION_STRING} ***")
|
||||
|
|
|
@ -3,6 +3,11 @@ Minetest-c55 changelog
|
|||
This should contain all the major changes.
|
||||
For minor stuff, refer to the commit log of the repository.
|
||||
|
||||
0.3.dev-20111021:
|
||||
- Modify dungeon masters to only try to shoot players
|
||||
- Fix object duplication bug at block load/unload bug
|
||||
- Improve network layer
|
||||
|
||||
0.3.dev-20111016:
|
||||
- Locked chest
|
||||
- Server user limit setting (max_users)
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
#keymap_jump = KEY_SPACE
|
||||
#keymap_sneak = KEY_LSHIFT
|
||||
#keymap_inventory = KEY_KEY_I
|
||||
# Go down ladder / go down in fly mode / go fast in fast mode
|
||||
#keymap_special1 = KEY_KEY_E
|
||||
#keymap_chat = KEY_KEY_T
|
||||
#keymap_rangeselect = KEY_KEY_R
|
||||
#keymap_freemove = KEY_KEY_K
|
||||
|
@ -46,7 +48,6 @@
|
|||
#keymap_frametime_graph = KEY_F1
|
||||
#keymap_screenshot = KEY_F12
|
||||
# Some (temporary) keys for debugging
|
||||
#keymap_special1 = KEY_KEY_E
|
||||
#keymap_print_debug_stacks = KEY_KEY_P
|
||||
|
||||
# The desired FPS
|
||||
|
@ -58,8 +59,8 @@
|
|||
#viewing_range_nodes_max = 300
|
||||
#viewing_range_nodes_min = 25
|
||||
# Initial window size
|
||||
screenW# = 800
|
||||
screenH# = 600
|
||||
#screenW = 800
|
||||
#screenH = 600
|
||||
# Address to connect to (#blank = start local server)
|
||||
#address =
|
||||
# Enable random user input, for testing
|
||||
|
@ -139,11 +140,11 @@ screenH# = 600
|
|||
# Player and object positions are sent at intervals specified by this
|
||||
#objectdata_interval = 0.2
|
||||
#active_object_send_range_blocks = 3
|
||||
#active_block_range = 5
|
||||
#active_block_range = 2
|
||||
#max_simultaneous_block_sends_per_client = 2
|
||||
#max_simultaneous_block_sends_server_total = 8
|
||||
#max_block_send_distance = 8
|
||||
#max_block_generate_distance = 8
|
||||
#max_block_send_distance = 7
|
||||
#max_block_generate_distance = 5
|
||||
#time_send_interval = 20
|
||||
# Length of day/night cycle. 72=20min, 360=4min, 1=24hour
|
||||
#time_speed = 72
|
||||
|
|
|
@ -342,7 +342,7 @@ void Camera::updateViewingRange(f32 frametime_in)
|
|||
<<std::endl;*/
|
||||
|
||||
m_draw_control.wanted_min_range = m_viewing_range_min;
|
||||
m_draw_control.wanted_max_blocks = (1.5*m_draw_control.blocks_would_have_drawn)+1;
|
||||
m_draw_control.wanted_max_blocks = (2.0*m_draw_control.blocks_would_have_drawn)+1;
|
||||
if (m_draw_control.wanted_max_blocks < 10)
|
||||
m_draw_control.wanted_max_blocks = 10;
|
||||
|
||||
|
@ -364,7 +364,9 @@ void Camera::updateViewingRange(f32 frametime_in)
|
|||
//dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;
|
||||
|
||||
// If needed frametime change is small, just return
|
||||
if (fabs(wanted_frametime_change) < m_wanted_frametime*0.4)
|
||||
// This value was 0.4 for many months until 2011-10-18 by c55;
|
||||
// Let's see how this works out.
|
||||
if (fabs(wanted_frametime_change) < m_wanted_frametime*0.33)
|
||||
{
|
||||
//dstream<<"ignoring small wanted_frametime_change"<<std::endl;
|
||||
return;
|
||||
|
|
|
@ -156,7 +156,7 @@ void * MeshUpdateThread::Thread()
|
|||
continue;
|
||||
}
|
||||
|
||||
ScopeProfiler sp(g_profiler, "mesh make");
|
||||
ScopeProfiler sp(g_profiler, "Client: Mesh making");
|
||||
|
||||
scene::SMesh *mesh_new = NULL;
|
||||
mesh_new = makeMapBlockMesh(q->data);
|
||||
|
@ -246,7 +246,7 @@ void Client::connect(Address address)
|
|||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
//JMutexAutoLock lock(m_con_mutex); //bulk comment-out
|
||||
m_con.setTimeoutMs(0);
|
||||
m_con.SetTimeoutMs(0);
|
||||
m_con.Connect(address);
|
||||
}
|
||||
|
||||
|
@ -563,8 +563,8 @@ void Client::step(float dtime)
|
|||
counter = 0.0;
|
||||
//JMutexAutoLock lock(m_con_mutex); //bulk comment-out
|
||||
// connectedAndInitialized() is true, peer exists.
|
||||
con::Peer *peer = m_con.GetPeer(PEER_ID_SERVER);
|
||||
infostream<<"Client: avg_rtt="<<peer->avg_rtt<<std::endl;
|
||||
float avg_rtt = m_con.GetPeerAvgRTT(PEER_ID_SERVER);
|
||||
infostream<<"Client: avg_rtt="<<avg_rtt<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -709,14 +709,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
|||
return;
|
||||
}
|
||||
|
||||
con::Peer *peer;
|
||||
{
|
||||
//JMutexAutoLock lock(m_con_mutex); //bulk comment-out
|
||||
// All data is coming from the server
|
||||
// PeerNotFoundException is handled by caller.
|
||||
peer = m_con.GetPeer(PEER_ID_SERVER);
|
||||
}
|
||||
|
||||
u8 ser_version = m_server_ser_ver;
|
||||
|
||||
//infostream<<"Client received command="<<(int)command<<std::endl;
|
||||
|
@ -2254,4 +2246,12 @@ ClientEvent Client::getClientEvent()
|
|||
return m_client_event_queue.pop_front();
|
||||
}
|
||||
|
||||
float Client::getRTT(void)
|
||||
{
|
||||
try{
|
||||
return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
|
||||
} catch(con::PeerNotFoundException &e){
|
||||
return 1337;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
12
src/client.h
12
src/client.h
|
@ -251,11 +251,11 @@ public:
|
|||
|
||||
float getAvgRtt()
|
||||
{
|
||||
//JMutexAutoLock lock(m_con_mutex); //bulk comment-out
|
||||
con::Peer *peer = m_con.GetPeerNoEx(PEER_ID_SERVER);
|
||||
if(peer == NULL)
|
||||
return 0.0;
|
||||
return peer->avg_rtt;
|
||||
try{
|
||||
return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
|
||||
} catch(con::PeerNotFoundException){
|
||||
return 1337;
|
||||
}
|
||||
}
|
||||
|
||||
bool getChatMessage(std::wstring &message)
|
||||
|
@ -301,6 +301,8 @@ public:
|
|||
return m_access_denied_reason;
|
||||
}
|
||||
|
||||
float getRTT(void);
|
||||
|
||||
//j
|
||||
inline ClientEnvironment * getEnv()
|
||||
{
|
||||
|
|
|
@ -175,6 +175,11 @@ enum ToClientCommand
|
|||
}
|
||||
*/
|
||||
|
||||
|
||||
//official minetest version has new commands
|
||||
//but we want our server's to be back-compatible with jachoo's version
|
||||
//we should delete this #ifdef on release
|
||||
#ifdef CELERON55_COMPATIBLE
|
||||
TOCLIENT_DEATHSCREEN = 0x37,
|
||||
/*
|
||||
u16 command
|
||||
|
@ -209,6 +214,12 @@ enum ToClientCommand
|
|||
u16 command
|
||||
u16 clan id
|
||||
*/
|
||||
#else //def CELERON55_COMPATIBLE
|
||||
TOCLIENT_DEATHSCREEN = 0x3A,
|
||||
TOCLIENT_PLAYER_CLAN = 0x37,
|
||||
TOCLIENT_CLAN_NAMES = 0x38,
|
||||
TOCLIENT_CLAN_DELETED = 0x39,
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -21,6 +21,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "noise.h"
|
||||
#include "constants.h"
|
||||
#include "debug.h"
|
||||
#include "main.h" // For g_profiler and g_settings
|
||||
#include "profiler.h"
|
||||
#include "settings.h"
|
||||
|
||||
Clouds::Clouds(
|
||||
scene::ISceneNode* parent,
|
||||
|
@ -76,6 +79,12 @@ void Clouds::render()
|
|||
if(SceneManager->getSceneNodeRenderPass() != scene::ESNRP_SOLID)
|
||||
return;
|
||||
|
||||
ScopeProfiler sp(g_profiler, "Rendering of clouds, avg", SPT_AVG);
|
||||
|
||||
int num_faces_to_draw = 6;
|
||||
if(g_settings->getBool("enable_2d_clouds"))
|
||||
num_faces_to_draw = 1;
|
||||
|
||||
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
|
||||
driver->setMaterial(m_material);
|
||||
|
||||
|
@ -144,7 +153,7 @@ void Clouds::render()
|
|||
f32 ry = 8*BS;
|
||||
f32 rz = cloud_size;
|
||||
|
||||
for(int i=0;i<6;i++)
|
||||
for(int i=0; i<num_faces_to_draw; i++)
|
||||
{
|
||||
switch(i)
|
||||
{
|
||||
|
|
1411
src/connection.cpp
1411
src/connection.cpp
File diff suppressed because it is too large
Load Diff
289
src/connection.h
289
src/connection.h
|
@ -319,28 +319,6 @@ struct Channel
|
|||
{
|
||||
Channel();
|
||||
~Channel();
|
||||
/*
|
||||
Processes a packet with the basic header stripped out.
|
||||
Parameters:
|
||||
packetdata: Data in packet (with no base headers)
|
||||
con: The connection to which the channel is associated
|
||||
(used for sending back stuff (ACKs))
|
||||
peer_id: peer id of the sender of the packet in question
|
||||
channelnum: channel on which the packet was sent
|
||||
reliable: true if recursing into a reliable packet
|
||||
*/
|
||||
SharedBuffer<u8> ProcessPacket(
|
||||
SharedBuffer<u8> packetdata,
|
||||
Connection *con,
|
||||
u16 peer_id,
|
||||
u8 channelnum,
|
||||
bool reliable=false);
|
||||
|
||||
// Returns next data from a buffer if possible
|
||||
// throws a NoIncomingDataException if no data is available
|
||||
// If found, sets peer_id
|
||||
SharedBuffer<u8> CheckIncomingBuffers(Connection *con,
|
||||
u16 &peer_id);
|
||||
|
||||
u16 next_outgoing_seqnum;
|
||||
u16 next_incoming_seqnum;
|
||||
|
@ -412,78 +390,237 @@ public:
|
|||
// with the id we have given to it
|
||||
bool has_sent_with_id;
|
||||
|
||||
float m_sendtime_accu;
|
||||
float m_max_packets_per_second;
|
||||
int m_num_sent;
|
||||
int m_max_num_sent;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class Connection
|
||||
/*
|
||||
Connection
|
||||
*/
|
||||
|
||||
struct OutgoingPacket
|
||||
{
|
||||
u16 peer_id;
|
||||
u8 channelnum;
|
||||
SharedBuffer<u8> data;
|
||||
bool reliable;
|
||||
|
||||
OutgoingPacket(u16 peer_id_, u8 channelnum_, SharedBuffer<u8> data_,
|
||||
bool reliable_):
|
||||
peer_id(peer_id_),
|
||||
channelnum(channelnum_),
|
||||
data(data_),
|
||||
reliable(reliable_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
enum ConnectionEventType{
|
||||
CONNEVENT_NONE,
|
||||
CONNEVENT_DATA_RECEIVED,
|
||||
CONNEVENT_PEER_ADDED,
|
||||
CONNEVENT_PEER_REMOVED,
|
||||
};
|
||||
|
||||
struct ConnectionEvent
|
||||
{
|
||||
enum ConnectionEventType type;
|
||||
u16 peer_id;
|
||||
SharedBuffer<u8> data;
|
||||
bool timeout;
|
||||
Address address;
|
||||
|
||||
ConnectionEvent(): type(CONNEVENT_NONE) {}
|
||||
|
||||
std::string describe()
|
||||
{
|
||||
switch(type){
|
||||
case CONNEVENT_NONE:
|
||||
return "CONNEVENT_NONE";
|
||||
case CONNEVENT_DATA_RECEIVED:
|
||||
return "CONNEVENT_DATA_RECEIVED";
|
||||
case CONNEVENT_PEER_ADDED:
|
||||
return "CONNEVENT_PEER_ADDED";
|
||||
case CONNEVENT_PEER_REMOVED:
|
||||
return "CONNEVENT_PEER_REMOVED";
|
||||
}
|
||||
return "Invalid ConnectionEvent";
|
||||
}
|
||||
|
||||
void dataReceived(u16 peer_id_, SharedBuffer<u8> data_)
|
||||
{
|
||||
type = CONNEVENT_DATA_RECEIVED;
|
||||
peer_id = peer_id_;
|
||||
data = data_;
|
||||
}
|
||||
void peerAdded(u16 peer_id_, Address address_)
|
||||
{
|
||||
type = CONNEVENT_PEER_ADDED;
|
||||
peer_id = peer_id_;
|
||||
address = address_;
|
||||
}
|
||||
void peerRemoved(u16 peer_id_, bool timeout_, Address address_)
|
||||
{
|
||||
type = CONNEVENT_PEER_REMOVED;
|
||||
peer_id = peer_id_;
|
||||
timeout = timeout_;
|
||||
address = address_;
|
||||
}
|
||||
};
|
||||
|
||||
enum ConnectionCommandType{
|
||||
CONNCMD_NONE,
|
||||
CONNCMD_SERVE,
|
||||
CONNCMD_CONNECT,
|
||||
CONNCMD_DISCONNECT,
|
||||
CONNCMD_SEND,
|
||||
CONNCMD_SEND_TO_ALL,
|
||||
CONNCMD_DELETE_PEER,
|
||||
};
|
||||
|
||||
struct ConnectionCommand
|
||||
{
|
||||
enum ConnectionCommandType type;
|
||||
u16 port;
|
||||
Address address;
|
||||
u16 peer_id;
|
||||
u8 channelnum;
|
||||
SharedBuffer<u8> data;
|
||||
bool reliable;
|
||||
|
||||
ConnectionCommand(): type(CONNCMD_NONE) {}
|
||||
|
||||
void serve(u16 port_)
|
||||
{
|
||||
type = CONNCMD_SERVE;
|
||||
port = port_;
|
||||
}
|
||||
void connect(Address address_)
|
||||
{
|
||||
type = CONNCMD_CONNECT;
|
||||
address = address_;
|
||||
}
|
||||
void disconnect()
|
||||
{
|
||||
type = CONNCMD_DISCONNECT;
|
||||
}
|
||||
void send(u16 peer_id_, u8 channelnum_,
|
||||
SharedBuffer<u8> data_, bool reliable_)
|
||||
{
|
||||
type = CONNCMD_SEND;
|
||||
peer_id = peer_id_;
|
||||
channelnum = channelnum_;
|
||||
data = data_;
|
||||
reliable = reliable_;
|
||||
}
|
||||
void sendToAll(u8 channelnum_, SharedBuffer<u8> data_, bool reliable_)
|
||||
{
|
||||
type = CONNCMD_SEND_TO_ALL;
|
||||
channelnum = channelnum_;
|
||||
data = data_;
|
||||
reliable = reliable_;
|
||||
}
|
||||
void deletePeer(u16 peer_id_)
|
||||
{
|
||||
type = CONNCMD_DELETE_PEER;
|
||||
peer_id = peer_id_;
|
||||
}
|
||||
};
|
||||
|
||||
class Connection: public SimpleThread
|
||||
{
|
||||
public:
|
||||
Connection(
|
||||
u32 protocol_id,
|
||||
u32 max_packet_size,
|
||||
float timeout,
|
||||
PeerHandler *peerhandler
|
||||
);
|
||||
Connection(u32 protocol_id, u32 max_packet_size, float timeout);
|
||||
Connection(u32 protocol_id, u32 max_packet_size, float timeout,
|
||||
PeerHandler *peerhandler);
|
||||
~Connection();
|
||||
void setTimeoutMs(int timeout){ m_socket.setTimeoutMs(timeout); }
|
||||
// Start being a server
|
||||
void * Thread();
|
||||
|
||||
/* Interface */
|
||||
|
||||
ConnectionEvent getEvent();
|
||||
ConnectionEvent waitEvent(u32 timeout_ms);
|
||||
void putCommand(ConnectionCommand &c);
|
||||
|
||||
void SetTimeoutMs(int timeout){ m_bc_receive_timeout = timeout; }
|
||||
void Serve(unsigned short port);
|
||||
// Connect to a server
|
||||
void Connect(Address address);
|
||||
bool Connected();
|
||||
|
||||
void Disconnect();
|
||||
|
||||
// Sets peer_id
|
||||
SharedBuffer<u8> GetFromBuffers(u16 &peer_id);
|
||||
|
||||
// The peer_id of sender is stored in peer_id
|
||||
// Return value: I guess this always throws an exception or
|
||||
// actually gets data
|
||||
// May call PeerHandler methods
|
||||
u32 Receive(u16 &peer_id, u8 *data, u32 datasize);
|
||||
|
||||
// These will automatically package the data as an original or split
|
||||
void SendToAll(u8 channelnum, SharedBuffer<u8> data, bool reliable);
|
||||
void Send(u16 peer_id, u8 channelnum, SharedBuffer<u8> data, bool reliable);
|
||||
// Send data as a packet; it will be wrapped in base header and
|
||||
// optionally to a reliable packet.
|
||||
void SendAsPacket(u16 peer_id, u8 channelnum,
|
||||
SharedBuffer<u8> data, bool reliable);
|
||||
// Sends a raw packet
|
||||
void RawSend(const BufferedPacket &packet);
|
||||
|
||||
// May call PeerHandler methods
|
||||
void RunTimeouts(float dtime);
|
||||
|
||||
// Can throw a PeerNotFoundException
|
||||
Peer* GetPeer(u16 peer_id);
|
||||
// returns NULL if failed
|
||||
Peer* GetPeerNoEx(u16 peer_id);
|
||||
core::list<Peer*> GetPeers();
|
||||
|
||||
// Calls PeerHandler::deletingPeer
|
||||
// Returns false if peer was not found
|
||||
bool deletePeer(u16 peer_id, bool timeout);
|
||||
|
||||
void SetPeerID(u16 id){ m_peer_id = id; }
|
||||
void RunTimeouts(float dtime); // dummy
|
||||
u16 GetPeerID(){ return m_peer_id; }
|
||||
u32 GetProtocolID(){ return m_protocol_id; }
|
||||
Address GetPeerAddress(u16 peer_id);
|
||||
float GetPeerAvgRTT(u16 peer_id);
|
||||
void DeletePeer(u16 peer_id);
|
||||
|
||||
private:
|
||||
void putEvent(ConnectionEvent &e);
|
||||
void processCommand(ConnectionCommand &c);
|
||||
void send(float dtime);
|
||||
void receive();
|
||||
void runTimeouts(float dtime);
|
||||
void serve(u16 port);
|
||||
void connect(Address address);
|
||||
void disconnect();
|
||||
void sendToAll(u8 channelnum, SharedBuffer<u8> data, bool reliable);
|
||||
void send(u16 peer_id, u8 channelnum, SharedBuffer<u8> data, bool reliable);
|
||||
void sendAsPacket(u16 peer_id, u8 channelnum,
|
||||
SharedBuffer<u8> data, bool reliable);
|
||||
void rawSendAsPacket(u16 peer_id, u8 channelnum,
|
||||
SharedBuffer<u8> data, bool reliable);
|
||||
void rawSend(const BufferedPacket &packet);
|
||||
Peer* getPeer(u16 peer_id);
|
||||
Peer* getPeerNoEx(u16 peer_id);
|
||||
core::list<Peer*> getPeers();
|
||||
bool getFromBuffers(u16 &peer_id, SharedBuffer<u8> &dst);
|
||||
// Returns next data from a buffer if possible
|
||||
// If found, returns true; if not, false.
|
||||
// If found, sets peer_id and dst
|
||||
bool checkIncomingBuffers(Channel *channel, u16 &peer_id,
|
||||
SharedBuffer<u8> &dst);
|
||||
/*
|
||||
Processes a packet with the basic header stripped out.
|
||||
Parameters:
|
||||
packetdata: Data in packet (with no base headers)
|
||||
peer_id: peer id of the sender of the packet in question
|
||||
channelnum: channel on which the packet was sent
|
||||
reliable: true if recursing into a reliable packet
|
||||
*/
|
||||
SharedBuffer<u8> processPacket(Channel *channel,
|
||||
SharedBuffer<u8> packetdata, u16 peer_id,
|
||||
u8 channelnum, bool reliable);
|
||||
bool deletePeer(u16 peer_id, bool timeout);
|
||||
|
||||
Queue<OutgoingPacket> m_outgoing_queue;
|
||||
MutexedQueue<ConnectionEvent> m_event_queue;
|
||||
MutexedQueue<ConnectionCommand> m_command_queue;
|
||||
|
||||
u32 m_protocol_id;
|
||||
u32 m_max_packet_size;
|
||||
float m_timeout;
|
||||
UDPSocket m_socket;
|
||||
u16 m_peer_id;
|
||||
|
||||
core::map<u16, Peer*> m_peers;
|
||||
JMutex m_peers_mutex;
|
||||
|
||||
// For debug printing
|
||||
// Backwards compatibility
|
||||
PeerHandler *m_bc_peerhandler;
|
||||
int m_bc_receive_timeout;
|
||||
|
||||
void SetPeerID(u16 id){ m_peer_id = id; }
|
||||
u32 GetProtocolID(){ return m_protocol_id; }
|
||||
void PrintInfo(std::ostream &out);
|
||||
void PrintInfo();
|
||||
std::string getDesc();
|
||||
u16 m_indentation;
|
||||
|
||||
private:
|
||||
u32 m_protocol_id;
|
||||
float m_timeout;
|
||||
PeerHandler *m_peerhandler;
|
||||
core::map<u16, Peer*> m_peers;
|
||||
u16 m_peer_id;
|
||||
//bool m_waiting_new_peer_id;
|
||||
u32 m_max_packet_size;
|
||||
UDPSocket m_socket;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -208,6 +208,35 @@ void ItemCAO::addToScene(scene::ISceneManager *smgr)
|
|||
// This is needed for changing the texture in the future
|
||||
m_node->setReadOnlyMaterials(true);
|
||||
updateNodePos();
|
||||
|
||||
/*
|
||||
Update image of node
|
||||
*/
|
||||
|
||||
// Create an inventory item to see what is its image
|
||||
std::istringstream is(m_inventorystring, std::ios_base::binary);
|
||||
video::ITexture *texture = NULL;
|
||||
try{
|
||||
InventoryItem *item = NULL;
|
||||
item = InventoryItem::deSerialize(is);
|
||||
infostream<<__FUNCTION_NAME<<": m_inventorystring=\""
|
||||
<<m_inventorystring<<"\" -> item="<<item
|
||||
<<std::endl;
|
||||
if(item)
|
||||
{
|
||||
texture = item->getImage();
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
catch(SerializationError &e)
|
||||
{
|
||||
infostream<<"WARNING: "<<__FUNCTION_NAME
|
||||
<<": error deSerializing inventorystring \""
|
||||
<<m_inventorystring<<"\""<<std::endl;
|
||||
}
|
||||
|
||||
// Set meshbuffer texture
|
||||
buf->getMaterial().setTexture(0, texture);
|
||||
}
|
||||
|
||||
void ItemCAO::removeFromScene()
|
||||
|
@ -289,49 +318,6 @@ void ItemCAO::initialize(const std::string &data)
|
|||
}
|
||||
|
||||
updateNodePos();
|
||||
|
||||
/*
|
||||
Update image of node
|
||||
*/
|
||||
|
||||
if(m_node == NULL)
|
||||
return;
|
||||
|
||||
scene::IMesh *mesh = m_node->getMesh();
|
||||
|
||||
if(mesh == NULL)
|
||||
return;
|
||||
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
|
||||
|
||||
if(buf == NULL)
|
||||
return;
|
||||
|
||||
// Create an inventory item to see what is its image
|
||||
std::istringstream is(m_inventorystring, std::ios_base::binary);
|
||||
video::ITexture *texture = NULL;
|
||||
try{
|
||||
InventoryItem *item = NULL;
|
||||
item = InventoryItem::deSerialize(is);
|
||||
infostream<<__FUNCTION_NAME<<": m_inventorystring=\""
|
||||
<<m_inventorystring<<"\" -> item="<<item
|
||||
<<std::endl;
|
||||
if(item)
|
||||
{
|
||||
texture = item->getImage();
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
catch(SerializationError &e)
|
||||
{
|
||||
infostream<<"WARNING: "<<__FUNCTION_NAME
|
||||
<<": error deSerializing inventorystring \""
|
||||
<<m_inventorystring<<"\""<<std::endl;
|
||||
}
|
||||
|
||||
// Set meshbuffer texture
|
||||
buf->getMaterial().setTexture(0, texture);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1007,11 +993,15 @@ void MobV2CAO::updateNodePos()
|
|||
void MobV2CAO::step(float dtime, ClientEnvironment *env)
|
||||
{
|
||||
scene::MyBillboardSceneNode *bill = m_node;
|
||||
if(!bill)
|
||||
return;
|
||||
|
||||
pos_translator.translate(dtime);
|
||||
|
||||
if(m_sprite_type == "humanoid_1"){
|
||||
scene::ICameraSceneNode* camera = m_node->getSceneManager()->getActiveCamera();
|
||||
if(!camera)
|
||||
return;
|
||||
v3f cam_to_mob = m_node->getAbsolutePosition() - camera->getAbsolutePosition();
|
||||
cam_to_mob.normalize();
|
||||
int col = 0;
|
||||
|
|
|
@ -72,8 +72,8 @@ std::string item_craft_get_image_name(const std::string &subname)
|
|||
else if(subname == "firefly")
|
||||
return "firefly.png";
|
||||
else if(subname == "apple")
|
||||
return "apple.png";
|
||||
else if(subname == "apple_iron")
|
||||
return "apple.png^[forcesingle";
|
||||
else if(subname == "apple_iron")
|
||||
return "apple_iron.png";
|
||||
else
|
||||
return "cloud.png"; // just something
|
||||
|
|
|
@ -143,7 +143,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
// New-style leaves material
|
||||
video::SMaterial material_leaves1;
|
||||
material_leaves1.setFlag(video::EMF_LIGHTING, false);
|
||||
//material_leaves1.setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material_leaves1.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
|
@ -229,25 +228,54 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
v3s16 p(x,y,z);
|
||||
|
||||
MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes+p);
|
||||
|
||||
|
||||
/*
|
||||
Add torches to mesh
|
||||
*/
|
||||
if(n.getContent() == CONTENT_TORCH)
|
||||
{
|
||||
v3s16 dir = unpackDir(n.param2);
|
||||
|
||||
const char *texturename = "torch.png";
|
||||
if(dir == v3s16(0,-1,0)){
|
||||
texturename = "torch_on_floor.png";
|
||||
} else if(dir == v3s16(0,1,0)){
|
||||
texturename = "torch_on_ceiling.png";
|
||||
// For backwards compatibility
|
||||
} else if(dir == v3s16(0,0,0)){
|
||||
texturename = "torch_on_floor.png";
|
||||
} else {
|
||||
texturename = "torch.png";
|
||||
}
|
||||
|
||||
AtlasPointer ap = g_texturesource->getTexture(texturename);
|
||||
|
||||
// Set material
|
||||
video::SMaterial material;
|
||||
material.setFlag(video::EMF_LIGHTING, false);
|
||||
material.setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
//material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
material.MaterialType
|
||||
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
material.setTexture(0, ap.atlas);
|
||||
|
||||
video::SColor c(255,255,255,255);
|
||||
|
||||
// Wall at X+ of node
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
|
||||
video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
|
||||
ap.x0(), ap.y1()),
|
||||
video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
|
||||
ap.x1(), ap.y1()),
|
||||
video::S3DVertex(BS/2,BS/2,0, 0,0,0, c,
|
||||
ap.x1(), ap.y0()),
|
||||
video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c,
|
||||
ap.x0(), ap.y0()),
|
||||
};
|
||||
|
||||
v3s16 dir = unpackDir(n.param2);
|
||||
|
||||
for(s32 i=0; i<4; i++)
|
||||
{
|
||||
if(dir == v3s16(1,0,0))
|
||||
|
@ -266,29 +294,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
|
||||
}
|
||||
|
||||
// Set material
|
||||
video::SMaterial material;
|
||||
material.setFlag(video::EMF_LIGHTING, false);
|
||||
material.setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
//material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
material.MaterialType
|
||||
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
|
||||
if(dir == v3s16(0,-1,0))
|
||||
material.setTexture(0,
|
||||
g_texturesource->getTextureRaw("torch_on_floor.png"));
|
||||
else if(dir == v3s16(0,1,0))
|
||||
material.setTexture(0,
|
||||
g_texturesource->getTextureRaw("torch_on_ceiling.png"));
|
||||
// For backwards compatibility
|
||||
else if(dir == v3s16(0,0,0))
|
||||
material.setTexture(0,
|
||||
g_texturesource->getTextureRaw("torch_on_floor.png"));
|
||||
else
|
||||
material.setTexture(0,
|
||||
g_texturesource->getTextureRaw("torch.png"));
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
// Add to mesh collector
|
||||
collector.append(material, vertices, 4, indices, 6);
|
||||
|
@ -298,6 +303,18 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
*/
|
||||
else if(n.getContent() == CONTENT_SIGN_WALL)
|
||||
{
|
||||
AtlasPointer ap = g_texturesource->getTexture("sign_wall.png");
|
||||
|
||||
// Set material
|
||||
video::SMaterial material;
|
||||
material.setFlag(video::EMF_LIGHTING, false);
|
||||
material.setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material.MaterialType
|
||||
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
material.setTexture(0, ap.atlas);
|
||||
|
||||
u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
|
||||
|
@ -305,10 +322,14 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
// Wall at X+ of node
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, 0,0),
|
||||
video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c,
|
||||
ap.x0(), ap.y1()),
|
||||
video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c,
|
||||
ap.x1(), ap.y1()),
|
||||
video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c,
|
||||
ap.x1(), ap.y0()),
|
||||
video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c,
|
||||
ap.x0(), ap.y0()),
|
||||
};
|
||||
|
||||
v3s16 dir = unpackDir(n.param2);
|
||||
|
@ -331,19 +352,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
|
||||
}
|
||||
|
||||
// Set material
|
||||
video::SMaterial material;
|
||||
material.setFlag(video::EMF_LIGHTING, false);
|
||||
material.setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
//material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
material.MaterialType
|
||||
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
|
||||
material.setTexture(0,
|
||||
g_texturesource->getTextureRaw("sign_wall.png"));
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
// Add to mesh collector
|
||||
collector.append(material, vertices, 4, indices, 6);
|
||||
|
@ -353,17 +361,37 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
*/
|
||||
else if(n.getContent() == CONTENT_TELEPORT)
|
||||
{
|
||||
AtlasPointer ap = g_texturesource->getTexture("teleport.png");
|
||||
|
||||
// Set material
|
||||
video::SMaterial material;
|
||||
material.setFlag(video::EMF_LIGHTING, false);
|
||||
material.setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
//material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
|
||||
material.setTexture(0,ap.atlas);
|
||||
|
||||
u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
|
||||
float d = (float)BS/16;
|
||||
// Wall at X+ of node
|
||||
video::S3DVertex vertices[4] =
|
||||
/*video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, 0,0),
|
||||
};*/
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(BS/2-d,-BS,-BS, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(BS/2-d,-BS,BS, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(BS/2-d,BS,BS, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(BS/2-d,BS,-BS, 0,0,0, c, 0,0),
|
||||
};
|
||||
|
||||
v3s16 dir = unpackDir(n.param2);
|
||||
|
@ -386,19 +414,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
|
||||
}
|
||||
|
||||
// Set material
|
||||
video::SMaterial material;
|
||||
material.setFlag(video::EMF_LIGHTING, false);
|
||||
material.setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
//material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
material.MaterialType
|
||||
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
|
||||
material.setTexture(0,
|
||||
g_texturesource->getTextureRaw("teleport.png"));
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
// Add to mesh collector
|
||||
collector.append(material, vertices, 4, indices, 6);
|
||||
|
@ -580,10 +595,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
/*video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_liquid1.x0(), pa_liquid1.y1()),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
|
||||
|
@ -665,10 +676,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
{
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
/*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_liquid1.x0(), pa_liquid1.y1()),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
|
||||
|
@ -723,10 +730,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
/*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_liquid1.x0(), pa_liquid1.y1()),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
|
||||
|
@ -760,10 +763,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
{
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
/*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
|
||||
video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
|
||||
pa_leaves1.x0(), pa_leaves1.y1()),
|
||||
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
|
||||
|
@ -982,10 +981,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
/*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
|
||||
video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
|
||||
ap.x0(), ap.y1()),
|
||||
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
|
||||
|
@ -1089,13 +1084,13 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
|
||||
pa_papyrus.x0(), pa_papyrus.y1()),
|
||||
pa_junglegrass.x0(), pa_junglegrass.y1()),
|
||||
video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
|
||||
pa_papyrus.x1(), pa_papyrus.y1()),
|
||||
pa_junglegrass.x1(), pa_junglegrass.y1()),
|
||||
video::S3DVertex(BS/2,BS/1,0, 0,0,0, c,
|
||||
pa_papyrus.x1(), pa_papyrus.y0()),
|
||||
pa_junglegrass.x1(), pa_junglegrass.y0()),
|
||||
video::S3DVertex(-BS/2,BS/1,0, 0,0,0, c,
|
||||
pa_papyrus.x0(), pa_papyrus.y0()),
|
||||
pa_junglegrass.x0(), pa_junglegrass.y0()),
|
||||
};
|
||||
|
||||
if(j == 0)
|
||||
|
@ -1132,9 +1127,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
}
|
||||
else if(n.getContent() == CONTENT_RAIL)
|
||||
{
|
||||
u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
|
||||
bool is_rail_x [] = { false, false }; /* x-1, x+1 */
|
||||
bool is_rail_z [] = { false, false }; /* z-1, z+1 */
|
||||
|
||||
|
@ -1152,18 +1144,25 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
if(n_plus_z.getContent() == CONTENT_RAIL)
|
||||
is_rail_z[1] = true;
|
||||
|
||||
float d = (float)BS/16;
|
||||
video::S3DVertex vertices[4] =
|
||||
int adjacencies = is_rail_x[0] + is_rail_x[1] + is_rail_z[0] + is_rail_z[1];
|
||||
|
||||
// Assign textures
|
||||
const char *texturename = "rail.png";
|
||||
if(adjacencies < 2)
|
||||
texturename = "rail.png";
|
||||
else if(adjacencies == 2)
|
||||
{
|
||||
video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c,
|
||||
0, 1),
|
||||
video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c,
|
||||
1, 1),
|
||||
video::S3DVertex(BS/2,-BS/2+d,BS/2, 0,0,0, c,
|
||||
1, 0),
|
||||
video::S3DVertex(-BS/2,-BS/2+d,BS/2, 0,0,0, c,
|
||||
0, 0),
|
||||
};
|
||||
if((is_rail_x[0] && is_rail_x[1]) || (is_rail_z[0] && is_rail_z[1]))
|
||||
texturename = "rail.png";
|
||||
else
|
||||
texturename = "rail_curved.png";
|
||||
}
|
||||
else if(adjacencies == 3)
|
||||
texturename = "rail_t_junction.png";
|
||||
else if(adjacencies == 4)
|
||||
texturename = "rail_crossing.png";
|
||||
|
||||
AtlasPointer ap = g_texturesource->getTexture(texturename);
|
||||
|
||||
video::SMaterial material_rail;
|
||||
material_rail.setFlag(video::EMF_LIGHTING, false);
|
||||
|
@ -1172,23 +1171,23 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
material_rail.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material_rail.MaterialType
|
||||
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
material_rail.setTexture(0, ap.atlas);
|
||||
|
||||
int adjacencies = is_rail_x[0] + is_rail_x[1] + is_rail_z[0] + is_rail_z[1];
|
||||
u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
|
||||
// Assign textures
|
||||
if(adjacencies < 2)
|
||||
material_rail.setTexture(0, g_texturesource->getTextureRaw("rail.png"));
|
||||
else if(adjacencies == 2)
|
||||
float d = (float)BS/16;
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
if((is_rail_x[0] && is_rail_x[1]) || (is_rail_z[0] && is_rail_z[1]))
|
||||
material_rail.setTexture(0, g_texturesource->getTextureRaw("rail.png"));
|
||||
else
|
||||
material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_curved.png"));
|
||||
}
|
||||
else if(adjacencies == 3)
|
||||
material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_t_junction.png"));
|
||||
else if(adjacencies == 4)
|
||||
material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_crossing.png"));
|
||||
video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c,
|
||||
ap.x0(), ap.y1()),
|
||||
video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c,
|
||||
ap.x1(), ap.y1()),
|
||||
video::S3DVertex(BS/2,-BS/2+d,BS/2, 0,0,0, c,
|
||||
ap.x1(), ap.y0()),
|
||||
video::S3DVertex(-BS/2,-BS/2+d,BS/2, 0,0,0, c,
|
||||
ap.x0(), ap.y0()),
|
||||
};
|
||||
|
||||
// Rotate textures
|
||||
int angle = 0;
|
||||
|
@ -1235,6 +1234,17 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
collector.append(material_rail, vertices, 4, indices, 6);
|
||||
}
|
||||
else if (n.getContent() == CONTENT_LADDER) {
|
||||
AtlasPointer ap = g_texturesource->getTexture("ladder.png");
|
||||
|
||||
// Set material
|
||||
video::SMaterial material_ladder;
|
||||
material_ladder.setFlag(video::EMF_LIGHTING, false);
|
||||
material_ladder.setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
material_ladder.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material_ladder.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material_ladder.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
material_ladder.setTexture(0, ap.atlas);
|
||||
|
||||
u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
|
||||
video::SColor c(255,l,l,l);
|
||||
|
||||
|
@ -1243,10 +1253,14 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
// Assume wall is at X+
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, 0,0),
|
||||
video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c,
|
||||
ap.x0(), ap.y1()),
|
||||
video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c,
|
||||
ap.x1(), ap.y1()),
|
||||
video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c,
|
||||
ap.x1(), ap.y0()),
|
||||
video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c,
|
||||
ap.x0(), ap.y0()),
|
||||
};
|
||||
|
||||
v3s16 dir = unpackDir(n.param2);
|
||||
|
@ -1269,14 +1283,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
|||
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
|
||||
}
|
||||
|
||||
video::SMaterial material_ladder;
|
||||
material_ladder.setFlag(video::EMF_LIGHTING, false);
|
||||
material_ladder.setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
material_ladder.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material_ladder.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material_ladder.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
material_ladder.setTexture(0, g_texturesource->getTextureRaw("ladder.png"));
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
// Add to mesh collector
|
||||
collector.append(material_ladder, vertices, 4, indices, 6);
|
||||
|
|
|
@ -117,6 +117,7 @@ void content_mapnode_init()
|
|||
f->setInventoryTextureCube("stone.png", "stone.png", "stone.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
f->often_contains_mineral = true;
|
||||
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_COBBLE)+" 1";
|
||||
setStoneLikeDiggingProperties(f->digging_properties, 1.0);
|
||||
if(invisible_stone)
|
||||
|
@ -219,6 +220,7 @@ void content_mapnode_init()
|
|||
i = CONTENT_JUNGLEGRASS;
|
||||
f = &content_features(i);
|
||||
f->setInventoryTexture("junglegrass.png");
|
||||
f->used_texturenames["junglegrass.png"] = true;
|
||||
f->light_propagates = true;
|
||||
f->param_type = CPT_LIGHT;
|
||||
//f->is_ground_content = true;
|
||||
|
@ -264,6 +266,7 @@ void content_mapnode_init()
|
|||
i = CONTENT_PAPYRUS;
|
||||
f = &content_features(i);
|
||||
f->setInventoryTexture("papyrus.png");
|
||||
f->used_texturenames["papyrus.png"] = true;
|
||||
f->light_propagates = true;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->is_ground_content = true;
|
||||
|
@ -306,11 +309,13 @@ void content_mapnode_init()
|
|||
f->solidness = 0; // drawn separately, makes no faces
|
||||
f->air_equivalent = true; // grass grows underneath
|
||||
f->setInventoryTexture("fence.png");
|
||||
f->used_texturenames["fence.png"] = true;
|
||||
setWoodLikeDiggingProperties(f->digging_properties, 0.75);
|
||||
|
||||
i = CONTENT_RAIL;
|
||||
f = &content_features(i);
|
||||
f->setInventoryTexture("rail.png");
|
||||
f->used_texturenames["rail.png"] = true;
|
||||
f->light_propagates = true;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->is_ground_content = true;
|
||||
|
@ -323,6 +328,7 @@ void content_mapnode_init()
|
|||
i = CONTENT_LADDER;
|
||||
f = &content_features(i);
|
||||
f->setInventoryTexture("ladder.png");
|
||||
f->used_texturenames["ladder.png"] = true;
|
||||
f->light_propagates = true;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->is_ground_content = true;
|
||||
|
@ -465,6 +471,7 @@ void content_mapnode_init()
|
|||
i = CONTENT_LAVA;
|
||||
f = &content_features(i);
|
||||
f->setInventoryTextureCube("lava.png", "lava.png", "lava.png");
|
||||
f->used_texturenames["lava.png"] = true;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = false;
|
||||
f->light_source = LIGHT_MAX-1;
|
||||
|
@ -501,6 +508,7 @@ void content_mapnode_init()
|
|||
i = CONTENT_LAVASOURCE;
|
||||
f = &content_features(i);
|
||||
f->setInventoryTextureCube("lava.png", "lava.png", "lava.png");
|
||||
f->used_texturenames["ladder.png"] = true;
|
||||
if(new_style_water)
|
||||
{
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
|
@ -554,6 +562,10 @@ void content_mapnode_init()
|
|||
i = CONTENT_TORCH;
|
||||
f = &content_features(i);
|
||||
f->setInventoryTexture("torch_on_floor.png");
|
||||
f->used_texturenames["torch_on_floor.png"] = true;
|
||||
f->used_texturenames["torch_on_ceiling.png"] = true;
|
||||
f->used_texturenames["torch_on_floor.png"] = true;
|
||||
f->used_texturenames["torch.png"] = true;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
f->sunlight_propagates = true;
|
||||
|
@ -568,6 +580,7 @@ void content_mapnode_init()
|
|||
i = CONTENT_SIGN_WALL;
|
||||
f = &content_features(i);
|
||||
f->setInventoryTexture("sign_wall.png");
|
||||
f->used_texturenames["sign_wall.png"] = true;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
f->sunlight_propagates = true;
|
||||
|
@ -670,6 +683,7 @@ void content_mapnode_init()
|
|||
f->param_type = CPT_LIGHT;
|
||||
f->setAllTextures("sapling.png");
|
||||
f->setInventoryTexture("sapling.png");
|
||||
f->used_texturenames["sapling.png"] = true;
|
||||
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
|
||||
f->light_propagates = true;
|
||||
f->air_equivalent = false;
|
||||
|
@ -692,8 +706,8 @@ void content_mapnode_init()
|
|||
|
||||
i = CONTENT_TELEPORT;
|
||||
f = &content_features(i);
|
||||
f->setAllTextures("teleport.png");
|
||||
//f->setInventoryTexture("teleport.png");
|
||||
//f->setAllTextures("teleport.png");
|
||||
f->setInventoryTexture("teleport.png");
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
f->light_source = 3; //?
|
||||
|
@ -710,6 +724,7 @@ void content_mapnode_init()
|
|||
i = CONTENT_APPLE;
|
||||
f = &content_features(i);
|
||||
f->setInventoryTexture("apple.png");
|
||||
f->used_texturenames["apple.png"] = true;
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
f->sunlight_propagates = true;
|
||||
|
|
|
@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "collision.h"
|
||||
#include "environment.h"
|
||||
#include "settings.h"
|
||||
#include "profiler.h"
|
||||
|
||||
core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
|
||||
|
||||
|
@ -137,6 +138,8 @@ ServerActiveObject* ItemSAO::create(ServerEnvironment *env, u16 id, v3f pos,
|
|||
|
||||
void ItemSAO::step(float dtime, bool send_recommended)
|
||||
{
|
||||
ScopeProfiler sp2(g_profiler, "ItemSAO::step avg", SPT_AVG);
|
||||
|
||||
assert(m_env);
|
||||
|
||||
const float interval = 0.2;
|
||||
|
@ -291,6 +294,8 @@ ServerActiveObject* RatSAO::create(ServerEnvironment *env, u16 id, v3f pos,
|
|||
|
||||
void RatSAO::step(float dtime, bool send_recommended)
|
||||
{
|
||||
ScopeProfiler sp2(g_profiler, "RatSAO::step avg", SPT_AVG);
|
||||
|
||||
assert(m_env);
|
||||
|
||||
if(m_is_active == false)
|
||||
|
@ -480,6 +485,8 @@ ServerActiveObject* Oerkki1SAO::create(ServerEnvironment *env, u16 id, v3f pos,
|
|||
|
||||
void Oerkki1SAO::step(float dtime, bool send_recommended)
|
||||
{
|
||||
ScopeProfiler sp2(g_profiler, "Oerkki1SAO::step avg", SPT_AVG);
|
||||
|
||||
assert(m_env);
|
||||
|
||||
if(m_is_active == false)
|
||||
|
@ -677,11 +684,25 @@ std::string Oerkki1SAO::getStaticData()
|
|||
return os.str();
|
||||
}
|
||||
|
||||
u16 Oerkki1SAO::punch(const std::string &toolname, v3f dir)
|
||||
u16 Oerkki1SAO::punch(const std::string &toolname, v3f dir,
|
||||
const std::string &playername)
|
||||
{
|
||||
m_speed_f += dir*12*BS;
|
||||
|
||||
u16 amount = 20;
|
||||
u16 amount = 5;
|
||||
/* See tool names in inventory.h */
|
||||
if(toolname == "WSword")
|
||||
amount = 10;
|
||||
if(toolname == "STSword")
|
||||
amount = 12;
|
||||
if(toolname == "SteelSword")
|
||||
amount = 16;
|
||||
if(toolname == "STAxe")
|
||||
amount = 7;
|
||||
if(toolname == "SteelAxe")
|
||||
amount = 9;
|
||||
if(toolname == "SteelPick")
|
||||
amount = 7;
|
||||
doDamage(amount);
|
||||
return 65536/100;
|
||||
}
|
||||
|
@ -752,6 +773,8 @@ ServerActiveObject* FireflySAO::create(ServerEnvironment *env, u16 id, v3f pos,
|
|||
|
||||
void FireflySAO::step(float dtime, bool send_recommended)
|
||||
{
|
||||
ScopeProfiler sp2(g_profiler, "FireflySAO::step avg", SPT_AVG);
|
||||
|
||||
assert(m_env);
|
||||
|
||||
if(m_is_active == false)
|
||||
|
@ -1065,6 +1088,8 @@ static void explodeSquare(Map *map, v3s16 p0, v3s16 size)
|
|||
|
||||
void MobV2SAO::step(float dtime, bool send_recommended)
|
||||
{
|
||||
ScopeProfiler sp2(g_profiler, "MobV2SAO::step avg", SPT_AVG);
|
||||
|
||||
assert(m_env);
|
||||
Map *map = &m_env->getMap();
|
||||
|
||||
|
@ -1239,8 +1264,6 @@ void MobV2SAO::step(float dtime, bool send_recommended)
|
|||
m_base_position = pos_f;
|
||||
|
||||
if((pos_f - next_pos_f).getLength() < 0.1 || arrived){
|
||||
verbosestream<<"Mob id="<<m_id<<": arrived to "
|
||||
<<PP(m_next_pos_i)<<std::endl;
|
||||
m_next_pos_exists = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,8 @@ public:
|
|||
std::string getClientInitializationData();
|
||||
std::string getStaticData();
|
||||
InventoryItem* createPickedUpItem(){return NULL;}
|
||||
u16 punch(const std::string &toolname, v3f dir);
|
||||
u16 punch(const std::string &toolname, v3f dir,
|
||||
const std::string &playername);
|
||||
bool isPeaceful(){return false;}
|
||||
private:
|
||||
void doDamage(u16 d);
|
||||
|
|
|
@ -36,6 +36,7 @@ void set_default_settings(Settings *settings)
|
|||
settings->setDefault("keymap_jump", "KEY_SPACE");
|
||||
settings->setDefault("keymap_sneak", "KEY_LSHIFT");
|
||||
settings->setDefault("keymap_inventory", "KEY_KEY_I");
|
||||
settings->setDefault("keymap_special1", "KEY_KEY_E");
|
||||
settings->setDefault("keymap_chat", "KEY_KEY_T");
|
||||
settings->setDefault("keymap_cmd", "/");
|
||||
settings->setDefault("keymap_rangeselect", "KEY_KEY_R");
|
||||
|
@ -43,8 +44,9 @@ void set_default_settings(Settings *settings)
|
|||
settings->setDefault("keymap_fastmove", "KEY_KEY_J");
|
||||
settings->setDefault("keymap_frametime_graph", "KEY_F1");
|
||||
settings->setDefault("keymap_screenshot", "KEY_F12");
|
||||
settings->setDefault("keymap_toggle_profiler", "KEY_F2");
|
||||
settings->setDefault("keymap_toggle_force_fog_off", "KEY_F3");
|
||||
// Some (temporary) keys for debugging
|
||||
settings->setDefault("keymap_special1", "KEY_KEY_E");
|
||||
settings->setDefault("keymap_print_debug_stacks", "KEY_KEY_P");
|
||||
|
||||
settings->setDefault("wanted_fps", "30");
|
||||
|
@ -75,6 +77,7 @@ void set_default_settings(Settings *settings)
|
|||
settings->setDefault("invisible_stone", "false");
|
||||
settings->setDefault("screenshot_path", ".");
|
||||
settings->setDefault("view_bobbing_amount", "1.0");
|
||||
settings->setDefault("enable_2d_clouds", "false");
|
||||
|
||||
// Server stuff
|
||||
// "map-dir" doesn't exist by default.
|
||||
|
@ -93,13 +96,13 @@ void set_default_settings(Settings *settings)
|
|||
settings->setDefault("enable_mapgen_debug_info", "false");
|
||||
settings->setDefault("objectdata_interval", "0.2");
|
||||
settings->setDefault("active_object_send_range_blocks", "3");
|
||||
settings->setDefault("active_block_range", "5");
|
||||
settings->setDefault("active_block_range", "2");
|
||||
//settings->setDefault("max_simultaneous_block_sends_per_client", "1");
|
||||
// This causes frametime jitter on client side, or does it?
|
||||
settings->setDefault("max_simultaneous_block_sends_per_client", "2");
|
||||
settings->setDefault("max_simultaneous_block_sends_server_total", "8");
|
||||
settings->setDefault("max_block_send_distance", "8");
|
||||
settings->setDefault("max_block_generate_distance", "8");
|
||||
settings->setDefault("max_block_send_distance", "7");
|
||||
settings->setDefault("max_block_generate_distance", "5");
|
||||
settings->setDefault("time_send_interval", "20");
|
||||
settings->setDefault("time_speed", "96");
|
||||
settings->setDefault("server_unload_unused_data_timeout", "60");
|
||||
|
|
|
@ -653,6 +653,92 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
|
|||
}
|
||||
}
|
||||
|
||||
void ServerEnvironment::clearAllObjects()
|
||||
{
|
||||
infostream<<"ServerEnvironment::clearAllObjects(): "
|
||||
<<"Removing all active objects"<<std::endl;
|
||||
core::list<u16> objects_to_remove;
|
||||
for(core::map<u16, ServerActiveObject*>::Iterator
|
||||
i = m_active_objects.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
ServerActiveObject* obj = i.getNode()->getValue();
|
||||
u16 id = i.getNode()->getKey();
|
||||
v3f objectpos = obj->getBasePosition();
|
||||
// Delete static object if block is loaded
|
||||
if(obj->m_static_exists){
|
||||
MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
|
||||
if(block){
|
||||
block->m_static_objects.remove(id);
|
||||
block->raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
obj->m_static_exists = false;
|
||||
}
|
||||
}
|
||||
// If known by some client, don't delete immediately
|
||||
if(obj->m_known_by_count > 0){
|
||||
obj->m_pending_deactivation = true;
|
||||
obj->m_removed = true;
|
||||
continue;
|
||||
}
|
||||
// Delete active object
|
||||
delete obj;
|
||||
// Id to be removed from m_active_objects
|
||||
objects_to_remove.push_back(id);
|
||||
}
|
||||
// Remove references from m_active_objects
|
||||
for(core::list<u16>::Iterator i = objects_to_remove.begin();
|
||||
i != objects_to_remove.end(); i++)
|
||||
{
|
||||
m_active_objects.remove(*i);
|
||||
}
|
||||
|
||||
core::list<v3s16> loadable_blocks;
|
||||
infostream<<"ServerEnvironment::clearAllObjects(): "
|
||||
<<"Listing all loadable blocks"<<std::endl;
|
||||
m_map->listAllLoadableBlocks(loadable_blocks);
|
||||
infostream<<"ServerEnvironment::clearAllObjects(): "
|
||||
<<"Done listing all loadable blocks: "
|
||||
<<loadable_blocks.size()
|
||||
<<", now clearing"<<std::endl;
|
||||
u32 report_interval = loadable_blocks.size() / 10;
|
||||
u32 num_blocks_checked = 0;
|
||||
u32 num_blocks_cleared = 0;
|
||||
u32 num_objs_cleared = 0;
|
||||
for(core::list<v3s16>::Iterator i = loadable_blocks.begin();
|
||||
i != loadable_blocks.end(); i++)
|
||||
{
|
||||
v3s16 p = *i;
|
||||
MapBlock *block = m_map->emergeBlock(p, false);
|
||||
if(!block){
|
||||
errorstream<<"ServerEnvironment::clearAllObjects(): "
|
||||
<<"Failed to emerge block "<<PP(p)<<std::endl;
|
||||
continue;
|
||||
}
|
||||
u32 num_stored = block->m_static_objects.m_stored.size();
|
||||
u32 num_active = block->m_static_objects.m_active.size();
|
||||
if(num_stored != 0 || num_active != 0){
|
||||
block->m_static_objects.m_stored.clear();
|
||||
block->m_static_objects.m_active.clear();
|
||||
block->raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
num_objs_cleared += num_stored + num_active;
|
||||
num_blocks_cleared++;
|
||||
}
|
||||
num_blocks_checked++;
|
||||
|
||||
if(num_blocks_checked % report_interval == 0){
|
||||
float percent = 100.0 * (float)num_blocks_checked /
|
||||
loadable_blocks.size();
|
||||
infostream<<"ServerEnvironment::clearAllObjects(): "
|
||||
<<"Cleared "<<num_objs_cleared<<" objects"
|
||||
<<" in "<<num_blocks_cleared<<" blocks ("
|
||||
<<percent<<"%)"<<std::endl;
|
||||
}
|
||||
}
|
||||
infostream<<"ServerEnvironment::clearAllObjects(): "
|
||||
<<"Finished: Cleared "<<num_objs_cleared<<" objects"
|
||||
<<" in "<<num_blocks_cleared<<" blocks"<<std::endl;
|
||||
}
|
||||
|
||||
static void getMob_dungeon_master(Settings &properties)
|
||||
{
|
||||
properties.set("looks", "dungeon_master");
|
||||
|
@ -690,7 +776,7 @@ void ServerEnvironment::step(float dtime)
|
|||
Handle players
|
||||
*/
|
||||
{
|
||||
ScopeProfiler sp(g_profiler, "SEnv: handle players avg", SPT_LOWPASS);
|
||||
ScopeProfiler sp(g_profiler, "SEnv: handle players avg", SPT_AVG);
|
||||
for(core::list<Player*>::Iterator i = m_players.begin();
|
||||
i != m_players.end(); i++)
|
||||
{
|
||||
|
@ -732,7 +818,7 @@ void ServerEnvironment::step(float dtime)
|
|||
*/
|
||||
if(m_active_blocks_management_interval.step(dtime, 2.0))
|
||||
{
|
||||
ScopeProfiler sp(g_profiler, "SEnv: manage act. block list avg", SPT_LOWPASS);
|
||||
ScopeProfiler sp(g_profiler, "SEnv: manage act. block list avg /2s", SPT_AVG);
|
||||
/*
|
||||
Get player block positions
|
||||
*/
|
||||
|
@ -809,7 +895,7 @@ void ServerEnvironment::step(float dtime)
|
|||
*/
|
||||
if(m_active_blocks_nodemetadata_interval.step(dtime, 1.0))
|
||||
{
|
||||
ScopeProfiler sp(g_profiler, "SEnv: mess in act. blocks avg", SPT_LOWPASS);
|
||||
ScopeProfiler sp(g_profiler, "SEnv: mess in act. blocks avg /1s", SPT_AVG);
|
||||
|
||||
float dtime = 1.0;
|
||||
|
||||
|
@ -848,7 +934,7 @@ void ServerEnvironment::step(float dtime)
|
|||
|
||||
if(m_active_blocks_test_interval.step(dtime, 10.0))
|
||||
{
|
||||
ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg", SPT_LOWPASS);
|
||||
ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg /10s", SPT_AVG);
|
||||
//float dtime = 10.0;
|
||||
|
||||
for(core::map<v3s16, bool>::Iterator
|
||||
|
@ -893,7 +979,18 @@ void ServerEnvironment::step(float dtime)
|
|||
if(block==NULL)
|
||||
continue;
|
||||
active_object_count_wider +=
|
||||
block->m_static_objects.m_active.size();
|
||||
block->m_static_objects.m_active.size()
|
||||
+ block->m_static_objects.m_stored.size();
|
||||
|
||||
/*if(block->m_static_objects.m_stored.size() != 0){
|
||||
errorstream<<"ServerEnvironment::step(): "
|
||||
<<PP(block->getPos())<<" contains "
|
||||
<<block->m_static_objects.m_stored.size()
|
||||
<<" stored objects; "
|
||||
<<"when spawning objects, when counting active "
|
||||
<<"objects in wide area. relative position: "
|
||||
<<"("<<x<<","<<y<<","<<z<<")"<<std::endl;
|
||||
}*/
|
||||
}
|
||||
|
||||
v3s16 p0;
|
||||
|
@ -1051,8 +1148,10 @@ void ServerEnvironment::step(float dtime)
|
|||
Step active objects
|
||||
*/
|
||||
{
|
||||
ScopeProfiler sp(g_profiler, "SEnv: step act. objs avg", SPT_LOWPASS);
|
||||
ScopeProfiler sp(g_profiler, "SEnv: step act. objs avg", SPT_AVG);
|
||||
//TimeTaker timer("Step active objects");
|
||||
|
||||
g_profiler->avg("SEnv: num of objects", m_active_objects.size());
|
||||
|
||||
// This helps the objects to send data at the same time
|
||||
bool send_recommended = false;
|
||||
|
@ -1092,7 +1191,7 @@ void ServerEnvironment::step(float dtime)
|
|||
*/
|
||||
if(m_object_management_interval.step(dtime, 0.5))
|
||||
{
|
||||
ScopeProfiler sp(g_profiler, "SEnv: remove removed objs avg", SPT_LOWPASS);
|
||||
ScopeProfiler sp(g_profiler, "SEnv: remove removed objs avg /.5s", SPT_AVG);
|
||||
/*
|
||||
Remove objects that satisfy (m_removed && m_known_by_count==0)
|
||||
*/
|
||||
|
@ -1347,21 +1446,24 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
|
|||
bool set_changed)
|
||||
{
|
||||
assert(object);
|
||||
if(object->getId() == 0)
|
||||
{
|
||||
if(object->getId() == 0){
|
||||
u16 new_id = getFreeServerActiveObjectId(m_active_objects);
|
||||
if(new_id == 0)
|
||||
{
|
||||
infostream<<"ServerEnvironment::addActiveObjectRaw(): "
|
||||
errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
|
||||
<<"no free ids available"<<std::endl;
|
||||
delete object;
|
||||
return 0;
|
||||
}
|
||||
object->setId(new_id);
|
||||
}
|
||||
else{
|
||||
verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
|
||||
<<"supplied with id "<<object->getId()<<std::endl;
|
||||
}
|
||||
if(isFreeServerActiveObjectId(object->getId(), m_active_objects) == false)
|
||||
{
|
||||
infostream<<"ServerEnvironment::addActiveObjectRaw(): "
|
||||
errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
|
||||
<<"id is not free ("<<object->getId()<<")"<<std::endl;
|
||||
delete object;
|
||||
return 0;
|
||||
|
@ -1370,7 +1472,12 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
|
|||
<<"added (id="<<object->getId()<<")"<<std::endl;*/
|
||||
|
||||
m_active_objects.insert(object->getId(), object);
|
||||
|
||||
|
||||
verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
|
||||
<<"Added id="<<object->getId()<<"; there are now "
|
||||
<<m_active_objects.size()<<" active objects."
|
||||
<<std::endl;
|
||||
|
||||
// Add static object to active static list of the block
|
||||
v3f objectpos = object->getBasePosition();
|
||||
std::string staticdata = object->getStaticData();
|
||||
|
@ -1385,11 +1492,12 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
|
|||
object->m_static_block = blockpos;
|
||||
|
||||
if(set_changed)
|
||||
block->setChangedFlag();
|
||||
block->raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
}
|
||||
else{
|
||||
infostream<<"ServerEnv: Could not find a block for "
|
||||
<<"storing newly added static active object"<<std::endl;
|
||||
errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
|
||||
<<"could not find block for storing id="<<object->getId()
|
||||
<<" statically"<<std::endl;
|
||||
}
|
||||
|
||||
return object->getId();
|
||||
|
@ -1429,11 +1537,12 @@ void ServerEnvironment::removeRemovedObjects()
|
|||
*/
|
||||
if(obj->m_static_exists && obj->m_removed)
|
||||
{
|
||||
MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
|
||||
MapBlock *block = m_map->emergeBlock(obj->m_static_block);
|
||||
if(block)
|
||||
{
|
||||
block->m_static_objects.remove(id);
|
||||
block->setChangedFlag();
|
||||
block->raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
obj->m_static_exists = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1454,6 +1563,40 @@ void ServerEnvironment::removeRemovedObjects()
|
|||
}
|
||||
}
|
||||
|
||||
static void print_hexdump(std::ostream &o, const std::string &data)
|
||||
{
|
||||
const int linelength = 16;
|
||||
for(int l=0; ; l++){
|
||||
int i0 = linelength * l;
|
||||
bool at_end = false;
|
||||
int thislinelength = linelength;
|
||||
if(i0 + thislinelength > (int)data.size()){
|
||||
thislinelength = data.size() - i0;
|
||||
at_end = true;
|
||||
}
|
||||
for(int di=0; di<linelength; di++){
|
||||
int i = i0 + di;
|
||||
char buf[4];
|
||||
if(di<thislinelength)
|
||||
snprintf(buf, 4, "%.2x ", data[i]);
|
||||
else
|
||||
snprintf(buf, 4, " ");
|
||||
o<<buf;
|
||||
}
|
||||
o<<" ";
|
||||
for(int di=0; di<thislinelength; di++){
|
||||
int i = i0 + di;
|
||||
if(data[i] >= 32)
|
||||
o<<data[i];
|
||||
else
|
||||
o<<".";
|
||||
}
|
||||
o<<std::endl;
|
||||
if(at_end)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Convert stored objects from blocks near the players to active.
|
||||
*/
|
||||
|
@ -1464,6 +1607,21 @@ void ServerEnvironment::activateObjects(MapBlock *block)
|
|||
// Ignore if no stored objects (to not set changed flag)
|
||||
if(block->m_static_objects.m_stored.size() == 0)
|
||||
return;
|
||||
verbosestream<<"ServerEnvironment::activateObjects(): "
|
||||
<<"activating objects of block "<<PP(block->getPos())
|
||||
<<" ("<<block->m_static_objects.m_stored.size()
|
||||
<<" objects)"<<std::endl;
|
||||
bool large_amount = (block->m_static_objects.m_stored.size() > 49);
|
||||
if(large_amount){
|
||||
errorstream<<"suspiciously large amount of objects detected: "
|
||||
<<block->m_static_objects.m_stored.size()<<" in "
|
||||
<<PP(block->getPos())
|
||||
<<"; removing all of them."<<std::endl;
|
||||
// Clear stored list
|
||||
block->m_static_objects.m_stored.clear();
|
||||
block->raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
return;
|
||||
}
|
||||
// A list for objects that couldn't be converted to static for some
|
||||
// reason. They will be stored back.
|
||||
core::list<StaticObject> new_stored;
|
||||
|
@ -1481,12 +1639,20 @@ void ServerEnvironment::activateObjects(MapBlock *block)
|
|||
// If couldn't create object, store static data back.
|
||||
if(obj==NULL)
|
||||
{
|
||||
errorstream<<"ServerEnvironment::activateObjects(): "
|
||||
<<"failed to create active object from static object "
|
||||
<<"in block "<<PP(s_obj.pos/BS)
|
||||
<<" type="<<(int)s_obj.type<<" data:"<<std::endl;
|
||||
print_hexdump(verbosestream, s_obj.data);
|
||||
|
||||
new_stored.push_back(s_obj);
|
||||
continue;
|
||||
}
|
||||
verbosestream<<"ServerEnvironment::activateObjects(): "
|
||||
<<"activated static object pos="<<PP(s_obj.pos/BS)
|
||||
<<" type="<<(int)s_obj.type<<std::endl;
|
||||
// This will also add the object to the active static list
|
||||
addActiveObjectRaw(obj, false);
|
||||
//u16 id = addActiveObjectRaw(obj, false);
|
||||
}
|
||||
// Clear stored list
|
||||
block->m_static_objects.m_stored.clear();
|
||||
|
@ -1498,13 +1664,18 @@ void ServerEnvironment::activateObjects(MapBlock *block)
|
|||
StaticObject &s_obj = *i;
|
||||
block->m_static_objects.m_stored.push_back(s_obj);
|
||||
}
|
||||
// Block has been modified
|
||||
// NOTE: No it has not really. Save I/O here.
|
||||
//block->setChangedFlag();
|
||||
/*
|
||||
Note: Block hasn't really been modified here.
|
||||
The objects have just been activated and moved from the stored
|
||||
static list to the active static list.
|
||||
As such, the block is essentially the same.
|
||||
Thus, do not call block->setChangedFlag().
|
||||
Otherwise there would be a huge amount of unnecessary I/O.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
Convert objects that are not in active blocks to static.
|
||||
Convert objects that are not standing inside active blocks to static.
|
||||
|
||||
If m_known_by_count != 0, active object is not deleted, but static
|
||||
data is still updated.
|
||||
|
@ -1524,12 +1695,16 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
|
|||
// This shouldn't happen but check it
|
||||
if(obj == NULL)
|
||||
{
|
||||
infostream<<"NULL object found in ServerEnvironment"
|
||||
errorstream<<"NULL object found in ServerEnvironment"
|
||||
<<std::endl;
|
||||
assert(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If pending deactivation, let removeRemovedObjects() do it
|
||||
if(obj->m_pending_deactivation)
|
||||
continue;
|
||||
|
||||
u16 id = i.getNode()->getKey();
|
||||
v3f objectpos = obj->getBasePosition();
|
||||
|
||||
|
@ -1540,69 +1715,112 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
|
|||
if(m_active_blocks.contains(blockpos_o))
|
||||
continue;
|
||||
|
||||
verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
|
||||
<<"deactivating object id="<<id<<" on inactive block "
|
||||
<<PP(blockpos_o)<<std::endl;
|
||||
|
||||
// If known by some client, don't immediately delete.
|
||||
bool pending_delete = (obj->m_known_by_count > 0 && !force_delete);
|
||||
|
||||
/*
|
||||
Update the static data
|
||||
*/
|
||||
|
||||
// Create new static object
|
||||
std::string staticdata_new = obj->getStaticData();
|
||||
StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
|
||||
|
||||
bool stays_in_same_block = false;
|
||||
bool data_changed = true;
|
||||
|
||||
if(obj->m_static_exists){
|
||||
if(obj->m_static_block == blockpos_o)
|
||||
stays_in_same_block = true;
|
||||
|
||||
MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
|
||||
|
||||
core::map<u16, StaticObject>::Node *n =
|
||||
block->m_static_objects.m_active.find(id);
|
||||
if(n){
|
||||
StaticObject static_old = n->getValue();
|
||||
|
||||
if(static_old.data == staticdata_new &&
|
||||
(static_old.pos - objectpos).getLength() < 2*BS)
|
||||
data_changed = false;
|
||||
} else {
|
||||
errorstream<<"ServerEnvironment::deactivateFarObjects(): "
|
||||
<<"id="<<id<<" m_static_exists=true but "
|
||||
<<"static data doesn't actually exist in "
|
||||
<<PP(obj->m_static_block)<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete old static object
|
||||
MapBlock *oldblock = NULL;
|
||||
if(obj->m_static_exists)
|
||||
{
|
||||
MapBlock *block = m_map->getBlockNoCreateNoEx
|
||||
(obj->m_static_block);
|
||||
MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
|
||||
if(block)
|
||||
{
|
||||
block->m_static_objects.remove(id);
|
||||
oldblock = block;
|
||||
obj->m_static_exists = false;
|
||||
// Only mark block as modified if data changed considerably
|
||||
if(!stays_in_same_block || data_changed)
|
||||
block->raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
}
|
||||
}
|
||||
// Create new static object
|
||||
std::string staticdata = obj->getStaticData();
|
||||
StaticObject s_obj(obj->getType(), objectpos, staticdata);
|
||||
|
||||
// Add to the block where the object is located in
|
||||
v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
|
||||
// Get or generate the block
|
||||
MapBlock *block = m_map->emergeBlock(blockpos);
|
||||
|
||||
/*MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
|
||||
if(block == NULL)
|
||||
{
|
||||
// Block not found. Is the old block still ok?
|
||||
if(oldblock)
|
||||
block = oldblock;
|
||||
// Load from disk or generate
|
||||
else
|
||||
block = m_map->emergeBlock(blockpos);
|
||||
}*/
|
||||
|
||||
if(block)
|
||||
{
|
||||
block->m_static_objects.insert(0, s_obj);
|
||||
block->setChangedFlag();
|
||||
obj->m_static_exists = true;
|
||||
obj->m_static_block = block->getPos();
|
||||
if(block->m_static_objects.m_stored.size() >= 49){
|
||||
errorstream<<"ServerEnv: Trying to store id="<<obj->getId()
|
||||
<<" statically but block "<<PP(blockpos)
|
||||
<<" already contains "
|
||||
<<block->m_static_objects.m_stored.size()
|
||||
<<" (over 49) objects."
|
||||
<<" Forcing delete."<<std::endl;
|
||||
force_delete = true;
|
||||
} else {
|
||||
u16 new_id = pending_delete ? id : 0;
|
||||
block->m_static_objects.insert(new_id, s_obj);
|
||||
|
||||
// Only mark block as modified if data changed considerably
|
||||
if(!stays_in_same_block || data_changed)
|
||||
block->raiseModified(MOD_STATE_WRITE_NEEDED);
|
||||
|
||||
obj->m_static_exists = true;
|
||||
obj->m_static_block = block->getPos();
|
||||
}
|
||||
}
|
||||
else{
|
||||
infostream<<"ServerEnv: Could not find or generate "
|
||||
<<"a block for storing static object"<<std::endl;
|
||||
obj->m_static_exists = false;
|
||||
errorstream<<"ServerEnv: Could not find or generate "
|
||||
<<"a block for storing id="<<obj->getId()
|
||||
<<" statically"<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
Delete active object if not known by some client,
|
||||
else set pending deactivation
|
||||
If known by some client, set pending deactivation.
|
||||
Otherwise delete it immediately.
|
||||
*/
|
||||
|
||||
// If known by some client, don't delete.
|
||||
if(obj->m_known_by_count > 0 && force_delete == false)
|
||||
if(pending_delete)
|
||||
{
|
||||
verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
|
||||
<<"object id="<<id<<" is known by clients"
|
||||
<<"; not deleting yet"<<std::endl;
|
||||
|
||||
obj->m_pending_deactivation = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*infostream<<"Server: Stored static data. Deleting object."
|
||||
<<std::endl;*/
|
||||
verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
|
||||
<<"object id="<<id<<" is not known by clients"
|
||||
<<"; deleting"<<std::endl;
|
||||
// Delete active object
|
||||
delete obj;
|
||||
// Id to be removed from m_active_objects
|
||||
|
|
|
@ -225,6 +225,11 @@ public:
|
|||
|
||||
void addActiveBlockModifier(ActiveBlockModifier *abm);
|
||||
|
||||
/* Other stuff */
|
||||
|
||||
// Clear all objects, loading and going through every MapBlock
|
||||
void clearAllObjects();
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
|
|
65
src/game.cpp
65
src/game.cpp
|
@ -450,10 +450,15 @@ void getPointedNode(Client *client, v3f player_position,
|
|||
v3f cpf = npf + dir_f;
|
||||
f32 distance = (cpf - camera_position).getLength();
|
||||
|
||||
v3f vertices[4] =
|
||||
/*v3f vertices[4] =
|
||||
{
|
||||
v3f(BS*0.42,-BS*0.4,-BS*0.4),
|
||||
v3f(BS*0.49, BS*0.4, BS*0.4),
|
||||
};*/
|
||||
v3f vertices[4] =
|
||||
{
|
||||
v3f(BS*0.42,-BS*0.8,-BS*0.8),
|
||||
v3f(BS*0.49, BS*0.8, BS*0.8),
|
||||
};
|
||||
|
||||
for(s32 i=0; i<2; i++)
|
||||
|
@ -922,7 +927,6 @@ void the_game(
|
|||
L"",
|
||||
core::rect<s32>(5, 5+(text_height+5)*1, 795, (5+text_height)*2),
|
||||
false, false, guiroot);
|
||||
|
||||
// At the middle of the screen
|
||||
// Object infos are shown in this
|
||||
gui::IGUIStaticText *guitext_info = guienv->addStaticText(
|
||||
|
@ -945,6 +949,15 @@ void the_game(
|
|||
//guitext_chat->setBackgroundColor(video::SColor(96,0,0,0));
|
||||
core::list<ChatLine> chat_lines;
|
||||
|
||||
// Profiler text
|
||||
gui::IGUIStaticText *guitext_profiler = guienv->addStaticText(
|
||||
L"<Profiler>",
|
||||
core::rect<s32>(6, 4+(text_height+5)*3, 400,
|
||||
(text_height+5)*3 + text_height*35),
|
||||
false, false);
|
||||
guitext_profiler->setBackgroundColor(video::SColor(80,0,0,0));
|
||||
guitext_profiler->setVisible(false);
|
||||
|
||||
/*GUIQuickInventory *quick_inventory = new GUIQuickInventory
|
||||
(guienv, NULL, v2s32(10, 70), 5, &local_inventory);*/
|
||||
/*GUIQuickInventory *quick_inventory = new GUIQuickInventory
|
||||
|
@ -998,6 +1011,10 @@ void the_game(
|
|||
|
||||
bool respawn_menu_active = false;
|
||||
|
||||
bool show_profiler = false;
|
||||
|
||||
bool force_fog_off = false;
|
||||
|
||||
/*
|
||||
Main loop
|
||||
*/
|
||||
|
@ -1129,7 +1146,8 @@ void the_game(
|
|||
|
||||
object_hit_delay_timer -= dtime;
|
||||
|
||||
g_profiler->add("Elapsed time", dtime * 1000);
|
||||
g_profiler->add("Elapsed time", dtime);
|
||||
g_profiler->avg("FPS", 1./dtime);
|
||||
|
||||
/*
|
||||
Log frametime for visualization
|
||||
|
@ -1220,15 +1238,24 @@ void the_game(
|
|||
*/
|
||||
float profiler_print_interval =
|
||||
g_settings->getFloat("profiler_print_interval");
|
||||
if(profiler_print_interval != 0)
|
||||
bool print_to_log = true;
|
||||
if(profiler_print_interval == 0){
|
||||
print_to_log = false;
|
||||
profiler_print_interval = 5;
|
||||
}
|
||||
if(m_profiler_interval.step(dtime, profiler_print_interval))
|
||||
{
|
||||
if(m_profiler_interval.step(0.030, profiler_print_interval))
|
||||
{
|
||||
if(print_to_log){
|
||||
infostream<<"Profiler:"<<std::endl;
|
||||
g_profiler->print(infostream);
|
||||
}
|
||||
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
g_profiler->print(os);
|
||||
guitext_profiler->setText(narrow_to_wide(os.str()).c_str());
|
||||
|
||||
g_profiler->clear();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Direct handling of user input
|
||||
|
@ -1357,6 +1384,15 @@ void the_game(
|
|||
image->drop();
|
||||
}
|
||||
}
|
||||
else if(input->wasKeyDown(getKeySetting("keymap_toggle_profiler")))
|
||||
{
|
||||
show_profiler = !show_profiler;
|
||||
guitext_profiler->setVisible(show_profiler);
|
||||
}
|
||||
else if(input->wasKeyDown(getKeySetting("keymap_toggle_force_fog_off")))
|
||||
{
|
||||
force_fog_off = !force_fog_off;
|
||||
}
|
||||
|
||||
// Item selection with mouse wheel
|
||||
{
|
||||
|
@ -2043,7 +2079,7 @@ void the_game(
|
|||
Fog
|
||||
*/
|
||||
|
||||
if(g_settings->getBool("enable_fog") == true)
|
||||
if(g_settings->getBool("enable_fog") == true && !force_fog_off)
|
||||
{
|
||||
f32 range;
|
||||
if(farmesh)
|
||||
|
@ -2053,10 +2089,11 @@ void the_game(
|
|||
else
|
||||
{
|
||||
range = draw_control.wanted_range*BS + MAP_BLOCKSIZE*BS*1.5;
|
||||
range *= 0.9;
|
||||
if(draw_control.range_all)
|
||||
range = 100000*BS;
|
||||
if(range < 50*BS)
|
||||
range = range * 0.5 + 25*BS;
|
||||
/*if(range < 50*BS)
|
||||
range = range * 0.5 + 25*BS;*/
|
||||
}
|
||||
|
||||
driver->setFog(
|
||||
|
@ -2121,14 +2158,15 @@ void the_game(
|
|||
"(% .1f, % .1f, % .1f)"
|
||||
" (% .3f < btime_jitter < % .3f"
|
||||
", dtime_jitter = % .1f %%"
|
||||
", v_range = %.1f)",
|
||||
", v_range = %.1f, RTT = %.3f)",
|
||||
player_position.X/BS,
|
||||
player_position.Y/BS,
|
||||
player_position.Z/BS,
|
||||
busytime_jitter1_min_sample,
|
||||
busytime_jitter1_max_sample,
|
||||
dtime_jitter1_max_fraction * 100.0,
|
||||
draw_control.wanted_range
|
||||
draw_control.wanted_range,
|
||||
client.getRTT()
|
||||
);
|
||||
|
||||
guitext2->setText(narrow_to_wide(temptext).c_str());
|
||||
|
@ -2210,7 +2248,8 @@ void the_game(
|
|||
|
||||
guitext_chat->setRelativePosition(rect);
|
||||
|
||||
if(chat_lines.size() == 0)
|
||||
// Don't show chat if empty or profiler is enabled
|
||||
if(chat_lines.size() == 0 || show_profiler)
|
||||
guitext_chat->setVisible(false);
|
||||
else
|
||||
guitext_chat->setVisible(true);
|
||||
|
|
|
@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include <IGUIButton.h>
|
||||
#include <IGUIStaticText.h>
|
||||
#include <IGUIFont.h>
|
||||
#include "log.h"
|
||||
|
||||
void drawInventoryItem(video::IVideoDriver *driver,
|
||||
gui::IGUIFont *font,
|
||||
|
@ -326,11 +327,11 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
|
|||
if(amount >= 0)
|
||||
{
|
||||
v2s32 p(event.MouseInput.X, event.MouseInput.Y);
|
||||
//dstream<<"Mouse down at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
|
||||
//infostream<<"Mouse down at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
|
||||
ItemSpec s = getItemAtPos(p);
|
||||
if(s.isValid())
|
||||
{
|
||||
dstream<<"Mouse down on "<<s.inventoryname
|
||||
infostream<<"Mouse down on "<<s.inventoryname
|
||||
<<"/"<<s.listname<<" "<<s.i<<std::endl;
|
||||
if(m_selected_item)
|
||||
{
|
||||
|
@ -345,15 +346,15 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
|
|||
InventoryList *list_to =
|
||||
inv_to->getList(s.listname);
|
||||
if(list_from == NULL)
|
||||
dstream<<"from list doesn't exist"<<std::endl;
|
||||
infostream<<"from list doesn't exist"<<std::endl;
|
||||
if(list_to == NULL)
|
||||
dstream<<"to list doesn't exist"<<std::endl;
|
||||
infostream<<"to list doesn't exist"<<std::endl;
|
||||
// Indicates whether source slot completely empties
|
||||
bool source_empties = false;
|
||||
if(list_from && list_to
|
||||
&& list_from->getItem(m_selected_item->i) != NULL)
|
||||
{
|
||||
dstream<<"Handing IACTION_MOVE to manager"<<std::endl;
|
||||
infostream<<"Handing IACTION_MOVE to manager"<<std::endl;
|
||||
IMoveAction *a = new IMoveAction();
|
||||
a->count = amount;
|
||||
a->from_inv = m_selected_item->inventoryname;
|
||||
|
@ -408,7 +409,7 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
|
|||
{
|
||||
if(!canTakeFocus(event.GUIEvent.Element))
|
||||
{
|
||||
dstream<<"GUIInventoryMenu: Not allowing focus change."
|
||||
infostream<<"GUIInventoryMenu: Not allowing focus change."
|
||||
<<std::endl;
|
||||
// Returning true disables focus change
|
||||
return true;
|
||||
|
@ -474,7 +475,7 @@ v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
|
|||
while(f.atend() == false)
|
||||
{
|
||||
std::string type = trim(f.next("["));
|
||||
//dstream<<"type="<<type<<std::endl;
|
||||
//infostream<<"type="<<type<<std::endl;
|
||||
if(type == "list")
|
||||
{
|
||||
std::string name = f.next(";");
|
||||
|
@ -485,7 +486,7 @@ v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
|
|||
s32 pos_y = stoi(f.next(";"));
|
||||
s32 geom_x = stoi(f.next(","));
|
||||
s32 geom_y = stoi(f.next(";"));
|
||||
dstream<<"list name="<<name<<", subname="<<subname
|
||||
infostream<<"list name="<<name<<", subname="<<subname
|
||||
<<", pos=("<<pos_x<<","<<pos_y<<")"
|
||||
<<", geom=("<<geom_x<<","<<geom_y<<")"
|
||||
<<std::endl;
|
||||
|
@ -498,14 +499,14 @@ v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
|
|||
{
|
||||
invsize.X = stoi(f.next(","));
|
||||
invsize.Y = stoi(f.next(";"));
|
||||
dstream<<"invsize ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl;
|
||||
infostream<<"invsize ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl;
|
||||
f.next("]");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ignore others
|
||||
std::string ts = f.next("]");
|
||||
dstream<<"Unknown DrawSpec: type="<<type<<", data=\""<<ts<<"\""
|
||||
infostream<<"Unknown DrawSpec: type="<<type<<", data=\""<<ts<<"\""
|
||||
<<std::endl;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "content_inventory.h"
|
||||
#include "content_sao.h"
|
||||
#include "player.h"
|
||||
#include "log.h"
|
||||
|
||||
/*
|
||||
InventoryItem
|
||||
|
@ -117,7 +118,7 @@ InventoryItem* InventoryItem::deSerialize(std::istream &is)
|
|||
}
|
||||
else
|
||||
{
|
||||
dstream<<"Unknown InventoryItem name=\""<<name<<"\""<<std::endl;
|
||||
infostream<<"Unknown InventoryItem name=\""<<name<<"\""<<std::endl;
|
||||
throw SerializationError("Unknown InventoryItem name");
|
||||
}
|
||||
}
|
||||
|
@ -738,51 +739,56 @@ InventoryAction * InventoryAction::deSerialize(std::istream &is)
|
|||
return a;
|
||||
}
|
||||
|
||||
static std::string describeC(const struct InventoryContext *c)
|
||||
{
|
||||
if(c->current_player == NULL)
|
||||
return "current_player=NULL";
|
||||
else
|
||||
return std::string("current_player=") + c->current_player->getName();
|
||||
}
|
||||
|
||||
void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr)
|
||||
{
|
||||
#if 1
|
||||
|
||||
/*dstream<<"from_inv="<<from_inv<<" to_inv="<<to_inv<<std::endl;
|
||||
dstream<<"from_list="<<from_list<<" to_list="<<to_list<<std::endl;
|
||||
dstream<<"from_i="<<from_i<<" to_i="<<to_i<<std::endl;*/
|
||||
|
||||
Inventory *inv_from = mgr->getInventory(c, from_inv);
|
||||
Inventory *inv_to = mgr->getInventory(c, to_inv);
|
||||
|
||||
if(!inv_from || !inv_to)
|
||||
{
|
||||
dstream<<__FUNCTION_NAME<<": Operation not allowed "
|
||||
<<"(inventories not found or ownership error)"<<std::endl;
|
||||
if(!inv_from){
|
||||
infostream<<"IMoveAction::apply(): FAIL: source inventory not found: "
|
||||
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
|
||||
<<", to_inv=\""<<to_inv<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
if(!inv_to){
|
||||
infostream<<"IMoveAction::apply(): FAIL: destination inventory not found: "
|
||||
"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
|
||||
<<", to_inv=\""<<to_inv<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
InventoryList *list_from = inv_from->getList(from_list);
|
||||
InventoryList *list_to = inv_to->getList(to_list);
|
||||
|
||||
/*dstream<<"list_from="<<list_from<<" list_to="<<list_to
|
||||
<<std::endl;*/
|
||||
/*if(list_from)
|
||||
dstream<<" list_from->getItem(from_i)="<<list_from->getItem(from_i)
|
||||
<<std::endl;
|
||||
if(list_to)
|
||||
dstream<<" list_to->getItem(to_i)="<<list_to->getItem(to_i)
|
||||
<<std::endl;*/
|
||||
|
||||
/*
|
||||
If a list doesn't exist or the source item doesn't exist
|
||||
*/
|
||||
if(!list_from || !list_to)
|
||||
{
|
||||
dstream<<__FUNCTION_NAME<<": Operation not allowed "
|
||||
<<"(a list doesn't exist)"
|
||||
<<std::endl;
|
||||
if(!list_from){
|
||||
infostream<<"IMoveAction::apply(): FAIL: source list not found: "
|
||||
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
|
||||
<<", from_list=\""<<from_list<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
if(!list_to){
|
||||
infostream<<"IMoveAction::apply(): FAIL: destination list not found: "
|
||||
<<"context=["<<describeC(c)<<"], to_inv=\""<<to_inv<<"\""
|
||||
<<", to_list=\""<<to_list<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
if(list_from->getItem(from_i) == NULL)
|
||||
{
|
||||
dstream<<__FUNCTION_NAME<<": Operation not allowed "
|
||||
<<"(the source item doesn't exist)"
|
||||
<<std::endl;
|
||||
infostream<<"IMoveAction::apply(): FAIL: source item not found: "
|
||||
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
|
||||
<<", from_list=\""<<from_list<<"\""
|
||||
<<" from_i="<<from_i<<std::endl;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
|
@ -790,8 +796,9 @@ void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr)
|
|||
*/
|
||||
if(inv_from == inv_to && list_from == list_to && from_i == to_i)
|
||||
{
|
||||
dstream<<__FUNCTION_NAME<<": Operation not allowed "
|
||||
<<"(source and the destination slots are the same)"<<std::endl;
|
||||
infostream<<"IMoveAction::apply(): FAIL: source and destination slots "
|
||||
<<"are the same: inv=\""<<from_inv<<"\" list=\""<<from_list
|
||||
<<"\" i="<<from_i<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -832,7 +839,16 @@ void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr)
|
|||
mgr->inventoryModified(c, from_inv);
|
||||
if(from_inv != to_inv)
|
||||
mgr->inventoryModified(c, to_inv);
|
||||
#endif
|
||||
|
||||
infostream<<"IMoveAction::apply(): moved at "
|
||||
<<"["<<describeC(c)<<"]"
|
||||
<<" from inv=\""<<from_inv<<"\""
|
||||
<<" list=\""<<from_list<<"\""
|
||||
<<" i="<<from_i
|
||||
<<" to inv=\""<<to_inv<<"\""
|
||||
<<" list=\""<<to_list<<"\""
|
||||
<<" i="<<to_i
|
||||
<<std::endl;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
16
src/main.cpp
16
src/main.cpp
|
@ -481,6 +481,8 @@ MainGameCallback *g_gamecallback = NULL;
|
|||
// Connection
|
||||
std::ostream *dout_con_ptr = &dummyout;
|
||||
std::ostream *derr_con_ptr = &verbosestream;
|
||||
//std::ostream *dout_con_ptr = &infostream;
|
||||
//std::ostream *derr_con_ptr = &errorstream;
|
||||
|
||||
// Server
|
||||
std::ostream *dout_server_ptr = &infostream;
|
||||
|
@ -1074,15 +1076,15 @@ void drawMenuBackground(video::IVideoDriver* driver)
|
|||
}
|
||||
}
|
||||
|
||||
class DstreamLogOutput: public ILogOutput
|
||||
class StderrLogOutput: public ILogOutput
|
||||
{
|
||||
public:
|
||||
/* line: Full line with timestamp, level and thread */
|
||||
void printLog(const std::string &line)
|
||||
{
|
||||
dstream<<line<<std::endl;
|
||||
std::cerr<<line<<std::endl;
|
||||
}
|
||||
} main_dstream_log_out;
|
||||
} main_stderr_log_out;
|
||||
|
||||
class DstreamNoStderrLogOutput: public ILogOutput
|
||||
{
|
||||
|
@ -1100,7 +1102,7 @@ int main(int argc, char *argv[])
|
|||
Initialization
|
||||
*/
|
||||
|
||||
log_add_output_maxlev(&main_dstream_log_out, LMT_ACTION);
|
||||
log_add_output_maxlev(&main_stderr_log_out, LMT_ACTION);
|
||||
log_add_output_all_levs(&main_dstream_no_stderr_log_out);
|
||||
|
||||
log_register_thread("main");
|
||||
|
@ -1175,7 +1177,7 @@ int main(int argc, char *argv[])
|
|||
#endif
|
||||
|
||||
if(cmd_args.getFlag("info-on-stderr"))
|
||||
log_add_output(&main_dstream_log_out, LMT_INFO);
|
||||
log_add_output(&main_stderr_log_out, LMT_INFO);
|
||||
|
||||
porting::signal_handler_init();
|
||||
bool &kill = *porting::signal_handler_killstatus();
|
||||
|
@ -1278,6 +1280,9 @@ int main(int argc, char *argv[])
|
|||
|
||||
// Initial call with g_texturesource not set.
|
||||
init_mapnode();
|
||||
// Must be called before g_texturesource is created
|
||||
// (for texture atlas making)
|
||||
init_mineral();
|
||||
|
||||
/*
|
||||
Run unit tests
|
||||
|
@ -1475,7 +1480,6 @@ int main(int argc, char *argv[])
|
|||
*/
|
||||
|
||||
init_mapnode(); // Second call with g_texturesource set
|
||||
init_mineral();
|
||||
|
||||
/*
|
||||
GUI stuff
|
||||
|
|
287
src/map.cpp
287
src/map.cpp
|
@ -21,7 +21,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "mapsector.h"
|
||||
#include "mapblock.h"
|
||||
#include "main.h"
|
||||
#ifndef SERVER
|
||||
#include "client.h"
|
||||
#endif
|
||||
#include "filesys.h"
|
||||
#include "utility.h"
|
||||
#include "voxel.h"
|
||||
|
@ -34,6 +36,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#endif
|
||||
#include "settings.h"
|
||||
#include "log.h"
|
||||
#include "profiler.h"
|
||||
|
||||
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
|
||||
|
||||
/*
|
||||
SQLite format specification:
|
||||
|
@ -1833,9 +1838,14 @@ NodeMetadata* Map::getNodeMetadata(v3s16 p)
|
|||
v3s16 blockpos = getNodeBlockPos(p);
|
||||
v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
|
||||
MapBlock *block = getBlockNoCreateNoEx(blockpos);
|
||||
if(block == NULL)
|
||||
if(!block){
|
||||
infostream<<"Map::getNodeMetadata(): Need to emerge "
|
||||
<<PP(blockpos)<<std::endl;
|
||||
block = emergeBlock(blockpos, false);
|
||||
}
|
||||
if(!block)
|
||||
{
|
||||
infostream<<"WARNING: Map::setNodeMetadata(): Block not found"
|
||||
infostream<<"WARNING: Map::getNodeMetadata(): Block not found"
|
||||
<<std::endl;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1848,7 +1858,12 @@ void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
|
|||
v3s16 blockpos = getNodeBlockPos(p);
|
||||
v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
|
||||
MapBlock *block = getBlockNoCreateNoEx(blockpos);
|
||||
if(block == NULL)
|
||||
if(!block){
|
||||
infostream<<"Map::setNodeMetadata(): Need to emerge "
|
||||
<<PP(blockpos)<<std::endl;
|
||||
block = emergeBlock(blockpos, false);
|
||||
}
|
||||
if(!block)
|
||||
{
|
||||
infostream<<"WARNING: Map::setNodeMetadata(): Block not found"
|
||||
<<std::endl;
|
||||
|
@ -2624,152 +2639,6 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
Do not generate over-limit
|
||||
*/
|
||||
if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
|
||||
|| p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
|
||||
|| p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
|
||||
|| p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
|
||||
|| p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
|
||||
|| p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
|
||||
throw InvalidPositionException("emergeBlock(): pos. over limit");
|
||||
|
||||
v2s16 p2d(p.X, p.Z);
|
||||
s16 block_y = p.Y;
|
||||
/*
|
||||
This will create or load a sector if not found in memory.
|
||||
If block exists on disk, it will be loaded.
|
||||
*/
|
||||
ServerMapSector *sector;
|
||||
try{
|
||||
sector = createSector(p2d);
|
||||
//sector = emergeSector(p2d, changed_blocks);
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
infostream<<"emergeBlock: createSector() failed: "
|
||||
<<e.what()<<std::endl;
|
||||
infostream<<"Path to failed sector: "<<getSectorDir(p2d)
|
||||
<<std::endl
|
||||
<<"You could try to delete it."<<std::endl;
|
||||
throw e;
|
||||
}
|
||||
catch(VersionMismatchException &e)
|
||||
{
|
||||
infostream<<"emergeBlock: createSector() failed: "
|
||||
<<e.what()<<std::endl;
|
||||
infostream<<"Path to failed sector: "<<getSectorDir(p2d)
|
||||
<<std::endl
|
||||
<<"You could try to delete it."<<std::endl;
|
||||
throw e;
|
||||
}
|
||||
|
||||
/*
|
||||
Try to get a block from the sector
|
||||
*/
|
||||
|
||||
bool does_not_exist = false;
|
||||
bool lighting_expired = false;
|
||||
MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
|
||||
|
||||
// If not found, try loading from disk
|
||||
if(block == NULL)
|
||||
{
|
||||
block = loadBlock(p);
|
||||
}
|
||||
|
||||
// Handle result
|
||||
if(block == NULL)
|
||||
{
|
||||
does_not_exist = true;
|
||||
}
|
||||
else if(block->isDummy() == true)
|
||||
{
|
||||
does_not_exist = true;
|
||||
}
|
||||
else if(block->getLightingExpired())
|
||||
{
|
||||
lighting_expired = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Valid block
|
||||
//infostream<<"emergeBlock(): Returning already valid block"<<std::endl;
|
||||
return block;
|
||||
}
|
||||
|
||||
/*
|
||||
If block was not found on disk and not going to generate a
|
||||
new one, make sure there is a dummy block in place.
|
||||
*/
|
||||
if(only_from_disk && (does_not_exist || lighting_expired))
|
||||
{
|
||||
//infostream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
|
||||
|
||||
if(block == NULL)
|
||||
{
|
||||
// Create dummy block
|
||||
block = new MapBlock(this, p, true);
|
||||
|
||||
// Add block to sector
|
||||
sector->insertBlock(block);
|
||||
}
|
||||
// Done.
|
||||
return block;
|
||||
}
|
||||
|
||||
//infostream<<"Not found on disk, generating."<<std::endl;
|
||||
// 0ms
|
||||
//TimeTaker("emergeBlock() generate");
|
||||
|
||||
//infostream<<"emergeBlock(): Didn't find valid block -> making one"<<std::endl;
|
||||
|
||||
/*
|
||||
If the block doesn't exist, generate the block.
|
||||
*/
|
||||
if(does_not_exist)
|
||||
{
|
||||
block = generateBlock(p, block, sector, changed_blocks,
|
||||
lighting_invalidated_blocks);
|
||||
}
|
||||
|
||||
if(lighting_expired)
|
||||
{
|
||||
lighting_invalidated_blocks.insert(p, block);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
Initially update sunlight
|
||||
*/
|
||||
{
|
||||
core::map<v3s16, bool> light_sources;
|
||||
bool black_air_left = false;
|
||||
bool bottom_invalid =
|
||||
block->propagateSunlight(light_sources, true,
|
||||
&black_air_left);
|
||||
|
||||
// If sunlight didn't reach everywhere and part of block is
|
||||
// above ground, lighting has to be properly updated
|
||||
//if(black_air_left && some_part_underground)
|
||||
if(black_air_left)
|
||||
{
|
||||
lighting_invalidated_blocks[block->getPos()] = block;
|
||||
}
|
||||
|
||||
if(bottom_invalid)
|
||||
{
|
||||
lighting_invalidated_blocks[block->getPos()] = block;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return block;
|
||||
}
|
||||
#endif
|
||||
|
||||
s16 ServerMap::findGroundLevel(v2s16 p2d)
|
||||
{
|
||||
#if 0
|
||||
|
@ -2868,6 +2737,12 @@ void ServerMap::verifyDatabase() {
|
|||
throw FileNotGoodException("Cannot prepare write statement");
|
||||
}
|
||||
|
||||
d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
|
||||
if(d != SQLITE_OK) {
|
||||
infostream<<"WARNING: Database list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
|
||||
throw FileNotGoodException("Cannot prepare read statement");
|
||||
}
|
||||
|
||||
infostream<<"Server: Database opened"<<std::endl;
|
||||
}
|
||||
}
|
||||
|
@ -3040,6 +2915,52 @@ void ServerMap::save(bool only_changed)
|
|||
}
|
||||
}
|
||||
|
||||
static s32 unsignedToSigned(s32 i, s32 max_positive)
|
||||
{
|
||||
if(i < max_positive)
|
||||
return i;
|
||||
else
|
||||
return i - 2*max_positive;
|
||||
}
|
||||
|
||||
// modulo of a negative number does not work consistently in C
|
||||
static sqlite3_int64 pythonmodulo(sqlite3_int64 i, sqlite3_int64 mod)
|
||||
{
|
||||
if(i >= 0)
|
||||
return i % mod;
|
||||
return mod - ((-i) % mod);
|
||||
}
|
||||
|
||||
v3s16 ServerMap::getIntegerAsBlock(sqlite3_int64 i)
|
||||
{
|
||||
s32 x = unsignedToSigned(pythonmodulo(i, 4096), 2048);
|
||||
i = (i - x) / 4096;
|
||||
s32 y = unsignedToSigned(pythonmodulo(i, 4096), 2048);
|
||||
i = (i - y) / 4096;
|
||||
s32 z = unsignedToSigned(pythonmodulo(i, 4096), 2048);
|
||||
return v3s16(x,y,z);
|
||||
}
|
||||
|
||||
void ServerMap::listAllLoadableBlocks(core::list<v3s16> &dst)
|
||||
{
|
||||
if(loadFromFolders()){
|
||||
errorstream<<"Map::listAllLoadableBlocks(): Result will be missing "
|
||||
<<"all blocks that are stored in flat files"<<std::endl;
|
||||
}
|
||||
|
||||
{
|
||||
verifyDatabase();
|
||||
|
||||
while(sqlite3_step(m_database_list) == SQLITE_ROW)
|
||||
{
|
||||
sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
|
||||
v3s16 p = getIntegerAsBlock(block_i);
|
||||
//dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
|
||||
dst.push_back(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServerMap::saveMapMeta()
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
@ -3752,22 +3673,35 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||
v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
|
||||
|
||||
// Take a fair amount as we will be dropping more out later
|
||||
// Umm... these additions are a bit strange but they are needed.
|
||||
v3s16 p_blocks_min(
|
||||
p_nodes_min.X / MAP_BLOCKSIZE - 2,
|
||||
p_nodes_min.Y / MAP_BLOCKSIZE - 2,
|
||||
p_nodes_min.Z / MAP_BLOCKSIZE - 2);
|
||||
p_nodes_min.X / MAP_BLOCKSIZE - 3,
|
||||
p_nodes_min.Y / MAP_BLOCKSIZE - 3,
|
||||
p_nodes_min.Z / MAP_BLOCKSIZE - 3);
|
||||
v3s16 p_blocks_max(
|
||||
p_nodes_max.X / MAP_BLOCKSIZE + 1,
|
||||
p_nodes_max.Y / MAP_BLOCKSIZE + 1,
|
||||
p_nodes_max.Z / MAP_BLOCKSIZE + 1);
|
||||
|
||||
u32 vertex_count = 0;
|
||||
u32 meshbuffer_count = 0;
|
||||
|
||||
// For limiting number of mesh updates per frame
|
||||
u32 mesh_update_count = 0;
|
||||
|
||||
// Number of blocks in rendering range
|
||||
u32 blocks_in_range = 0;
|
||||
// Number of blocks in rendering range but don't have a mesh
|
||||
u32 blocks_in_range_without_mesh = 0;
|
||||
// Blocks that had mesh that would have been drawn according to
|
||||
// rendering range (if max blocks limit didn't kick in)
|
||||
u32 blocks_would_have_drawn = 0;
|
||||
// Blocks that were drawn and had a mesh
|
||||
u32 blocks_drawn = 0;
|
||||
// Blocks which had a corresponding meshbuffer for this pass
|
||||
u32 blocks_had_pass_meshbuf = 0;
|
||||
// Blocks from which stuff was actually drawn
|
||||
u32 blocks_without_stuff = 0;
|
||||
|
||||
int timecheck_counter = 0;
|
||||
core::map<v2s16, MapSector*>::Iterator si;
|
||||
|
@ -3840,6 +3774,8 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||
/*if(m_control.range_all == false &&
|
||||
d - 0.5*BS*MAP_BLOCKSIZE > range)
|
||||
continue;*/
|
||||
|
||||
blocks_in_range++;
|
||||
|
||||
#if 1
|
||||
/*
|
||||
|
@ -3858,8 +3794,10 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||
|
||||
// Mesh has not been expired and there is no mesh:
|
||||
// block has no content
|
||||
if(block->mesh == NULL && mesh_expired == false)
|
||||
if(block->mesh == NULL && mesh_expired == false){
|
||||
blocks_in_range_without_mesh++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
f32 faraway = BS*50;
|
||||
|
@ -3897,9 +3835,11 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||
JMutexAutoLock lock(block->mesh_mutex);
|
||||
|
||||
scene::SMesh *mesh = block->mesh;
|
||||
|
||||
if(mesh == NULL)
|
||||
|
||||
if(mesh == NULL){
|
||||
blocks_in_range_without_mesh++;
|
||||
continue;
|
||||
}
|
||||
|
||||
blocks_would_have_drawn++;
|
||||
if(blocks_drawn >= m_control.wanted_max_blocks
|
||||
|
@ -3911,7 +3851,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||
sector_blocks_drawn++;
|
||||
|
||||
u32 c = mesh->getMeshBufferCount();
|
||||
|
||||
bool stuff_actually_drawn = false;
|
||||
for(u32 i=0; i<c; i++)
|
||||
{
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
|
||||
|
@ -3922,16 +3862,25 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||
// Render transparent on transparent pass and likewise.
|
||||
if(transparent == is_transparent_pass)
|
||||
{
|
||||
if(buf->getVertexCount() == 0)
|
||||
errorstream<<"Block ["<<analyze_block(block)
|
||||
<<"] contains an empty meshbuf"<<std::endl;
|
||||
/*
|
||||
This *shouldn't* hurt too much because Irrlicht
|
||||
doesn't change opengl textures if the old
|
||||
material is set again.
|
||||
material has the same texture.
|
||||
*/
|
||||
driver->setMaterial(buf->getMaterial());
|
||||
driver->drawMeshBuffer(buf);
|
||||
vertex_count += buf->getVertexCount();
|
||||
meshbuffer_count++;
|
||||
stuff_actually_drawn = true;
|
||||
}
|
||||
}
|
||||
if(stuff_actually_drawn)
|
||||
blocks_had_pass_meshbuf++;
|
||||
else
|
||||
blocks_without_stuff++;
|
||||
}
|
||||
} // foreach sectorblocks
|
||||
|
||||
|
@ -3941,6 +3890,30 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||
}
|
||||
}
|
||||
|
||||
std::string prefix = "CM: ";
|
||||
|
||||
// Log only on solid pass because values are the same
|
||||
if(pass == scene::ESNRP_SOLID){
|
||||
g_profiler->avg(prefix+"blocks in range", blocks_in_range);
|
||||
if(blocks_in_range != 0)
|
||||
g_profiler->avg(prefix+"blocks in range without mesh (frac)",
|
||||
(float)blocks_in_range_without_mesh/blocks_in_range);
|
||||
g_profiler->avg(prefix+"blocks drawn", blocks_drawn);
|
||||
}
|
||||
|
||||
if(pass == scene::ESNRP_SOLID)
|
||||
prefix = "CM: solid: ";
|
||||
else
|
||||
prefix = "CM: transparent: ";
|
||||
|
||||
g_profiler->avg(prefix+"vertices drawn", vertex_count);
|
||||
if(blocks_had_pass_meshbuf != 0)
|
||||
g_profiler->avg(prefix+"meshbuffers per block",
|
||||
(float)meshbuffer_count / (float)blocks_had_pass_meshbuf);
|
||||
if(blocks_drawn != 0)
|
||||
g_profiler->avg(prefix+"empty blocks (frac)",
|
||||
(float)blocks_without_stuff / blocks_drawn);
|
||||
|
||||
m_control.blocks_drawn = blocks_drawn;
|
||||
m_control.blocks_would_have_drawn = blocks_would_have_drawn;
|
||||
|
||||
|
|
|
@ -157,6 +157,10 @@ public:
|
|||
// Returns NULL if not found
|
||||
MapBlock * getBlockNoCreateNoEx(v3s16 p);
|
||||
|
||||
/* Server overrides */
|
||||
virtual MapBlock * emergeBlock(v3s16 p, bool allow_generate=true)
|
||||
{ return getBlockNoCreateNoEx(p); }
|
||||
|
||||
// Returns InvalidPositionException if not found
|
||||
bool isNodeUnderground(v3s16 p);
|
||||
|
||||
|
@ -379,6 +383,7 @@ public:
|
|||
void verifyDatabase();
|
||||
// Get an integer suitable for a block
|
||||
static sqlite3_int64 getBlockAsInteger(const v3s16 pos);
|
||||
static v3s16 getIntegerAsBlock(sqlite3_int64 i);
|
||||
|
||||
// Returns true if the database file does not exist
|
||||
bool loadFromFolders();
|
||||
|
@ -390,6 +395,8 @@ public:
|
|||
void save(bool only_changed);
|
||||
//void loadAll();
|
||||
|
||||
void listAllLoadableBlocks(core::list<v3s16> &dst);
|
||||
|
||||
// Saves map seed and possibly other stuff
|
||||
void saveMapMeta();
|
||||
void loadMapMeta();
|
||||
|
@ -454,6 +461,7 @@ private:
|
|||
sqlite3 *m_database;
|
||||
sqlite3_stmt *m_database_read;
|
||||
sqlite3_stmt *m_database_write;
|
||||
sqlite3_stmt *m_database_list;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "main.h" // For g_settings and g_texturesource
|
||||
#include "content_mapblock.h"
|
||||
#include "settings.h"
|
||||
#include "profiler.h"
|
||||
|
||||
void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
|
||||
{
|
||||
|
@ -527,7 +528,7 @@ void updateFastFaceRow(
|
|||
next_tile);
|
||||
|
||||
if(next_makes_face == makes_face
|
||||
&& next_p_corrected == p_corrected
|
||||
&& next_p_corrected == p_corrected + translate_dir
|
||||
&& next_face_dir_corrected == face_dir_corrected
|
||||
&& next_lights[0] == lights[0]
|
||||
&& next_lights[1] == lights[1]
|
||||
|
@ -537,6 +538,29 @@ void updateFastFaceRow(
|
|||
{
|
||||
next_is_different = false;
|
||||
}
|
||||
else{
|
||||
/*if(makes_face){
|
||||
g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
|
||||
next_makes_face != makes_face ? 1 : 0);
|
||||
g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
|
||||
(next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
|
||||
g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
|
||||
next_face_dir_corrected != face_dir_corrected ? 1 : 0);
|
||||
g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
|
||||
(next_lights[0] != lights[0] ||
|
||||
next_lights[0] != lights[0] ||
|
||||
next_lights[0] != lights[0] ||
|
||||
next_lights[0] != lights[0]) ? 1 : 0);
|
||||
g_profiler->add("Meshgen: diff: !(next_tile == tile)",
|
||||
!(next_tile == tile) ? 1 : 0);
|
||||
}*/
|
||||
}
|
||||
/*g_profiler->add("Meshgen: Total faces checked", 1);
|
||||
if(makes_face)
|
||||
g_profiler->add("Meshgen: Total makes_face checked", 1);*/
|
||||
} else {
|
||||
/*if(makes_face)
|
||||
g_profiler->add("Meshgen: diff: last position", 1);*/
|
||||
}
|
||||
|
||||
continuous_tiles_count++;
|
||||
|
@ -568,6 +592,8 @@ void updateFastFaceRow(
|
|||
v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
|
||||
// Center point of face (kind of)
|
||||
v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
|
||||
if(continuous_tiles_count != 1)
|
||||
sp += translate_dir_f;
|
||||
v3f scale(1,1,1);
|
||||
|
||||
if(translate_dir.X != 0)
|
||||
|
@ -586,6 +612,11 @@ void updateFastFaceRow(
|
|||
makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
|
||||
sp, face_dir_corrected, scale,
|
||||
posRelative_f, dest);
|
||||
|
||||
g_profiler->avg("Meshgen: faces drawn by tiling", 0);
|
||||
for(int i=1; i<continuous_tiles_count; i++){
|
||||
g_profiler->avg("Meshgen: faces drawn by tiling", 1);
|
||||
}
|
||||
}
|
||||
|
||||
continuous_tiles_count = 0;
|
||||
|
@ -707,10 +738,13 @@ scene::SMesh* makeMapBlockMesh(MeshMakeData *data)
|
|||
|
||||
video::SMaterial material;
|
||||
material.setFlag(video::EMF_LIGHTING, false);
|
||||
material.setFlag(video::EMF_BACK_FACE_CULLING, true);
|
||||
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
//material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
|
||||
//material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
|
||||
material.MaterialType
|
||||
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
|
||||
for(u32 i=0; i<fastfaces_new.size(); i++)
|
||||
{
|
||||
|
|
|
@ -42,6 +42,8 @@ ContentFeatures::~ContentFeatures()
|
|||
#ifndef SERVER
|
||||
void ContentFeatures::setTexture(u16 i, std::string name, u8 alpha)
|
||||
{
|
||||
used_texturenames[name] = true;
|
||||
|
||||
if(g_texturesource)
|
||||
{
|
||||
tiles[i].texture = g_texturesource->getTexture(name);
|
||||
|
|
|
@ -124,6 +124,10 @@ struct ContentFeatures
|
|||
AtlasPointer *special_atlas;
|
||||
#endif
|
||||
|
||||
// List of all block textures that have been used (value is dummy)
|
||||
// Exists on server too for cleaner code in content_mapnode.cpp
|
||||
core::map<std::string, bool> used_texturenames;
|
||||
|
||||
// Type of MapNode::param1
|
||||
ContentParamType param_type;
|
||||
// True for all ground-like things like stone and mud, false for eg. trees
|
||||
|
@ -151,6 +155,10 @@ struct ContentFeatures
|
|||
// If true, node is equivalent to air. Torches are, air is. Water is not.
|
||||
// Is used for example to check whether a mud block can have grass on.
|
||||
bool air_equivalent;
|
||||
// Whether this content type often contains mineral.
|
||||
// Used for texture atlas creation.
|
||||
// Currently only enabled for CONTENT_STONE.
|
||||
bool often_contains_mineral;
|
||||
|
||||
// Inventory item string as which the node appears in inventory when dug.
|
||||
// Mineral overrides this.
|
||||
|
@ -207,6 +215,7 @@ struct ContentFeatures
|
|||
liquid_type = LIQUID_NONE;
|
||||
wall_mounted = false;
|
||||
air_equivalent = false;
|
||||
often_contains_mineral = false;
|
||||
dug_item = "";
|
||||
initial_metadata = NULL;
|
||||
liquid_alternative_flowing = CONTENT_IGNORE;
|
||||
|
|
|
@ -41,28 +41,48 @@ public:
|
|||
void add(const std::string &name, float value)
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
core::map<std::string, float>::Node *n = m_data.find(name);
|
||||
if(n == NULL)
|
||||
{
|
||||
m_data[name] = value;
|
||||
/* No average shall have been used; mark add used as -2 */
|
||||
core::map<std::string, int>::Node *n = m_avgcounts.find(name);
|
||||
if(n == NULL)
|
||||
m_avgcounts[name] = -2;
|
||||
else{
|
||||
if(n->getValue() == -1)
|
||||
n->setValue(-2);
|
||||
assert(n->getValue() == -2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
n->setValue(n->getValue() + value);
|
||||
core::map<std::string, float>::Node *n = m_data.find(name);
|
||||
if(n == NULL)
|
||||
m_data[name] = value;
|
||||
else
|
||||
n->setValue(n->getValue() + value);
|
||||
}
|
||||
}
|
||||
|
||||
void lowpass(const std::string &name, float value, float factor)
|
||||
void avg(const std::string &name, float value)
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
core::map<std::string, float>::Node *n = m_data.find(name);
|
||||
if(n == NULL)
|
||||
{
|
||||
m_data[name] = value;
|
||||
core::map<std::string, int>::Node *n = m_avgcounts.find(name);
|
||||
if(n == NULL)
|
||||
m_avgcounts[name] = 1;
|
||||
else{
|
||||
/* No add shall have been used */
|
||||
assert(n->getValue() != -2);
|
||||
if(n->getValue() <= 0)
|
||||
n->setValue(1);
|
||||
else
|
||||
n->setValue(n->getValue() + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
n->setValue(n->getValue() * (1.0 - 1.0/factor) + value / factor);
|
||||
core::map<std::string, float>::Node *n = m_data.find(name);
|
||||
if(n == NULL)
|
||||
m_data[name] = value;
|
||||
else
|
||||
n->setValue(n->getValue() + value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,6 +95,7 @@ public:
|
|||
{
|
||||
i.getNode()->setValue(0);
|
||||
}
|
||||
m_avgcounts.clear();
|
||||
}
|
||||
|
||||
void print(std::ostream &o)
|
||||
|
@ -85,6 +106,12 @@ public:
|
|||
i.atEnd() == false; i++)
|
||||
{
|
||||
std::string name = i.getNode()->getKey();
|
||||
int avgcount = 1;
|
||||
core::map<std::string, int>::Node *n = m_avgcounts.find(name);
|
||||
if(n){
|
||||
if(n->getValue() >= 1)
|
||||
avgcount = n->getValue();
|
||||
}
|
||||
o<<" "<<name<<": ";
|
||||
s32 clampsize = 40;
|
||||
s32 space = clampsize - name.size();
|
||||
|
@ -95,7 +122,7 @@ public:
|
|||
else
|
||||
o<<" ";
|
||||
}
|
||||
o<<i.getNode()->getValue();
|
||||
o<<(i.getNode()->getValue() / avgcount);
|
||||
o<<std::endl;
|
||||
}
|
||||
}
|
||||
|
@ -103,11 +130,12 @@ public:
|
|||
private:
|
||||
JMutex m_mutex;
|
||||
core::map<std::string, float> m_data;
|
||||
core::map<std::string, int> m_avgcounts;
|
||||
};
|
||||
|
||||
enum ScopeProfilerType{
|
||||
SPT_ADD,
|
||||
SPT_LOWPASS
|
||||
SPT_AVG
|
||||
};
|
||||
|
||||
class ScopeProfiler
|
||||
|
@ -138,14 +166,15 @@ public:
|
|||
{
|
||||
if(m_timer)
|
||||
{
|
||||
u32 duration = m_timer->stop(true);
|
||||
float duration_ms = m_timer->stop(true);
|
||||
float duration = duration_ms / 1000.0;
|
||||
if(m_profiler){
|
||||
switch(m_type){
|
||||
case SPT_ADD:
|
||||
m_profiler->add(m_name, duration);
|
||||
break;
|
||||
case SPT_LOWPASS:
|
||||
m_profiler->lowpass(m_name, duration, 20.0);
|
||||
case SPT_AVG:
|
||||
m_profiler->avg(m_name, duration);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
181
src/server.cpp
181
src/server.cpp
|
@ -354,11 +354,10 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
|||
|
||||
// Increment timers
|
||||
m_nothing_to_send_pause_timer -= dtime;
|
||||
m_nearest_unsent_reset_timer += dtime;
|
||||
|
||||
if(m_nothing_to_send_pause_timer >= 0)
|
||||
{
|
||||
// Keep this reset
|
||||
m_nearest_unsent_reset_timer = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -410,17 +409,13 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
|||
/*infostream<<"m_nearest_unsent_reset_timer="
|
||||
<<m_nearest_unsent_reset_timer<<std::endl;*/
|
||||
|
||||
// This has to be incremented only when the nothing to send pause
|
||||
// is not active
|
||||
m_nearest_unsent_reset_timer += dtime;
|
||||
|
||||
// Reset periodically to avoid possible bugs or other mishaps
|
||||
if(m_nearest_unsent_reset_timer > 10.0)
|
||||
// Reset periodically to workaround for some bugs or stuff
|
||||
if(m_nearest_unsent_reset_timer > 20.0)
|
||||
{
|
||||
m_nearest_unsent_reset_timer = 0;
|
||||
m_nearest_unsent_d = 0;
|
||||
/*infostream<<"Resetting m_nearest_unsent_d for "
|
||||
<<server->getPlayerName(peer_id)<<std::endl;*/
|
||||
//infostream<<"Resetting m_nearest_unsent_d for "
|
||||
// <<server->getPlayerName(peer_id)<<std::endl;
|
||||
}
|
||||
|
||||
//s16 last_nearest_unsent_d = m_nearest_unsent_d;
|
||||
|
@ -463,22 +458,24 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
|||
s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
|
||||
|
||||
// Don't loop very much at a time
|
||||
if(d_max > d_start+1)
|
||||
d_max = d_start+1;
|
||||
s16 max_d_increment_at_time = 2;
|
||||
if(d_max > d_start + max_d_increment_at_time)
|
||||
d_max = d_start + max_d_increment_at_time;
|
||||
/*if(d_max_gen > d_start+2)
|
||||
d_max_gen = d_start+2;*/
|
||||
|
||||
//infostream<<"Starting from "<<d_start<<std::endl;
|
||||
|
||||
bool sending_something = false;
|
||||
|
||||
bool no_blocks_found_for_sending = true;
|
||||
|
||||
s32 nearest_emerged_d = -1;
|
||||
s32 nearest_emergefull_d = -1;
|
||||
s32 nearest_sent_d = -1;
|
||||
bool queue_is_full = false;
|
||||
|
||||
s16 d;
|
||||
for(d = d_start; d <= d_max; d++)
|
||||
{
|
||||
/*errorstream<<"checking d="<<d<<" for "
|
||||
<<server->getPlayerName(peer_id)<<std::endl;*/
|
||||
//infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
|
||||
|
||||
/*
|
||||
|
@ -550,12 +547,12 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
|||
if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
|
||||
generate = false;*/
|
||||
|
||||
// Limit the send area vertically to 2/3
|
||||
if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
|
||||
// Limit the send area vertically to 1/2
|
||||
if(abs(p.Y - center.Y) > d_max / 2)
|
||||
continue;
|
||||
}
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
/*
|
||||
If block is far away, don't generate it unless it is
|
||||
near ground level.
|
||||
|
@ -588,7 +585,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
|||
#endif
|
||||
|
||||
//infostream<<"d="<<d<<std::endl;
|
||||
|
||||
#if 1
|
||||
/*
|
||||
Don't generate or send if not in sight
|
||||
FIXME This only works if the client uses a small enough
|
||||
|
@ -600,7 +597,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
|||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
Don't send already sent blocks
|
||||
*/
|
||||
|
@ -658,7 +655,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
|||
Block is near ground level if night-time mesh
|
||||
differs from day-time mesh.
|
||||
*/
|
||||
if(d > 3)
|
||||
if(d >= 4)
|
||||
{
|
||||
if(block->dayNightDiffed() == false)
|
||||
continue;
|
||||
|
@ -676,18 +673,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
|||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
Record the lowest d from which a block has been
|
||||
found being not sent and possibly to exist
|
||||
*/
|
||||
if(no_blocks_found_for_sending)
|
||||
{
|
||||
if(generate == true)
|
||||
new_nearest_unsent_d = d;
|
||||
}
|
||||
|
||||
no_blocks_found_for_sending = false;
|
||||
|
||||
/*
|
||||
Add inexistent block to emerge queue.
|
||||
*/
|
||||
|
@ -697,7 +682,8 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
|||
// Allow only one block in emerge queue
|
||||
//if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
|
||||
// Allow two blocks in queue per client
|
||||
if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
|
||||
//if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
|
||||
if(server->m_emerge_queue.peerItemCount(peer_id) < 25)
|
||||
{
|
||||
//infostream<<"Adding block to emerge queue"<<std::endl;
|
||||
|
||||
|
@ -709,55 +695,63 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
|||
|
||||
server->m_emerge_queue.addBlock(peer_id, p, flags);
|
||||
server->m_emergethread.trigger();
|
||||
|
||||
if(nearest_emerged_d == -1)
|
||||
nearest_emerged_d = d;
|
||||
} else {
|
||||
if(nearest_emergefull_d == -1)
|
||||
nearest_emergefull_d = d;
|
||||
}
|
||||
|
||||
// get next one.
|
||||
continue;
|
||||
}
|
||||
|
||||
if(nearest_sent_d == -1)
|
||||
nearest_sent_d = d;
|
||||
|
||||
/*
|
||||
Add block to send queue
|
||||
*/
|
||||
|
||||
/*errorstream<<"sending from d="<<d<<" to "
|
||||
<<server->getPlayerName(peer_id)<<std::endl;*/
|
||||
|
||||
PrioritySortedBlockTransfer q((float)d, p, peer_id);
|
||||
|
||||
dest.push_back(q);
|
||||
|
||||
num_blocks_selected += 1;
|
||||
sending_something = true;
|
||||
}
|
||||
}
|
||||
queue_full_break:
|
||||
|
||||
//infostream<<"Stopped at "<<d<<std::endl;
|
||||
|
||||
if(no_blocks_found_for_sending)
|
||||
{
|
||||
if(queue_is_full == false)
|
||||
new_nearest_unsent_d = d;
|
||||
// If nothing was found for sending and nothing was queued for
|
||||
// emerging, continue next time browsing from here
|
||||
if(nearest_emerged_d != -1){
|
||||
new_nearest_unsent_d = nearest_emerged_d;
|
||||
} else if(nearest_emergefull_d != -1){
|
||||
new_nearest_unsent_d = nearest_emergefull_d;
|
||||
} else {
|
||||
if(d > g_settings->getS16("max_block_send_distance")){
|
||||
new_nearest_unsent_d = 0;
|
||||
m_nothing_to_send_pause_timer = 2.0;
|
||||
/*infostream<<"GetNextBlocks(): d wrapped around for "
|
||||
<<server->getPlayerName(peer_id)
|
||||
<<"; setting to 0 and pausing"<<std::endl;*/
|
||||
} else {
|
||||
if(nearest_sent_d != -1)
|
||||
new_nearest_unsent_d = nearest_sent_d;
|
||||
else
|
||||
new_nearest_unsent_d = d;
|
||||
}
|
||||
}
|
||||
|
||||
if(new_nearest_unsent_d != -1)
|
||||
m_nearest_unsent_d = new_nearest_unsent_d;
|
||||
|
||||
if(sending_something == false)
|
||||
{
|
||||
m_nothing_to_send_counter++;
|
||||
if((s16)m_nothing_to_send_counter >=
|
||||
g_settings->getS16("max_block_send_distance"))
|
||||
{
|
||||
// Pause time in seconds
|
||||
m_nothing_to_send_pause_timer = 1.0;
|
||||
/*infostream<<"nothing to send to "
|
||||
<<server->getPlayerName(peer_id)
|
||||
<<" (d="<<d<<")"<<std::endl;*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nothing_to_send_counter = 0;
|
||||
}
|
||||
|
||||
/*timer_result = timer.stop(true);
|
||||
if(timer_result != 0)
|
||||
infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
|
||||
|
@ -1080,7 +1074,7 @@ void Server::start(unsigned short port)
|
|||
m_thread.stop();
|
||||
|
||||
// Initialize connection
|
||||
m_con.setTimeoutMs(30);
|
||||
m_con.SetTimeoutMs(30);
|
||||
m_con.Serve(port);
|
||||
|
||||
// Start thread
|
||||
|
@ -1214,7 +1208,7 @@ void Server::AsyncRunStep()
|
|||
JMutexAutoLock lock(m_env_mutex);
|
||||
// Step environment
|
||||
ScopeProfiler sp(g_profiler, "SEnv step");
|
||||
ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_LOWPASS);
|
||||
ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
|
||||
m_env.step(dtime);
|
||||
}
|
||||
|
||||
|
@ -1470,7 +1464,7 @@ void Server::AsyncRunStep()
|
|||
JMutexAutoLock envlock(m_env_mutex);
|
||||
JMutexAutoLock conlock(m_con_mutex);
|
||||
|
||||
ScopeProfiler sp(g_profiler, "Server: sending object messages");
|
||||
//ScopeProfiler sp(g_profiler, "Server: sending object messages");
|
||||
|
||||
// Key = object id
|
||||
// Value = data sent by object
|
||||
|
@ -1710,7 +1704,7 @@ void Server::AsyncRunStep()
|
|||
JMutexAutoLock lock1(m_env_mutex);
|
||||
JMutexAutoLock lock2(m_con_mutex);
|
||||
|
||||
ScopeProfiler sp(g_profiler, "Server: sending player positions");
|
||||
//ScopeProfiler sp(g_profiler, "Server: sending player positions");
|
||||
|
||||
SendObjectData(counter);
|
||||
|
||||
|
@ -1829,9 +1823,18 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
JMutexAutoLock envlock(m_env_mutex);
|
||||
JMutexAutoLock conlock(m_con_mutex);
|
||||
|
||||
con::Peer *peer;
|
||||
try{
|
||||
peer = m_con.GetPeer(peer_id);
|
||||
Address address = m_con.GetPeerAddress(peer_id);
|
||||
|
||||
// drop player if is ip is banned
|
||||
if(m_banmanager.isIpBanned(address.serializeString())){
|
||||
SendAccessDenied(m_con, peer_id,
|
||||
L"Your ip is banned. Banned name was "
|
||||
+narrow_to_wide(m_banmanager.getBanName(
|
||||
address.serializeString())));
|
||||
m_con.DeletePeer(peer_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch(con::PeerNotFoundException &e)
|
||||
{
|
||||
|
@ -1840,17 +1843,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
return;
|
||||
}
|
||||
|
||||
// drop player if is ip is banned
|
||||
if(m_banmanager.isIpBanned(peer->address.serializeString())){
|
||||
SendAccessDenied(m_con, peer_id,
|
||||
L"Your ip is banned. Banned name was "
|
||||
+narrow_to_wide(m_banmanager.getBanName(
|
||||
peer->address.serializeString())));
|
||||
m_con.deletePeer(peer_id, false);
|
||||
return;
|
||||
}
|
||||
|
||||
u8 peer_ser_ver = getClient(peer->id)->serialization_version;
|
||||
u8 peer_ser_ver = getClient(peer_id)->serialization_version;
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -1871,7 +1864,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
return;
|
||||
|
||||
infostream<<"Server: Got TOSERVER_INIT from "
|
||||
<<peer->id<<std::endl;
|
||||
<<peer_id<<std::endl;
|
||||
|
||||
// First byte after command is maximum supported
|
||||
// serialization version
|
||||
|
@ -1884,7 +1877,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
deployed = SER_FMT_VER_INVALID;
|
||||
|
||||
//peer->serialization_version = deployed;
|
||||
getClient(peer->id)->pending_serialization_version = deployed;
|
||||
getClient(peer_id)->pending_serialization_version = deployed;
|
||||
|
||||
if(deployed == SER_FMT_VER_INVALID)
|
||||
{
|
||||
|
@ -1906,7 +1899,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
|
||||
}
|
||||
|
||||
getClient(peer->id)->net_proto_version = net_proto_version;
|
||||
getClient(peer_id)->net_proto_version = net_proto_version;
|
||||
|
||||
if(net_proto_version == 0)
|
||||
{
|
||||
|
@ -2051,11 +2044,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
if(command == TOSERVER_INIT2)
|
||||
{
|
||||
infostream<<"Server: Got TOSERVER_INIT2 from "
|
||||
<<peer->id<<std::endl;
|
||||
<<peer_id<<std::endl;
|
||||
|
||||
|
||||
getClient(peer->id)->serialization_version
|
||||
= getClient(peer->id)->pending_serialization_version;
|
||||
getClient(peer_id)->serialization_version
|
||||
= getClient(peer_id)->pending_serialization_version;
|
||||
|
||||
/*
|
||||
Send some initialization data
|
||||
|
@ -2065,8 +2058,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
SendPlayerInfos();
|
||||
|
||||
// Send inventory to player
|
||||
UpdateCrafting(peer->id);
|
||||
SendInventory(peer->id);
|
||||
UpdateCrafting(peer_id);
|
||||
SendInventory(peer_id);
|
||||
|
||||
// Send player items to all players
|
||||
SendPlayerItems();
|
||||
|
@ -2082,7 +2075,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
{
|
||||
SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
|
||||
m_env.getTimeOfDay());
|
||||
m_con.Send(peer->id, 0, data, true);
|
||||
m_con.Send(peer_id, 0, data, true);
|
||||
}
|
||||
|
||||
// Send information about server to player in chat
|
||||
|
@ -2103,7 +2096,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
}
|
||||
|
||||
// Warnings about protocol version can be issued here
|
||||
if(getClient(peer->id)->net_proto_version < PROTOCOL_VERSION)
|
||||
if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
|
||||
{
|
||||
SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
|
||||
}
|
||||
|
@ -2445,7 +2438,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
else if(action == 2)
|
||||
{
|
||||
#if 0
|
||||
RemoteClient *client = getClient(peer->id);
|
||||
RemoteClient *client = getClient(peer_id);
|
||||
JMutexAutoLock digmutex(client->m_dig_mutex);
|
||||
client->m_dig_tool_item = -1;
|
||||
#endif
|
||||
|
@ -2728,7 +2721,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
}
|
||||
|
||||
// Reset build time counter
|
||||
getClient(peer->id)->m_time_from_building = 0.0;
|
||||
getClient(peer_id)->m_time_from_building = 0.0;
|
||||
|
||||
// Create node data
|
||||
MaterialItem *mitem = (MaterialItem*)item;
|
||||
|
@ -3539,11 +3532,10 @@ core::list<PlayerInfo> Server::getPlayerInfo()
|
|||
Player *player = *i;
|
||||
|
||||
try{
|
||||
con::Peer *peer = m_con.GetPeer(player->peer_id);
|
||||
// Copy info from peer to info struct
|
||||
info.id = peer->id;
|
||||
info.address = peer->address;
|
||||
info.avg_rtt = peer->avg_rtt;
|
||||
// Copy info from connection to info struct
|
||||
info.id = player->peer_id;
|
||||
info.address = m_con.GetPeerAddress(player->peer_id);
|
||||
info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
|
||||
}
|
||||
catch(con::PeerNotFoundException &e)
|
||||
{
|
||||
|
@ -4426,6 +4418,11 @@ void Server::notifyPlayer(const char *name, const std::wstring msg)
|
|||
SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
|
||||
}
|
||||
|
||||
void Server::notifyPlayers(const std::wstring msg)
|
||||
{
|
||||
BroadcastChatMessage(msg);
|
||||
}
|
||||
|
||||
v3f findSpawnPos(ServerMap &map)
|
||||
{
|
||||
//return v3f(50,50,50)*BS;
|
||||
|
|
|
@ -476,13 +476,14 @@ public:
|
|||
return m_banmanager.getBanDescription(ip_or_name);
|
||||
}
|
||||
|
||||
con::Peer* getPeerNoEx(u16 peer_id)
|
||||
Address getPeerAddress(u16 peer_id)
|
||||
{
|
||||
return m_con.GetPeerNoEx(peer_id);
|
||||
return m_con.GetPeerAddress(peer_id);
|
||||
}
|
||||
|
||||
// Envlock and conlock should be locked when calling this
|
||||
void notifyPlayer(const char *name, const std::wstring msg);
|
||||
void notifyPlayers(const std::wstring msg);
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -251,19 +251,18 @@ void cmd_banunban(std::wostringstream &os, ServerCommandContext *ctx)
|
|||
return;
|
||||
}
|
||||
|
||||
con::Peer *peer = ctx->server->getPeerNoEx(player->peer_id);
|
||||
if(peer == NULL)
|
||||
{
|
||||
dstream<<__FUNCTION_NAME<<": peer was not found"<<std::endl;
|
||||
return;
|
||||
}
|
||||
std::string ip_string = peer->address.serializeString();
|
||||
try{
|
||||
Address address = ctx->server->getPeerAddress(player->peer_id);
|
||||
std::string ip_string = address.serializeString();
|
||||
ctx->server->setIpBanned(ip_string, player->getName());
|
||||
os<<L"-!- Banned "<<narrow_to_wide(ip_string)<<L"|"
|
||||
<<narrow_to_wide(player->getName());
|
||||
|
||||
actionstream<<ctx->player->getName()<<" bans "
|
||||
<<player->getName()<<" / "<<ip_string<<std::endl;
|
||||
} catch(con::PeerNotFoundException){
|
||||
dstream<<__FUNCTION_NAME<<": peer was not found"<<std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -277,6 +276,36 @@ void cmd_banunban(std::wostringstream &os, ServerCommandContext *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
void cmd_clearobjects(std::wostringstream &os,
|
||||
ServerCommandContext *ctx)
|
||||
{
|
||||
if((ctx->privs & PRIV_SERVER) ==0)
|
||||
{
|
||||
os<<L"-!- You don't have permission to do that";
|
||||
return;
|
||||
}
|
||||
|
||||
actionstream<<ctx->player->getName()
|
||||
<<" clears all objects"<<std::endl;
|
||||
|
||||
{
|
||||
std::wstring msg;
|
||||
msg += L"Clearing all objects. This may take long.";
|
||||
msg += L" You may experience a timeout. (by ";
|
||||
msg += narrow_to_wide(ctx->player->getName());
|
||||
msg += L")";
|
||||
ctx->server->notifyPlayers(msg);
|
||||
}
|
||||
|
||||
ctx->env->clearAllObjects();
|
||||
|
||||
actionstream<<"object clearing done"<<std::endl;
|
||||
|
||||
os<<L"*** cleared all objects";
|
||||
ctx->flags |= SEND_TO_OTHERS;
|
||||
}
|
||||
|
||||
|
||||
//j
|
||||
void cmd_clanNew(std::wostringstream &os,
|
||||
ServerCommandContext *ctx)
|
||||
|
@ -454,41 +483,25 @@ std::wstring processServerCommand(ServerCommandContext *ctx)
|
|||
os<<L" ban unban";
|
||||
}
|
||||
else if(ctx->parms[0] == L"status")
|
||||
{
|
||||
cmd_status(os, ctx);
|
||||
}
|
||||
else if(ctx->parms[0] == L"privs")
|
||||
{
|
||||
cmd_privs(os, ctx);
|
||||
}
|
||||
else if(ctx->parms[0] == L"grant" || ctx->parms[0] == L"revoke")
|
||||
{
|
||||
cmd_grantrevoke(os, ctx);
|
||||
}
|
||||
else if(ctx->parms[0] == L"time")
|
||||
{
|
||||
cmd_time(os, ctx);
|
||||
}
|
||||
else if(ctx->parms[0] == L"shutdown")
|
||||
{
|
||||
cmd_shutdown(os, ctx);
|
||||
}
|
||||
else if(ctx->parms[0] == L"setting")
|
||||
{
|
||||
cmd_setting(os, ctx);
|
||||
}
|
||||
else if(ctx->parms[0] == L"teleport")
|
||||
{
|
||||
cmd_teleport(os, ctx);
|
||||
}
|
||||
else if(ctx->parms[0] == L"ban" || ctx->parms[0] == L"unban")
|
||||
{
|
||||
cmd_banunban(os, ctx);
|
||||
}
|
||||
else if(ctx->parms[0] == L"me")
|
||||
{
|
||||
cmd_me(os, ctx);
|
||||
}
|
||||
else if(ctx->parms[0] == L"clearobjects")
|
||||
cmd_clearobjects(os, ctx);
|
||||
else if(ctx->parms[0] == L"clan-new")
|
||||
{
|
||||
cmd_clanNew(os, ctx);
|
||||
|
@ -506,9 +519,8 @@ std::wstring processServerCommand(ServerCommandContext *ctx)
|
|||
cmd_clanKick(os, ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
os<<L"-!- Invalid command: " + ctx->parms[0];
|
||||
}
|
||||
|
||||
return os.str();
|
||||
}
|
||||
|
||||
|
|
|
@ -117,15 +117,15 @@ u32 getTimeMs()
|
|||
return porting::getTimeMs();
|
||||
}
|
||||
|
||||
class DstreamLogOutput: public ILogOutput
|
||||
class StderrLogOutput: public ILogOutput
|
||||
{
|
||||
public:
|
||||
/* line: Full line with timestamp, level and thread */
|
||||
void printLog(const std::string &line)
|
||||
{
|
||||
dstream<<line<<std::endl;
|
||||
std::cerr<<line<<std::endl;
|
||||
}
|
||||
} main_dstream_log_out;
|
||||
} main_stderr_log_out;
|
||||
|
||||
class DstreamNoStderrLogOutput: public ILogOutput
|
||||
{
|
||||
|
@ -143,7 +143,7 @@ int main(int argc, char *argv[])
|
|||
Initialization
|
||||
*/
|
||||
|
||||
log_add_output_maxlev(&main_dstream_log_out, LMT_ACTION);
|
||||
log_add_output_maxlev(&main_stderr_log_out, LMT_ACTION);
|
||||
log_add_output_all_levs(&main_dstream_no_stderr_log_out);
|
||||
|
||||
log_register_thread("main");
|
||||
|
@ -245,7 +245,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
if(cmd_args.getFlag("info-on-stderr"))
|
||||
log_add_output(&main_dstream_log_out, LMT_INFO);
|
||||
log_add_output(&main_stderr_log_out, LMT_INFO);
|
||||
|
||||
/*
|
||||
Basic initialization
|
||||
|
|
|
@ -97,7 +97,7 @@ void Address::Resolve(const char *name)
|
|||
freeaddrinfo(resolved);
|
||||
}
|
||||
|
||||
std::string Address::serializeString()
|
||||
std::string Address::serializeString() const
|
||||
{
|
||||
unsigned int a, b, c, d;
|
||||
a = (m_address & 0xFF000000)>>24;
|
||||
|
|
|
@ -97,7 +97,7 @@ public:
|
|||
void setPort(unsigned short port);
|
||||
void print(std::ostream *s) const;
|
||||
void print() const;
|
||||
std::string serializeString();
|
||||
std::string serializeString() const;
|
||||
private:
|
||||
unsigned int m_address;
|
||||
unsigned short m_port;
|
||||
|
|
48
src/test.cpp
48
src/test.cpp
|
@ -819,7 +819,10 @@ struct TestConnection
|
|||
|
||||
/*
|
||||
Test some real connections
|
||||
|
||||
NOTE: This mostly tests the legacy interface.
|
||||
*/
|
||||
|
||||
u32 proto_id = 0xad26846a;
|
||||
|
||||
Handler hand_server("server");
|
||||
|
@ -843,11 +846,30 @@ struct TestConnection
|
|||
|
||||
sleep_ms(50);
|
||||
|
||||
// Client should not have added client yet
|
||||
assert(hand_client.count == 0);
|
||||
|
||||
try
|
||||
{
|
||||
u16 peer_id;
|
||||
u8 data[100];
|
||||
infostream<<"** running client.Receive()"<<std::endl;
|
||||
u32 size = client.Receive(peer_id, data, 100);
|
||||
infostream<<"** Client received: peer_id="<<peer_id
|
||||
<<", size="<<size
|
||||
<<std::endl;
|
||||
}
|
||||
catch(con::NoIncomingDataException &e)
|
||||
{
|
||||
}
|
||||
|
||||
// Client should have added server now
|
||||
assert(hand_client.count == 1);
|
||||
assert(hand_client.last_id == 1);
|
||||
// But server should not have added client
|
||||
// Server should not have added client yet
|
||||
assert(hand_server.count == 0);
|
||||
|
||||
sleep_ms(50);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -930,7 +952,7 @@ struct TestConnection
|
|||
}
|
||||
|
||||
u16 peer_id_client = 2;
|
||||
|
||||
#if 0
|
||||
{
|
||||
/*
|
||||
Send consequent packets in different order
|
||||
|
@ -941,13 +963,13 @@ struct TestConnection
|
|||
SharedBuffer<u8> data2 = SharedBufferFromString("Hello2");
|
||||
|
||||
Address client_address =
|
||||
server.GetPeer(peer_id_client)->address;
|
||||
server.GetPeerAddress(peer_id_client);
|
||||
|
||||
infostream<<"*** Sending packets in wrong order (2,1,2)"
|
||||
<<std::endl;
|
||||
|
||||
u8 chn = 0;
|
||||
con::Channel *ch = &server.GetPeer(peer_id_client)->channels[chn];
|
||||
con::Channel *ch = &server.getPeer(peer_id_client)->channels[chn];
|
||||
u16 sn = ch->next_outgoing_seqnum;
|
||||
ch->next_outgoing_seqnum = sn+1;
|
||||
server.Send(peer_id_client, chn, data2, true);
|
||||
|
@ -1004,6 +1026,7 @@ struct TestConnection
|
|||
}
|
||||
assert(got_exception);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
const int datasize = 30000;
|
||||
SharedBuffer<u8> data1(datasize);
|
||||
|
@ -1022,12 +1045,25 @@ struct TestConnection
|
|||
|
||||
server.Send(peer_id_client, 0, data1, true);
|
||||
|
||||
sleep_ms(50);
|
||||
sleep_ms(3000);
|
||||
|
||||
u8 recvdata[datasize + 1000];
|
||||
infostream<<"** running client.Receive()"<<std::endl;
|
||||
u16 peer_id = 132;
|
||||
u16 size = client.Receive(peer_id, recvdata, datasize + 1000);
|
||||
u16 size = 0;
|
||||
bool received = false;
|
||||
u32 timems0 = porting::getTimeMs();
|
||||
for(;;){
|
||||
if(porting::getTimeMs() - timems0 > 5000)
|
||||
break;
|
||||
try{
|
||||
size = client.Receive(peer_id, recvdata, datasize + 1000);
|
||||
received = true;
|
||||
}catch(con::NoIncomingDataException &e){
|
||||
}
|
||||
sleep_ms(10);
|
||||
}
|
||||
assert(received);
|
||||
infostream<<"** Client received: peer_id="<<peer_id
|
||||
<<", size="<<size
|
||||
<<std::endl;
|
||||
|
|
136
src/tile.cpp
136
src/tile.cpp
|
@ -25,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "settings.h"
|
||||
#include <ICameraSceneNode.h>
|
||||
#include "log.h"
|
||||
#include "mapnode.h" // For texture atlas making
|
||||
#include "mineral.h" // For texture atlas making
|
||||
|
||||
/*
|
||||
A cache from texture name to texture path
|
||||
|
@ -507,52 +509,62 @@ void TextureSource::buildMainAtlas()
|
|||
}
|
||||
|
||||
/*
|
||||
A list of stuff to include in the texture atlas.
|
||||
|
||||
It is a single-dimensional texture atlas due to the need to tile
|
||||
textures.
|
||||
|
||||
It should contain as much of the stuff shown in game as possible,
|
||||
to minimize texture changes.
|
||||
|
||||
It fills up quickly, so do not add anything that isn't contained
|
||||
in most MapBlocks. E.g. mese isn't suitable but stone is.
|
||||
Grab list of stuff to include in the texture atlas from the
|
||||
main content features
|
||||
*/
|
||||
|
||||
core::array<std::string> sourcelist;
|
||||
core::map<std::string, bool> sourcelist;
|
||||
|
||||
sourcelist.push_back("stone.png");
|
||||
sourcelist.push_back("mud.png");
|
||||
sourcelist.push_back("sand.png");
|
||||
sourcelist.push_back("grass.png");
|
||||
sourcelist.push_back("grass_footsteps.png");
|
||||
sourcelist.push_back("tree.png");
|
||||
sourcelist.push_back("tree_top.png");
|
||||
sourcelist.push_back("water.png");
|
||||
sourcelist.push_back("leaves.png");
|
||||
sourcelist.push_back("glass.png");
|
||||
sourcelist.push_back("mud.png^grass_side.png");
|
||||
sourcelist.push_back("cobble.png");
|
||||
sourcelist.push_back("mossycobble.png");
|
||||
sourcelist.push_back("gravel.png");
|
||||
sourcelist.push_back("jungletree.png");
|
||||
|
||||
sourcelist.push_back("stone.png^mineral_coal.png");
|
||||
sourcelist.push_back("stone.png^mineral_iron.png");
|
||||
for(u16 j=0; j<MAX_CONTENT+1; j++)
|
||||
{
|
||||
if(j == CONTENT_IGNORE || j == CONTENT_AIR)
|
||||
continue;
|
||||
ContentFeatures *f = &content_features(j);
|
||||
for(core::map<std::string, bool>::Iterator
|
||||
i = f->used_texturenames.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
std::string name = i.getNode()->getKey();
|
||||
sourcelist[name] = true;
|
||||
|
||||
if(f->often_contains_mineral){
|
||||
for(int k=1; k<MINERAL_COUNT; k++){
|
||||
std::string mineraltexture = mineral_block_texture(k);
|
||||
std::string fulltexture = name + "^" + mineraltexture;
|
||||
sourcelist[fulltexture] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
infostream<<"Creating texture atlas out of textures: ";
|
||||
for(core::map<std::string, bool>::Iterator
|
||||
i = sourcelist.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
std::string name = i.getNode()->getKey();
|
||||
infostream<<"\""<<name<<"\" ";
|
||||
}
|
||||
infostream<<std::endl;
|
||||
|
||||
// Padding to disallow texture bleeding
|
||||
s32 padding = 16;
|
||||
|
||||
s32 column_width = 256;
|
||||
s32 column_padding = 16;
|
||||
|
||||
/*
|
||||
First pass: generate almost everything
|
||||
*/
|
||||
core::position2d<s32> pos_in_atlas(0,0);
|
||||
|
||||
pos_in_atlas.Y += padding;
|
||||
pos_in_atlas.Y = padding;
|
||||
|
||||
for(u32 i=0; i<sourcelist.size(); i++)
|
||||
for(core::map<std::string, bool>::Iterator
|
||||
i = sourcelist.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
std::string name = sourcelist[i];
|
||||
std::string name = i.getNode()->getKey();
|
||||
|
||||
/*video::IImage *img = driver->createImageFromFile(
|
||||
getTexturePath(name.c_str()).c_str());
|
||||
|
@ -586,20 +598,26 @@ void TextureSource::buildMainAtlas()
|
|||
continue;
|
||||
}
|
||||
|
||||
// Stop making atlas if atlas is full
|
||||
// Wrap columns and stop making atlas if atlas is full
|
||||
if(pos_in_atlas.Y + dim.Height > atlas_dim.Height)
|
||||
{
|
||||
infostream<<"TextureSource::buildMainAtlas(): "
|
||||
<<"Atlas is full, not adding more textures."
|
||||
<<std::endl;
|
||||
break;
|
||||
if(pos_in_atlas.X > (s32)atlas_dim.Width - 256 - padding){
|
||||
errorstream<<"TextureSource::buildMainAtlas(): "
|
||||
<<"Atlas is full, not adding more textures."
|
||||
<<std::endl;
|
||||
break;
|
||||
}
|
||||
pos_in_atlas.Y = padding;
|
||||
pos_in_atlas.X += column_width + column_padding;
|
||||
}
|
||||
|
||||
infostream<<"TextureSource::buildMainAtlas(): Adding \""<<name
|
||||
<<"\" to texture atlas"<<std::endl;
|
||||
|
||||
// Tile it a few times in the X direction
|
||||
u16 xwise_tiling = 16;
|
||||
u16 xwise_tiling = column_width / dim.Width;
|
||||
if(xwise_tiling > 16) // Limit to 16 (more gives no benefit)
|
||||
xwise_tiling = 16;
|
||||
for(u32 j=0; j<xwise_tiling; j++)
|
||||
{
|
||||
// Copy the copy to the atlas
|
||||
|
@ -627,7 +645,7 @@ void TextureSource::buildMainAtlas()
|
|||
dst_y = -y0 + pos_in_atlas.Y-1;
|
||||
src_y = pos_in_atlas.Y;
|
||||
}
|
||||
s32 x = x0 + pos_in_atlas.X * dim.Width;
|
||||
s32 x = x0 + pos_in_atlas.X;
|
||||
video::SColor c = atlas_img->getPixel(x, src_y);
|
||||
atlas_img->setPixel(x,dst_y,c);
|
||||
}
|
||||
|
@ -668,9 +686,11 @@ void TextureSource::buildMainAtlas()
|
|||
/*
|
||||
Second pass: set texture pointer in generated AtlasPointers
|
||||
*/
|
||||
for(u32 i=0; i<sourcelist.size(); i++)
|
||||
for(core::map<std::string, bool>::Iterator
|
||||
i = sourcelist.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
std::string name = sourcelist[i];
|
||||
std::string name = i.getNode()->getKey();
|
||||
if(m_name_to_id.find(name) == NULL)
|
||||
continue;
|
||||
u32 id = m_name_to_id[name];
|
||||
|
@ -681,8 +701,12 @@ void TextureSource::buildMainAtlas()
|
|||
/*
|
||||
Write image to file so that it can be inspected
|
||||
*/
|
||||
/*driver->writeImageToFile(atlas_img,
|
||||
getTexturePath("main_atlas.png").c_str());*/
|
||||
/*std::string atlaspath = porting::path_userdata
|
||||
+ DIR_DELIM + "generated_texture_atlas.png";
|
||||
infostream<<"Removing and writing texture atlas for inspection to "
|
||||
<<atlaspath<<std::endl;
|
||||
fs::RecursiveDelete(atlaspath);
|
||||
driver->writeImageToFile(atlas_img, atlaspath.c_str());*/
|
||||
}
|
||||
|
||||
video::IImage* generate_image_from_scratch(std::string name,
|
||||
|
@ -1092,22 +1116,23 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
|||
core::dimension2d<u32> dim = image->getDimension();
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
|
||||
// Blit
|
||||
image->copyTo(baseimg);
|
||||
|
||||
image->drop();
|
||||
|
||||
for(u32 y=0; y<dim.Height; y++)
|
||||
for(u32 x=0; x<dim.Width; x++)
|
||||
{
|
||||
video::SColor c = image->getPixel(x,y);
|
||||
video::SColor c = baseimg->getPixel(x,y);
|
||||
u32 r = c.getRed();
|
||||
u32 g = c.getGreen();
|
||||
u32 b = c.getBlue();
|
||||
if(!(r == r1 && g == g1 && b == b1))
|
||||
continue;
|
||||
c.setAlpha(0);
|
||||
image->setPixel(x,y,c);
|
||||
baseimg->setPixel(x,y,c);
|
||||
}
|
||||
// Blit
|
||||
image->copyTo(baseimg);
|
||||
|
||||
image->drop();
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
@ -1149,11 +1174,16 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
|||
{
|
||||
core::dimension2d<u32> dim = image->getDimension();
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
|
||||
// Blit
|
||||
image->copyTo(baseimg);
|
||||
|
||||
image->drop();
|
||||
|
||||
for(u32 y=0; y<dim.Height; y++)
|
||||
for(u32 x=0; x<dim.Width; x++)
|
||||
{
|
||||
video::SColor c = image->getPixel(x,y);
|
||||
video::SColor c = baseimg->getPixel(x,y);
|
||||
u32 r = c.getRed();
|
||||
u32 g = c.getGreen();
|
||||
u32 b = c.getBlue();
|
||||
|
@ -1161,12 +1191,8 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
|||
!(r == r2 && g == g2 && b == b2))
|
||||
continue;
|
||||
c.setAlpha(0);
|
||||
image->setPixel(x,y,c);
|
||||
baseimg->setPixel(x,y,c);
|
||||
}
|
||||
// Blit
|
||||
image->copyTo(baseimg);
|
||||
|
||||
image->drop();
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
|
|
@ -283,9 +283,9 @@ struct TileSpec
|
|||
TileSpec():
|
||||
texture(0),
|
||||
alpha(255),
|
||||
material_type(MATERIAL_ALPHA_NONE),
|
||||
//material_type(MATERIAL_ALPHA_NONE),
|
||||
// Use this so that leaves don't need a separate material
|
||||
//material_type(MATERIAL_ALPHA_SIMPLE),
|
||||
material_type(MATERIAL_ALPHA_SIMPLE),
|
||||
material_flags(
|
||||
//0 // <- DEBUG, Use the one below
|
||||
MATERIAL_FLAG_BACKFACE_CULLING
|
||||
|
|
|
@ -236,7 +236,7 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
|
|||
|
||||
// If block is (nearly) touching the camera, don't
|
||||
// bother validating further (that is, render it anyway)
|
||||
if(d > block_max_radius * 1.5)
|
||||
if(d > block_max_radius)
|
||||
{
|
||||
// Cosine of the angle between the camera direction
|
||||
// and the block direction (camera_dir is an unit vector)
|
||||
|
|
Loading…
Reference in New Issue