Merge branch 'master' of git://github.com/celeron55/minetest

Also: Some changes, bigger teleports
master
jachoo 2011-10-26 23:20:14 +02:00
commit 0d367550bc
39 changed files with 2230 additions and 1326 deletions

View File

@ -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} ***")

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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()
{

View File

@ -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
};

View File

@ -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)
{

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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");

View File

@ -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

View File

@ -225,6 +225,11 @@ public:
void addActiveBlockModifier(ActiveBlockModifier *abm);
/* Other stuff */
// Clear all objects, loading and going through every MapBlock
void clearAllObjects();
private:
/*

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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;
}
/*

View File

@ -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

View File

@ -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;

View File

@ -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;
};
/*

View File

@ -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++)
{

View File

@ -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);

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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:

View File

@ -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();
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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();
}
}
/*

View File

@ -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

View File

@ -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)