aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgignore5
-rw-r--r--.hgtags3
-rw-r--r--CMakeLists.txt2
-rw-r--r--data/oerkki1_damaged.pngbin0 -> 341 bytes
-rw-r--r--data/unknown_block.pngbin0 -> 582 bytes
-rw-r--r--doc/changelog.txt5
-rw-r--r--minetest.conf.example144
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/activeobject.h9
-rw-r--r--src/client.cpp373
-rw-r--r--src/client.h130
-rw-r--r--src/clientobject.cpp673
-rw-r--r--src/clientobject.h217
-rw-r--r--src/clientserver.h2
-rw-r--r--src/collision.cpp54
-rw-r--r--src/collision.h7
-rw-r--r--src/content_cao.cpp753
-rw-r--r--src/content_cao.h248
-rw-r--r--src/content_inventory.cpp3
-rw-r--r--src/content_mapblock.cpp2
-rw-r--r--src/content_mapnode.cpp1
-rw-r--r--src/content_object.h29
-rw-r--r--src/content_sao.cpp694
-rw-r--r--src/content_sao.h118
-rw-r--r--src/defaultsettings.cpp9
-rw-r--r--src/environment.cpp99
-rw-r--r--src/environment.h14
-rw-r--r--src/farmesh.cpp3
-rw-r--r--src/game.cpp138
-rw-r--r--src/inventory.cpp1
-rw-r--r--src/main.cpp157
-rw-r--r--src/main.h2
-rw-r--r--src/map.cpp413
-rw-r--r--src/map.h134
-rw-r--r--src/mapblock.cpp63
-rw-r--r--src/mapblock.h15
-rw-r--r--src/mapblock_mesh.cpp6
-rw-r--r--src/mapblockobject.cpp12
-rw-r--r--src/mapchunk.h6
-rw-r--r--src/mapgen.cpp102
-rw-r--r--src/mapnode.cpp103
-rw-r--r--src/mapnode.h140
-rw-r--r--src/mapsector.cpp112
-rw-r--r--src/mapsector.h180
-rw-r--r--src/mineral.h1
-rw-r--r--src/noise.cpp6
-rw-r--r--src/noise.h3
-rw-r--r--src/player.cpp38
-rw-r--r--src/serialization.h5
-rw-r--r--src/server.cpp211
-rw-r--r--src/server.h1
-rw-r--r--src/serverobject.cpp598
-rw-r--r--src/serverobject.h102
-rw-r--r--src/test.cpp20
54 files changed, 3330 insertions, 2838 deletions
diff --git a/.hgignore b/.hgignore
index 0870e3c67..964b22bd9 100644
--- a/.hgignore
+++ b/.hgignore
@@ -9,7 +9,12 @@ src/jthread/CMakeFiles/*
src/jthread/Makefile
src/jthread/cmake_config.h
src/jthread/cmake_install.cmake
+src/.*.swp
+src/sqlite/libsqlite3.a
+src/session.vim
+util/uloste.png
minetest.conf
+debug.txt
bin/
CMakeCache.txt
CPackConfig.cmake
diff --git a/.hgtags b/.hgtags
index a124357b7..726f5ccfb 100644
--- a/.hgtags
+++ b/.hgtags
@@ -11,3 +11,6 @@ cf6dd618ef0b7514c81ae87749733b5a328fc763 0.2.20110529_2
0000000000000000000000000000000000000000 0.2.20110602_0
6f17cd3f6c5481e6abc906fc441980c764632cbc 0.2.20110602_0
dd08a9b5cb84d55b7576bb3fde3068dd263bc3bc 0.2.20110618_0_dev
+25aa2021937f7a8b36808390983cebbc16ae6965 0.2.20110704_0
+25aa2021937f7a8b36808390983cebbc16ae6965 0.2.20110704_0
+0000000000000000000000000000000000000000 0.2.20110704_0
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 854c4b48d..15f4a6453 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,7 +9,7 @@ project(minetest)
set(VERSION_MAJOR 0)
set(VERSION_MINOR 2)
-set(VERSION_PATCH 20110618_0_dev)
+set(VERSION_PATCH 20110704_0)
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
# Configuration options
diff --git a/data/oerkki1_damaged.png b/data/oerkki1_damaged.png
new file mode 100644
index 000000000..9b777387c
--- /dev/null
+++ b/data/oerkki1_damaged.png
Binary files differ
diff --git a/data/unknown_block.png b/data/unknown_block.png
new file mode 100644
index 000000000..a27cb8ca9
--- /dev/null
+++ b/data/unknown_block.png
Binary files differ
diff --git a/doc/changelog.txt b/doc/changelog.txt
index 5a01b6bc4..58d28d236 100644
--- a/doc/changelog.txt
+++ b/doc/changelog.txt
@@ -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.
+2011-07-04:
+- Many small fixes
+- Code reorganizing to aid further development
+- Renewed map generator
+
2011-06-02:
- Password crash on windows fixed
- Optimized server CPU usage a lot
diff --git a/minetest.conf.example b/minetest.conf.example
index 6e8a82bac..b81cc5fc6 100644
--- a/minetest.conf.example
+++ b/minetest.conf.example
@@ -9,25 +9,28 @@
#
# Further documentation:
# http://celeron.55.lt/~celeron55/minetest/wiki/doku.php
-
#
-# Client side stuff
+# NOTE: This file might not be up-to-date, refer to the
+# defaultsettings.cpp file for an up-to-date list:
+# https://bitbucket.org/celeron55/minetest/src/tip/src/defaultsettings.cpp
#
+# A vim command to convert most of defaultsettings.cpp to conf file format:
+# :'<,'>s/\tg_settings\.setDefault("\([^"]*\)", "\([^"]*\)");.*/#\1 = \2/g
-# Initial window size
-#screenW = 800
-#screenH = 600
-
-# Port to connect to and to bind a server at
-#port = 30000
-
-# Address to connect to (blank = start local server)
-#address =
+#
+# Client and server
+#
-# Name of player. On server, this is the default admin.
+# Network port (UDP)
+#port =
+# Name of player; on a server this is the main admin
#name =
-# Key configuration.
+#
+# Client stuff
+#
+
+# Key mappings
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
#keymap_forward = KEY_KEY_W
#keymap_backward = KEY_KEY_S
@@ -38,108 +41,99 @@
#keymap_inventory = KEY_KEY_I
#keymap_chat = KEY_KEY_T
#keymap_rangeselect = KEY_KEY_R
-# Some (temporary) keys for debugging features
+#keymap_freemove = KEY_KEY_K
+#keymap_fastmove = KEY_KEY_J
+#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
-#invert_mouse = false
-
# The desired FPS
#wanted_fps = 30
-
# If FPS would go higher than this, limit it by sleeping
# (to not waste CPU power for no benefit)
#fps_max = 60
-
# The allowed adjustment range for the automatic rendering range adjustment
#viewing_range_nodes_max = 300
-#viewing_range_nodes_min = 35
-
+#viewing_range_nodes_min = 25
+# Initial window size
+screenW# = 800
+screenH# = 600
+# Address to connect to (#blank = start local server)
+#address =
+# Enable random user input, for testing
+#random_input = false
+# Timeout for client to remove unused map data from memory
+#client_unload_unused_data_timeout = 600
# Whether to fog out the end of the visible area
#enable_fog = true
-
-# Enable/disable clouds
-#enable_clouds = true
-
-# Experimental
-#enable_farmesh = false
-
-# Enable a bit lower water surface; disable for speed
-#new_style_water = true
-
+# Enable a bit lower water surface; disable for speed (not quite optimized)
+#new_style_water = false
# Enable nice leaves; disable for speed
#new_style_leaves = true
-
# Enable smooth lighting with simple ambient occlusion;
# disable for speed or for different looks.
#smooth_lighting = true
-
# Whether to draw a frametime graph (for debugging frametime)
#frametime_graph = false
-
# Enable combining mainly used textures to a bigger one for improved speed
# disable if it causes graphics glitches.
#enable_texture_atlas = true
-
# Path to texture directory. All textures are first searched from here.
-#texture_path =
-
+#texture_path =
# Video back-end.
# Possible values: null, software, burningsvideo, direct3d8, direct3d9, opengl
#video_driver = opengl
-
-# Enable random user input, for testing
-#random_input = false
-
-# Timeout for client to remove unused map data from memory
-#client_delete_unused_sectors_timeout = 1200
+# Unobstructed movement without physics, downwards key is keymap_special1
+#free_move = false
+# Continuous forward movement (for testing)
+#continuous_forward = false
+# Fast movement (keymap_special1)
+#fast_move = false
+# Invert mouse
+#invert_mouse = false
+# FarMesh thingy
+#enable_farmesh = false
+# Enable/disable clouds
+#enable_clouds = true
+# Don't draw stone (for testing)
+#invisible_stone = false
+# Path for screenshots
+#screenshot_path = .
#
-# Server side stuff
+# Server stuff
#
# Map directory (everything in the world is stored here)
-#map-dir = /home/palle/custom_map
-
+#map-#dir = /custom/map
+# Set to true to enable experimental features or stuff that is tested
+# (varies from version to version, usually not useful at all)
+#enable_experimental = false
# Set to true to enable creative mode (unlimited inventory)
#creative_mode = false
-
#enable_damage = false
-
+# Gives some stuff to players at the beginning
+#give_initial_stuff = false
#default_password =
-
# Available privileges: build, teleport, settime, privs, shout
#default_privs = build, shout
-
-# Gives some stuff to players at the beginning
-#give_initial_stuff = false
-
-# Set to true to enable experimental features
-# (varies from version to version, see wiki)
-#enable_experimental = false
-
-# Profiler data print interval. 0 = disable.
-#profiler_print_interval = 10
+# Profiler data print interval. #0 = disable.
+#profiler_print_interval = 0
+#enable_mapgen_debug_info = false
# Player and object positions are sent at intervals specified by this
-#objectdata_inverval = 0.2
-
+#objectdata_interval = 0.2
#active_object_range = 2
-
-#max_simultaneous_block_sends_per_client = 1
-#max_simultaneous_block_sends_server_total = 4
-
-#max_block_send_distance = 5
-#max_block_generate_distance = 4
-
-# 20 min/day
+#max_simultaneous_block_sends_per_client = 2
+#max_simultaneous_block_sends_server_total = 8
+#max_block_send_distance = 8
+#max_block_generate_distance = 8
+#time_send_interval = 20
+# Length of day/night cycle. 72=20min, 360=4min, 1=24hour
#time_speed = 72
-# 4 min/day
-#time_speed = 360
-# 1 min/day
-#time_speed = 1440
-
-#time_send_interval = 5
-#server_unload_unused_sectors_timeout = 60
+#server_unload_unused_data_timeout = 60
#server_map_save_interval = 60
+#full_block_send_enable_min_time_from_building = 2.0
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f62a8626b..dfe5b5753 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -61,6 +61,7 @@ configure_file(
)
set(common_SRCS
+ content_sao.cpp
mapgen.cpp
content_inventory.cpp
content_nodemeta.cpp
@@ -102,6 +103,7 @@ set(common_SRCS
# Client sources
set(minetest_SRCS
${common_SRCS}
+ content_cao.cpp
mapblock_mesh.cpp
farmesh.cpp
keycode.cpp
diff --git a/src/activeobject.h b/src/activeobject.h
index 382f7f798..09ee23a14 100644
--- a/src/activeobject.h
+++ b/src/activeobject.h
@@ -23,6 +23,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h"
#include <string>
+#define ACTIVEOBJECT_TYPE_INVALID 0
+// Other types are defined in content_object.h
+
struct ActiveObjectMessage
{
ActiveObjectMessage(u16 id_, bool reliable_=true, std::string data_=""):
@@ -36,12 +39,6 @@ struct ActiveObjectMessage
std::string datastring;
};
-#define ACTIVEOBJECT_TYPE_INVALID 0
-#define ACTIVEOBJECT_TYPE_TEST 1
-#define ACTIVEOBJECT_TYPE_ITEM 2
-#define ACTIVEOBJECT_TYPE_RAT 3
-#define ACTIVEOBJECT_TYPE_OERKKI1 4
-
/*
Parent class for ServerActiveObject and ClientActiveObject
*/
diff --git a/src/client.cpp b/src/client.cpp
index e86b3a4f8..4f0baa573 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -25,6 +25,105 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "main.h"
#include <sstream>
#include "porting.h"
+#include "mapsector.h"
+#include "mapblock_mesh.h"
+#include "mapblock.h"
+
+/*
+ QueuedMeshUpdate
+*/
+
+QueuedMeshUpdate::QueuedMeshUpdate():
+ p(-1337,-1337,-1337),
+ data(NULL),
+ ack_block_to_server(false)
+{
+}
+
+QueuedMeshUpdate::~QueuedMeshUpdate()
+{
+ if(data)
+ delete data;
+}
+
+/*
+ MeshUpdateQueue
+*/
+
+MeshUpdateQueue::MeshUpdateQueue()
+{
+ m_mutex.Init();
+}
+
+MeshUpdateQueue::~MeshUpdateQueue()
+{
+ JMutexAutoLock lock(m_mutex);
+
+ core::list<QueuedMeshUpdate*>::Iterator i;
+ for(i=m_queue.begin(); i!=m_queue.end(); i++)
+ {
+ QueuedMeshUpdate *q = *i;
+ delete q;
+ }
+}
+
+/*
+ peer_id=0 adds with nobody to send to
+*/
+void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server)
+{
+ DSTACK(__FUNCTION_NAME);
+
+ assert(data);
+
+ JMutexAutoLock lock(m_mutex);
+
+ /*
+ Find if block is already in queue.
+ If it is, update the data and quit.
+ */
+ core::list<QueuedMeshUpdate*>::Iterator i;
+ for(i=m_queue.begin(); i!=m_queue.end(); i++)
+ {
+ QueuedMeshUpdate *q = *i;
+ if(q->p == p)
+ {
+ if(q->data)
+ delete q->data;
+ q->data = data;
+ if(ack_block_to_server)
+ q->ack_block_to_server = true;
+ return;
+ }
+ }
+
+ /*
+ Add the block
+ */
+ QueuedMeshUpdate *q = new QueuedMeshUpdate;
+ q->p = p;
+ q->data = data;
+ q->ack_block_to_server = ack_block_to_server;
+ m_queue.push_back(q);
+}
+
+// Returned pointer must be deleted
+// Returns NULL if queue is empty
+QueuedMeshUpdate * MeshUpdateQueue::pop()
+{
+ JMutexAutoLock lock(m_mutex);
+
+ core::list<QueuedMeshUpdate*>::Iterator i = m_queue.begin();
+ if(i == m_queue.end())
+ return NULL;
+ QueuedMeshUpdate *q = *i;
+ m_queue.erase(i);
+ return q;
+}
+
+/*
+ MeshUpdateThread
+*/
void * MeshUpdateThread::Thread()
{
@@ -36,6 +135,15 @@ void * MeshUpdateThread::Thread()
while(getRun())
{
+ /*// Wait for output queue to flush.
+ // Allow 2 in queue, this makes less frametime jitter.
+ // Umm actually, there is no much difference
+ if(m_queue_out.size() >= 2)
+ {
+ sleep_ms(3);
+ continue;
+ }*/
+
QueuedMeshUpdate *q = m_queue_in.pop();
if(q == NULL)
{
@@ -91,7 +199,7 @@ Client::Client(
m_access_denied(false)
{
m_packetcounter_timer = 0.0;
- m_delete_unused_sectors_timer = 0.0;
+ //m_delete_unused_sectors_timer = 0.0;
m_connection_reinit_timer = 0.0;
m_avg_rtt_timer = 0.0;
m_playerpos_send_timer = 0.0;
@@ -195,7 +303,11 @@ void Client::step(float dtime)
m_packetcounter.clear();
}
}
+
+ // Get connection status
+ bool connected = connectedAndInitialized();
+#if 0
{
/*
Delete unused sectors
@@ -225,16 +337,16 @@ void Client::step(float dtime)
true, &deleted_blocks);*/
// Delete whole sectors
- u32 num = m_env.getMap().unloadUnusedData
+ m_env.getMap().unloadUnusedData
(delete_unused_sectors_timeout,
- false, &deleted_blocks);
+ &deleted_blocks);
- if(num > 0)
+ if(deleted_blocks.size() > 0)
{
/*dstream<<DTIME<<"Client: Deleted blocks of "<<num
<<" unused sectors"<<std::endl;*/
- dstream<<DTIME<<"Client: Deleted "<<num
- <<" unused sectors"<<std::endl;
+ /*dstream<<DTIME<<"Client: Deleted "<<num
+ <<" unused sectors"<<std::endl;*/
/*
Send info to server
@@ -284,8 +396,7 @@ void Client::step(float dtime)
}
}
}
-
- bool connected = connectedAndInitialized();
+#endif
if(connected == false)
{
@@ -331,6 +442,67 @@ void Client::step(float dtime)
*/
/*
+ Run Map's timers and unload unused data
+ */
+ const float map_timer_and_unload_dtime = 5.25;
+ if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
+ {
+ ScopeProfiler sp(&g_profiler, "Client: map timer and unload");
+ core::list<v3s16> deleted_blocks;
+ m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
+ g_settings.getFloat("client_unload_unused_data_timeout"),
+ &deleted_blocks);
+
+ /*if(deleted_blocks.size() > 0)
+ dstream<<"Client: Unloaded "<<deleted_blocks.size()
+ <<" unused blocks"<<std::endl;*/
+
+ /*
+ Send info to server
+ NOTE: This loop is intentionally iterated the way it is.
+ */
+
+ core::list<v3s16>::Iterator i = deleted_blocks.begin();
+ core::list<v3s16> sendlist;
+ for(;;)
+ {
+ if(sendlist.size() == 255 || i == deleted_blocks.end())
+ {
+ if(sendlist.size() == 0)
+ break;
+ /*
+ [0] u16 command
+ [2] u8 count
+ [3] v3s16 pos_0
+ [3+6] v3s16 pos_1
+ ...
+ */
+ u32 replysize = 2+1+6*sendlist.size();
+ SharedBuffer<u8> reply(replysize);
+ writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
+ reply[2] = sendlist.size();
+ u32 k = 0;
+ for(core::list<v3s16>::Iterator
+ j = sendlist.begin();
+ j != sendlist.end(); j++)
+ {
+ writeV3S16(&reply[2+1+6*k], *j);
+ k++;
+ }
+ m_con.Send(PEER_ID_SERVER, 1, reply, true);
+
+ if(i == deleted_blocks.end())
+ break;
+
+ sendlist.clear();
+ }
+
+ sendlist.push_back(*i);
+ i++;
+ }
+ }
+
+ /*
Handle environment
*/
{
@@ -345,23 +517,23 @@ void Client::step(float dtime)
//TimeTaker envtimer("env step", m_device);
// Step environment
m_env.step(dtime);
-
- // Step active blocks
+
+ /*
+ Handle active blocks
+ NOTE: These old objects are DEPRECATED. TODO: Remove
+ */
for(core::map<v3s16, bool>::Iterator
i = m_active_blocks.getIterator();
i.atEnd() == false; i++)
{
v3s16 p = i.getNode()->getKey();
- MapBlock *block = NULL;
- try
- {
- block = m_env.getMap().getBlockNoCreate(p);
- block->stepObjects(dtime, false, m_env.getDayNightRatio());
- }
- catch(InvalidPositionException &e)
- {
- }
+ MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(p);
+ if(block == NULL)
+ continue;
+
+ // Step MapBlockObjects
+ block->stepObjects(dtime, false, m_env.getDayNightRatio());
}
/*
@@ -695,78 +867,43 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
MapSector *sector;
MapBlock *block;
- { //envlock
- //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
-
- v2s16 p2d(p.X, p.Z);
- sector = m_env.getMap().emergeSector(p2d);
-
- v2s16 sp = sector->getPos();
- if(sp != p2d)
- {
- dstream<<"ERROR: Got sector with getPos()="
- <<"("<<sp.X<<","<<sp.Y<<"), tried to get"
- <<"("<<p2d.X<<","<<p2d.Y<<")"<<std::endl;
- }
-
- assert(sp == p2d);
- //assert(sector->getPos() == p2d);
+ v2s16 p2d(p.X, p.Z);
+ sector = m_env.getMap().emergeSector(p2d);
+
+ assert(sector->getPos() == p2d);
- //TimeTaker timer("MapBlock deSerialize");
- // 0ms
-
- try{
- block = sector->getBlockNoCreate(p.Y);
- /*
- Update an existing block
- */
- //dstream<<"Updating"<<std::endl;
- block->deSerialize(istr, ser_version);
- //block->setChangedFlag();
- }
- catch(InvalidPositionException &e)
- {
- /*
- Create a new block
- */
- //dstream<<"Creating new"<<std::endl;
- block = new MapBlock(&m_env.getMap(), p);
- block->deSerialize(istr, ser_version);
- sector->insertBlock(block);
- //block->setChangedFlag();
-
- //DEBUG
- /*NodeMod mod;
- mod.type = NODEMOD_CHANGECONTENT;
- mod.param = CONTENT_MESE;
- block->setTempMod(v3s16(8,10,8), mod);
- block->setTempMod(v3s16(8,9,8), mod);
- block->setTempMod(v3s16(8,8,8), mod);
- block->setTempMod(v3s16(8,7,8), mod);
- block->setTempMod(v3s16(8,6,8), mod);*/
-#if 0
- /*
- Add some coulds
- Well, this is a dumb way to do it, they should just
- be drawn as separate objects. But the looks of them
- can be tested this way.
- */
- if(p.Y == 3)
- {
- NodeMod mod;
- mod.type = NODEMOD_CHANGECONTENT;
- mod.param = CONTENT_CLOUD;
- v3s16 p2;
- p2.Y = 8;
- for(p2.X=3; p2.X<=13; p2.X++)
- for(p2.Z=3; p2.Z<=13; p2.Z++)
- {
- block->setTempMod(p2, mod);
- }
- }
-#endif
- }
- } //envlock
+ //TimeTaker timer("MapBlock deSerialize");
+ // 0ms
+
+ block = sector->getBlockNoCreateNoEx(p.Y);
+ if(block)
+ {
+ /*
+ Update an existing block
+ */
+ //dstream<<"Updating"<<std::endl;
+ block->deSerialize(istr, ser_version);
+ }
+ else
+ {
+ /*
+ Create a new block
+ */
+ //dstream<<"Creating new"<<std::endl;
+ block = new MapBlock(&m_env.getMap(), p);
+ block->deSerialize(istr, ser_version);
+ sector->insertBlock(block);
+
+ //DEBUG
+ /*NodeMod mod;
+ mod.type = NODEMOD_CHANGECONTENT;
+ mod.param = CONTENT_MESE;
+ block->setTempMod(v3s16(8,10,8), mod);
+ block->setTempMod(v3s16(8,9,8), mod);
+ block->setTempMod(v3s16(8,8,8), mod);
+ block->setTempMod(v3s16(8,7,8), mod);
+ block->setTempMod(v3s16(8,6,8), mod);*/
+ }
#if 0
/*
@@ -798,6 +935,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
/*
Add it to mesh update queue and set it to be acknowledged after update.
*/
+ //std::cerr<<"Adding mesh update task for received block"<<std::endl;
addUpdateMeshTaskWithEdge(p, true);
}
else if(command == TOCLIENT_PLAYERPOS)
@@ -974,6 +1112,8 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
}
else if(command == TOCLIENT_SECTORMETA)
{
+ dstream<<"Client received DEPRECATED TOCLIENT_SECTORMETA"<<std::endl;
+#if 0
/*
[0] u16 command
[2] u8 sector count
@@ -1009,6 +1149,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
((ClientMap&)m_env.getMap()).deSerializeSector(pos, is);
}
} //envlock
+#endif
}
else if(command == TOCLIENT_INVENTORY)
{
@@ -1105,6 +1246,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
/*
Read block objects
+ NOTE: Deprecated stuff here, TODO: Remove
*/
// Read active block count
@@ -1753,7 +1895,7 @@ void Client::addNode(v3s16 p, MapNode n)
try
{
- TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
+ //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
}
catch(InvalidPositionException &e)
@@ -1981,12 +2123,6 @@ void Client::printDebugInfo(std::ostream &os)
<<std::endl;*/
}
-/*s32 Client::getDayNightIndex()
-{
- assert(m_daynight_i >= 0 && m_daynight_i < DAYNIGHT_CACHE_COUNT);
- return m_daynight_i;
-}*/
-
u32 Client::getDayNightRatio()
{
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
@@ -2000,6 +2136,40 @@ u16 Client::getHP()
return player->hp;
}
+void Client::setTempMod(v3s16 p, NodeMod mod)
+{
+ //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
+ assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
+
+ core::map<v3s16, MapBlock*> affected_blocks;
+ ((ClientMap&)m_env.getMap()).setTempMod(p, mod,
+ &affected_blocks);
+
+ for(core::map<v3s16, MapBlock*>::Iterator
+ i = affected_blocks.getIterator();
+ i.atEnd() == false; i++)
+ {
+ i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
+ }
+}
+
+void Client::clearTempMod(v3s16 p)
+{
+ //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
+ assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
+
+ core::map<v3s16, MapBlock*> affected_blocks;
+ ((ClientMap&)m_env.getMap()).clearTempMod(p,
+ &affected_blocks);
+
+ for(core::map<v3s16, MapBlock*>::Iterator
+ i = affected_blocks.getIterator();
+ i.atEnd() == false; i++)
+ {
+ i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
+ }
+}
+
void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
{
/*dstream<<"Client::addUpdateMeshTask(): "
@@ -2009,7 +2179,7 @@ void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
if(b == NULL)
return;
-
+
/*
Create a task to update the mesh of the block
*/
@@ -2018,7 +2188,8 @@ void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
{
//TimeTaker timer("data fill");
- // 0ms
+ // Release: ~0ms
+ // Debug: 1-6ms, avg=2ms
data->fill(getDayNightRatio(), b);
}
@@ -2044,6 +2215,10 @@ void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
}
#endif
+ /*
+ Mark mesh as non-expired at this point so that it can already
+ be marked as expired again if the data changes
+ */
b->setMeshExpired(false);
}
diff --git a/src/client.h b/src/client.h
index a1b1c66b4..0150b687e 100644
--- a/src/client.h
+++ b/src/client.h
@@ -28,6 +28,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "jmutex.h"
#include <ostream>
#include "clientobject.h"
+#include "utility.h" // For IntervalLimiter
+
+struct MeshMakeData;
class ClientNotReadyException : public BaseException
{
@@ -43,18 +46,8 @@ struct QueuedMeshUpdate
MeshMakeData *data;
bool ack_block_to_server;
- QueuedMeshUpdate():
- p(-1337,-1337,-1337),
- data(NULL),
- ack_block_to_server(false)
- {
- }
-
- ~QueuedMeshUpdate()
- {
- if(data)
- delete data;
- }
+ QueuedMeshUpdate();
+ ~QueuedMeshUpdate();
};
/*
@@ -63,76 +56,18 @@ struct QueuedMeshUpdate
class MeshUpdateQueue
{
public:
- MeshUpdateQueue()
- {
- m_mutex.Init();
- }
+ MeshUpdateQueue();
- ~MeshUpdateQueue()
- {
- JMutexAutoLock lock(m_mutex);
-
- core::list<QueuedMeshUpdate*>::Iterator i;
- for(i=m_queue.begin(); i!=m_queue.end(); i++)
- {
- QueuedMeshUpdate *q = *i;
- delete q;
- }
- }
+ ~MeshUpdateQueue();
/*
peer_id=0 adds with nobody to send to
*/
- void addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server)
- {
- DSTACK(__FUNCTION_NAME);
-
- assert(data);
-
- JMutexAutoLock lock(m_mutex);
-
- /*
- Find if block is already in queue.
- If it is, update the data and quit.
- */
- core::list<QueuedMeshUpdate*>::Iterator i;
- for(i=m_queue.begin(); i!=m_queue.end(); i++)
- {
- QueuedMeshUpdate *q = *i;
- if(q->p == p)
- {
- if(q->data)
- delete q->data;
- q->data = data;
- if(ack_block_to_server)
- q->ack_block_to_server = true;
- return;
- }
- }
-
- /*
- Add the block
- */
- QueuedMeshUpdate *q = new QueuedMeshUpdate;
- q->p = p;
- q->data = data;
- q->ack_block_to_server = ack_block_to_server;
- m_queue.push_back(q);
- }
+ void addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server);
// Returned pointer must be deleted
// Returns NULL if queue is empty
- QueuedMeshUpdate * pop()
- {
- JMutexAutoLock lock(m_mutex);
-
- core::list<QueuedMeshUpdate*>::Iterator i = m_queue.begin();
- if(i == m_queue.end())
- return NULL;
- QueuedMeshUpdate *q = *i;
- m_queue.erase(i);
- return q;
- }
+ QueuedMeshUpdate * pop();
u32 size()
{
@@ -309,40 +244,8 @@ public:
u16 getHP();
- //void updateSomeExpiredMeshes();
-
- void setTempMod(v3s16 p, NodeMod mod)
- {
- //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
- assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
-
- core::map<v3s16, MapBlock*> affected_blocks;
- ((ClientMap&)m_env.getMap()).setTempMod(p, mod,
- &affected_blocks);
-
- for(core::map<v3s16, MapBlock*>::Iterator
- i = affected_blocks.getIterator();
- i.atEnd() == false; i++)
- {
- i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
- }
- }
- void clearTempMod(v3s16 p)
- {
- //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
- assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
-
- core::map<v3s16, MapBlock*> affected_blocks;
- ((ClientMap&)m_env.getMap()).clearTempMod(p,
- &affected_blocks);
-
- for(core::map<v3s16, MapBlock*>::Iterator
- i = affected_blocks.getIterator();
- i.atEnd() == false; i++)
- {
- i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
- }
- }
+ void setTempMod(v3s16 p, NodeMod mod);
+ void clearTempMod(v3s16 p);
float getAvgRtt()
{
@@ -389,6 +292,15 @@ public:
{
return m_access_denied_reason;
}
+
+ /*
+ This should only be used for calling the special drawing stuff in
+ ClientEnvironment
+ */
+ ClientEnvironment * getEnv()
+ {
+ return &m_env;
+ }
private:
@@ -404,11 +316,11 @@ private:
void sendPlayerInfo();
float m_packetcounter_timer;
- float m_delete_unused_sectors_timer;
float m_connection_reinit_timer;
float m_avg_rtt_timer;
float m_playerpos_send_timer;
float m_ignore_damage_timer; // Used after server moves player
+ IntervalLimiter m_map_timer_and_unload_interval;
MeshUpdateThread m_mesh_update_thread;
diff --git a/src/clientobject.cpp b/src/clientobject.cpp
index 402535ffc..787efef29 100644
--- a/src/clientobject.cpp
+++ b/src/clientobject.cpp
@@ -21,9 +21,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "debug.h"
#include "porting.h"
#include "constants.h"
-#include "utility.h"
-#include "environment.h"
-#include "tile.h"
/*
ClientActiveObject
@@ -68,674 +65,4 @@ void ClientActiveObject::registerType(u16 type, Factory f)
m_types.insert(type, f);
}
-/*
- TestCAO
-*/
-
-// Prototype
-TestCAO proto_TestCAO;
-
-TestCAO::TestCAO():
- ClientActiveObject(0),
- m_node(NULL),
- m_position(v3f(0,10*BS,0))
-{
- ClientActiveObject::registerType(getType(), create);
-}
-
-TestCAO::~TestCAO()
-{
-}
-
-ClientActiveObject* TestCAO::create()
-{
- return new TestCAO();
-}
-
-void TestCAO::addToScene(scene::ISceneManager *smgr)
-{
- if(m_node != NULL)
- return;
-
- video::IVideoDriver* driver = smgr->getVideoDriver();
-
- scene::SMesh *mesh = new scene::SMesh();
- scene::IMeshBuffer *buf = new scene::SMeshBuffer();
- video::SColor c(255,255,255,255);
- video::S3DVertex vertices[4] =
- {
- video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
- video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
- video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
- video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),
- };
- u16 indices[] = {0,1,2,2,3,0};
- buf->append(vertices, 4, indices, 6);
- // Set material
- buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
- buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
- buf->getMaterial().setTexture
- (0, driver->getTexture(getTexturePath("rat.png").c_str()));
- buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
- buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
- buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
- // Add to mesh
- mesh->addMeshBuffer(buf);
- buf->drop();
- m_node = smgr->addMeshSceneNode(mesh, NULL);
- mesh->drop();
- updateNodePos();
-}
-
-void TestCAO::removeFromScene()
-{
- if(m_node == NULL)
- return;
-
- m_node->remove();
- m_node = NULL;
-}
-
-void TestCAO::updateLight(u8 light_at_pos)
-{
-}
-
-v3s16 TestCAO::getLightPosition()
-{
- return floatToInt(m_position, BS);
-}
-
-void TestCAO::updateNodePos()
-{
- if(m_node == NULL)
- return;
-
- m_node->setPosition(m_position);
- //m_node->setRotation(v3f(0, 45, 0));
-}
-
-void TestCAO::step(float dtime, ClientEnvironment *env)
-{
- if(m_node)
- {
- v3f rot = m_node->getRotation();
- //dstream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
- rot.Y += dtime * 180;
- m_node->setRotation(rot);
- }
-}
-
-void TestCAO::processMessage(const std::string &data)
-{
- dstream<<"TestCAO: Got data: "<<data<<std::endl;
- std::istringstream is(data, std::ios::binary);
- u16 cmd;
- is>>cmd;
- if(cmd == 0)
- {
- v3f newpos;
- is>>newpos.X;
- is>>newpos.Y;
- is>>newpos.Z;
- m_position = newpos;
- updateNodePos();
- }
-}
-
-/*
- ItemCAO
-*/
-
-#include "inventory.h"
-
-// Prototype
-ItemCAO proto_ItemCAO;
-
-ItemCAO::ItemCAO():
- ClientActiveObject(0),
- m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.),
- m_node(NULL),
- m_position(v3f(0,10*BS,0))
-{
- ClientActiveObject::registerType(getType(), create);
-}
-
-ItemCAO::~ItemCAO()
-{
-}
-
-ClientActiveObject* ItemCAO::create()
-{
- return new ItemCAO();
-}
-
-void ItemCAO::addToScene(scene::ISceneManager *smgr)
-{
- if(m_node != NULL)
- return;
-
- video::IVideoDriver* driver = smgr->getVideoDriver();
-
- scene::SMesh *mesh = new scene::SMesh();
- scene::IMeshBuffer *buf = new scene::SMeshBuffer();
- video::SColor c(255,255,255,255);
- video::S3DVertex vertices[4] =
- {
- /*video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
- video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
- video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
- video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),*/
- video::S3DVertex(BS/3.,0,0, 0,0,0, c, 0,1),
- video::S3DVertex(-BS/3.,0,0, 0,0,0, c, 1,1),
- video::S3DVertex(-BS/3.,0+BS*2./3.,0, 0,0,0, c, 1,0),
- video::S3DVertex(BS/3.,0+BS*2./3.,0, 0,0,0, c, 0,0),
- };
- u16 indices[] = {0,1,2,2,3,0};
- buf->append(vertices, 4, indices, 6);
- // Set material
- buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
- buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
- //buf->getMaterial().setTexture(0, NULL);
- // Initialize with the stick texture
- buf->getMaterial().setTexture
- (0, driver->getTexture(getTexturePath("stick.png").c_str()));
- buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
- buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
- buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
- // Add to mesh
- mesh->addMeshBuffer(buf);
- buf->drop();
- m_node = smgr->addMeshSceneNode(mesh, NULL);
- mesh->drop();
- // Set it to use the materials of the meshbuffers directly.
- // This is needed for changing the texture in the future
- m_node->setReadOnlyMaterials(true);
- updateNodePos();
-}
-
-void ItemCAO::removeFromScene()
-{
- if(m_node == NULL)
- return;
-
- m_node->remove();
- m_node = NULL;
-}
-
-void ItemCAO::updateLight(u8 light_at_pos)
-{
- if(m_node == NULL)
- return;
-
- u8 li = decode_light(light_at_pos);
- video::SColor color(255,li,li,li);
-
- scene::IMesh *mesh = m_node->getMesh();
- if(mesh == NULL)
- return;
-
- u16 mc = mesh->getMeshBufferCount();
- for(u16 j=0; j<mc; j++)
- {
- scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
- video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
- u16 vc = buf->getVertexCount();
- for(u16 i=0; i<vc; i++)
- {
- vertices[i].Color = color;
- }
- }
-}
-
-v3s16 ItemCAO::getLightPosition()
-{
- return floatToInt(m_position, BS);
-}
-
-void ItemCAO::updateNodePos()
-{
- if(m_node == NULL)
- return;
-
- m_node->setPosition(m_position);
-}
-
-void ItemCAO::step(float dtime, ClientEnvironment *env)
-{
- if(m_node)
- {
- /*v3f rot = m_node->getRotation();
- rot.Y += dtime * 120;
- m_node->setRotation(rot);*/
- LocalPlayer *player = env->getLocalPlayer();
- assert(player);
- v3f rot = m_node->getRotation();
- rot.Y = 180.0 - (player->getYaw());
- m_node->setRotation(rot);
- }
-}
-
-void ItemCAO::processMessage(const std::string &data)
-{
- dstream<<"ItemCAO: Got message"<<std::endl;
- std::istringstream is(data, std::ios::binary);
- // command
- u8 cmd = readU8(is);
- if(cmd == 0)
- {
- // pos
- m_position = readV3F1000(is);
- updateNodePos();
- }
-}
-
-void ItemCAO::initialize(const std::string &data)
-{
- dstream<<"ItemCAO: Got init data"<<std::endl;
-
- {
- std::istringstream is(data, std::ios::binary);
- // version
- u8 version = readU8(is);
- // check version
- if(version != 0)
- return;
- // pos
- m_position = readV3F1000(is);
- // inventorystring
- m_inventorystring = deSerializeString(is);
- }
-
- 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);
- dstream<<__FUNCTION_NAME<<": m_inventorystring=\""
- <<m_inventorystring<<"\" -> item="<<item
- <<std::endl;
- if(item)
- {
- texture = item->getImage();
- delete item;
- }
- }
- catch(SerializationError &e)
- {
- dstream<<"WARNING: "<<__FUNCTION_NAME
- <<": error deSerializing inventorystring \""
- <<m_inventorystring<<"\""<<std::endl;
- }
-
- // Set meshbuffer texture
- buf->getMaterial().setTexture(0, texture);
-
-}
-
-/*
- RatCAO
-*/
-
-#include "inventory.h"
-
-// Prototype
-RatCAO proto_RatCAO;
-
-RatCAO::RatCAO():
- ClientActiveObject(0),
- m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
- m_node(NULL),
- m_position(v3f(0,10*BS,0)),
- m_yaw(0)
-{
- ClientActiveObject::registerType(getType(), create);
-}
-
-RatCAO::~RatCAO()
-{
-}
-
-ClientActiveObject* RatCAO::create()
-{
- return new RatCAO();
-}
-
-void RatCAO::addToScene(scene::ISceneManager *smgr)
-{
- if(m_node != NULL)
- return;
-
- video::IVideoDriver* driver = smgr->getVideoDriver();
-
- scene::SMesh *mesh = new scene::SMesh();
- scene::IMeshBuffer *buf = new scene::SMeshBuffer();
- video::SColor c(255,255,255,255);
- video::S3DVertex vertices[4] =
- {
- video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
- video::S3DVertex(BS/2,0,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),
- };
- u16 indices[] = {0,1,2,2,3,0};
- buf->append(vertices, 4, indices, 6);
- // Set material
- buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
- buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
- //buf->getMaterial().setTexture(0, NULL);
- buf->getMaterial().setTexture
- (0, driver->getTexture(getTexturePath("rat.png").c_str()));
- buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
- buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
- buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
- // Add to mesh
- mesh->addMeshBuffer(buf);
- buf->drop();
- m_node = smgr->addMeshSceneNode(mesh, NULL);
- mesh->drop();
- // Set it to use the materials of the meshbuffers directly.
- // This is needed for changing the texture in the future
- m_node->setReadOnlyMaterials(true);
- updateNodePos();
-}
-
-void RatCAO::removeFromScene()
-{
- if(m_node == NULL)
- return;
-
- m_node->remove();
- m_node = NULL;
-}
-
-void RatCAO::updateLight(u8 light_at_pos)
-{
- if(m_node == NULL)
- return;
-
- u8 li = decode_light(light_at_pos);
- video::SColor color(255,li,li,li);
-
- scene::IMesh *mesh = m_node->getMesh();
- if(mesh == NULL)
- return;
-
- u16 mc = mesh->getMeshBufferCount();
- for(u16 j=0; j<mc; j++)
- {
- scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
- video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
- u16 vc = buf->getVertexCount();
- for(u16 i=0; i<vc; i++)
- {
- vertices[i].Color = color;
- }
- }
-}
-
-v3s16 RatCAO::getLightPosition()
-{
- return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
-}
-
-void RatCAO::updateNodePos()
-{
- if(m_node == NULL)
- return;
-
- //m_node->setPosition(m_position);
- m_node->setPosition(pos_translator.vect_show);
-
- v3f rot = m_node->getRotation();
- rot.Y = 180.0 - m_yaw;
- m_node->setRotation(rot);
-}
-
-void RatCAO::step(float dtime, ClientEnvironment *env)
-{
- pos_translator.translate(dtime);
- updateNodePos();
-}
-
-void RatCAO::processMessage(const std::string &data)
-{
- //dstream<<"RatCAO: Got message"<<std::endl;
- std::istringstream is(data, std::ios::binary);
- // command
- u8 cmd = readU8(is);
- if(cmd == 0)
- {
- // pos
- m_position = readV3F1000(is);
- pos_translator.update(m_position);
- // yaw
- m_yaw = readF1000(is);
- updateNodePos();
- }
-}
-
-void RatCAO::initialize(const std::string &data)
-{
- //dstream<<"RatCAO: Got init data"<<std::endl;
-
- {
- std::istringstream is(data, std::ios::binary);
- // version
- u8 version = readU8(is);
- // check version
- if(version != 0)
- return;
- // pos
- m_position = readV3F1000(is);
- pos_translator.init(m_position);
- }
-
- updateNodePos();
-}
-
-/*
- Oerkki1CAO
-*/
-
-#include "inventory.h"
-
-// Prototype
-Oerkki1CAO proto_Oerkki1CAO;
-
-Oerkki1CAO::Oerkki1CAO():
- ClientActiveObject(0),
- m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2.,BS/3.),
- m_node(NULL),
- m_position(v3f(0,10*BS,0)),
- m_yaw(0)
-{
- ClientActiveObject::registerType(getType(), create);
-}
-
-Oerkki1CAO::~Oerkki1CAO()
-{
-}
-
-ClientActiveObject* Oerkki1CAO::create()
-{
- return new Oerkki1CAO();
-}
-
-void Oerkki1CAO::addToScene(scene::ISceneManager *smgr)
-{
- if(m_node != NULL)
- return;
-
- video::IVideoDriver* driver = smgr->getVideoDriver();
-
- scene::SMesh *mesh = new scene::SMesh();
- scene::IMeshBuffer *buf = new scene::SMeshBuffer();
- video::SColor c(255,255,255,255);
- video::S3DVertex vertices[4] =
- {
- video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
- video::S3DVertex(BS/2,0,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),
- };
- u16 indices[] = {0,1,2,2,3,0};
- buf->append(vertices, 4, indices, 6);
- // Set material
- buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
- buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
- //buf->getMaterial().setTexture(0, NULL);
- buf->getMaterial().setTexture
- (0, driver->getTexture(getTexturePath("oerkki1.png").c_str()));
- buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
- buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
- buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
- // Add to mesh
- mesh->addMeshBuffer(buf);
- buf->drop();
- m_node = smgr->addMeshSceneNode(mesh, NULL);
- mesh->drop();
- // Set it to use the materials of the meshbuffers directly.
- // This is needed for changing the texture in the future
- m_node->setReadOnlyMaterials(true);
- updateNodePos();
-}
-
-void Oerkki1CAO::removeFromScene()
-{
- if(m_node == NULL)
- return;
-
- m_node->remove();
- m_node = NULL;
-}
-
-void Oerkki1CAO::updateLight(u8 light_at_pos)
-{
- if(m_node == NULL)
- return;
-
- if(light_at_pos <= 2)
- {
- m_node->setVisible(false);
- return;
- }
-
- m_node->setVisible(true);
-
- u8 li = decode_light(light_at_pos);
- video::SColor color(255,li,li,li);
-
- scene::IMesh *mesh = m_node->getMesh();
- if(mesh == NULL)
- return;
-
- u16 mc = mesh->getMeshBufferCount();
- for(u16 j=0; j<mc; j++)
- {
- scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
- video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
- u16 vc = buf->getVertexCount();
- for(u16 i=0; i<vc; i++)
- {
- vertices[i].Color = color;
- }
- }
-}
-
-v3s16 Oerkki1CAO::getLightPosition()
-{
- return floatToInt(m_position+v3f(0,BS*1.5,0), BS);
-}
-
-void Oerkki1CAO::updateNodePos()
-{
- if(m_node == NULL)
- return;
-
- //m_node->setPosition(m_position);
- m_node->setPosition(pos_translator.vect_show);
-
- v3f rot = m_node->getRotation();
- rot.Y = 180.0 - m_yaw + 90.0;
- m_node->setRotation(rot);
-}
-
-void Oerkki1CAO::step(float dtime, ClientEnvironment *env)
-{
- pos_translator.translate(dtime);
- updateNodePos();
-
- LocalPlayer *player = env->getLocalPlayer();
- assert(player);
-
- v3f playerpos = player->getPosition();
- v2f playerpos_2d(playerpos.X,playerpos.Z);
- v2f objectpos_2d(m_position.X,m_position.Z);
-
- if(fabs(m_position.Y - playerpos.Y) < 3.0*BS &&
- objectpos_2d.getDistanceFrom(playerpos_2d) < 1.0*BS)
- {
- if(m_attack_interval.step(dtime, 0.5))
- {
- env->damageLocalPlayer(2);
- }
- }
-}
-
-void Oerkki1CAO::processMessage(const std::string &data)
-{
- //dstream<<"Oerkki1CAO: Got message"<<std::endl;
- std::istringstream is(data, std::ios::binary);
- // command
- u8 cmd = readU8(is);
- if(cmd == 0)
- {
- // pos
- m_position = readV3F1000(is);
- pos_translator.update(m_position);
- // yaw
- m_yaw = readF1000(is);
- updateNodePos();
- }
-}
-
-void Oerkki1CAO::initialize(const std::string &data)
-{
- //dstream<<"Oerkki1CAO: Got init data"<<std::endl;
-
- {
- std::istringstream is(data, std::ios::binary);
- // version
- u8 version = readU8(is);
- // check version
- if(version != 0)
- return;
- // pos
- m_position = readV3F1000(is);
- pos_translator.init(m_position);
- }
-
- updateNodePos();
-}
-
diff --git a/src/clientobject.h b/src/clientobject.h
index 8d211fef3..c90648483 100644
--- a/src/clientobject.h
+++ b/src/clientobject.h
@@ -22,7 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h"
#include "activeobject.h"
-#include "utility.h"
/*
@@ -36,63 +35,6 @@ Some planning
*/
-/*
- SmoothTranslator
-*/
-
-struct SmoothTranslator
-{
- v3f vect_old;
- f32 anim_counter;
- f32 anim_time;
- f32 anim_time_counter;
- v3f vect_show;
- v3f vect_aim;
-
- SmoothTranslator():
- vect_old(0,0,0),
- anim_counter(0),
- anim_time(0),
- anim_time_counter(0),
- vect_show(0,0,0),
- vect_aim(0,0,0)
- {}
-
- void init(v3f vect)
- {
- vect_old = vect;
- vect_show = vect;
- vect_aim = vect;
- }
-
- void update(v3f vect_new)
- {
- vect_old = vect_show;
- vect_aim = vect_new;
- if(anim_time < 0.001 || anim_time > 1.0)
- anim_time = anim_time_counter;
- else
- anim_time = anim_time * 0.9 + anim_time_counter * 0.1;
- anim_time_counter = 0;
- anim_counter = 0;
- }
-
- void translate(f32 dtime)
- {
- anim_time_counter = anim_time_counter + dtime;
- anim_counter = anim_counter + dtime;
- v3f vect_move = vect_aim - vect_old;
- f32 moveratio = 1.0;
- if(anim_time > 0.001)
- moveratio = anim_time_counter / anim_time;
- // Move a bit less than should, to avoid oscillation
- moveratio = moveratio * 0.8;
- if(moveratio > 1.5)
- moveratio = 1.5;
- vect_show = vect_old + vect_move * moveratio;
- }
-};
-
class ClientEnvironment;
class ClientActiveObject : public ActiveObject
@@ -153,164 +95,5 @@ struct DistanceSortedActiveObject
}
};
-/*
- TestCAO
-*/
-
-class TestCAO : public ClientActiveObject
-{
-public:
- TestCAO();
- virtual ~TestCAO();
-
- u8 getType() const
- {
- return ACTIVEOBJECT_TYPE_TEST;
- }
-
- static ClientActiveObject* create();
-
- void addToScene(scene::ISceneManager *smgr);
- void removeFromScene();
- void updateLight(u8 light_at_pos);
- v3s16 getLightPosition();
- void updateNodePos();
-
- void step(float dtime, ClientEnvironment *env);
-
- void processMessage(const std::string &data);
-
-private:
- scene::IMeshSceneNode *m_node;
- v3f m_position;
-};
-
-/*
- ItemCAO
-*/
-
-class ItemCAO : public ClientActiveObject
-{
-public:
- ItemCAO();
- virtual ~ItemCAO();
-
- u8 getType() const
- {
- return ACTIVEOBJECT_TYPE_ITEM;
- }
-
- static ClientActiveObject* create();
-
- void addToScene(scene::ISceneManager *smgr);
- void removeFromScene();
- void updateLight(u8 light_at_pos);
- v3s16 getLightPosition();
- void updateNodePos();
-
- void step(float dtime, ClientEnvironment *env);
-
- void processMessage(const std::string &data);
-
- void initialize(const std::string &data);
-
- core::aabbox3d<f32>* getSelectionBox()
- {return &m_selection_box;}
- v3f getPosition()
- {return m_position;}
-
-private:
- core::aabbox3d<f32> m_selection_box;
- scene::IMeshSceneNode *m_node;
- v3f m_position;
- std::string m_inventorystring;
-};
-
-/*
- RatCAO
-*/
-
-class RatCAO : public ClientActiveObject
-{
-public:
- RatCAO();
- virtual ~RatCAO();
-
- u8 getType() const
- {
- return ACTIVEOBJECT_TYPE_RAT;
- }
-
- static ClientActiveObject* create();
-
- void addToScene(scene::ISceneManager *smgr);
- void removeFromScene();
- void updateLight(u8 light_at_pos);
- v3s16 getLightPosition();
- void updateNodePos();
-
- void step(float dtime, ClientEnvironment *env);
-
- void processMessage(const std::string &data);
-
- void initialize(const std::string &data);
-
- core::aabbox3d<f32>* getSelectionBox()
- {return &m_selection_box;}
- v3f getPosition()
- {return m_position;}
-
-private:
- core::aabbox3d<f32> m_selection_box;
- scene::IMeshSceneNode *m_node;
- v3f m_position;
- float m_yaw;
- SmoothTranslator pos_translator;
-};
-
-/*
- Oerkki1CAO
-*/
-
-class Oerkki1CAO : public ClientActiveObject
-{
-public:
- Oerkki1CAO();
- virtual ~Oerkki1CAO();
-
- u8 getType() const
- {
- return ACTIVEOBJECT_TYPE_OERKKI1;
- }
-
- static ClientActiveObject* create();
-
- void addToScene(scene::ISceneManager *smgr);
- void removeFromScene();
- void updateLight(u8 light_at_pos);
- v3s16 getLightPosition();
- void updateNodePos();
-
- void step(float dtime, ClientEnvironment *env);
-
- void processMessage(const std::string &data);
-
- void initialize(const std::string &data);
-
- core::aabbox3d<f32>* getSelectionBox()
- {return &m_selection_box;}
- v3f getPosition()
- {return pos_translator.vect_show;}
- //{return m_position;}
-
-private:
- IntervalLimiter m_attack_interval;
- core::aabbox3d<f32> m_selection_box;
- scene::IMeshSceneNode *m_node;
- v3f m_position;
- float m_yaw;
- SmoothTranslator pos_translator;
-};
-
#endif
diff --git a/src/clientserver.h b/src/clientserver.h
index 7972762c0..35484fe76 100644
--- a/src/clientserver.h
+++ b/src/clientserver.h
@@ -37,7 +37,7 @@ enum ToClientCommand
[0] u16 TOSERVER_INIT
[2] u8 deployed version
[3] v3s16 player's position + v3f(0,BS/2,0) floatToInt'd
- ([4] u64 map seed (new as of 2011-02-27))
+ [12] u64 map seed (new as of 2011-02-27)
NOTE: The position in here is deprecated; position is
explicitly sent afterwards
diff --git a/src/collision.cpp b/src/collision.cpp
index 63186a84a..01d546284 100644
--- a/src/collision.cpp
+++ b/src/collision.cpp
@@ -182,4 +182,58 @@ collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
return result;
}
+collisionMoveResult collisionMovePrecise(Map *map, f32 pos_max_d,
+ const core::aabbox3d<f32> &box_0,
+ f32 dtime, v3f &pos_f, v3f &speed_f)
+{
+ collisionMoveResult final_result;
+
+ // Maximum time increment (for collision detection etc)
+ // time = distance / speed
+ f32 dtime_max_increment = pos_max_d / speed_f.getLength();
+
+ // Maximum time increment is 10ms or lower
+ if(dtime_max_increment > 0.01)
+ dtime_max_increment = 0.01;
+
+ // Don't allow overly huge dtime
+ if(dtime > 2.0)
+ dtime = 2.0;
+
+ f32 dtime_downcount = dtime;
+
+ u32 loopcount = 0;
+ do
+ {
+ loopcount++;
+
+ f32 dtime_part;
+ if(dtime_downcount > dtime_max_increment)
+ {
+ dtime_part = dtime_max_increment;
+ dtime_downcount -= dtime_part;
+ }
+ else
+ {
+ dtime_part = dtime_downcount;
+ /*
+ Setting this to 0 (no -=dtime_part) disables an infinite loop
+ when dtime_part is so small that dtime_downcount -= dtime_part
+ does nothing
+ */
+ dtime_downcount = 0;
+ }
+
+ collisionMoveResult result = collisionMoveSimple(map, pos_max_d,
+ box_0, dtime_part, pos_f, speed_f);
+
+ if(result.touching_ground)
+ final_result.touching_ground = true;
+ }
+ while(dtime_downcount > 0.001);
+
+
+ return final_result;
+}
+
diff --git a/src/collision.h b/src/collision.h
index 9c913c6a9..6d167bb7b 100644
--- a/src/collision.h
+++ b/src/collision.h
@@ -33,10 +33,15 @@ struct collisionMoveResult
{}
};
+// Moves using a single iteration; speed should not exceed pos_max_d/dtime
collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
const core::aabbox3d<f32> &box_0,
f32 dtime, v3f &pos_f, v3f &speed_f);
-//{return collisionMoveResult();}
+
+// Moves using as many iterations as needed
+collisionMoveResult collisionMovePrecise(Map *map, f32 pos_max_d,
+ const core::aabbox3d<f32> &box_0,
+ f32 dtime, v3f &pos_f, v3f &speed_f);
enum CollisionType
{
diff --git a/src/content_cao.cpp b/src/content_cao.cpp
new file mode 100644
index 000000000..ab20f1a95
--- /dev/null
+++ b/src/content_cao.cpp
@@ -0,0 +1,753 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "content_cao.h"
+#include "tile.h"
+#include "environment.h"
+
+/*
+ TestCAO
+*/
+
+// Prototype
+TestCAO proto_TestCAO;
+
+TestCAO::TestCAO():
+ ClientActiveObject(0),
+ m_node(NULL),
+ m_position(v3f(0,10*BS,0))
+{
+ ClientActiveObject::registerType(getType(), create);
+}
+
+TestCAO::~TestCAO()
+{
+}
+
+ClientActiveObject* TestCAO::create()
+{
+ return new TestCAO();
+}
+
+void TestCAO::addToScene(scene::ISceneManager *smgr)
+{
+ if(m_node != NULL)
+ return;
+
+ video::IVideoDriver* driver = smgr->getVideoDriver();
+
+ scene::SMesh *mesh = new scene::SMesh();
+ scene::IMeshBuffer *buf = new scene::SMeshBuffer();
+ video::SColor c(255,255,255,255);
+ video::S3DVertex vertices[4] =
+ {
+ video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
+ video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
+ video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
+ video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),
+ };
+ u16 indices[] = {0,1,2,2,3,0};
+ buf->append(vertices, 4, indices, 6);
+ // Set material
+ buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
+ buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
+ buf->getMaterial().setTexture
+ (0, driver->getTexture(getTexturePath("rat.png").c_str()));
+ buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
+ buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
+ buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+ // Add to mesh
+ mesh->addMeshBuffer(buf);
+ buf->drop();
+ m_node = smgr->addMeshSceneNode(mesh, NULL);
+ mesh->drop();
+ updateNodePos();
+}
+
+void TestCAO::removeFromScene()
+{
+ if(m_node == NULL)
+ return;
+
+ m_node->remove();
+ m_node = NULL;
+}
+
+void TestCAO::updateLight(u8 light_at_pos)
+{
+}
+
+v3s16 TestCAO::getLightPosition()
+{
+ return floatToInt(m_position, BS);
+}
+
+void TestCAO::updateNodePos()
+{
+ if(m_node == NULL)
+ return;
+
+ m_node->setPosition(m_position);
+ //m_node->setRotation(v3f(0, 45, 0));
+}
+
+void TestCAO::step(float dtime, ClientEnvironment *env)
+{
+ if(m_node)
+ {
+ v3f rot = m_node->getRotation();
+ //dstream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
+ rot.Y += dtime * 180;
+ m_node->setRotation(rot);
+ }
+}
+
+void TestCAO::processMessage(const std::string &data)
+{
+ dstream<<"TestCAO: Got data: "<<data<<std::endl;
+ std::istringstream is(data, std::ios::binary);
+ u16 cmd;
+ is>>cmd;
+ if(cmd == 0)
+ {
+ v3f newpos;
+ is>>newpos.X;
+ is>>newpos.Y;
+ is>>newpos.Z;
+ m_position = newpos;
+ updateNodePos();
+ }
+}
+
+/*
+ ItemCAO
+*/
+
+#include "inventory.h"
+
+// Prototype
+ItemCAO proto_ItemCAO;
+
+ItemCAO::ItemCAO():
+ ClientActiveObject(0),
+ m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.),
+ m_node(NULL),
+ m_position(v3f(0,10*BS,0))
+{
+ ClientActiveObject::registerType(getType(), create);
+}
+
+ItemCAO::~ItemCAO()
+{
+}
+
+ClientActiveObject* ItemCAO::create()
+{
+ return new ItemCAO();
+}
+
+void ItemCAO::addToScene(scene::ISceneManager *smgr)
+{
+ if(m_node != NULL)
+ return;
+
+ video::IVideoDriver* driver = smgr->getVideoDriver();
+
+ scene::SMesh *mesh = new scene::SMesh();
+ scene::IMeshBuffer *buf = new scene::SMeshBuffer();
+ video::SColor c(255,255,255,255);
+ video::S3DVertex vertices[4] =
+ {
+ /*video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
+ video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
+ video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
+ video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),*/
+ video::S3DVertex(BS/3.,0,0, 0,0,0, c, 0,1),
+ video::S3DVertex(-BS/3.,0,0, 0,0,0, c, 1,1),
+ video::S3DVertex(-BS/3.,0+BS*2./3.,0, 0,0,0, c, 1,0),
+ video::S3DVertex(BS/3.,0+BS*2./3.,0, 0,0,0, c, 0,0),
+ };
+ u16 indices[] = {0,1,2,2,3,0};
+ buf->append(vertices, 4, indices, 6);
+ // Set material
+ buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
+ buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
+ //buf->getMaterial().setTexture(0, NULL);
+ // Initialize with the stick texture
+ buf->getMaterial().setTexture
+ (0, driver->getTexture(getTexturePath("stick.png").c_str()));
+ buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
+ buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
+ buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+ // Add to mesh
+ mesh->addMeshBuffer(buf);
+ buf->drop();
+ m_node = smgr->addMeshSceneNode(mesh, NULL);
+ mesh->drop();
+ // Set it to use the materials of the meshbuffers directly.
+ // This is needed for changing the texture in the future
+ m_node->setReadOnlyMaterials(true);
+ updateNodePos();
+}
+
+void ItemCAO::removeFromScene()
+{
+ if(m_node == NULL)
+ return;
+
+ m_node->remove();
+ m_node = NULL;
+}
+
+void ItemCAO::updateLight(u8 light_at_pos)
+{
+ if(m_node == NULL)
+ return;
+
+ u8 li = decode_light(light_at_pos);
+ video::SColor color(255,li,li,li);
+
+ scene::IMesh *mesh = m_node->getMesh();
+ if(mesh == NULL)
+ return;
+
+ u16 mc = mesh->getMeshBufferCount();
+ for(u16 j=0; j<mc; j++)
+ {
+ scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+ video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
+ u16 vc = buf->getVertexCount();
+ for(u16 i=0; i<vc; i++)
+ {
+ vertices[i].Color = color;
+ }
+ }
+}
+
+v3s16 ItemCAO::getLightPosition()
+{
+ return floatToInt(m_position, BS);
+}
+
+void ItemCAO::updateNodePos()
+{
+ if(m_node == NULL)
+ return;
+
+ m_node->setPosition(m_position);
+}
+
+void ItemCAO::step(float dtime, ClientEnvironment *env)
+{
+ if(m_node)
+ {
+ /*v3f rot = m_node->getRotation();
+ rot.Y += dtime * 120;
+ m_node->setRotation(rot);*/
+ LocalPlayer *player = env->getLocalPlayer();
+ assert(player);
+ v3f rot = m_node->getRotation();
+ rot.Y = 180.0 - (player->getYaw());
+ m_node->setRotation(rot);
+ }
+}
+
+void ItemCAO::processMessage(const std::string &data)
+{
+ dstream<<"ItemCAO: Got message"<<std::endl;
+ std::istringstream is(data, std::ios::binary);
+ // command
+ u8 cmd = readU8(is);
+ if(cmd == 0)
+ {
+ // pos
+ m_position = readV3F1000(is);
+ updateNodePos();
+ }
+}
+
+void ItemCAO::initialize(const std::string &data)
+{
+ dstream<<"ItemCAO: Got init data"<<std::endl;
+
+ {
+ std::istringstream is(data, std::ios::binary);
+ // version
+ u8 version = readU8(is);
+ // check version
+ if(version != 0)
+ return;
+ // pos
+ m_position = readV3F1000(is);
+ // inventorystring
+ m_inventorystring = deSerializeString(is);
+ }
+
+ 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);
+ dstream<<__FUNCTION_NAME<<": m_inventorystring=\""
+ <<m_inventorystring<<"\" -> item="<<item
+ <<std::endl;
+ if(item)
+ {
+ texture = item->getImage();
+ delete item;
+ }
+ }
+ catch(SerializationError &e)
+ {
+ dstream<<"WARNING: "<<__FUNCTION_NAME
+ <<": error deSerializing inventorystring \""
+ <<m_inventorystring<<"\""<<std::endl;
+ }
+
+ // Set meshbuffer texture
+ buf->getMaterial().setTexture(0, texture);
+
+}
+
+/*
+ RatCAO
+*/
+
+#include "inventory.h"
+
+// Prototype
+RatCAO proto_RatCAO;
+
+RatCAO::RatCAO():
+ ClientActiveObject(0),
+ m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
+ m_node(NULL),
+ m_position(v3f(0,10*BS,0)),
+ m_yaw(0)
+{
+ ClientActiveObject::registerType(getType(), create);
+}
+
+RatCAO::~RatCAO()
+{
+}
+
+ClientActiveObject* RatCAO::create()
+{
+ return new RatCAO();
+}
+
+void RatCAO::addToScene(scene::ISceneManager *smgr)
+{
+ if(m_node != NULL)
+ return;
+
+ video::IVideoDriver* driver = smgr->getVideoDriver();
+
+ scene::SMesh *mesh = new scene::SMesh();
+ scene::IMeshBuffer *buf = new scene::SMeshBuffer();
+ video::SColor c(255,255,255,255);
+ video::S3DVertex vertices[4] =
+ {
+ video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
+ video::S3DVertex(BS/2,0,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),
+ };
+ u16 indices[] = {0,1,2,2,3,0};
+ buf->append(vertices, 4, indices, 6);
+ // Set material
+ buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
+ buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
+ //buf->getMaterial().setTexture(0, NULL);
+ buf->getMaterial().setTexture
+ (0, driver->getTexture(getTexturePath("rat.png").c_str()));
+ buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
+ buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
+ buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+ // Add to mesh
+ mesh->addMeshBuffer(buf);
+ buf->drop();
+ m_node = smgr->addMeshSceneNode(mesh, NULL);
+ mesh->drop();
+ // Set it to use the materials of the meshbuffers directly.
+ // This is needed for changing the texture in the future
+ m_node->setReadOnlyMaterials(true);
+ updateNodePos();
+}
+
+void RatCAO::removeFromScene()
+{
+ if(m_node == NULL)
+ return;
+
+ m_node->remove();
+ m_node = NULL;
+}
+
+void RatCAO::updateLight(u8 light_at_pos)
+{
+ if(m_node == NULL)
+ return;
+
+ u8 li = decode_light(light_at_pos);
+ video::SColor color(255,li,li,li);
+
+ scene::IMesh *mesh = m_node->getMesh();
+ if(mesh == NULL)
+ return;
+
+ u16 mc = mesh->getMeshBufferCount();
+ for(u16 j=0; j<mc; j++)
+ {
+ scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+ video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
+ u16 vc = buf->getVertexCount();
+ for(u16 i=0; i<vc; i++)
+ {
+ vertices[i].Color = color;
+ }
+ }
+}
+
+v3s16 RatCAO::getLightPosition()
+{
+ return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
+}
+
+void RatCAO::updateNodePos()
+{
+ if(m_node == NULL)
+ return;
+
+ //m_node->setPosition(m_position);
+ m_node->setPosition(pos_translator.vect_show);
+
+ v3f rot = m_node->getRotation();
+ rot.Y = 180.0 - m_yaw;
+ m_node->setRotation(rot);
+}
+
+void RatCAO::step(float dtime, ClientEnvironment *env)
+{
+ pos_translator.translate(dtime);
+ updateNodePos();
+}
+
+void RatCAO::processMessage(const std::string &data)
+{
+ //dstream<<"RatCAO: Got message"<<std::endl;
+ std::istringstream is(data, std::ios::binary);
+ // command
+ u8 cmd = readU8(is);
+ if(cmd == 0)
+ {
+ // pos
+ m_position = readV3F1000(is);
+ pos_translator.update(m_position);
+ // yaw
+ m_yaw = readF1000(is);
+ updateNodePos();
+ }
+}
+
+void RatCAO::initialize(const std::string &data)
+{
+ //dstream<<"RatCAO: Got init data"<<std::endl;
+
+ {
+ std::istringstream is(data, std::ios::binary);
+ // version
+ u8 version = readU8(is);
+ // check version
+ if(version != 0)
+ return;
+ // pos
+ m_position = readV3F1000(is);
+ pos_translator.init(m_position);
+ }
+
+ updateNodePos();
+}
+
+/*
+ Oerkki1CAO
+*/
+
+#include "inventory.h"
+
+// Prototype
+Oerkki1CAO proto_Oerkki1CAO;
+
+Oerkki1CAO::Oerkki1CAO():
+ ClientActiveObject(0),
+ m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2.,BS/3.),
+ m_node(NULL),
+ m_position(v3f(0,10*BS,0)),
+ m_yaw(0),
+ m_damage_visual_timer(0),
+ m_damage_texture_enabled(false)
+{
+ ClientActiveObject::registerType(getType(), create);
+}
+
+Oerkki1CAO::~Oerkki1CAO()
+{
+}
+
+ClientActiveObject* Oerkki1CAO::create()
+{
+ return new Oerkki1CAO();
+}
+
+void Oerkki1CAO::addToScene(scene::ISceneManager *smgr)
+{
+ if(m_node != NULL)
+ return;
+
+ video::IVideoDriver* driver = smgr->getVideoDriver();
+
+ scene::SMesh *mesh = new scene::SMesh();
+ scene::IMeshBuffer *buf = new scene::SMeshBuffer();
+ video::SColor c(255,255,255,255);
+ video::S3DVertex vertices[4] =
+ {
+ video::S3DVertex(-BS/2-BS,0,0, 0,0,0, c, 0,1),
+ video::S3DVertex(BS/2+BS,0,0, 0,0,0, c, 1,1),
+ video::S3DVertex(BS/2+BS,BS*2,0, 0,0,0, c, 1,0),
+ video::S3DVertex(-BS/2-BS,BS*2,0, 0,0,0, c, 0,0),
+ };
+ u16 indices[] = {0,1,2,2,3,0};
+ buf->append(vertices, 4, indices, 6);
+ // Set material
+ buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
+ buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
+ //buf->getMaterial().setTexture(0, NULL);
+ buf->getMaterial().setTexture
+ (0, driver->getTexture(getTexturePath("oerkki1.png").c_str()));
+ buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
+ buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
+ buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+ // Add to mesh
+ mesh->addMeshBuffer(buf);
+ buf->drop();
+ m_node = smgr->addMeshSceneNode(mesh, NULL);
+ mesh->drop();
+ // Set it to use the materials of the meshbuffers directly.
+ // This is needed for changing the texture in the future
+ m_node->setReadOnlyMaterials(true);
+ updateNodePos();
+}
+
+void Oerkki1CAO::removeFromScene()
+{
+ if(m_node == NULL)
+ return;
+
+ m_node->remove();
+ m_node = NULL;
+}
+
+void Oerkki1CAO::updateLight(u8 light_at_pos)
+{
+ if(m_node == NULL)
+ return;
+
+ if(light_at_pos <= 2)
+ {
+ m_node->setVisible(false);
+ return;
+ }
+
+ m_node->setVisible(true);
+
+ u8 li = decode_light(light_at_pos);
+ video::SColor color(255,li,li,li);
+
+ scene::IMesh *mesh = m_node->getMesh();
+ if(mesh == NULL)
+ return;
+
+ u16 mc = mesh->getMeshBufferCount();
+ for(u16 j=0; j<mc; j++)
+ {
+ scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+ video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
+ u16 vc = buf->getVertexCount();
+ for(u16 i=0; i<vc; i++)
+ {
+ vertices[i].Color = color;
+ }
+ }
+}
+
+v3s16 Oerkki1CAO::getLightPosition()
+{
+ return floatToInt(m_position+v3f(0,BS*1.5,0), BS);
+}
+
+void Oerkki1CAO::updateNodePos()
+{
+ if(m_node == NULL)
+ return;
+
+ //m_node->setPosition(m_position);
+ m_node->setPosition(pos_translator.vect_show);
+
+ v3f rot = m_node->getRotation();
+ rot.Y = 180.0 - m_yaw + 90.0;
+ m_node->setRotation(rot);
+}
+
+void Oerkki1CAO::step(float dtime, ClientEnvironment *env)
+{
+ pos_translator.translate(dtime);
+ updateNodePos();
+
+ LocalPlayer *player = env->getLocalPlayer();
+ assert(player);
+
+ v3f playerpos = player->getPosition();
+ v2f playerpos_2d(playerpos.X,playerpos.Z);
+ v2f objectpos_2d(m_position.X,m_position.Z);
+
+ if(fabs(m_position.Y - playerpos.Y) < 3.0*BS &&
+ objectpos_2d.getDistanceFrom(playerpos_2d) < 1.5*BS)
+ {
+ if(m_attack_interval.step(dtime, 0.5))
+ {
+ env->damageLocalPlayer(2);
+ }
+ }
+
+ if(m_damage_visual_timer > 0)
+ {
+ if(!m_damage_texture_enabled)
+ {
+ // Enable damage texture
+ if(m_node)
+ {
+ video::IVideoDriver* driver =
+ m_node->getSceneManager()->getVideoDriver();
+
+ scene::IMesh *mesh = m_node->getMesh();
+ if(mesh == NULL)
+ return;
+
+ u16 mc = mesh->getMeshBufferCount();
+ for(u16 j=0; j<mc; j++)
+ {
+ scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+ buf->getMaterial().setTexture(0, driver->getTexture(
+ getTexturePath("oerkki1_damaged.png").c_str()));
+ }
+ }
+ m_damage_texture_enabled = true;
+ }
+ m_damage_visual_timer -= dtime;
+ }
+ else
+ {
+ if(m_damage_texture_enabled)
+ {
+ // Disable damage texture
+ if(m_node)
+ {
+ video::IVideoDriver* driver =
+ m_node->getSceneManager()->getVideoDriver();
+
+ scene::IMesh *mesh = m_node->getMesh();
+ if(mesh == NULL)
+ return;
+
+ u16 mc = mesh->getMeshBufferCount();
+ for(u16 j=0; j<mc; j++)
+ {
+ scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+ buf->getMaterial().setTexture(0, driver->getTexture(
+ getTexturePath("oerkki1.png").c_str()));
+ }
+ }
+ m_damage_texture_enabled = false;
+ }
+ }
+}
+
+void Oerkki1CAO::processMessage(const std::string &data)
+{
+ //dstream<<"Oerkki1CAO: Got message"<<std::endl;
+ std::istringstream is(data, std::ios::binary);
+ // command
+ u8 cmd = readU8(is);
+ if(cmd == 0)
+ {
+ // pos
+ m_position = readV3F1000(is);
+ pos_translator.update(m_position);
+ // yaw
+ m_yaw = readF1000(is);
+ updateNodePos();
+ }
+ else if(cmd == 1)
+ {
+ u16 damage = readU8(is);
+ m_damage_visual_timer = 1.0;
+ }
+}
+
+void Oerkki1CAO::initialize(const std::string &data)
+{
+ //dstream<<"Oerkki1CAO: Got init data"<<std::endl;
+
+ {
+ std::istringstream is(data, std::ios::binary);
+ // version
+ u8 version = readU8(is);
+ // check version
+ if(version != 0)
+ return;
+ // pos
+ m_position = readV3F1000(is);
+ pos_translator.init(m_position);
+ }
+
+ updateNodePos();
+}
+
+
diff --git a/src/content_cao.h b/src/content_cao.h
new file mode 100644
index 000000000..146e23b0c
--- /dev/null
+++ b/src/content_cao.h
@@ -0,0 +1,248 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef CONTENT_CAO_HEADER
+#define CONTENT_CAO_HEADER
+
+#include "clientobject.h"
+#include "content_object.h"
+#include "utility.h" // For IntervalLimiter
+
+/*
+ SmoothTranslator
+*/
+
+struct SmoothTranslator
+{
+ v3f vect_old;
+ f32 anim_counter;
+ f32 anim_time;
+ f32 anim_time_counter;
+ v3f vect_show;
+ v3f vect_aim;
+
+ SmoothTranslator():
+ vect_old(0,0,0),
+ anim_counter(0),
+ anim_time(0),
+ anim_time_counter(0),
+ vect_show(0,0,0),
+ vect_aim(0,0,0)
+ {}
+
+ void init(v3f vect)
+ {
+ vect_old = vect;
+ vect_show = vect;
+ vect_aim = vect;
+ }
+
+ void update(v3f vect_new)
+ {
+ vect_old = vect_show;
+ vect_aim = vect_new;
+ if(anim_time < 0.001 || anim_time > 1.0)
+ anim_time = anim_time_counter;
+ else
+ anim_time = anim_time * 0.9 + anim_time_counter * 0.1;
+ anim_time_counter = 0;
+ anim_counter = 0;
+ }
+
+ void translate(f32 dtime)
+ {
+ anim_time_counter = anim_time_counter + dtime;
+ anim_counter = anim_counter + dtime;
+ v3f vect_move = vect_aim - vect_old;
+ f32 moveratio = 1.0;
+ if(anim_time > 0.001)
+ moveratio = anim_time_counter / anim_time;
+ // Move a bit less than should, to avoid oscillation
+ moveratio = moveratio * 0.8;
+ if(moveratio > 1.5)
+ moveratio = 1.5;
+ vect_show = vect_old + vect_move * moveratio;
+ }
+};
+
+
+/*
+ TestCAO
+*/
+
+class TestCAO : public ClientActiveObject
+{
+public:
+ TestCAO();
+ virtual ~TestCAO();
+
+ u8 getType() const
+ {
+ return ACTIVEOBJECT_TYPE_TEST;
+ }
+
+ static ClientActiveObject* create();
+
+ void addToScene(scene::ISceneManager *smgr);
+ void removeFromScene();
+ void updateLight(u8 light_at_pos);
+ v3s16 getLightPosition();
+ void updateNodePos();
+
+ void step(float dtime, ClientEnvironment *env);
+
+ void processMessage(const std::string &data);
+
+private:
+ scene::IMeshSceneNode *m_node;
+ v3f m_position;
+};
+
+/*
+ ItemCAO
+*/
+
+class ItemCAO : public ClientActiveObject
+{
+public:
+ ItemCAO();
+ virtual ~ItemCAO();
+
+ u8 getType() const
+ {
+ return ACTIVEOBJECT_TYPE_ITEM;
+ }
+
+ static ClientActiveObject* create();
+
+ void addToScene(scene::ISceneManager *smgr);
+ void removeFromScene();
+ void updateLight(u8 light_at_pos);
+ v3s16 getLightPosition();
+ void updateNodePos();
+
+ void step(float dtime, ClientEnvironment *env);
+
+ void processMessage(const std::string &data);
+
+ void initialize(const std::string &data);
+
+ core::aabbox3d<f32>* getSelectionBox()
+ {return &m_selection_box;}
+ v3f getPosition()
+ {return m_position;}
+
+private:
+ core::aabbox3d<f32> m_selection_box;
+ scene::IMeshSceneNode *m_node;
+ v3f m_position;
+ std::string m_inventorystring;
+};
+
+/*
+ RatCAO
+*/
+
+class RatCAO : public ClientActiveObject
+{
+public:
+ RatCAO();
+ virtual ~RatCAO();
+
+ u8 getType() const
+ {
+ return ACTIVEOBJECT_TYPE_RAT;
+ }
+
+ static ClientActiveObject* create();
+
+ void addToScene(scene::ISceneManager *smgr);
+ void removeFromScene();
+ void updateLight(u8 light_at_pos);
+ v3s16 getLightPosition();
+ void updateNodePos();
+
+ void step(float dtime, ClientEnvironment *env);
+
+ void processMessage(const std::string &data);
+
+ void initialize(const std::string &data);
+
+ core::aabbox3d<f32>* getSelectionBox()
+ {return &m_selection_box;}
+ v3f getPosition()
+ {return m_position;}
+
+private:
+ core::aabbox3d<f32> m_selection_box;
+ scene::IMeshSceneNode *m_node;
+ v3f m_position;
+ float m_yaw;
+ SmoothTranslator pos_translator;
+};
+
+/*
+ Oerkki1CAO
+*/
+
+class Oerkki1CAO : public ClientActiveObject
+{
+public:
+ Oerkki1CAO();
+ virtual ~Oerkki1CAO();
+
+ u8 getType() const
+ {
+ return ACTIVEOBJECT_TYPE_OERKKI1;
+ }
+
+ static ClientActiveObject* create();
+
+ void addToScene(scene::ISceneManager *smgr);
+ void removeFromScene();
+ void updateLight(u8 light_at_pos);
+ v3s16 getLightPosition();
+ void updateNodePos();
+
+ void step(float dtime, ClientEnvironment *env);
+
+ void processMessage(const std::string &data);
+
+ void initialize(const std::string &data);
+
+ core::aabbox3d<f32>* getSelectionBox()
+ {return &m_selection_box;}
+ v3f getPosition()
+ {return pos_translator.vect_show;}
+ //{return m_position;}
+
+private:
+ IntervalLimiter m_attack_interval;
+ core::aabbox3d<f32> m_selection_box;
+ scene::IMeshSceneNode *m_node;
+ v3f m_position;
+ float m_yaw;
+ SmoothTranslator pos_translator;
+ float m_damage_visual_timer;
+ bool m_damage_texture_enabled;
+};
+
+
+#endif
+
diff --git a/src/content_inventory.cpp b/src/content_inventory.cpp
index 357c8ef26..7d995cb5f 100644
--- a/src/content_inventory.cpp
+++ b/src/content_inventory.cpp
@@ -19,8 +19,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_inventory.h"
#include "inventory.h"
-#include "serverobject.h"
#include "content_mapnode.h"
+//#include "serverobject.h"
+#include "content_sao.h"
bool item_material_is_cookable(u8 content)
{
diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp
index 9ef0599d1..4c28fe3c6 100644
--- a/src/content_mapblock.cpp
+++ b/src/content_mapblock.cpp
@@ -272,7 +272,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
/*
Signs on walls
*/
- if(n.d == CONTENT_SIGN_WALL)
+ else if(n.d == CONTENT_SIGN_WALL)
{
u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
video::SColor c(255,l,l,l);
diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp
index 38356599f..79e10fd61 100644
--- a/src/content_mapnode.cpp
+++ b/src/content_mapnode.cpp
@@ -224,7 +224,6 @@ void content_mapnode_init()
// Deprecated
i = CONTENT_COALSTONE;
f = &content_features(i);
- //f->translate_to = new MapNode(CONTENT_STONE, MINERAL_COAL);
f->setAllTextures("stone.png^mineral_coal.png");
f->is_ground_content = true;
setStoneLikeDiggingProperties(f->digging_properties, 1.5);
diff --git a/src/content_object.h b/src/content_object.h
new file mode 100644
index 000000000..ecabd8a38
--- /dev/null
+++ b/src/content_object.h
@@ -0,0 +1,29 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef CONTENT_OBJECT_HEADER
+#define CONTENT_OBJECT_HEADER
+
+#define ACTIVEOBJECT_TYPE_TEST 1
+#define ACTIVEOBJECT_TYPE_ITEM 2
+#define ACTIVEOBJECT_TYPE_RAT 3
+#define ACTIVEOBJECT_TYPE_OERKKI1 4
+
+#endif
+
diff --git a/src/content_sao.cpp b/src/content_sao.cpp
new file mode 100644
index 000000000..fc6f208a0
--- /dev/null
+++ b/src/content_sao.cpp
@@ -0,0 +1,694 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "content_sao.h"
+#include "collision.h"
+#include "environment.h"
+
+/*
+ TestSAO
+*/
+
+// Prototype
+TestSAO proto_TestSAO(NULL, 0, v3f(0,0,0));
+
+TestSAO::TestSAO(ServerEnvironment *env, u16 id, v3f pos):
+ ServerActiveObject(env, id, pos),
+ m_timer1(0),
+ m_age(0)
+{
+ ServerActiveObject::registerType(getType(), create);
+}
+
+ServerActiveObject* TestSAO::create(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data)
+{
+ return new TestSAO(env, id, pos);
+}
+
+void TestSAO::step(float dtime, bool send_recommended)
+{
+ m_age += dtime;
+ if(m_age > 10)
+ {
+ m_removed = true;
+ return;
+ }
+
+ m_base_position.Y += dtime * BS * 2;
+ if(m_base_position.Y > 8*BS)
+ m_base_position.Y = 2*BS;
+
+ if(send_recommended == false)
+ return;
+
+ m_timer1 -= dtime;
+ if(m_timer1 < 0.0)
+ {
+ m_timer1 += 0.125;
+ //dstream<<"TestSAO: id="<<getId()<<" sending data"<<std::endl;
+
+ std::string data;
+
+ data += itos(0); // 0 = position
+ data += " ";
+ data += itos(m_base_position.X);
+ data += " ";
+ data += itos(m_base_position.Y);
+ data += " ";
+ data += itos(m_base_position.Z);
+
+ ActiveObjectMessage aom(getId(), false, data);
+ m_messages_out.push_back(aom);
+ }
+}
+
+
+/*
+ ItemSAO
+*/
+
+// Prototype
+ItemSAO proto_ItemSAO(NULL, 0, v3f(0,0,0), "");
+
+ItemSAO::ItemSAO(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string inventorystring):
+ ServerActiveObject(env, id, pos),
+ m_inventorystring(inventorystring),
+ m_speed_f(0,0,0),
+ m_last_sent_position(0,0,0)
+{
+ ServerActiveObject::registerType(getType(), create);
+}
+
+ServerActiveObject* ItemSAO::create(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data)
+{
+ std::istringstream is(data, std::ios::binary);
+ char buf[1];
+ // read version
+ is.read(buf, 1);
+ u8 version = buf[0];
+ // check if version is supported
+ if(version != 0)
+ return NULL;
+ std::string inventorystring = deSerializeString(is);
+ dstream<<"ItemSAO::create(): Creating item \""
+ <<inventorystring<<"\""<<std::endl;
+ return new ItemSAO(env, id, pos, inventorystring);
+}
+
+void ItemSAO::step(float dtime, bool send_recommended)
+{
+ assert(m_env);
+
+ const float interval = 0.2;
+ if(m_move_interval.step(dtime, interval)==false)
+ return;
+ dtime = interval;
+
+ core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
+ collisionMoveResult moveresult;
+ // Apply gravity
+ m_speed_f += v3f(0, -dtime*9.81*BS, 0);
+ // Maximum movement without glitches
+ f32 pos_max_d = BS*0.25;
+ // Limit speed
+ if(m_speed_f.getLength()*dtime > pos_max_d)
+ m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
+ v3f pos_f = getBasePosition();
+ v3f pos_f_old = pos_f;
+ moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
+ box, dtime, pos_f, m_speed_f);
+
+ if(send_recommended == false)
+ return;
+
+ if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
+ {
+ setBasePosition(pos_f);
+ m_last_sent_position = pos_f;
+
+ std::ostringstream os(std::ios::binary);
+ char buf[6];
+ // command (0 = update position)
+ buf[0] = 0;
+ os.write(buf, 1);
+ // pos
+ writeS32((u8*)buf, m_base_position.X*1000);
+ os.write(buf, 4);
+ writeS32((u8*)buf, m_base_position.Y*1000);
+ os.write(buf, 4);
+ writeS32((u8*)buf, m_base_position.Z*1000);
+ os.write(buf, 4);
+ // create message and add to list
+ ActiveObjectMessage aom(getId(), false, os.str());
+ m_messages_out.push_back(aom);
+ }
+}
+
+std::string ItemSAO::getClientInitializationData()
+{
+ std::ostringstream os(std::ios::binary);
+ char buf[6];
+ // version
+ buf[0] = 0;
+ os.write(buf, 1);
+ // pos
+ writeS32((u8*)buf, m_base_position.X*1000);
+ os.write(buf, 4);
+ writeS32((u8*)buf, m_base_position.Y*1000);
+ os.write(buf, 4);
+ writeS32((u8*)buf, m_base_position.Z*1000);
+ os.write(buf, 4);
+ // inventorystring
+ os<<serializeString(m_inventorystring);
+ return os.str();
+}
+
+std::string ItemSAO::getStaticData()
+{
+ dstream<<__FUNCTION_NAME<<std::endl;
+ std::ostringstream os(std::ios::binary);
+ char buf[1];
+ // version
+ buf[0] = 0;
+ os.write(buf, 1);
+ // inventorystring
+ os<<serializeString(m_inventorystring);
+ return os.str();
+}
+
+InventoryItem * ItemSAO::createInventoryItem()
+{
+ try{
+ std::istringstream is(m_inventorystring, std::ios_base::binary);
+ InventoryItem *item = InventoryItem::deSerialize(is);
+ dstream<<__FUNCTION_NAME<<": m_inventorystring=\""
+ <<m_inventorystring<<"\" -> item="<<item
+ <<std::endl;
+ return item;
+ }
+ catch(SerializationError &e)
+ {
+ dstream<<__FUNCTION_NAME<<": serialization error: "
+ <<"m_inventorystring=\""<<m_inventorystring<<"\""<<std::endl;
+ return NULL;
+ }
+}
+
+
+/*
+ RatSAO
+*/
+
+// Prototype
+RatSAO proto_RatSAO(NULL, 0, v3f(0,0,0));
+
+RatSAO::RatSAO(ServerEnvironment *env, u16 id, v3f pos):
+ ServerActiveObject(env, id, pos),
+ m_is_active(false),
+ m_speed_f(0,0,0)
+{
+ ServerActiveObject::registerType(getType(), create);
+
+ m_oldpos = v3f(0,0,0);
+ m_last_sent_position = v3f(0,0,0);
+ m_yaw = 0;
+ m_counter1 = 0;
+ m_counter2 = 0;
+ m_age = 0;
+ m_touching_ground = false;
+}
+
+ServerActiveObject* RatSAO::create(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data)
+{
+ std::istringstream is(data, std::ios::binary);
+ char buf[1];
+ // read version
+ is.read(buf, 1);
+ u8 version = buf[0];
+ // check if version is supported
+ if(version != 0)
+ return NULL;
+ return new RatSAO(env, id, pos);
+}
+
+void RatSAO::step(float dtime, bool send_recommended)
+{
+ assert(m_env);
+
+ if(m_is_active == false)
+ {
+ if(m_inactive_interval.step(dtime, 0.5)==false)
+ return;
+ }
+
+ /*
+ The AI
+ */
+
+ /*m_age += dtime;
+ if(m_age > 60)
+ {
+ // Die
+ m_removed = true;
+ return;
+ }*/
+
+ // Apply gravity
+ m_speed_f.Y -= dtime*9.81*BS;
+
+ /*
+ Move around if some player is close
+ */
+ bool player_is_close = false;
+ // Check connected players
+ core::list<Player*> players = m_env->getPlayers(true);
+ core::list<Player*>::Iterator i;
+ for(i = players.begin();
+ i != players.end(); i++)
+ {
+ Player *player = *i;
+ v3f playerpos = player->getPosition();
+ if(m_base_position.getDistanceFrom(playerpos) < BS*10.0)
+ {
+ player_is_close = true;
+ break;
+ }
+ }
+
+ m_is_active = player_is_close;
+
+ if(player_is_close == false)
+ {
+ m_speed_f.X = 0;
+ m_speed_f.Z = 0;
+ }
+ else
+ {
+ // Move around
+ v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
+ f32 speed = 2*BS;
+ m_speed_f.X = speed * dir.X;
+ m_speed_f.Z = speed * dir.Z;
+
+ if(m_touching_ground && (m_oldpos - m_base_position).getLength()
+ < dtime*speed/2)
+ {
+ m_counter1 -= dtime;
+ if(m_counter1 < 0.0)
+ {
+ m_counter1 += 1.0;
+ m_speed_f.Y = 5.0*BS;
+ }
+ }
+
+ {
+ m_counter2 -= dtime;
+ if(m_counter2 < 0.0)
+ {
+ m_counter2 += (float)(myrand()%100)/100*3.0;
+ m_yaw += ((float)(myrand()%200)-100)/100*180;
+ m_yaw = wrapDegrees(m_yaw);
+ }
+ }
+ }
+
+ m_oldpos = m_base_position;
+
+ /*
+ Move it, with collision detection
+ */
+
+ core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
+ collisionMoveResult moveresult;
+ // Maximum movement without glitches
+ f32 pos_max_d = BS*0.25;
+ // Limit speed
+ if(m_speed_f.getLength()*dtime > pos_max_d)
+ m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
+ v3f pos_f = getBasePosition();
+ v3f pos_f_old = pos_f;
+ moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
+ box, dtime, pos_f, m_speed_f);
+ m_touching_ground = moveresult.touching_ground;
+
+ setBasePosition(pos_f);
+
+ if(send_recommended == false)
+ return;
+
+ if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
+ {
+ m_last_sent_position = pos_f;
+
+ std::ostringstream os(std::ios::binary);
+ // command (0 = update position)
+ writeU8(os, 0);
+ // pos
+ writeV3F1000(os, m_base_position);
+ // yaw
+ writeF1000(os, m_yaw);
+ // create message and add to list
+ ActiveObjectMessage aom(getId(), false, os.str());
+ m_messages_out.push_back(aom);
+ }
+}
+
+std::string RatSAO::getClientInitializationData()
+{
+ std::ostringstream os(std::ios::binary);
+ // version
+ writeU8(os, 0);
+ // pos
+ writeV3F1000(os, m_base_position);
+ return os.str();
+}
+
+std::string RatSAO::getStaticData()
+{
+ //dstream<<__FUNCTION_NAME<<std::endl;
+ std::ostringstream os(std::ios::binary);
+ // version
+ writeU8(os, 0);
+ return os.str();
+}
+
+InventoryItem* RatSAO::createPickedUpItem()
+{
+ std::istringstream is("CraftItem rat 1", std::ios_base::binary);
+ InventoryItem *item = InventoryItem::deSerialize(is);
+ return item;
+}
+
+/*
+ Oerkki1SAO
+*/
+
+// Y is copied, X and Z change is limited
+void accelerate_xz(v3f &speed, v3f target_speed, f32 max_increase)
+{
+ v3f d_wanted = target_speed - speed;
+ d_wanted.Y = 0;
+ f32 dl_wanted = d_wanted.getLength();
+ f32 dl = dl_wanted;
+ if(dl > max_increase)
+ dl = max_increase;
+
+ v3f d = d_wanted.normalize() * dl;
+
+ speed.X += d.X;
+ speed.Z += d.Z;
+ speed.Y = target_speed.Y;
+}
+
+// Prototype
+Oerkki1SAO proto_Oerkki1SAO(NULL, 0, v3f(0,0,0));
+
+Oerkki1SAO::Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos):
+ ServerActiveObject(env, id, pos),
+ m_is_active(false),
+ m_speed_f(0,0,0)
+{
+ ServerActiveObject::registerType(getType(), create);
+
+ m_oldpos = v3f(0,0,0);
+ m_last_sent_position = v3f(0,0,0);
+ m_yaw = 0;
+ m_counter1 = 0;
+ m_counter2 = 0;
+ m_age = 0;
+ m_touching_ground = false;
+ m_hp = 20;
+ m_after_jump_timer = 0;
+}
+
+ServerActiveObject* Oerkki1SAO::create(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data)
+{
+ std::istringstream is(data, std::ios::binary);
+ // read version
+ u8 version = readU8(is);
+ // read hp
+ u8 hp = readU8(is);
+ // check if version is supported
+ if(version != 0)
+ return NULL;
+ Oerkki1SAO *o = new Oerkki1SAO(env, id, pos);
+ o->m_hp = hp;
+ return o;
+}
+
+void Oerkki1SAO::step(float dtime, bool send_recommended)
+{
+ assert(m_env);
+
+ if(m_is_active == false)
+ {
+ if(m_inactive_interval.step(dtime, 0.5)==false)
+ return;
+ }
+
+ /*
+ The AI
+ */
+
+ m_age += dtime;
+ if(m_age > 120)
+ {
+ // Die
+ m_removed = true;
+ return;
+ }
+
+ m_after_jump_timer -= dtime;
+
+ v3f old_speed = m_speed_f;
+
+ // Apply gravity
+ m_speed_f.Y -= dtime*9.81*BS;
+
+ /*
+ Move around if some player is close
+ */
+ bool player_is_close = false;
+ bool player_is_too_close = false;
+ v3f near_player_pos;
+ // Check connected players
+ core::list<Player*> players = m_env->getPlayers(true);
+ core::list<Player*>::Iterator i;
+ for(i = players.begin();
+ i != players.end(); i++)
+ {
+ Player *player = *i;
+ v3f playerpos = player->getPosition();
+ f32 dist = m_base_position.getDistanceFrom(playerpos);
+ if(dist < BS*1.45)
+ {
+ player_is_too_close = true;
+ near_player_pos = playerpos;
+ break;
+ }
+ else if(dist < BS*15.0)
+ {
+ player_is_close = true;
+ near_player_pos = playerpos;
+ }
+ }
+
+ m_is_active = player_is_close;
+
+ v3f target_speed = m_speed_f;
+
+ if(!player_is_close)
+ {
+ target_speed = v3f(0,0,0);
+ }
+ else
+ {
+ // Move around
+
+ v3f ndir = near_player_pos - m_base_position;
+ ndir.Y = 0;
+ ndir.normalize();
+
+ f32 nyaw = 180./PI*atan2(ndir.Z,ndir.X);
+ if(nyaw < m_yaw - 180)
+ nyaw += 360;
+ else if(nyaw > m_yaw + 180)
+ nyaw -= 360;
+ m_yaw = 0.95*m_yaw + 0.05*nyaw;
+ m_yaw = wrapDegrees(m_yaw);
+
+ f32 speed = 2*BS;
+
+ if((m_touching_ground || m_after_jump_timer > 0.0)
+ && !player_is_too_close)
+ {
+ v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
+ target_speed.X = speed * dir.X;
+ target_speed.Z = speed * dir.Z;
+ }
+
+ if(m_touching_ground && (m_oldpos - m_base_position).getLength()
+ < dtime*speed/2)
+ {
+ m_counter1 -= dtime;
+ if(m_counter1 < 0.0)
+ {
+ m_counter1 += 0.2;
+ // Jump
+ target_speed.Y = 5.0*BS;
+ m_after_jump_timer = 1.0;
+ }
+ }
+
+ {
+ m_counter2 -= dtime;
+ if(m_counter2 < 0.0)
+ {
+ m_counter2 += (float)(myrand()%100)/100*3.0;
+ //m_yaw += ((float)(myrand()%200)-100)/100*180;
+ m_yaw += ((float)(myrand()%200)-100)/100*90;
+ m_yaw = wrapDegrees(m_yaw);
+ }
+ }
+ }
+
+ if((m_speed_f - target_speed).getLength() > BS*4 || player_is_too_close)
+ accelerate_xz(m_speed_f, target_speed, dtime*BS*8);
+ else
+ accelerate_xz(m_speed_f, target_speed, dtime*BS*4);
+
+ m_oldpos = m_base_position;
+
+ /*
+ Move it, with collision detection
+ */
+
+ core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*5./3.,BS/3.);
+ collisionMoveResult moveresult;
+ // Maximum movement without glitches
+ f32 pos_max_d = BS*0.25;
+ /*// Limit speed
+ if(m_speed_f.getLength()*dtime > pos_max_d)
+ m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);*/
+ v3f pos_f = getBasePosition();
+ v3f pos_f_old = pos_f;
+ moveresult = collisionMovePrecise(&m_env->getMap(), pos_max_d,
+ box, dtime, pos_f, m_speed_f);
+ m_touching_ground = moveresult.touching_ground;
+
+ // Do collision damage
+ float tolerance = BS*12;
+ float factor = BS*0.5;
+ v3f speed_diff = old_speed - m_speed_f;
+ // Increase effect in X and Z
+ speed_diff.X *= 2;
+ speed_diff.Z *= 2;
+ float vel = speed_diff.getLength();
+ if(vel > tolerance)
+ {
+ f32 damage_f = (vel - tolerance)/BS*factor;
+ u16 damage = (u16)(damage_f+0.5);
+ doDamage(damage);
+ }
+
+ setBasePosition(pos_f);
+
+ if(send_recommended == false && m_speed_f.getLength() < 3.0*BS)
+ return;
+
+ if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
+ {
+ m_last_sent_position = pos_f;
+
+ std::ostringstream os(std::ios::binary);
+ // command (0 = update position)
+ writeU8(os, 0);
+ // pos
+ writeV3F1000(os, m_base_position);
+ // yaw
+ writeF1000(os, m_yaw);
+ // create message and add to list
+ ActiveObjectMessage aom(getId(), false, os.str());
+ m_messages_out.push_back(aom);
+ }
+}
+
+std::string Oerkki1SAO::getClientInitializationData()
+{
+ std::ostringstream os(std::ios::binary);
+ // version
+ writeU8(os, 0);
+ // pos
+ writeV3F1000(os, m_base_position);
+ return os.str();
+}
+
+std::string Oerkki1SAO::getStaticData()
+{
+ //dstream<<__FUNCTION_NAME<<std::endl;
+ std::ostringstream os(std::ios::binary);
+ // version
+ writeU8(os, 0);
+ // hp
+ writeU8(os, m_hp);
+ return os.str();
+}
+
+u16 Oerkki1SAO::punch(const std::string &toolname, v3f dir)
+{
+ m_speed_f += dir*12*BS;
+
+ u16 amount = 5;
+ doDamage(amount);
+ return 65536/100;
+}
+
+void Oerkki1SAO::doDamage(u16 d)
+{
+ dstream<<"oerkki damage: "<<d<<std::endl;
+
+ if(d < m_hp)
+ {
+ m_hp -= d;
+ }
+ else
+ {
+ // Die
+ m_hp = 0;
+ m_removed = true;
+ }
+
+ {
+ std::ostringstream os(std::ios::binary);
+ // command (1 = damage)
+ writeU8(os, 1);
+ // amount
+ writeU8(os, d);
+ // create message and add to list
+ ActiveObjectMessage aom(getId(), false, os.str());
+ m_messages_out.push_back(aom);
+ }
+}
+
+
diff --git a/src/content_sao.h b/src/content_sao.h
new file mode 100644
index 000000000..030232a9e
--- /dev/null
+++ b/src/content_sao.h
@@ -0,0 +1,118 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef CONTENT_SAO_HEADER
+#define CONTENT_SAO_HEADER
+
+#include "serverobject.h"
+#include "content_object.h"
+
+class TestSAO : public ServerActiveObject
+{
+public:
+ TestSAO(ServerEnvironment *env, u16 id, v3f pos);
+ u8 getType() const
+ {return ACTIVEOBJECT_TYPE_TEST;}
+ static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data);
+ void step(float dtime, bool send_recommended);
+private:
+ float m_timer1;
+ float m_age;
+};
+
+class ItemSAO : public ServerActiveObject
+{
+public:
+ ItemSAO(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string inventorystring);
+ u8 getType() const
+ {return ACTIVEOBJECT_TYPE_ITEM;}
+ static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data);
+ void step(float dtime, bool send_recommended);
+ std::string getClientInitializationData();
+ std::string getStaticData();
+ InventoryItem* createInventoryItem();
+ InventoryItem* createPickedUpItem(){return createInventoryItem();}
+private:
+ std::string m_inventorystring;
+ v3f m_speed_f;
+ v3f m_last_sent_position;
+ IntervalLimiter m_move_interval;
+};
+
+class RatSAO : public ServerActiveObject
+{
+public:
+ RatSAO(ServerEnvironment *env, u16 id, v3f pos);
+ u8 getType() const
+ {return ACTIVEOBJECT_TYPE_RAT;}
+ static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data);
+ void step(float dtime, bool send_recommended);
+ std::string getClientInitializationData();
+ std::string getStaticData();
+ InventoryItem* createPickedUpItem();
+private:
+ bool m_is_active;
+ IntervalLimiter m_inactive_interval;
+ v3f m_speed_f;
+ v3f m_oldpos;
+ v3f m_last_sent_position;
+ float m_yaw;
+ float m_counter1;
+ float m_counter2;
+ float m_age;
+ bool m_touching_ground;
+};
+
+class Oerkki1SAO : public ServerActiveObject
+{
+public:
+ Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos);
+ u8 getType() const
+ {return ACTIVEOBJECT_TYPE_OERKKI1;}
+ static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
+ const std::string &data);
+ void step(float dtime, bool send_recommended);
+ std::string getClientInitializationData();
+ std::string getStaticData();
+ InventoryItem* createPickedUpItem(){return NULL;}
+ u16 punch(const std::string &toolname, v3f dir);
+private:
+ void doDamage(u16 d);
+
+ bool m_is_active;
+ IntervalLimiter m_inactive_interval;
+ v3f m_speed_f;
+ v3f m_oldpos;
+ v3f m_last_sent_position;
+ float m_yaw;
+ float m_counter1;
+ float m_counter2;
+ float m_age;
+ bool m_touching_ground;
+ u8 m_hp;
+ float m_after_jump_timer;
+};
+
+
+#endif
+
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index ac1983ed1..cbc78ad3f 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -42,6 +42,8 @@ void set_default_settings()
g_settings.setDefault("keymap_rangeselect", "KEY_KEY_R");
g_settings.setDefault("keymap_freemove", "KEY_KEY_K");
g_settings.setDefault("keymap_fastmove", "KEY_KEY_J");
+ g_settings.setDefault("keymap_frametime_graph", "KEY_F1");
+ g_settings.setDefault("keymap_screenshot", "KEY_F12");
// Some (temporary) keys for debugging
g_settings.setDefault("keymap_special1", "KEY_KEY_E");
g_settings.setDefault("keymap_print_debug_stacks", "KEY_KEY_P");
@@ -54,7 +56,7 @@ void set_default_settings()
g_settings.setDefault("screenH", "600");
g_settings.setDefault("address", "");
g_settings.setDefault("random_input", "false");
- g_settings.setDefault("client_delete_unused_sectors_timeout", "1200");
+ g_settings.setDefault("client_unload_unused_data_timeout", "600");
g_settings.setDefault("enable_fog", "true");
g_settings.setDefault("new_style_water", "false");
g_settings.setDefault("new_style_leaves", "true");
@@ -72,6 +74,7 @@ void set_default_settings()
g_settings.setDefault("farmesh_distance", "40");
g_settings.setDefault("enable_clouds", "true");
g_settings.setDefault("invisible_stone", "false");
+ g_settings.setDefault("screenshot_path", ".");
// Server stuff
g_settings.setDefault("enable_experimental", "false");
@@ -81,17 +84,19 @@ void set_default_settings()
g_settings.setDefault("default_password", "");
g_settings.setDefault("default_privs", "build, shout");
g_settings.setDefault("profiler_print_interval", "0");
+ g_settings.setDefault("enable_mapgen_debug_info", "false");
g_settings.setDefault("objectdata_interval", "0.2");
g_settings.setDefault("active_object_range", "2");
//g_settings.setDefault("max_simultaneous_block_sends_per_client", "1");
+ // This causes frametime jitter on client side, or does it?
g_settings.setDefault("max_simultaneous_block_sends_per_client", "2");
g_settings.setDefault("max_simultaneous_block_sends_server_total", "8");
g_settings.setDefault("max_block_send_distance", "8");
g_settings.setDefault("max_block_generate_distance", "8");
g_settings.setDefault("time_send_interval", "20");
g_settings.setDefault("time_speed", "96");
- g_settings.setDefault("server_unload_unused_sectors_timeout", "60");
+ g_settings.setDefault("server_unload_unused_data_timeout", "60");
g_settings.setDefault("server_map_save_interval", "60");
g_settings.setDefault("full_block_send_enable_min_time_from_building", "2.0");
//g_settings.setDefault("dungeon_rarity", "0.025");
diff --git a/src/environment.cpp b/src/environment.cpp
index e2c704259..0dab54213 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -22,7 +22,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "porting.h"
#include "collision.h"
#include "content_mapnode.h"
-
+#include "mapblock.h"
+#include "serverobject.h"
+#include "content_sao.h"
Environment::Environment():
m_time_of_day(9000)
@@ -659,14 +661,6 @@ void ServerEnvironment::step(float dtime)
}
/*
- Let map update it's timers
- */
- {
- //TimeTaker timer("Server m_map->timerUpdate()");
- m_map->timerUpdate(dtime);
- }
-
- /*
Handle players
*/
for(core::list<Player*>::Iterator i = m_players.begin();
@@ -867,6 +861,9 @@ void ServerEnvironment::step(float dtime)
MapBlock *block = m_map->getBlockNoCreateNoEx(p);
if(block==NULL)
continue;
+
+ // Reset block usage timer
+ block->resetUsageTimer();
// Set current time as timestamp
block->setTimestampNoChangedFlag(m_game_time);
@@ -986,8 +983,14 @@ void ServerEnvironment::step(float dtime)
// Don't step if is to be removed or stored statically
if(obj->m_removed || obj->m_pending_deactivation)
continue;
- // Step object, putting messages directly to the queue
- obj->step(dtime, m_active_object_messages, send_recommended);
+ // Step object
+ obj->step(dtime, send_recommended);
+ // Read messages from object
+ while(obj->m_messages_out.size() > 0)
+ {
+ m_active_object_messages.push_back(
+ obj->m_messages_out.pop_front());
+ }
}
}
@@ -1242,7 +1245,7 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
block->setChangedFlag();
}
else{
- dstream<<"WARNING: Server: Could not find a block for "
+ dstream<<"WARNING: ServerEnv: Could not find a block for "
<<"storing newly added static active object"<<std::endl;
}
@@ -1414,7 +1417,20 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
StaticObject s_obj(obj->getType(), objectpos, staticdata);
// Add to the block where the object is located in
v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
- MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
+ // 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);
@@ -1422,17 +1438,9 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
obj->m_static_exists = true;
obj->m_static_block = block->getPos();
}
- // If not possible, add back to previous block
- else if(oldblock)
- {
- oldblock->m_static_objects.insert(0, s_obj);
- oldblock->setChangedFlag();
- obj->m_static_exists = true;
- obj->m_static_block = oldblock->getPos();
- }
else{
- dstream<<"WARNING: Server: Could not find a block for "
- <<"storing static object"<<std::endl;
+ dstream<<"WARNING: ServerEnv: Could not find or generate "
+ <<"a block for storing static object"<<std::endl;
obj->m_static_exists = false;
continue;
}
@@ -1526,11 +1534,6 @@ void ClientEnvironment::step(float dtime)
bool free_move = g_settings.getBool("free_move");
bool footprints = g_settings.getBool("footprints");
- {
- //TimeTaker timer("Client m_map->timerUpdate()");
- m_map->timerUpdate(dtime);
- }
-
// Get local player
LocalPlayer *lplayer = getLocalPlayer();
assert(lplayer);
@@ -1728,17 +1731,21 @@ void ClientEnvironment::step(float dtime)
ClientActiveObject* obj = i.getNode()->getValue();
// Step object
obj->step(dtime, this);
- // Update lighting
- //u8 light = LIGHT_MAX;
- u8 light = 0;
- try{
- // Get node at head
- v3s16 p = obj->getLightPosition();
- MapNode n = m_map->getNode(p);
- light = n.getLightBlend(getDayNightRatio());
+
+ if(m_active_object_light_update_interval.step(dtime, 0.21))
+ {
+ // Update lighting
+ //u8 light = LIGHT_MAX;
+ u8 light = 0;
+ try{
+ // Get node at head
+ v3s16 p = obj->getLightPosition();
+ MapNode n = m_map->getNode(p);
+ light = n.getLightBlend(getDayNightRatio());
+ }
+ catch(InvalidPositionException &e) {}
+ obj->updateLight(light);
}
- catch(InvalidPositionException &e) {}
- obj->updateLight(light);
}
}
@@ -1926,6 +1933,22 @@ ClientEnvEvent ClientEnvironment::getClientEvent()
return m_client_event_queue.pop_front();
}
+void ClientEnvironment::drawPostFx(video::IVideoDriver* driver, v3f camera_pos)
+{
+ /*LocalPlayer *player = getLocalPlayer();
+ assert(player);
+ v3f pos_f = player->getPosition() + v3f(0,BS*1.625,0);*/
+ v3f pos_f = camera_pos;
+ v3s16 p_nodes = floatToInt(pos_f, BS);
+ MapNode n = m_map->getNodeNoEx(p_nodes);
+ if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
+ {
+ v2u32 ss = driver->getScreenSize();
+ core::rect<s32> rect(0,0, ss.X, ss.Y);
+ driver->draw2DRectangle(video::SColor(64, 100, 100, 200), rect);
+ }
+}
+
#endif // #ifndef SERVER
diff --git a/src/environment.h b/src/environment.h
index eac69d222..b6767858a 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -36,6 +36,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h"
#include <ostream>
#include "utility.h"
+#include "activeobject.h"
+
+class Server;
+class ActiveBlockModifier;
+class ServerActiveObject;
class Environment
{
@@ -118,11 +123,6 @@ private:
This is not thread-safe. Server uses an environment mutex.
*/
-#include "serverobject.h"
-
-class Server;
-class ActiveBlockModifier;
-
class ServerEnvironment : public Environment
{
public:
@@ -406,12 +406,16 @@ public:
// Get event from queue. CEE_NONE is returned if queue is empty.
ClientEnvEvent getClientEvent();
+
+ // Post effects
+ void drawPostFx(video::IVideoDriver* driver, v3f camera_pos);
private:
ClientMap *m_map;
scene::ISceneManager *m_smgr;
core::map<u16, ClientActiveObject*> m_active_objects;
Queue<ClientEnvEvent> m_client_event_queue;
+ IntervalLimiter m_active_object_light_update_interval;
};
#endif
diff --git a/src/farmesh.cpp b/src/farmesh.cpp
index a35983729..2cd922434 100644
--- a/src/farmesh.cpp
+++ b/src/farmesh.cpp
@@ -280,7 +280,8 @@ void FarMesh::render()
if(h_avg < WATER_LEVEL*BS && h_max < (WATER_LEVEL+5)*BS)
{
//c = video::SColor(255,59,86,146);
- c = video::SColor(255,82,120,204);
+ //c = video::SColor(255,82,120,204);
+ c = video::SColor(255,74,105,170);
/*// Set to water level
for(u32 i=0; i<4; i++)
diff --git a/src/game.cpp b/src/game.cpp
index 367abebe1..d77b45da5 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -30,8 +30,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "clouds.h"
#include "keycode.h"
#include "farmesh.h"
+#include "mapblock.h"
-// TODO: Move content-aware stuff to separate file
+/*
+ TODO: Move content-aware stuff to separate file by adding properties
+ and virtual interfaces
+*/
#include "content_mapnode.h"
#include "content_nodemeta.h"
@@ -672,6 +676,34 @@ void update_skybox(video::IVideoDriver* driver,
}
}
+/*
+ Draws a screen with a single text on it.
+ Text will be removed when the screen is drawn the next time.
+*/
+/*gui::IGUIStaticText **/
+void draw_load_screen(const std::wstring &text,
+ video::IVideoDriver* driver, gui::IGUIFont* font)
+{
+ v2u32 screensize = driver->getScreenSize();
+ const wchar_t *loadingtext = text.c_str();
+ core::vector2d<u32> textsize_u = font->getDimension(loadingtext);
+ core::vector2d<s32> textsize(textsize_u.X,textsize_u.Y);
+ core::vector2d<s32> center(screensize.X/2, screensize.Y/2);
+ core::rect<s32> textrect(center - textsize/2, center + textsize/2);
+
+ gui::IGUIStaticText *guitext = guienv->addStaticText(
+ loadingtext, textrect, false, false);
+ guitext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
+
+ driver->beginScene(true, true, video::SColor(255,0,0,0));
+ guienv->drawAll();
+ driver->endScene();
+
+ guitext->remove();
+
+ //return guitext;
+}
+
void the_game(
bool &kill,
bool random_input,
@@ -688,13 +720,18 @@ void the_game(
{
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
+
+ // Calculate text height using the font
+ u32 text_height = font->getDimension(L"Random test string").Height;
v2u32 screensize(0,0);
v2u32 last_screensize(0,0);
screensize = driver->getScreenSize();
const s32 hotbar_itemcount = 8;
- const s32 hotbar_imagesize = 36;
+ //const s32 hotbar_imagesize = 36;
+ //const s32 hotbar_imagesize = 64;
+ s32 hotbar_imagesize = 48;
// The color of the sky
@@ -705,20 +742,10 @@ void the_game(
/*
Draw "Loading" screen
*/
- const wchar_t *loadingtext = L"Loading and connecting...";
- u32 text_height = font->getDimension(loadingtext).Height;
- core::vector2d<s32> center(screensize.X/2, screensize.Y/2);
- core::vector2d<s32> textsize(300, text_height);
- core::rect<s32> textrect(center - textsize/2, center + textsize/2);
-
- gui::IGUIStaticText *gui_loadingtext = guienv->addStaticText(
- loadingtext, textrect, false, false);
- gui_loadingtext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
-
- driver->beginScene(true, true, video::SColor(255,0,0,0));
- guienv->drawAll();
- driver->endScene();
+ /*gui::IGUIStaticText *gui_loadingtext = */
+ //draw_load_screen(L"Loading and connecting...", driver, font);
+ draw_load_screen(L"Loading...", driver, font);
/*
Create server.
@@ -726,6 +753,7 @@ void the_game(
*/
SharedPtr<Server> server;
if(address == ""){
+ draw_load_screen(L"Creating server...", driver, font);
std::cout<<DTIME<<"Creating server"<<std::endl;
server = new Server(map_dir);
server->start(port);
@@ -735,9 +763,11 @@ void the_game(
Create client
*/
+ draw_load_screen(L"Creating client...", driver, font);
std::cout<<DTIME<<"Creating client"<<std::endl;
Client client(device, playername.c_str(), password, draw_control);
+ draw_load_screen(L"Resolving address...", driver, font);
Address connect_address(0,0,0,0, port);
try{
if(address == "")
@@ -751,7 +781,7 @@ void the_game(
std::cout<<DTIME<<"Couldn't resolve address"<<std::endl;
//return 0;
error_message = L"Couldn't resolve address";
- gui_loadingtext->remove();
+ //gui_loadingtext->remove();
return;
}
@@ -784,11 +814,17 @@ void the_game(
{
break;
}
+
+ std::wostringstream ss;
+ ss<<L"Connecting to server... (timeout in ";
+ ss<<(int)(10.0 - time_counter + 1.0);
+ ss<<L" seconds)";
+ draw_load_screen(ss.str(), driver, font);
- // Update screen
+ /*// Update screen
driver->beginScene(true, true, video::SColor(255,0,0,0));
guienv->drawAll();
- driver->endScene();
+ driver->endScene();*/
// Update client and server
@@ -818,7 +854,7 @@ void the_game(
error_message = L"Connection timed out.";
std::cout<<DTIME<<"Timed out."<<std::endl;
}
- gui_loadingtext->remove();
+ //gui_loadingtext->remove();
return;
}
@@ -880,7 +916,7 @@ void the_game(
Move into game
*/
- gui_loadingtext->remove();
+ //gui_loadingtext->remove();
/*
Add some gui stuff
@@ -973,6 +1009,8 @@ void the_game(
while(device->run() && kill == false)
{
+ //std::cerr<<"frame"<<std::endl;
+
if(g_gamecallback->disconnect_requested)
{
g_gamecallback->disconnect_requested = false;
@@ -998,6 +1036,14 @@ void the_game(
screensize = driver->getScreenSize();
v2s32 displaycenter(screensize.X/2,screensize.Y/2);
//bool screensize_changed = screensize != last_screensize;
+
+ // Resize hotbar
+ if(screensize.Y <= 600)
+ hotbar_imagesize = 32;
+ else if(screensize.Y <= 1024)
+ hotbar_imagesize = 48;
+ else
+ hotbar_imagesize = 64;
// Hilight boxes collected during the loop and displayed
core::list< core::aabbox3d<f32> > hilightboxes;
@@ -1090,7 +1136,7 @@ void the_game(
*/
static f32 dtime_avg1 = 0.0;
- dtime_avg1 = dtime_avg1 * 0.98 + dtime * 0.02;
+ dtime_avg1 = dtime_avg1 * 0.96 + dtime * 0.04;
f32 dtime_jitter1 = dtime - dtime_avg1;
static f32 dtime_jitter1_max_sample = 0.0;
@@ -1254,6 +1300,38 @@ void the_game(
chat_lines.push_back(ChatLine(L"fast_move enabled"));
}
}
+ else if(input->wasKeyDown(getKeySetting("keymap_frametime_graph")))
+ {
+ if(g_settings.getBool("frametime_graph"))
+ {
+ g_settings.set("frametime_graph","false");
+ chat_lines.push_back(ChatLine(L"frametime_graph disabled"));
+ }
+ else
+ {
+ g_settings.set("frametime_graph","true");
+ chat_lines.push_back(ChatLine(L"frametime_graph enabled"));
+ }
+ }
+ else if(input->wasKeyDown(getKeySetting("keymap_screenshot")))
+ {
+ irr::video::IImage* const image = driver->createScreenShot();
+ if (image) {
+ irr::c8 filename[256];
+ snprintf(filename, 256, "%s/screenshot_%u.png",
+ g_settings.get("screenshot_path").c_str(),
+ device->getTimer()->getRealTime());
+ if (driver->writeImageToFile(image, filename)) {
+ std::wstringstream sstr;
+ sstr<<"Saved screenshot to '"<<filename<<"'";
+ dstream<<"Saved screenshot to '"<<filename<<"'"<<std::endl;
+ chat_lines.push_back(ChatLine(sstr.str()));
+ } else{
+ dstream<<"Failed to save screenshot '"<<filename<<"'"<<std::endl;
+ }
+ image->drop();
+ }
+ }
// Item selection with mouse wheel
{
@@ -2194,6 +2272,13 @@ void the_game(
core::rect<s32>(0,0,screensize.X,screensize.Y),
NULL);
}
+
+ /*
+ Environment post fx
+ */
+ {
+ client.getEnv()->drawPostFx(driver, camera_position);
+ }
/*
End scene
@@ -2237,15 +2322,12 @@ void the_game(
generator and other stuff quits
*/
{
- const wchar_t *shuttingdowntext = L"Shutting down stuff...";
- gui::IGUIStaticText *gui_shuttingdowntext = guienv->addStaticText(
- shuttingdowntext, textrect, false, false);
- gui_shuttingdowntext->setTextAlignment(gui::EGUIA_CENTER,
- gui::EGUIA_UPPERLEFT);
- driver->beginScene(true, true, video::SColor(255,0,0,0));
+ /*gui::IGUIStaticText *gui_shuttingdowntext = */
+ draw_load_screen(L"Shutting down stuff...", driver, font);
+ /*driver->beginScene(true, true, video::SColor(255,0,0,0));
guienv->drawAll();
driver->endScene();
- gui_shuttingdowntext->remove();
+ gui_shuttingdowntext->remove();*/
}
}
diff --git a/src/inventory.cpp b/src/inventory.cpp
index 0c76ed845..fec51a759 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serverobject.h"
#include "content_mapnode.h"
#include "content_inventory.h"
+#include "content_sao.h"
/*
InventoryItem
diff --git a/src/main.cpp b/src/main.cpp
index 41da310f4..698c5fc71 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -27,6 +27,33 @@ NOTE: Global locale is now set at initialization
NOTE: If VBO (EHM_STATIC) is used, remember to explicitly free the
hardware buffer (it is not freed automatically)
+NOTE: A random to-do list saved here as documentation:
+A list of "active blocks" in which stuff happens. (+=done)
+ + Add a never-resetted game timer to the server
+ + Add a timestamp value to blocks
+ + The simple rule: All blocks near some player are "active"
+ - Do stuff in real time in active blocks
+ + Handle objects
+ - Grow grass, delete leaves without a tree
+ - Spawn some mobs based on some rules
+ - Transform cobble to mossy cobble near water
+ - Run a custom script
+ - ...And all kinds of other dynamic stuff
+ + Keep track of when a block becomes active and becomes inactive
+ + When a block goes inactive:
+ + Store objects statically to block
+ + Store timer value as the timestamp
+ + When a block goes active:
+ + Create active objects out of static objects
+ - Simulate the results of what would have happened if it would have
+ been active for all the time
+ - Grow a lot of grass and so on
+ + Initially it is fine to send information about every active object
+ to every player. Eventually it should be modified to only send info
+ about the nearest ones.
+ + This was left to be done by the old system and it sends only the
+ nearest ones.
+
Old, wild and random suggestions that probably won't be done:
-------------------------------------------------------------
@@ -73,9 +100,6 @@ SUGG: Make the amount of blocks sending to client and the total
SUGG: Meshes of blocks could be split into 6 meshes facing into
different directions and then only those drawn that need to be
-SUGG: Calculate lighting per vertex to get a lighting effect like in
- bartwe's game
-
SUGG: Background music based on cellular automata?
http://www.earslap.com/projectslab/otomata
@@ -90,6 +114,8 @@ SUGG: Make a system for pregenerating quick information for mapblocks, so
or even generated.
SUGG: Erosion simulation at map generation time
+ - This might be plausible if larger areas of map were pregenerated
+ without lighting (which is slow)
- Simulate water flows, which would carve out dirt fast and
then turn stone into gravel and sand and relocate it.
- How about relocating minerals, too? Coal and gold in
@@ -100,6 +126,16 @@ SUGG: Erosion simulation at map generation time
- Simulate rock falling from cliffs when water has removed
enough solid rock from the bottom
+SUGG: For non-mapgen FarMesh: Add a per-sector database to store surface
+ stuff as simple flags/values
+ - Light?
+ - A building?
+ And at some point make the server send this data to the client too,
+ instead of referring to the noise functions
+ - Ground height
+ - Surface ground type
+ - Trees?
+
Gaming ideas:
-------------
@@ -173,12 +209,13 @@ SUGG: Make fetching sector's blocks more efficient when rendering
sectors that have very large amounts of blocks (on client)
- Is this necessary at all?
-TODO: Flowing water animation
-
SUGG: Draw cubes in inventory directly with 3D drawing commands, so that
animating them is easier.
SUGG: Option for enabling proper alpha channel for textures
+
+TODO: Flowing water animation
+
TODO: A setting for enabling bilinear filtering for textures
TODO: Better control of draw_control.wanted_max_blocks
@@ -193,6 +230,12 @@ TODO: Artificial (night) light could be more yellow colored than sunlight.
SUGG: Somehow make the night less colorful
+TODO: Occlusion culling
+ - At the same time, move some of the renderMap() block choosing code
+ to the same place as where the new culling happens.
+ - Shoot some rays per frame and when ready, make a new list of
+ blocks for usage of renderMap and give it a new pointer to it.
+
Configuration:
--------------
@@ -231,6 +274,7 @@ FIXME: Server sometimes goes into some infinite PeerNotFoundException loop
* Fix the problem with the server constantly saving one or a few
blocks? List the first saved block, maybe it explains.
- It is probably caused by oscillating water
+ - TODO: Investigate if this still happens (this is a very old one)
* Make a small history check to transformLiquids to detect and log
continuous oscillations, in such detail that they can be fixed.
@@ -238,44 +282,12 @@ FIXME: The new optimized map sending doesn't sometimes send enough blocks
from big caves and such
FIXME: Block send distance configuration does not take effect for some reason
-TODO: Map saving should be done by EmergeThread
-
-SUGG: Map unloading based on sector reference is not very good, it keeps
- unnecessary stuff in memory. I guess. Investigate this.
-
-TODO: When block is placed and it has param_type==CPT_FACEDIR_SIMPLE, set
- the direction accordingly.
-
Environment:
------------
-TODO: A list of "active blocks" in which stuff happens. (+=done)
- + Add a never-resetted game timer to the server
- + Add a timestamp value to blocks
- + The simple rule: All blocks near some player are "active"
- - Do stuff in real time in active blocks
- + Handle objects
- TODO: Make proper hooks in here
- - Grow grass, delete leaves without a tree
- - Spawn some mobs based on some rules
- - Transform cobble to mossy cobble near water
- - Run a custom script
- - ...And all kinds of other dynamic stuff
- + Keep track of when a block becomes active and becomes inactive
- + When a block goes inactive:
- + Store objects statically to block
- + Store timer value as the timestamp
- + When a block goes active:
- + Create active objects out of static objects
- TODO: Make proper hooks in here
- - Simulate the results of what would have happened if it would have
- been active for all the time
- - Grow a lot of grass and so on
- + Initially it is fine to send information about every active object
- to every player. Eventually it should be modified to only send info
- about the nearest ones.
- + This was left to be done by the old system and it sends only the
- nearest ones.
+TODO: Add proper hooks to when adding and removing active blocks
+
+TODO: Finish the ActiveBlockModifier stuff and use it for something
Objects:
--------
@@ -287,6 +299,7 @@ TODO: Get rid of MapBlockObjects and use only ActiveObjects
SUGG: MovingObject::move and Player::move are basically the same.
combine them.
+ - NOTE: This is a bit tricky because player has the sneaking ability
- NOTE: Player::move is more up-to-date.
- NOTE: There is a simple move implementation now in collision.{h,cpp}
- NOTE: MovingObject will be deleted (MapBlockObject)
@@ -305,59 +318,25 @@ TODO: Mineral and ground material properties
TODO: Flowing water to actually contain flow direction information
- There is a space for this - it just has to be implemented.
-SUGG: Try out the notch way of generating maps, that is, make bunches
- of low-res 3d noise and interpolate linearly.
-
-Mapgen v2 (the current one):
-* Possibly add some kind of erosion and other stuff
-* Better water generation (spread it to underwater caverns but don't
- fill dungeons that don't touch big water masses)
-* When generating a chunk and the neighboring chunk doesn't have mud
- and stuff yet and the ground is fairly flat, the mud will flow to
- the other chunk making nasty straight walls when the other chunk
- is generated. Fix it. Maybe just a special case if the ground is
- flat?
-* Consider not updating this one and make a good mainly block-based
- generator
-
-SUGG: Make two "modified states", one that forces the block to be saved at
- the next save event, and one that makes the block to be saved at exit
- time.
-
-TODO: Add a not_fully_generated flag to MapBlock, which would be set for
- blocks that contain eg. trees from neighboring generations but haven't
- been generated itself. This is required for the future generator.
+TODO: Consider smoothening cave floors after generating them
Misc. stuff:
------------
-- Make sure server handles removing grass when a block is placed (etc)
- - The client should not do it by itself
-- Block cube placement around player's head
-- Protocol version field
-- Consider getting some textures from cisoun's texture pack
- - Ask from Cisoun
-- Make sure the fence implementation and data format is good
- - Think about using same bits for material for fences and doors, for
- example
-- Finish the ActiveBlockModifier stuff and use it for something
-- Move mineral to param2, increment map serialization version, add conversion
-
-TODO: Add a per-sector database to store surface stuff as simple flags/values
- - Light?
- - A building?
- And at some point make the server send this data to the client too,
- instead of referring to the noise functions
- - Ground height
- - Surface ground type
- - Trees?
+TODO: Make sure server handles removing grass when a block is placed (etc)
+ - The client should not do it by itself
+ - NOTE: I think nobody does it currently...
+TODO: Block cube placement around player's head
+TODO: Protocol version field
+TODO: Think about using same bits for material for fences and doors, for
+ example
+TODO: Move mineral to param2, increment map serialization version, add
+ conversion
TODO: Restart irrlicht completely when coming back to main menu from game.
- This gets rid of everything that is stored in irrlicht's caches.
TODO: Merge bahamada's audio stuff (clean patch available)
-TODO: Merge spongie's chest/furnace direction (by hand)
-
TODO: Merge key configuration menu (no clean patch available)
Making it more portable:
@@ -375,9 +354,6 @@ Stuff to do after release:
Doing currently:
----------------
-TODO: Use MapBlock::resetUsageTimer() in appropriate places
- (on client and server)
-
======================================================================
*/
@@ -406,16 +382,12 @@ TODO: Use MapBlock::resetUsageTimer() in appropriate places
#include <iostream>
#include <fstream>
-//#include <jmutexautolock.h>
#include <locale.h>
#include "main.h"
#include "common_irrlicht.h"
#include "debug.h"
-//#include "map.h"
-//#include "player.h"
#include "test.h"
#include "server.h"
-//#include "client.h"
#include "constants.h"
#include "porting.h"
#include "gettime.h"
@@ -424,11 +396,10 @@ TODO: Use MapBlock::resetUsageTimer() in appropriate places
#include "config.h"
#include "guiMainMenu.h"
#include "mineral.h"
-//#include "noise.h"
-//#include "tile.h"
#include "materials.h"
#include "game.h"
#include "keycode.h"
+#include "tile.h"
// This makes textures
ITextureSource *g_texturesource = NULL;
diff --git a/src/main.h b/src/main.h
index 450525c26..b2dee1494 100644
--- a/src/main.h
+++ b/src/main.h
@@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
extern Settings g_settings;
// This makes and maps textures
-#include "tile.h"
+class ITextureSource;
extern ITextureSource *g_texturesource;
// Global profiler
diff --git a/src/map.cpp b/src/map.cpp
index d3e898357..10e1302b1 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -18,18 +18,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "map.h"
+#include "mapsector.h"
+#include "mapblock.h"
#include "main.h"
-#include "jmutexautolock.h"
#include "client.h"
#include "filesys.h"
#include "utility.h"
#include "voxel.h"
#include "porting.h"
-#include "mineral.h"
-#include "noise.h"
-#include "serverobject.h"
-#include "content_mapnode.h"
#include "mapgen.h"
+#include "nodemetadata.h"
extern "C" {
#include "sqlite3.h"
@@ -122,42 +120,23 @@ MapSector * Map::getSectorNoGenerate(v2s16 p)
return sector;
}
-MapBlock * Map::getBlockNoCreate(v3s16 p3d)
-{
- v2s16 p2d(p3d.X, p3d.Z);
- MapSector * sector = getSectorNoGenerate(p2d);
-
- MapBlock *block = sector->getBlockNoCreate(p3d.Y);
-
- return block;
-}
-
MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
{
- try
- {
- v2s16 p2d(p3d.X, p3d.Z);
- MapSector * sector = getSectorNoGenerate(p2d);
- MapBlock *block = sector->getBlockNoCreate(p3d.Y);
- return block;
- }
- catch(InvalidPositionException &e)
- {
+ v2s16 p2d(p3d.X, p3d.Z);
+ MapSector * sector = getSectorNoGenerateNoEx(p2d);
+ if(sector == NULL)
return NULL;
- }
+ MapBlock *block = sector->getBlockNoCreateNoEx(p3d.Y);
+ return block;
}
-/*MapBlock * Map::getBlockCreate(v3s16 p3d)
-{
- v2s16 p2d(p3d.X, p3d.Z);
- MapSector * sector = getSectorCreate(p2d);
- assert(sector);
- MapBlock *block = sector->getBlockNoCreate(p3d.Y);
- if(block)
- return block;
- block = sector->createBlankBlock(p3d.Y);
+MapBlock * Map::getBlockNoCreate(v3s16 p3d)
+{
+ MapBlock *block = getBlockNoCreateNoEx(p3d);
+ if(block == NULL)
+ throw InvalidPositionException();
return block;
-}*/
+}
bool Map::isNodeUnderground(v3s16 p)
{
@@ -172,6 +151,45 @@ bool Map::isNodeUnderground(v3s16 p)
}
}
+bool Map::isValidPosition(v3s16 p)
+{
+ v3s16 blockpos = getNodeBlockPos(p);
+ MapBlock *block = getBlockNoCreate(blockpos);
+ return (block != NULL);
+}
+
+// Returns a CONTENT_IGNORE node if not found
+MapNode Map::getNodeNoEx(v3s16 p)
+{
+ v3s16 blockpos = getNodeBlockPos(p);
+ MapBlock *block = getBlockNoCreateNoEx(blockpos);
+ if(block == NULL)
+ return MapNode(CONTENT_IGNORE);
+ v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
+ return block->getNodeNoCheck(relpos);
+}
+
+// throws InvalidPositionException if not found
+MapNode Map::getNode(v3s16 p)
+{
+ v3s16 blockpos = getNodeBlockPos(p);
+ MapBlock *block = getBlockNoCreateNoEx(blockpos);
+ if(block == NULL)
+ throw InvalidPositionException();
+ v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
+ return block->getNodeNoCheck(relpos);
+}
+
+// throws InvalidPositionException if not found
+void Map::setNode(v3s16 p, MapNode & n)
+{
+ v3s16 blockpos = getNodeBlockPos(p);
+ MapBlock *block = getBlockNoCreate(blockpos);
+ v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
+ block->setNodeNoCheck(relpos, n);
+}
+
+
/*
Goes recursively through the neighbours of the node.
@@ -737,6 +755,25 @@ void Map::updateLighting(enum LightBank bank,
}
}
+
+ /*
+ Enable this to disable proper lighting for speeding up map
+ generation for testing or whatever
+ */
+#if 0
+ //if(g_settings.get(""))
+ {
+ core::map<v3s16, MapBlock*>::Iterator i;
+ i = blocks_to_update.getIterator();
+ for(; i.atEnd() == false; i++)
+ {
+ MapBlock *block = i.getNode()->getValue();
+ v3s16 p = block->getPos();
+ block->setLightingExpired(false);
+ }
+ return;
+ }
+#endif
#if 0
{
@@ -879,7 +916,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
{
}
-#if 1
+#if 0
/*
If the new node is solid and there is grass below, change it to mud
*/
@@ -1357,9 +1394,14 @@ bool Map::dayNightDiffed(v3s16 blockpos)
/*
Updates usage timers
*/
-void Map::timerUpdate(float dtime)
+void Map::timerUpdate(float dtime, float unload_timeout,
+ core::list<v3s16> *unloaded_blocks)
{
- //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
+ bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
+
+ core::list<v2s16> sector_deletion_queue;
+ u32 deleted_blocks_count = 0;
+ u32 saved_blocks_count = 0;
core::map<v2s16, MapSector*>::Iterator si;
@@ -1368,48 +1410,85 @@ void Map::timerUpdate(float dtime)
{
MapSector *sector = si.getNode()->getValue();
+ bool all_blocks_deleted = true;
+
core::list<MapBlock*> blocks;
sector->getBlocks(blocks);
for(core::list<MapBlock*>::Iterator i = blocks.begin();
i != blocks.end(); i++)
{
- (*i)->incrementUsageTimer(dtime);
+ MapBlock *block = (*i);
+
+ block->incrementUsageTimer(dtime);
+
+ if(block->getUsageTimer() > unload_timeout)
+ {
+ v3s16 p = block->getPos();
+
+ // Save if modified
+ if(block->getModified() != MOD_STATE_CLEAN
+ && save_before_unloading)
+ {
+ saveBlock(block);
+ saved_blocks_count++;
+ }
+
+ // Delete from memory
+ sector->deleteBlock(block);
+
+ if(unloaded_blocks)
+ unloaded_blocks->push_back(p);
+
+ deleted_blocks_count++;
+ }
+ else
+ {
+ all_blocks_deleted = false;
+ }
+ }
+
+ if(all_blocks_deleted)
+ {
+ sector_deletion_queue.push_back(si.getNode()->getKey());
}
}
+
+ // Finally delete the empty sectors
+ deleteSectors(sector_deletion_queue);
+
+ if(deleted_blocks_count != 0)
+ {
+ PrintInfo(dstream); // ServerMap/ClientMap:
+ dstream<<"Unloaded "<<deleted_blocks_count
+ <<" blocks from memory";
+ if(save_before_unloading)
+ dstream<<", of which "<<saved_blocks_count<<" were written";
+ dstream<<"."<<std::endl;
+ }
}
-void Map::deleteSectors(core::list<v2s16> &list, bool only_blocks)
+void Map::deleteSectors(core::list<v2s16> &list)
{
core::list<v2s16>::Iterator j;
for(j=list.begin(); j!=list.end(); j++)
{
MapSector *sector = m_sectors[*j];
- if(only_blocks)
- {
- sector->deleteBlocks();
- }
- else
- {
- /*
- If sector is in sector cache, remove it from there
- */
- if(m_sector_cache == sector)
- {
- m_sector_cache = NULL;
- }
- /*
- Remove from map and delete
- */
- m_sectors.remove(*j);
- delete sector;
- }
+ // If sector is in sector cache, remove it from there
+ if(m_sector_cache == sector)
+ m_sector_cache = NULL;
+ // Remove from map and delete
+ m_sectors.remove(*j);
+ delete sector;
}
}
-u32 Map::unloadUnusedData(float timeout, bool only_blocks,
+#if 0
+void Map::unloadUnusedData(float timeout,
core::list<v3s16> *deleted_blocks)
{
core::list<v2s16> sector_deletion_queue;
+ u32 deleted_blocks_count = 0;
+ u32 saved_blocks_count = 0;
core::map<v2s16, MapSector*>::Iterator si = m_sectors.getIterator();
for(; si.atEnd() == false; si++)
@@ -1424,15 +1503,18 @@ u32 Map::unloadUnusedData(float timeout, bool only_blocks,
i != blocks.end(); i++)
{
MapBlock *block = (*i);
-
+
if(block->getUsageTimer() > timeout)
{
// Save if modified
if(block->getModified() != MOD_STATE_CLEAN)
+ {
saveBlock(block);
- // Unload
- sector->removeBlock(block);
- delete block;
+ saved_blocks_count++;
+ }
+ // Delete from memory
+ sector->deleteBlock(block);
+ deleted_blocks_count++;
}
else
{
@@ -1446,37 +1528,16 @@ u32 Map::unloadUnusedData(float timeout, bool only_blocks,
}
}
-#if 0
- core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
- for(; i.atEnd() == false; i++)
- {
- MapSector *sector = i.getNode()->getValue();
- /*
- Delete sector from memory if it hasn't been used in a long time
- */
- if(sector->usage_timer > timeout)
- {
- sector_deletion_queue.push_back(i.getNode()->getKey());
+ deleteSectors(sector_deletion_queue);
- if(deleted_blocks != NULL)
- {
- // Collect positions of blocks of sector
- MapSector *sector = i.getNode()->getValue();
- core::list<MapBlock*> blocks;
- sector->getBlocks(blocks);
- for(core::list<MapBlock*>::Iterator i = blocks.begin();
- i != blocks.end(); i++)
- {
- deleted_blocks->push_back((*i)->getPos());
- }
- }
- }
- }
-#endif
+ dstream<<"Map: Unloaded "<<deleted_blocks_count<<" blocks from memory"
+ <<", of which "<<saved_blocks_count<<" were wr."
+ <<std::endl;
- deleteSectors(sector_deletion_queue, only_blocks);
- return sector_deletion_queue.getSize();
+ //return sector_deletion_queue.getSize();
+ //return deleted_blocks_count;
}
+#endif
void Map::PrintInfo(std::ostream &out)
{
@@ -1503,7 +1564,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
*/
v3s16 p0 = m_transforming_liquid.pop_front();
- MapNode n0 = getNode(p0);
+ MapNode n0 = getNodeNoEx(p0);
// Don't deal with non-liquids
if(content_liquid(n0.d) == false)
@@ -1538,13 +1599,10 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
};
for(u16 i=0; i<5; i++)
{
- try
- {
-
bool from_top = (i==0);
v3s16 p2 = p0 + dirs_from[i];
- MapNode n2 = getNode(p2);
+ MapNode n2 = getNodeNoEx(p2);
if(content_liquid(n2.d))
{
@@ -1593,10 +1651,6 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
if(new_liquid_level > new_liquid_level_max)
new_liquid_level_max = new_liquid_level;
}
-
- }catch(InvalidPositionException &e)
- {
- }
} //for
/*
@@ -1645,20 +1699,13 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
};
for(u16 i=0; i<6; i++)
{
- try
- {
-
v3s16 p2 = p0 + dirs[i];
- MapNode n2 = getNode(p2);
+ MapNode n2 = getNodeNoEx(p2);
if(content_flowing_liquid(n2.d))
{
m_transforming_liquid.push_back(p2);
}
-
- }catch(InvalidPositionException &e)
- {
- }
}
}
}
@@ -1679,9 +1726,6 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
};
for(u16 i=0; i<5; i++)
{
- try
- {
-
bool to_bottom = (i == 0);
// If liquid is at lowest possible height, it's not going
@@ -1707,7 +1751,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
v3s16 p2 = p0 + dirs_to[i];
- MapNode n2 = getNode(p2);
+ MapNode n2 = getNodeNoEx(p2);
//dstream<<"[1] n2.param="<<(int)n2.param<<std::endl;
if(content_liquid(n2.d))
@@ -1773,10 +1817,6 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
// If n2_changed to bottom, don't flow anywhere else
if(to_bottom && flowed && !is_source)
break;
-
- }catch(InvalidPositionException &e)
- {
- }
}
loopcount++;
@@ -1972,7 +2012,6 @@ ServerMap::~ServerMap()
{
if(m_map_saving_enabled)
{
- //save(false);
// Save only changed parts
save(true);
dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
@@ -2079,6 +2118,8 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
return NULL;
}
+ bool enable_mapgen_debug_info = g_settings.getBool("enable_mapgen_debug_info");
+
/*dstream<<"Resulting vmanip:"<<std::endl;
data->vmanip.print(dstream);*/
@@ -2091,10 +2132,11 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
//TimeTaker timer("finishBlockMake() blitBackAll");
data->vmanip->blitBackAll(&changed_blocks);
}
-#if 1
- dstream<<"finishBlockMake: changed_blocks.size()="
- <<changed_blocks.size()<<std::endl;
-#endif
+
+ if(enable_mapgen_debug_info)
+ dstream<<"finishBlockMake: changed_blocks.size()="
+ <<changed_blocks.size()<<std::endl;
+
/*
Copy transforming liquid information
*/
@@ -2128,28 +2170,38 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
/*
NOTE: Lighting and object adding shouldn't really be here, but
lighting is a bit tricky to move properly to makeBlock.
- TODO: Do this the right way anyway.
+ TODO: Do this the right way anyway, that is, move it to makeBlock.
+ - There needs to be some way for makeBlock to report back if
+ the lighting update is going further down because of the
+ new block blocking light
*/
/*
Update lighting
+ NOTE: This takes ~60ms, TODO: Investigate why
*/
-
- core::map<v3s16, MapBlock*> lighting_update_blocks;
- // Center block
- lighting_update_blocks.insert(block->getPos(), block);
-#if 0
- // All modified blocks
- for(core::map<v3s16, MapBlock*>::Iterator
- i = changed_blocks.getIterator();
- i.atEnd() == false; i++)
{
- lighting_update_blocks.insert(i.getNode()->getKey(),
- i.getNode()->getValue());
+ TimeTaker t("finishBlockMake lighting update");
+
+ core::map<v3s16, MapBlock*> lighting_update_blocks;
+ // Center block
+ lighting_update_blocks.insert(block->getPos(), block);
+ #if 0
+ // All modified blocks
+ for(core::map<v3s16, MapBlock*>::Iterator
+ i = changed_blocks.getIterator();
+ i.atEnd() == false; i++)
+ {
+ lighting_update_blocks.insert(i.getNode()->getKey(),
+ i.getNode()->getValue());
+ }
+ #endif
+ updateLighting(lighting_update_blocks, changed_blocks);
+
+ if(enable_mapgen_debug_info == false)
+ t.stop(true); // Hide output
}
-#endif
- updateLighting(lighting_update_blocks, changed_blocks);
-
+
/*
Add random objects to block
*/
@@ -2262,6 +2314,8 @@ MapBlock * ServerMap::generateBlock(
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
<<std::endl;*/
+ bool enable_mapgen_debug_info = g_settings.getBool("enable_mapgen_debug_info");
+
TimeTaker timer("generateBlock");
//MapBlock *block = original_dummy;
@@ -2290,6 +2344,9 @@ MapBlock * ServerMap::generateBlock(
{
TimeTaker t("mapgen::make_block()");
mapgen::make_block(&data);
+
+ if(enable_mapgen_debug_info == false)
+ t.stop(true); // Hide output
}
/*
@@ -2348,6 +2405,9 @@ MapBlock * ServerMap::generateBlock(
}
#endif
+ if(enable_mapgen_debug_info == false)
+ timer.stop(true); // Hide output
+
return block;
}
@@ -2414,23 +2474,51 @@ MapBlock * ServerMap::createBlock(v3s16 p)
return block;
}
-#if 0
-MapBlock * ServerMap::emergeBlock(
- v3s16 p,
- bool only_from_disk,
- core::map<v3s16, MapBlock*> &changed_blocks,
- core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
-)
+MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate)
{
- DSTACKF("%s: p=(%d,%d,%d), only_from_disk=%d",
+ DSTACKF("%s: p=(%d,%d,%d), allow_generate=%d",
__FUNCTION_NAME,
- p.X, p.Y, p.Z, only_from_disk);
+ p.X, p.Y, p.Z, allow_generate);
- // This has to be redone or removed
- assert(0);
+ {
+ MapBlock *block = getBlockNoCreateNoEx(p);
+ if(block)
+ return block;
+ }
+
+ {
+ MapBlock *block = loadBlock(p);
+ if(block)
+ return block;
+ }
+
+ if(allow_generate)
+ {
+ core::map<v3s16, MapBlock*> modified_blocks;
+ MapBlock *block = generateBlock(p, modified_blocks);
+ if(block)
+ {
+ MapEditEvent event;
+ event.type = MEET_OTHER;
+ event.p = p;
+
+ // Copy modified_blocks to event
+ for(core::map<v3s16, MapBlock*>::Iterator
+ i = modified_blocks.getIterator();
+ i.atEnd()==false; i++)
+ {
+ event.modified_blocks.insert(i.getNode()->getKey(), false);
+ }
+
+ // Queue event
+ dispatchEvent(&event);
+
+ return block;
+ }
+ }
+
return NULL;
}
-#endif
#if 0
/*
@@ -2877,10 +2965,10 @@ MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load
// format. Just go ahead and create the sector.
if(fs::PathExists(sectordir))
{
- dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
+ /*dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
<<fullpath<<" doesn't exist but directory does."
<<" Continuing with a sector with no metadata."
- <<std::endl;
+ <<std::endl;*/
sector = new ServerMapSector(this, p2d);
m_sectors.insert(p2d, sector);
}
@@ -3094,10 +3182,8 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
MapBlock *block = NULL;
bool created_new = false;
- try{
- block = sector->getBlockNoCreate(p3d.Y);
- }
- catch(InvalidPositionException &e)
+ block = sector->getBlockNoCreateNoEx(p3d.Y);
+ if(block == NULL)
{
block = sector->createBlankBlockNoInsert(p3d.Y);
created_new = true;
@@ -3267,6 +3353,7 @@ MapSector * ClientMap::emergeSector(v2s16 p2d)
return sector;
}
+#if 0
void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
{
DSTACK(__FUNCTION_NAME);
@@ -3292,6 +3379,7 @@ void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
sector->deSerialize(is);
}
+#endif
void ClientMap::OnRegisterSceneNode()
{
@@ -3350,13 +3438,13 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
// Take a fair amount as we will be dropping more out later
v3s16 p_blocks_min(
- p_nodes_min.X / MAP_BLOCKSIZE - 1,
- p_nodes_min.Y / MAP_BLOCKSIZE - 1,
- p_nodes_min.Z / MAP_BLOCKSIZE - 1);
+ p_nodes_min.X / MAP_BLOCKSIZE - 2,
+ p_nodes_min.Y / MAP_BLOCKSIZE - 2,
+ p_nodes_min.Z / MAP_BLOCKSIZE - 2);
v3s16 p_blocks_max(
- p_nodes_max.X / MAP_BLOCKSIZE,
- p_nodes_max.Y / MAP_BLOCKSIZE,
- p_nodes_max.Z / MAP_BLOCKSIZE);
+ 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;
@@ -3428,6 +3516,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
{
continue;
}
+
+ // Okay, this block will be drawn. Reset usage timer.
+ block->resetUsageTimer();
// This is ugly (spherical distance limit?)
/*if(m_control.range_all == false &&
diff --git a/src/map.h b/src/map.h
index 86b6b6e18..a8aa8e679 100644
--- a/src/map.h
+++ b/src/map.h
@@ -21,25 +21,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MAP_HEADER
#include <jmutex.h>
+#include <jmutexautolock.h>
#include <jthread.h>
#include <iostream>
-#ifdef _WIN32
- #include <windows.h>
- #define sleep_s(x) Sleep((x*1000))
-#else
- #include <unistd.h>
- #define sleep_s(x) sleep(x)
-#endif
-
#include "common_irrlicht.h"
#include "mapnode.h"
-#include "mapblock.h"
-#include "mapsector.h"
+#include "mapblock_nodemod.h"
#include "constants.h"
#include "voxel.h"
-#include "mapchunk.h"
-#include "nodemetadata.h"
+
+class MapSector;
+class ServerMapSector;
+class ClientMapSector;
+class MapBlock;
+class NodeMetadata;
namespace mapgen{
struct BlockMakeData;
@@ -61,7 +57,7 @@ enum MapEditEventType{
// Node metadata of block changed (not knowing which node exactly)
// p stores block coordinate
MEET_BLOCK_NODE_METADATA_CHANGED,
- // Anything else
+ // Anything else (modified_blocks are set unsent)
MEET_OTHER
};
@@ -104,17 +100,17 @@ public:
virtual void onMapEditEvent(MapEditEvent *event) = 0;
};
-class Map : public NodeContainer
+class Map /*: public NodeContainer*/
{
public:
Map(std::ostream &dout);
virtual ~Map();
- virtual u16 nodeContainerId() const
+ /*virtual u16 nodeContainerId() const
{
return NODECONTAINER_ID_MAP;
- }
+ }*/
virtual s32 mapType() const
{
@@ -155,66 +151,20 @@ public:
MapBlock * getBlockNoCreate(v3s16 p);
// Returns NULL if not found
MapBlock * getBlockNoCreateNoEx(v3s16 p);
- // Gets an existing block or creates an empty one
- //MapBlock * getBlockCreate(v3s16 p);
// Returns InvalidPositionException if not found
bool isNodeUnderground(v3s16 p);
- // virtual from NodeContainer
- bool isValidPosition(v3s16 p)
- {
- v3s16 blockpos = getNodeBlockPos(p);
- MapBlock *blockref;
- try{
- blockref = getBlockNoCreate(blockpos);
- }
- catch(InvalidPositionException &e)
- {
- return false;
- }
- return true;
- /*v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
- bool is_valid = blockref->isValidPosition(relpos);
- return is_valid;*/
- }
+ bool isValidPosition(v3s16 p);
- // virtual from NodeContainer
// throws InvalidPositionException if not found
- MapNode getNode(v3s16 p)
- {
- v3s16 blockpos = getNodeBlockPos(p);
- MapBlock * blockref = getBlockNoCreate(blockpos);
- v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
+ MapNode getNode(v3s16 p);
- return blockref->getNodeNoCheck(relpos);
- }
-
- // virtual from NodeContainer
// throws InvalidPositionException if not found
- void setNode(v3s16 p, MapNode & n)
- {
- v3s16 blockpos = getNodeBlockPos(p);
- MapBlock * blockref = getBlockNoCreate(blockpos);
- v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
- blockref->setNodeNoCheck(relpos, n);
- }
+ void setNode(v3s16 p, MapNode & n);
// Returns a CONTENT_IGNORE node if not found
- MapNode getNodeNoEx(v3s16 p)
- {
- try{
- v3s16 blockpos = getNodeBlockPos(p);
- MapBlock * blockref = getBlockNoCreate(blockpos);
- v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
-
- return blockref->getNodeNoCheck(relpos);
- }
- catch(InvalidPositionException &e)
- {
- return MapNode(CONTENT_IGNORE);
- }
- }
+ MapNode getNodeNoEx(v3s16 p);
void unspreadLight(enum LightBank bank,
core::map<v3s16, u8> & from_nodes,
@@ -273,23 +223,33 @@ public:
virtual void save(bool only_changed){assert(0);};
- // Server implements this
+ // Server implements this.
+ // Client leaves it as no-op.
virtual void saveBlock(MapBlock *block){};
/*
- Updates usage timers
+ Updates usage timers and unloads unused blocks and sectors.
+ Saves modified blocks before unloading on MAPTYPE_SERVER.
*/
- void timerUpdate(float dtime);
-
+ void timerUpdate(float dtime, float unload_timeout,
+ core::list<v3s16> *unloaded_blocks=NULL);
+
+ // Deletes sectors and their blocks from memory
// Takes cache into account
- // sector mutex should be locked when calling
- void deleteSectors(core::list<v2s16> &list, bool only_blocks);
-
- // Returns count of deleted sectors
- u32 unloadUnusedData(float timeout, bool only_blocks=false,
+ // If deleted sector is in sector cache, clears cache
+ void deleteSectors(core::list<v2s16> &list);
+
+#if 0
+ /*
+ Unload unused data
+ = flush changed to disk and delete from memory, if usage timer of
+ block is more than timeout
+ */
+ void unloadUnusedData(float timeout,
core::list<v3s16> *deleted_blocks=NULL);
+#endif
- // For debug printing
+ // For debug printing. Prints "Map: ", "ServerMap: " or "ClientMap: "
virtual void PrintInfo(std::ostream &out);
void transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks);
@@ -321,7 +281,6 @@ protected:
core::map<MapEventReceiver*, bool> m_event_receivers;
core::map<v2s16, MapSector*> m_sectors;
- //JMutex m_sector_mutex;
// Be sure to set this to NULL when the cached sector is deleted
MapSector *m_sector_cache;
@@ -379,24 +338,13 @@ public:
*/
MapBlock * createBlock(v3s16 p);
-#if 0
/*
- NOTE: This comment might be outdated
-
Forcefully get a block from somewhere.
-
- InvalidPositionException possible if only_from_disk==true
-
- Parameters:
- changed_blocks: Blocks that have been modified
+ - Memory
+ - Load from disk
+ - Generate
*/
- MapBlock * emergeBlock(
- v3s16 p,
- bool only_from_disk,
- core::map<v3s16, MapBlock*> &changed_blocks,
- core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
- );
-#endif
+ MapBlock * emergeBlock(v3s16 p, bool allow_generate=true);
// Helper for placing objects on ground level
s16 findGroundLevel(v2s16 p2d);
@@ -547,7 +495,7 @@ public:
*/
MapSector * emergeSector(v2s16 p);
- void deSerializeSector(v2s16 p2d, std::istream &is);
+ //void deSerializeSector(v2s16 p2d, std::istream &is);
/*
ISceneNode methods
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index 2f6a4b850..647a17756 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
MapBlock
*/
-MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy):
+MapBlock::MapBlock(Map *parent, v3s16 pos, bool dummy):
m_parent(parent),
m_pos(pos),
m_modified(MOD_STATE_WRITE_NEEDED),
@@ -38,7 +38,7 @@ MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy):
m_generated(false),
m_objects(this),
m_timestamp(BLOCK_TIMESTAMP_UNDEFINED),
- m_usage_timer(BLOCK_TIMESTAMP_UNDEFINED)
+ m_usage_timer(0)
{
data = NULL;
if(dummy == false)
@@ -607,24 +607,20 @@ void MapBlock::serialize(std::ostream &os, u8 version)
Get data
*/
- SharedBuffer<u8> databuf(nodecount*3);
-
- // Get contents
+ // Serialize nodes
+ SharedBuffer<u8> databuf_nodelist(nodecount*3);
for(u32 i=0; i<nodecount; i++)
{
- databuf[i] = data[i].d;
+ data[i].serialize(&databuf_nodelist[i*3], version);
}
-
- // Get params
- for(u32 i=0; i<nodecount; i++)
- {
- databuf[i+nodecount] = data[i].param;
- }
-
- // Get param2
+
+ // Create buffer with different parameters sorted
+ SharedBuffer<u8> databuf(nodecount*3);
for(u32 i=0; i<nodecount; i++)
{
- databuf[i+nodecount*2] = data[i].param2;
+ databuf[i] = databuf_nodelist[i*3];
+ databuf[i+nodecount] = databuf_nodelist[i*3+1];
+ databuf[i+nodecount*2] = databuf_nodelist[i*3+2];
}
/*
@@ -773,20 +769,14 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
("MapBlock::deSerialize: decompress resulted in size"
" other than nodecount*3");
- // Set contents
- for(u32 i=0; i<nodecount; i++)
- {
- data[i].d = s[i];
- }
- // Set params
- for(u32 i=0; i<nodecount; i++)
- {
- data[i].param = s[i+nodecount];
- }
- // Set param2
+ // deserialize nodes from buffer
for(u32 i=0; i<nodecount; i++)
{
- data[i].param2 = s[i+nodecount*2];
+ u8 buf[3];
+ buf[0] = s[i];
+ buf[1] = s[i+nodecount];
+ buf[2] = s[i+nodecount*2];
+ data[i].deSerialize(buf, version);
}
/*
@@ -818,25 +808,6 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
}
}
}
-
- /*
- Translate nodes as specified in the translate_to fields of
- node features
-
- NOTE: This isn't really used. Should it be removed?
- */
- for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
- {
- MapNode &n = data[i];
-
- MapNode *translate_to = content_features(n.d).translate_to;
- if(translate_to)
- {
- dstream<<"MapBlock: WARNING: Translating node "<<n.d<<" to "
- <<translate_to->d<<std::endl;
- n = *translate_to;
- }
- }
}
void MapBlock::serializeDiskExtra(std::ostream &os, u8 version)
diff --git a/src/mapblock.h b/src/mapblock.h
index 693bc5190..8f3b8464a 100644
--- a/src/mapblock.h
+++ b/src/mapblock.h
@@ -38,6 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapblock_mesh.h"
#endif
+class Map;
#define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
@@ -81,6 +82,7 @@ enum ModifiedState
BLOCKGEN_FULLY_GENERATED=6
};*/
+#if 0
enum
{
NODECONTAINER_ID_MAPBLOCK,
@@ -108,23 +110,24 @@ public:
}
}
};
+#endif
/*
MapBlock itself
*/
-class MapBlock : public NodeContainer
+class MapBlock /*: public NodeContainer*/
{
public:
- MapBlock(NodeContainer *parent, v3s16 pos, bool dummy=false);
+ MapBlock(Map *parent, v3s16 pos, bool dummy=false);
~MapBlock();
- virtual u16 nodeContainerId() const
+ /*virtual u16 nodeContainerId() const
{
return NODECONTAINER_ID_MAPBLOCK;
- }
+ }*/
- NodeContainer * getParent()
+ Map * getParent()
{
return m_parent;
}
@@ -640,7 +643,7 @@ private:
*/
// NOTE: Lots of things rely on this being the Map
- NodeContainer *m_parent;
+ Map *m_parent;
// Position in blocks on parent
v3s16 m_pos;
diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp
index d4921c2c5..447716d00 100644
--- a/src/mapblock_mesh.cpp
+++ b/src/mapblock_mesh.cpp
@@ -64,11 +64,7 @@ void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
*/
// Get map
- NodeContainer *parentcontainer = block->getParent();
- // This will only work if the parent is the map
- assert(parentcontainer->nodeContainerId() == NODECONTAINER_ID_MAP);
- // OK, we have the map!
- Map *map = (Map*)parentcontainer;
+ Map *map = block->getParent();
for(u16 i=0; i<6; i++)
{
diff --git a/src/mapblockobject.cpp b/src/mapblockobject.cpp
index 009163a18..ab1c20267 100644
--- a/src/mapblockobject.cpp
+++ b/src/mapblockobject.cpp
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h"
#include "inventory.h"
#include "utility.h"
+#include "mapblock.h"
/*
MapBlockObject
@@ -856,16 +857,7 @@ bool MapBlockObjectList::wrapObject(MapBlockObject *object)
assert(m_objects.find(object->m_id) != NULL);
assert(m_objects[object->m_id] == object);
- NodeContainer *parentcontainer = m_block->getParent();
- // This will only work if the parent is the map
- if(parentcontainer->nodeContainerId() != NODECONTAINER_ID_MAP)
- {
- dstream<<"WARNING: Wrapping object not possible: "
- "MapBlock's parent is not map"<<std::endl;
- return true;
- }
- // OK, we have the map!
- Map *map = (Map*)parentcontainer;
+ Map *map = m_block->getParent();
// Calculate blockpos on map
v3s16 oldblock_pos_i_on_map = m_block->getPosRelative();
diff --git a/src/mapchunk.h b/src/mapchunk.h
index 9860abad0..98df7ce66 100644
--- a/src/mapchunk.h
+++ b/src/mapchunk.h
@@ -21,6 +21,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MAPCHUNK_HEADER
/*
+ TODO: Remove
+*/
+
+#if 0
+/*
MapChunk contains map-generation-time metadata for an area of
some MapSectors. (something like 16x16)
*/
@@ -66,6 +71,7 @@ private:
u8 m_generation_level;
bool m_modified;
};
+#endif
#endif
diff --git a/src/mapgen.cpp b/src/mapgen.cpp
index a491ac81a..d7b6e56c4 100644
--- a/src/mapgen.cpp
+++ b/src/mapgen.cpp
@@ -23,8 +23,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "noise.h"
#include "mapblock.h"
#include "map.h"
-#include "serverobject.h"
#include "mineral.h"
+//#include "serverobject.h"
+#include "content_sao.h"
namespace mapgen
{
@@ -531,7 +532,7 @@ static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
else
length = random.range(1,6);
length = random.range(1,13);
- u32 partlength = random.range(1,length);
+ u32 partlength = random.range(1,13);
u32 partcount = 0;
s16 make_stairs = 0;
if(random.next()%2 == 0 && partlength >= 3)
@@ -700,14 +701,30 @@ public:
continue;
v3s16 roomplace;
// X east, Z north, Y up
+#if 1
+ if(doordir == v3s16(1,0,0)) // X+
+ roomplace = doorplace +
+ v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
+ if(doordir == v3s16(-1,0,0)) // X-
+ roomplace = doorplace +
+ v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
+ if(doordir == v3s16(0,0,1)) // Z+
+ roomplace = doorplace +
+ v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
+ if(doordir == v3s16(0,0,-1)) // Z-
+ roomplace = doorplace +
+ v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
+#endif
+#if 0
if(doordir == v3s16(1,0,0)) // X+
- roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2+m_random.range(-roomsize.Z/2+1,roomsize.Z/2-1));
+ roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
if(doordir == v3s16(-1,0,0)) // X-
- roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2+m_random.range(-roomsize.Z/2+1,roomsize.Z/2-1));
+ roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
if(doordir == v3s16(0,0,1)) // Z+
- roomplace = doorplace + v3s16(-roomsize.X/2+m_random.range(-roomsize.X/2+1,roomsize.X/2-1),-1,0);
+ roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
if(doordir == v3s16(0,0,-1)) // Z-
- roomplace = doorplace + v3s16(-roomsize.X/2+m_random.range(-roomsize.X/2+1,roomsize.X/2-1),-1,-roomsize.Z+1);
+ roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
+#endif
// Check fit
bool fits = true;
@@ -818,7 +835,7 @@ static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random)
// Determine walker start position
- bool start_in_last_room = (random.range(0,1)==0);
+ bool start_in_last_room = (random.range(0,2)!=0);
//bool start_in_last_room = true;
v3s16 walker_start_place;
@@ -877,30 +894,47 @@ static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random)
Noise functions. Make sure seed is mangled differently in each one.
*/
-// This affects the shape of the contour
+/*
+ Scaling the output of the noise function affects the overdrive of the
+ contour function, which affects the shape of the output considerably.
+*/
+#define CAVE_NOISE_SCALE 12.0
//#define CAVE_NOISE_SCALE 10.0
//#define CAVE_NOISE_SCALE 7.5
-#define CAVE_NOISE_SCALE 5.0
+//#define CAVE_NOISE_SCALE 5.0
+//#define CAVE_NOISE_SCALE 1.0
+
+//#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
+#define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
NoiseParams get_cave_noise1_params(u64 seed)
{
/*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
200, CAVE_NOISE_SCALE);*/
- return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
- 100, CAVE_NOISE_SCALE);
+ /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
+ 100, CAVE_NOISE_SCALE);*/
+ /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
+ 100, CAVE_NOISE_SCALE);*/
+ /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
+ 100, CAVE_NOISE_SCALE);*/
+ return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
+ 50, CAVE_NOISE_SCALE);
+ //return NoiseParams(NOISE_CONSTANT_ONE);
}
NoiseParams get_cave_noise2_params(u64 seed)
{
/*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
200, CAVE_NOISE_SCALE);*/
- return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
- 100, CAVE_NOISE_SCALE);
+ /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
+ 100, CAVE_NOISE_SCALE);*/
+ /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
+ 100, CAVE_NOISE_SCALE);*/
+ return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
+ 50, CAVE_NOISE_SCALE);
+ //return NoiseParams(NOISE_CONSTANT_ONE);
}
-//#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
-#define CAVE_NOISE_THRESHOLD (2.0/CAVE_NOISE_SCALE)
-
NoiseParams get_ground_noise1_params(u64 seed)
{
return NoiseParams(NOISE_PERLIN, seed+983240, 4,
@@ -937,13 +971,13 @@ bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
{
//return ((double)p.Y < ground_noise1_val);
- double f = 0.8 + noise2d_perlin(
+ double f = 0.55 + noise2d_perlin(
0.5+(float)p.X/250, 0.5+(float)p.Z/250,
seed+920381, 3, 0.45);
if(f < 0.01)
f = 0.01;
else if(f >= 1.0)
- f *= 2.0;
+ f *= 1.6;
double h = WATER_LEVEL + 10 * noise2d_perlin(
0.5+(float)p.X/250, 0.5+(float)p.Z/250,
seed+84174, 4, 0.5);
@@ -1082,6 +1116,7 @@ double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
double a = -31000;
+ // Corners
a = MYMAX(a, find_ground_level_from_noise(seed,
v2s16(node_min.X, node_min.Y), p));
a = MYMAX(a, find_ground_level_from_noise(seed,
@@ -1090,8 +1125,18 @@ double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
v2s16(node_max.X, node_max.Y), p));
a = MYMAX(a, find_ground_level_from_noise(seed,
v2s16(node_min.X, node_min.Y), p));
+ // Center
a = MYMAX(a, find_ground_level_from_noise(seed,
v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
+ // Side middle points
+ a = MYMAX(a, find_ground_level_from_noise(seed,
+ v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
+ a = MYMAX(a, find_ground_level_from_noise(seed,
+ v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
+ a = MYMAX(a, find_ground_level_from_noise(seed,
+ v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
+ a = MYMAX(a, find_ground_level_from_noise(seed,
+ v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
return a;
}
@@ -1102,6 +1147,7 @@ double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
double a = 31000;
+ // Corners
a = MYMIN(a, find_ground_level_from_noise(seed,
v2s16(node_min.X, node_min.Y), p));
a = MYMIN(a, find_ground_level_from_noise(seed,
@@ -1110,8 +1156,18 @@ double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
v2s16(node_max.X, node_max.Y), p));
a = MYMIN(a, find_ground_level_from_noise(seed,
v2s16(node_min.X, node_min.Y), p));
+ // Center
a = MYMIN(a, find_ground_level_from_noise(seed,
v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
+ // Side middle points
+ a = MYMIN(a, find_ground_level_from_noise(seed,
+ v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
+ a = MYMIN(a, find_ground_level_from_noise(seed,
+ v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
+ a = MYMIN(a, find_ground_level_from_noise(seed,
+ v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
+ a = MYMIN(a, find_ground_level_from_noise(seed,
+ v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
return a;
}
@@ -1358,12 +1414,12 @@ void make_block(BlockMakeData *data)
If block is deep underground, this is set to true and ground
density noise is not generated, for speed optimization.
*/
- bool all_is_ground_except_caves = (minimum_ground_depth > 16);
+ bool all_is_ground_except_caves = (minimum_ground_depth > 40);
/*
Create a block-specific seed
*/
- u32 blockseed = (data->seed%0x100000000) + full_node_min.Z*38134234
+ u32 blockseed = (u32)(data->seed%0x100000000) + full_node_min.Z*38134234
+ full_node_min.Y*42123 + full_node_min.X*23;
/*
@@ -1385,13 +1441,13 @@ void make_block(BlockMakeData *data)
/*
Cave noise
*/
-
+#if 1
noisebuf_cave.create(get_cave_noise1_params(data->seed),
minpos_f.X, minpos_f.Y, minpos_f.Z,
maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
- 4, 3, 4);
-
+ 2, 2, 2);
noisebuf_cave.multiply(get_cave_noise2_params(data->seed));
+#endif
/*
Ground noise
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index dae21e7cc..391e593f9 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -30,8 +30,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
ContentFeatures::~ContentFeatures()
{
- if(translate_to)
- delete translate_to;
+ /*if(translate_to)
+ delete translate_to;*/
if(initial_metadata)
delete initial_metadata;
}
@@ -139,6 +139,17 @@ void init_mapnode()
}
/*
+ Initially set every block to be shown as an unknown block.
+ Don't touch CONTENT_IGNORE or CONTENT_AIR.
+ */
+ for(u16 i=0; i<=253; i++)
+ {
+ ContentFeatures *f = &g_content_features[i];
+ f->setAllTextures("unknown_block.png");
+ f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
+ }
+
+ /*
Initialize mapnode content
*/
content_mapnode_init();
@@ -230,6 +241,94 @@ u8 MapNode::getMineral()
return MINERAL_NONE;
}
+u32 MapNode::serializedLength(u8 version)
+{
+ if(!ser_ver_supported(version))
+ throw VersionMismatchException("ERROR: MapNode format not supported");
+
+ if(version == 0)
+ return 1;
+ else if(version <= 9)
+ return 2;
+ else
+ return 3;
+}
+void MapNode::serialize(u8 *dest, u8 version)
+{
+ if(!ser_ver_supported(version))
+ throw VersionMismatchException("ERROR: MapNode format not supported");
+
+ u8 actual_d = d;
+
+ // Convert from new version to old
+ if(version <= 18)
+ {
+ // In these versions, CONTENT_IGNORE and CONTENT_AIR
+ // are 255 and 254
+ if(d == CONTENT_IGNORE)
+ d = 255;
+ else if(d == CONTENT_AIR)
+ d = 254;
+ }
+
+ if(version == 0)
+ {
+ dest[0] = actual_d;
+ }
+ else if(version <= 9)
+ {
+ dest[0] = actual_d;
+ dest[1] = param;
+ }
+ else
+ {
+ dest[0] = actual_d;
+ dest[1] = param;
+ dest[2] = param2;
+ }
+}
+void MapNode::deSerialize(u8 *source, u8 version)
+{
+ if(!ser_ver_supported(version))
+ throw VersionMismatchException("ERROR: MapNode format not supported");
+
+ if(version == 0)
+ {
+ d = source[0];
+ }
+ else if(version == 1)
+ {
+ d = source[0];
+ // This version doesn't support saved lighting
+ if(light_propagates() || light_source() > 0)
+ param = 0;
+ else
+ param = source[1];
+ }
+ else if(version <= 9)
+ {
+ d = source[0];
+ param = source[1];
+ }
+ else
+ {
+ d = source[0];
+ param = source[1];
+ param2 = source[2];
+
+ // Convert from old version to new
+ if(version <= 18)
+ {
+ // In these versions, CONTENT_IGNORE and CONTENT_AIR
+ // are 255 and 254
+ if(d == 255)
+ d = CONTENT_IGNORE;
+ else if(d == 254)
+ d = CONTENT_AIR;
+ }
+ }
+}
+
/*
Gets lighting value at face of node
diff --git a/src/mapnode.h b/src/mapnode.h
index d4ba0fed5..8bbd4eb79 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -37,6 +37,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
/*
+ Ranges:
+ 0x000...0x07f: param2 is fully usable
+ 0x800...0xfff: param2 lower 4 bytes are free
+*/
+typedef u16 content_t;
+
+/*
Initializes all kind of stuff in here.
Many things depend on this.
@@ -59,14 +66,16 @@ void init_mapnode();
Doesn't create faces with anything and is considered being
out-of-map in the game map.
*/
-#define CONTENT_IGNORE 255
+//#define CONTENT_IGNORE 255
+#define CONTENT_IGNORE 127
#define CONTENT_IGNORE_DEFAULT_PARAM 0
/*
The common material through which the player can walk and which
is transparent to light
*/
-#define CONTENT_AIR 254
+//#define CONTENT_AIR 254
+#define CONTENT_AIR 126
/*
Content feature list
@@ -94,7 +103,7 @@ class NodeMetadata;
struct ContentFeatures
{
// If non-NULL, content is translated to this when deserialized
- MapNode *translate_to;
+ //MapNode *translate_to;
// Type of MapNode::param
ContentParamType param_type;
@@ -156,7 +165,7 @@ struct ContentFeatures
void reset()
{
- translate_to = NULL;
+ //translate_to = NULL;
param_type = CPT_NONE;
inventory_texture = NULL;
is_ground_content = false;
@@ -196,6 +205,8 @@ struct ContentFeatures
{
setTexture(i, name, alpha);
}
+ // Force inventory texture too
+ setInventoryTexture(name);
}
void setTile(u16 i, const TileSpec &tile)
@@ -399,20 +410,30 @@ enum LightBank
struct MapNode
{
- // Content
- u8 d;
+ /*
+ Main content
+ 0x00-0x7f: Short content type
+ 0x80-0xff: Long content type (param2>>4 makes up low bytes)
+ */
+ union
+ {
+ u8 param0;
+ u8 d;
+ };
/*
Misc parameter. Initialized to 0.
- For light_propagates() blocks, this is light intensity,
stored logarithmically from 0 to LIGHT_MAX.
Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
- - Contains 2 values, day- and night lighting. Each takes 4 bits.
+ - Contains 2 values, day- and night lighting. Each takes 4 bits.
+ - Mineral content (should be removed from here)
+ - Uhh... well, most blocks have light or nothing in here.
*/
union
{
- s8 param;
u8 param1;
+ s8 param;
};
/*
@@ -437,14 +458,6 @@ struct MapNode
param2 = a_param2;
}
- /*MapNode & operator=(const MapNode &other)
- {
- d = other.d;
- param = other.param;
- param2 = other.param2;
- return *this;
- }*/
-
bool operator==(const MapNode &other)
{
return (d == other.d
@@ -452,6 +465,16 @@ struct MapNode
&& param2 == other.param2);
}
+ // To be used everywhere
+ content_t getContent()
+ {
+ return d;
+ }
+ void setContent(content_t c)
+ {
+ d = c;
+ }
+
/*
These four are DEPRECATED I guess. -c55
*/
@@ -566,88 +589,15 @@ struct MapNode
MINERAL_NONE if doesn't contain or isn't able to contain mineral.
*/
u8 getMineral();
-
+
/*
- These serialization functions are used when informing client
- of a single node add.
-
- NOTE: When loading a MapBlock, these are not used. Should they?
+ Serialization functions
*/
- static u32 serializedLength(u8 version)
- {
- if(!ser_ver_supported(version))
- throw VersionMismatchException("ERROR: MapNode format not supported");
-
- if(version == 0)
- return 1;
- else if(version <= 9)
- return 2;
- else
- return 3;
- }
- void serialize(u8 *dest, u8 version)
- {
- if(!ser_ver_supported(version))
- throw VersionMismatchException("ERROR: MapNode format not supported");
-
- if(version == 0)
- {
- dest[0] = d;
- }
- else if(version <= 9)
- {
- dest[0] = d;
- dest[1] = param;
- }
- else
- {
- dest[0] = d;
- dest[1] = param;
- dest[2] = param2;
- }
- }
- void deSerialize(u8 *source, u8 version)
- {
- if(!ser_ver_supported(version))
- throw VersionMismatchException("ERROR: MapNode format not supported");
-
- if(version == 0)
- {
- d = source[0];
- }
- else if(version == 1)
- {
- d = source[0];
- // This version doesn't support saved lighting
- if(light_propagates() || light_source() > 0)
- param = 0;
- else
- param = source[1];
- }
- else if(version <= 9)
- {
- d = source[0];
- param = source[1];
- }
- else
- {
- d = source[0];
- param = source[1];
- param2 = source[2];
- }
-
- // Translate deprecated stuff
- // NOTE: This doesn't get used because MapBlock handles node
- // parameters directly
- MapNode *translate_to = content_features(d).translate_to;
- if(translate_to)
- {
- dstream<<"MapNode: WARNING: Translating "<<d<<" to "
- <<translate_to->d<<std::endl;
- *this = *translate_to;
- }
- }
+ static u32 serializedLength(u8 version);
+ void serialize(u8 *dest, u8 version);
+ void deSerialize(u8 *source, u8 version);
+
};
/*
diff --git a/src/mapsector.cpp b/src/mapsector.cpp
index 97101dd36..4a526c412 100644
--- a/src/mapsector.cpp
+++ b/src/mapsector.cpp
@@ -21,15 +21,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "jmutexautolock.h"
#include "client.h"
#include "exceptions.h"
+#include "mapblock.h"
-MapSector::MapSector(NodeContainer *parent, v2s16 pos):
- differs_from_disk(true),
+MapSector::MapSector(Map *parent, v2s16 pos):
+ differs_from_disk(false),
m_parent(parent),
m_pos(pos),
m_block_cache(NULL)
{
- m_mutex.Init();
- assert(m_mutex.IsInitialized());
}
MapSector::~MapSector()
@@ -39,8 +38,6 @@ MapSector::~MapSector()
void MapSector::deleteBlocks()
{
- JMutexAutoLock lock(m_mutex);
-
// Clear cache
m_block_cache = NULL;
@@ -83,26 +80,12 @@ MapBlock * MapSector::getBlockBuffered(s16 y)
MapBlock * MapSector::getBlockNoCreateNoEx(s16 y)
{
- JMutexAutoLock lock(m_mutex);
-
return getBlockBuffered(y);
}
-MapBlock * MapSector::getBlockNoCreate(s16 y)
-{
- MapBlock *block = getBlockNoCreateNoEx(y);
-
- if(block == NULL)
- throw InvalidPositionException();
-
- return block;
-}
-
MapBlock * MapSector::createBlankBlockNoInsert(s16 y)
{
- // There should not be a block at this position
- if(getBlockBuffered(y) != NULL)
- throw AlreadyExistsException("Block already exists");
+ assert(getBlockBuffered(y) == NULL);
v3s16 blockpos_map(m_pos.X, y, m_pos.Y);
@@ -113,8 +96,6 @@ MapBlock * MapSector::createBlankBlockNoInsert(s16 y)
MapBlock * MapSector::createBlankBlock(s16 y)
{
- JMutexAutoLock lock(m_mutex);
-
MapBlock *block = createBlankBlockNoInsert(y);
m_blocks.insert(y, block);
@@ -126,39 +107,34 @@ void MapSector::insertBlock(MapBlock *block)
{
s16 block_y = block->getPos().Y;
- {
- JMutexAutoLock lock(m_mutex);
-
- MapBlock *block2 = getBlockBuffered(block_y);
- if(block2 != NULL){
- throw AlreadyExistsException("Block already exists");
- }
-
- v2s16 p2d(block->getPos().X, block->getPos().Z);
- assert(p2d == m_pos);
-
- // Insert into container
- m_blocks.insert(block_y, block);
+ MapBlock *block2 = getBlockBuffered(block_y);
+ if(block2 != NULL){
+ throw AlreadyExistsException("Block already exists");
}
+
+ v2s16 p2d(block->getPos().X, block->getPos().Z);
+ assert(p2d == m_pos);
+
+ // Insert into container
+ m_blocks.insert(block_y, block);
}
-void MapSector::removeBlock(MapBlock *block)
+void MapSector::deleteBlock(MapBlock *block)
{
s16 block_y = block->getPos().Y;
- JMutexAutoLock lock(m_mutex);
-
// Clear from cache
m_block_cache = NULL;
// Remove from container
m_blocks.remove(block_y);
+
+ // Delete
+ delete block;
}
void MapSector::getBlocks(core::list<MapBlock*> &dest)
{
- JMutexAutoLock lock(m_mutex);
-
core::list<MapBlock*> ref_list;
core::map<s16, MapBlock*>::Iterator bi;
@@ -175,7 +151,7 @@ void MapSector::getBlocks(core::list<MapBlock*> &dest)
ServerMapSector
*/
-ServerMapSector::ServerMapSector(NodeContainer *parent, v2s16 pos):
+ServerMapSector::ServerMapSector(Map *parent, v2s16 pos):
MapSector(parent, pos)
{
}
@@ -184,15 +160,6 @@ ServerMapSector::~ServerMapSector()
{
}
-f32 ServerMapSector::getGroundHeight(v2s16 p, bool generate)
-{
- return GROUNDHEIGHT_NOTFOUND_SETVALUE;
-}
-
-void ServerMapSector::setGroundHeight(v2s16 p, f32 y, bool generate)
-{
-}
-
void ServerMapSector::serialize(std::ostream &os, u8 version)
{
if(!ser_ver_supported(version))
@@ -217,7 +184,7 @@ void ServerMapSector::serialize(std::ostream &os, u8 version)
ServerMapSector* ServerMapSector::deSerialize(
std::istream &is,
- NodeContainer *parent,
+ Map *parent,
v2s16 p2d,
core::map<v2s16, MapSector*> & sectors
)
@@ -280,7 +247,7 @@ ServerMapSector* ServerMapSector::deSerialize(
ClientMapSector
*/
-ClientMapSector::ClientMapSector(NodeContainer *parent, v2s16 pos):
+ClientMapSector::ClientMapSector(Map *parent, v2s16 pos):
MapSector(parent, pos)
{
}
@@ -289,45 +256,6 @@ ClientMapSector::~ClientMapSector()
{
}
-void ClientMapSector::deSerialize(std::istream &is)
-{
- /*
- [0] u8 serialization version
- [1] s16 corners[0]
- [3] s16 corners[1]
- [5] s16 corners[2]
- [7] s16 corners[3]
- size = 9
-
- In which corners are in these positions
- v2s16(0,0),
- v2s16(1,0),
- v2s16(1,1),
- v2s16(0,1),
- */
-
- // Read version
- u8 version = SER_FMT_VER_INVALID;
- is.read((char*)&version, 1);
-
- if(!ser_ver_supported(version))
- throw VersionMismatchException("ERROR: MapSector format not supported");
-
- u8 buf[2];
-
- // Dummy read corners
- is.read((char*)buf, 2);
- is.read((char*)buf, 2);
- is.read((char*)buf, 2);
- is.read((char*)buf, 2);
-
- /*
- Set stuff in sector
- */
-
- // Nothing here
-
-}
#endif // !SERVER
//END
diff --git a/src/mapsector.h b/src/mapsector.h
index fda290cd7..44f45d8f0 100644
--- a/src/mapsector.h
+++ b/src/mapsector.h
@@ -26,9 +26,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <jmutex.h>
#include "common_irrlicht.h"
-#include "mapblock.h"
-//#include "heightmap.h"
#include "exceptions.h"
+#include <ostream>
+
+class MapBlock;
+class Map;
/*
This is an Y-wise stack of MapBlocks.
@@ -37,18 +39,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MAPSECTOR_SERVER 0
#define MAPSECTOR_CLIENT 1
-class MapSector: public NodeContainer
+class MapSector
{
public:
- MapSector(NodeContainer *parent, v2s16 pos);
+ MapSector(Map *parent, v2s16 pos);
virtual ~MapSector();
- virtual u16 nodeContainerId() const
- {
- return NODECONTAINER_ID_MAPSECTOR;
- }
-
virtual u32 getId() const = 0;
void deleteBlocks();
@@ -59,167 +56,32 @@ public:
}
MapBlock * getBlockNoCreateNoEx(s16 y);
- MapBlock * getBlockNoCreate(s16 y);
MapBlock * createBlankBlockNoInsert(s16 y);
MapBlock * createBlankBlock(s16 y);
- //MapBlock * getBlock(s16 y, bool generate=true);
void insertBlock(MapBlock *block);
- // This is used to remove a dummy from the sector while generating it.
- // Block is only removed from internal container, not deleted.
- void removeBlock(MapBlock *block);
+ void deleteBlock(MapBlock *block);
- /*
- This might not be a thread-safe depending on the day.
- See the implementation.
- */
void getBlocks(core::list<MapBlock*> &dest);
- /*
- If all nodes in area can be accessed, returns true and
- adds all blocks in area to blocks.
-
- If all nodes in area cannot be accessed, returns false.
-
- The implementation of this is quite slow
-
- if blocks==NULL; it is not accessed at all.
- */
- bool isValidArea(v3s16 p_min_nodes, v3s16 p_max_nodes,
- core::map<s16, MapBlock*> *blocks)
- {
- core::map<s16, MapBlock*> bs;
-
- v3s16 p_min = getNodeBlockPos(p_min_nodes);
- v3s16 p_max = getNodeBlockPos(p_max_nodes);
- if(p_min.X != 0 || p_min.Z != 0
- || p_max.X != 0 || p_max.Z != 0)
- return false;
- v3s16 y;
- for(s16 y=p_min.Y; y<=p_max.Y; y++)
- {
- try{
- MapBlock *block = getBlockNoCreate(y);
- if(block->isDummy())
- return false;
- if(blocks!=NULL)
- bs[y] = block;
- }
- catch(InvalidPositionException &e)
- {
- return false;
- }
- }
-
- if(blocks!=NULL)
- {
- for(core::map<s16, MapBlock*>::Iterator i=bs.getIterator();
- i.atEnd()==false; i++)
- {
- MapBlock *block = i.getNode()->getValue();
- s16 y = i.getNode()->getKey();
- blocks->insert(y, block);
- }
- }
- return true;
- }
-
- void getBlocksInArea(v3s16 p_min_nodes, v3s16 p_max_nodes,
- core::map<v3s16, MapBlock*> &blocks)
- {
- v3s16 p_min = getNodeBlockPos(p_min_nodes);
- v3s16 p_max = getNodeBlockPos(p_max_nodes);
- v3s16 y;
- for(s16 y=p_min.Y; y<=p_max.Y; y++)
- {
- try{
- MapBlock *block = getBlockNoCreate(y);
- blocks.insert(block->getPos(), block);
- }
- catch(InvalidPositionException &e)
- {
- }
- }
- }
-
- // virtual from NodeContainer
- bool isValidPosition(v3s16 p)
- {
- v3s16 blockpos = getNodeBlockPos(p);
-
- if(blockpos.X != 0 || blockpos.Z != 0)
- return false;
-
- MapBlock *blockref;
- try{
- blockref = getBlockNoCreate(blockpos.Y);
- }
- catch(InvalidPositionException &e)
- {
- return false;
- }
-
- return true;
- }
-
- // virtual from NodeContainer
- MapNode getNode(v3s16 p)
- {
- v3s16 blockpos = getNodeBlockPos(p);
- if(blockpos.X != 0 || blockpos.Z != 0)
- throw InvalidPositionException
- ("MapSector only allows Y");
-
- MapBlock * blockref = getBlockNoCreate(blockpos.Y);
- v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
-
- return blockref->getNode(relpos);
- }
- // virtual from NodeContainer
- void setNode(v3s16 p, MapNode & n)
- {
- v3s16 blockpos = getNodeBlockPos(p);
- if(blockpos.X != 0 || blockpos.Z != 0)
- throw InvalidPositionException
- ("MapSector only allows Y");
-
- MapBlock * blockref = getBlockNoCreate(blockpos.Y);
- v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
- blockref->setNode(relpos, n);
- }
-
- // DEPRECATED?
- virtual f32 getGroundHeight(v2s16 p, bool generate=false)
- {
- return GROUNDHEIGHT_NOTFOUND_SETVALUE;
- }
- virtual void setGroundHeight(v2s16 p, f32 y, bool generate=false)
- {
- }
-
- // When true, sector metadata is changed from the one on disk
- // (sector metadata = all but blocks)
- // Basically, this should be changed to true in every setter method
+ // Always false at the moment, because sector contains no metadata.
bool differs_from_disk;
protected:
// The pile of MapBlocks
core::map<s16, MapBlock*> m_blocks;
- //JMutex m_blocks_mutex; // For public access functions
- NodeContainer *m_parent;
+ Map *m_parent;
// Position on parent (in MapBlock widths)
v2s16 m_pos;
-
+
+ // Last-used block is cached here for quicker access.
// Be sure to set this to NULL when the cached block is deleted
MapBlock *m_block_cache;
s16 m_block_cache_y;
- // This is used for protecting m_blocks
- JMutex m_mutex;
-
/*
Private methods
*/
@@ -230,27 +92,24 @@ protected:
class ServerMapSector : public MapSector
{
public:
- ServerMapSector(NodeContainer *parent, v2s16 pos);
+ ServerMapSector(Map *parent, v2s16 pos);
~ServerMapSector();
u32 getId() const
{
return MAPSECTOR_SERVER;
}
-
- // DEPRECATED?
- f32 getGroundHeight(v2s16 p, bool generate=false);
- void setGroundHeight(v2s16 p, f32 y, bool generate=false);
/*
These functions handle metadata.
They do not handle blocks.
*/
+
void serialize(std::ostream &os, u8 version);
static ServerMapSector* deSerialize(
std::istream &is,
- NodeContainer *parent,
+ Map *parent,
v2s16 p2d,
core::map<v2s16, MapSector*> & sectors
);
@@ -262,7 +121,7 @@ private:
class ClientMapSector : public MapSector
{
public:
- ClientMapSector(NodeContainer *parent, v2s16 pos);
+ ClientMapSector(Map *parent, v2s16 pos);
~ClientMapSector();
u32 getId() const
@@ -270,16 +129,7 @@ public:
return MAPSECTOR_CLIENT;
}
- void deSerialize(std::istream &is);
-
- /*s16 getCorner(u16 i)
- {
- return m_corners[i];
- }*/
-
private:
- // The ground height of the corners is stored in here
- //s16 m_corners[4];
};
#endif
diff --git a/src/mineral.h b/src/mineral.h
index 970ff1f78..61776e669 100644
--- a/src/mineral.h
+++ b/src/mineral.h
@@ -21,7 +21,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MINERAL_HEADER
#include "inventory.h"
-#include "tile.h"
/*
Minerals
diff --git a/src/noise.cpp b/src/noise.cpp
index b755a824a..9c2141ce0 100644
--- a/src/noise.cpp
+++ b/src/noise.cpp
@@ -238,7 +238,11 @@ double noise3d_param(const NoiseParams &param, double x, double y, double z)
y /= s;
z /= s;
- if(param.type == NOISE_PERLIN)
+ if(param.type == NOISE_CONSTANT_ONE)
+ {
+ return 1.0;
+ }
+ else if(param.type == NOISE_PERLIN)
{
return param.noise_scale*noise3d_perlin(x,y,z, param.seed,
param.octaves,
diff --git a/src/noise.h b/src/noise.h
index c8d8985c6..ed75f316d 100644
--- a/src/noise.h
+++ b/src/noise.h
@@ -82,10 +82,11 @@ double noise3d_perlin_abs(double x, double y, double z, int seed,
enum NoiseType
{
+ NOISE_CONSTANT_ONE,
NOISE_PERLIN,
NOISE_PERLIN_ABS,
NOISE_PERLIN_CONTOUR,
- NOISE_PERLIN_CONTOUR_FLIP_YZ
+ NOISE_PERLIN_CONTOUR_FLIP_YZ,
};
struct NoiseParams
diff --git a/src/player.cpp b/src/player.cpp
index 198eca957..6bacb088d 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -309,6 +309,8 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
v3f oldpos = position;
v3s16 oldpos_i = floatToInt(oldpos, BS);
+ v3f old_speed = m_speed;
+
/*std::cout<<"oldpos_i=("<<oldpos_i.X<<","<<oldpos_i.Y<<","
<<oldpos_i.Z<<")"<<std::endl;*/
@@ -405,8 +407,23 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
if(position.Y < min_y)
{
position.Y = min_y;
+
+ //v3f old_speed = m_speed;
+
if(m_speed.Y < 0)
m_speed.Y = 0;
+
+ /*if(collision_info)
+ {
+ // Report fall collision
+ if(old_speed.Y < m_speed.Y - 0.1)
+ {
+ CollisionInfo info;
+ info.t = COLLISION_FALL;
+ info.speed = m_speed.Y - old_speed.Y;
+ collision_info->push_back(info);
+ }
+ }*/
}
}
@@ -557,13 +574,13 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
*/
if(other_axes_overlap && main_axis_collides)
{
- v3f old_speed = m_speed;
+ //v3f old_speed = m_speed;
m_speed -= m_speed.dotProduct(dirs[i]) * dirs[i];
position -= position.dotProduct(dirs[i]) * dirs[i];
position += oldpos.dotProduct(dirs[i]) * dirs[i];
- if(collision_info)
+ /*if(collision_info)
{
// Report fall collision
if(old_speed.Y < m_speed.Y - 0.1)
@@ -573,7 +590,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
info.speed = m_speed.Y - old_speed.Y;
collision_info->push_back(info);
}
- }
+ }*/
}
}
@@ -656,6 +673,21 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
Set new position
*/
setPosition(position);
+
+ /*
+ Report collisions
+ */
+ if(collision_info)
+ {
+ // Report fall collision
+ if(old_speed.Y < m_speed.Y - 0.1)
+ {
+ CollisionInfo info;
+ info.t = COLLISION_FALL;
+ info.speed = m_speed.Y - old_speed.Y;
+ collision_info->push_back(info);
+ }
+ }
}
void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
diff --git a/src/serialization.h b/src/serialization.h
index 80a336101..974ae95d8 100644
--- a/src/serialization.h
+++ b/src/serialization.h
@@ -53,12 +53,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
15: StaticObjects
16: larger maximum size of node metadata, and compression
17: MapBlocks contain timestamp
- 18: sqlite/new generator/whatever
+ 18: new generator (not really necessary, but it's there)
+ 19: new content type handling
*/
// This represents an uninitialized or invalid format
#define SER_FMT_VER_INVALID 255
// Highest supported serialization version
-#define SER_FMT_VER_HIGHEST 18
+#define SER_FMT_VER_HIGHEST 19
// Lowest supported serialization version
#define SER_FMT_VER_LOWEST 0
diff --git a/src/server.cpp b/src/server.cpp
index cf8b57773..c2433e1af 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -34,6 +34,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_mapnode.h"
#include "content_craft.h"
#include "content_nodemeta.h"
+#include "mapblock.h"
+#include "serverobject.h"
#define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
@@ -600,6 +602,9 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
bool block_is_invalid = false;
if(block != NULL)
{
+ // Reset usage timer, this block will be of use in the future.
+ block->resetUsageTimer();
+
// Block is dummy if data doesn't exist.
// It means it has been not found from disk and not generated
if(block->isDummy())
@@ -1295,12 +1300,21 @@ void Server::AsyncRunStep()
}
{
- // Step environment
- // This also runs Map's timers
JMutexAutoLock lock(m_env_mutex);
+ // Step environment
ScopeProfiler sp(&g_profiler, "Server: environment step");
m_env.step(dtime);
}
+
+ const float map_timer_and_unload_dtime = 5.15;
+ if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
+ {
+ JMutexAutoLock lock(m_env_mutex);
+ // Run Map's timers and unload unused data
+ ScopeProfiler sp(&g_profiler, "Server: map timer and unload");
+ m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
+ g_settings.getFloat("server_unload_unused_data_timeout"));
+ }
/*
Do background stuff
@@ -1656,9 +1670,22 @@ void Server::AsyncRunStep()
*/
{
// Don't send too many at a time
- u32 count = 0;
+ //u32 count = 0;
+
+ // Single change sending is disabled if queue size is not small
+ bool disable_single_change_sending = false;
+ if(m_unsent_map_edit_queue.size() >= 4)
+ disable_single_change_sending = true;
+
+ bool got_any_events = false;
+
+ // We'll log the amount of each
+ Profiler prof;
+
while(m_unsent_map_edit_queue.size() != 0)
{
+ got_any_events = true;
+
MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
// Players far away from the change are stored here.
@@ -1668,28 +1695,41 @@ void Server::AsyncRunStep()
if(event->type == MEET_ADDNODE)
{
- dstream<<"Server: MEET_ADDNODE"<<std::endl;
- sendAddNode(event->p, event->n, event->already_known_by_peer,
- &far_players, 30);
+ //dstream<<"Server: MEET_ADDNODE"<<std::endl;
+ prof.add("MEET_ADDNODE", 1);
+ if(disable_single_change_sending)
+ sendAddNode(event->p, event->n, event->already_known_by_peer,
+ &far_players, 5);
+ else
+ sendAddNode(event->p, event->n, event->already_known_by_peer,
+ &far_players, 30);
}
else if(event->type == MEET_REMOVENODE)
{
- dstream<<"Server: MEET_REMOVENODE"<<std::endl;
- sendRemoveNode(event->p, event->already_known_by_peer,
- &far_players, 30);
+ //dstream<<"Server: MEET_REMOVENODE"<<std::endl;
+ prof.add("MEET_REMOVENODE", 1);
+ if(disable_single_change_sending)
+ sendRemoveNode(event->p, event->already_known_by_peer,
+ &far_players, 5);
+ else
+ sendRemoveNode(event->p, event->already_known_by_peer,
+ &far_players, 30);
}
else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
{
dstream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
+ prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
setBlockNotSent(event->p);
}
else if(event->type == MEET_OTHER)
{
+ prof.add("MEET_OTHER", 1);
dstream<<"WARNING: Server: MEET_OTHER not implemented"
<<std::endl;
}
else
{
+ prof.add("unknown", 1);
dstream<<"WARNING: Server: Unknown MapEditEvent "
<<((u32)event->type)<<std::endl;
}
@@ -1697,32 +1737,45 @@ void Server::AsyncRunStep()
/*
Set blocks not sent to far players
*/
- core::map<v3s16, MapBlock*> modified_blocks2;
- for(core::map<v3s16, bool>::Iterator
- i = event->modified_blocks.getIterator();
- i.atEnd()==false; i++)
- {
- v3s16 p = i.getNode()->getKey();
- modified_blocks2.insert(p, m_env.getMap().getBlockNoCreateNoEx(p));
- }
- for(core::list<u16>::Iterator
- i = far_players.begin();
- i != far_players.end(); i++)
+ if(far_players.size() > 0)
{
- u16 peer_id = *i;
- RemoteClient *client = getClient(peer_id);
- if(client==NULL)
- continue;
- client->SetBlocksNotSent(modified_blocks2);
+ // Convert list format to that wanted by SetBlocksNotSent
+ core::map<v3s16, MapBlock*> modified_blocks2;
+ for(core::map<v3s16, bool>::Iterator
+ i = event->modified_blocks.getIterator();
+ i.atEnd()==false; i++)
+ {
+ v3s16 p = i.getNode()->getKey();
+ modified_blocks2.insert(p,
+ m_env.getMap().getBlockNoCreateNoEx(p));
+ }
+ // Set blocks not sent
+ for(core::list<u16>::Iterator
+ i = far_players.begin();
+ i != far_players.end(); i++)
+ {
+ u16 peer_id = *i;
+ RemoteClient *client = getClient(peer_id);
+ if(client==NULL)
+ continue;
+ client->SetBlocksNotSent(modified_blocks2);
+ }
}
delete event;
- // Don't send too many at a time
+ /*// Don't send too many at a time
count++;
if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
- break;
+ break;*/
+ }
+
+ if(got_any_events)
+ {
+ dstream<<"Server: MapEditEvents:"<<std::endl;
+ prof.print(dstream);
}
+
}
/*
@@ -1746,39 +1799,6 @@ void Server::AsyncRunStep()
}
/*
- Step node metadata
- TODO: Move to ServerEnvironment and utilize active block stuff
- */
- /*{
- //TimeTaker timer("Step node metadata");
-
- JMutexAutoLock envlock(m_env_mutex);
- JMutexAutoLock conlock(m_con_mutex);
-
- ScopeProfiler sp(&g_profiler, "Server: stepping node metadata");
-
- core::map<v3s16, MapBlock*> changed_blocks;
- m_env.getMap().nodeMetadataStep(dtime, changed_blocks);
-
- // Use setBlockNotSent
-
- for(core::map<v3s16, MapBlock*>::Iterator
- i = changed_blocks.getIterator();
- i.atEnd() == false; i++)
- {
- MapBlock *block = i.getNode()->getValue();
-
- for(core::map<u16, RemoteClient*>::Iterator
- i = m_clients.getIterator();
- i.atEnd()==false; i++)
- {
- RemoteClient *client = i.getNode()->getValue();
- client->SetBlockNotSent(block->getPos());
- }
- }
- }*/
-
- /*
Trigger emergethread (it somehow gets to a non-triggered but
bysy state sometimes)
*/
@@ -1809,26 +1829,29 @@ void Server::AsyncRunStep()
// Map
JMutexAutoLock lock(m_env_mutex);
- if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == true)
- {
- // Save only changed parts
- m_env.getMap().save(true);
- // Delete unused sectors
- u32 deleted_count = m_env.getMap().unloadUnusedData(
- g_settings.getFloat("server_unload_unused_sectors_timeout"));
- if(deleted_count > 0)
- {
- dout_server<<"Server: Unloaded "<<deleted_count
- <<" sectors from memory"<<std::endl;
- }
+ /*// Unload unused data (delete from memory)
+ m_env.getMap().unloadUnusedData(
+ g_settings.getFloat("server_unload_unused_sectors_timeout"));
+ */
+ /*u32 deleted_count = m_env.getMap().unloadUnusedData(
+ g_settings.getFloat("server_unload_unused_sectors_timeout"));
+ */
- // Save players
- m_env.serializePlayers(m_mapsavedir);
-
- // Save environment metadata
- m_env.saveMeta(m_mapsavedir);
- }
+ // Save only changed parts
+ m_env.getMap().save(true);
+
+ /*if(deleted_count > 0)
+ {
+ dout_server<<"Server: Unloaded "<<deleted_count
+ <<" blocks from memory"<<std::endl;
+ }*/
+
+ // Save players
+ m_env.serializePlayers(m_mapsavedir);
+
+ // Save environment metadata
+ m_env.saveMeta(m_mapsavedir);
}
}
}
@@ -2392,8 +2415,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
toolname = titem->getToolName();
}
}
+
+ v3f playerpos = player->getPosition();
+ v3f objpos = obj->getBasePosition();
+ v3f dir = (objpos - playerpos).normalize();
- u16 wear = obj->punch(toolname);
+ u16 wear = obj->punch(toolname, dir);
if(titem)
{
@@ -2710,9 +2737,31 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
MaterialItem *mitem = (MaterialItem*)item;
MapNode n;
n.d = mitem->getMaterial();
+
+ // Calculate direction for wall mounted stuff
if(content_features(n.d).wall_mounted)
n.dir = packDir(p_under - p_over);
-
+
+ // Calculate the direction for furnaces and chests and stuff
+ if(content_features(n.d).param_type == CPT_FACEDIR_SIMPLE)
+ {
+ v3f playerpos = player->getPosition();
+ v3f blockpos = intToFloat(p_over, BS) - playerpos;
+ blockpos = blockpos.normalize();
+ n.param1 = 0;
+ if (fabs(blockpos.X) > fabs(blockpos.Z)) {
+ if (blockpos.X < 0)
+ n.param1 = 3;
+ else
+ n.param1 = 1;
+ } else {
+ if (blockpos.Z < 0)
+ n.param1 = 2;
+ else
+ n.param1 = 0;
+ }
+ }
+
/*
Send to all close-by players
*/
@@ -3286,7 +3335,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
void Server::onMapEditEvent(MapEditEvent *event)
{
- dstream<<"Server::onMapEditEvent()"<<std::endl;
+ //dstream<<"Server::onMapEditEvent()"<<std::endl;
if(m_ignore_map_edit_events)
return;
MapEditEvent *e = event->clone();
diff --git a/src/server.h b/src/server.h
index b88369ddf..1da004da5 100644
--- a/src/server.h
+++ b/src/server.h
@@ -534,6 +534,7 @@ private:
float m_objectdata_timer;
float m_emergethread_trigger_timer;
float m_savemap_timer;
+ IntervalLimiter m_map_timer_and_unload_interval;
// NOTE: If connection and environment are both to be locked,
// environment shall be locked first.
diff --git a/src/serverobject.cpp b/src/serverobject.cpp
index d31e9a31c..8acb35f6d 100644
--- a/src/serverobject.cpp
+++ b/src/serverobject.cpp
@@ -19,9 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serverobject.h"
#include <fstream>
-#include "environment.h"
#include "inventory.h"
-#include "collision.h"
core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
@@ -71,600 +69,4 @@ void ServerActiveObject::registerType(u16 type, Factory f)
}
-/*
- TestSAO
-*/
-
-// Prototype
-TestSAO proto_TestSAO(NULL, 0, v3f(0,0,0));
-
-TestSAO::TestSAO(ServerEnvironment *env, u16 id, v3f pos):
- ServerActiveObject(env, id, pos),
- m_timer1(0),
- m_age(0)
-{
- ServerActiveObject::registerType(getType(), create);
-}
-
-ServerActiveObject* TestSAO::create(ServerEnvironment *env, u16 id, v3f pos,
- const std::string &data)
-{
- return new TestSAO(env, id, pos);
-}
-
-void TestSAO::step(float dtime, Queue<ActiveObjectMessage> &messages,
- bool send_recommended)
-{
- m_age += dtime;
- if(m_age > 10)
- {
- m_removed = true;
- return;
- }
-
- m_base_position.Y += dtime * BS * 2;
- if(m_base_position.Y > 8*BS)
- m_base_position.Y = 2*BS;
-
- if(send_recommended == false)
- return;
-
- m_timer1 -= dtime;
- if(m_timer1 < 0.0)
- {
- m_timer1 += 0.125;
- //dstream<<"TestSAO: id="<<getId()<<" sending data"<<std::endl;
-
- std::string data;
-
- data += itos(0); // 0 = position
- data += " ";
- data += itos(m_base_position.X);
- data += " ";
- data += itos(m_base_position.Y);
- data += " ";
- data += itos(m_base_position.Z);
-
- ActiveObjectMessage aom(getId(), false, data);
- messages.push_back(aom);
- }
-}
-
-
-/*
- ItemSAO
-*/
-
-// Prototype
-ItemSAO proto_ItemSAO(NULL, 0, v3f(0,0,0), "");
-
-ItemSAO::ItemSAO(ServerEnvironment *env, u16 id, v3f pos,
- const std::string inventorystring):
- ServerActiveObject(env, id, pos),
- m_inventorystring(inventorystring),
- m_speed_f(0,0,0),
- m_last_sent_position(0,0,0)
-{
- ServerActiveObject::registerType(getType(), create);
-}
-
-ServerActiveObject* ItemSAO::create(ServerEnvironment *env, u16 id, v3f pos,
- const std::string &data)
-{
- std::istringstream is(data, std::ios::binary);
- char buf[1];
- // read version
- is.read(buf, 1);
- u8 version = buf[0];
- // check if version is supported
- if(version != 0)
- return NULL;
- std::string inventorystring = deSerializeString(is);
- dstream<<"ItemSAO::create(): Creating item \""
- <<inventorystring<<"\""<<std::endl;
- return new ItemSAO(env, id, pos, inventorystring);
-}
-
-void ItemSAO::step(float dtime, Queue<ActiveObjectMessage> &messages,
- bool send_recommended)
-{
- assert(m_env);
-
- const float interval = 0.2;
- if(m_move_interval.step(dtime, interval)==false)
- return;
- dtime = interval;
-
- core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
- collisionMoveResult moveresult;
- // Apply gravity
- m_speed_f += v3f(0, -dtime*9.81*BS, 0);
- // Maximum movement without glitches
- f32 pos_max_d = BS*0.25;
- // Limit speed
- if(m_speed_f.getLength()*dtime > pos_max_d)
- m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
- v3f pos_f = getBasePosition();
- v3f pos_f_old = pos_f;
- moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
- box, dtime, pos_f, m_speed_f);
-
- if(send_recommended == false)
- return;
-
- if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
- {
- setBasePosition(pos_f);
- m_last_sent_position = pos_f;
-
- std::ostringstream os(std::ios::binary);
- char buf[6];
- // command (0 = update position)
- buf[0] = 0;
- os.write(buf, 1);
- // pos
- writeS32((u8*)buf, m_base_position.X*1000);
- os.write(buf, 4);
- writeS32((u8*)buf, m_base_position.Y*1000);
- os.write(buf, 4);
- writeS32((u8*)buf, m_base_position.Z*1000);
- os.write(buf, 4);
- // create message and add to list
- ActiveObjectMessage aom(getId(), false, os.str());
- messages.push_back(aom);
- }
-}
-
-std::string ItemSAO::getClientInitializationData()
-{
- std::ostringstream os(std::ios::binary);
- char buf[6];
- // version
- buf[0] = 0;
- os.write(buf, 1);
- // pos
- writeS32((u8*)buf, m_base_position.X*1000);
- os.write(buf, 4);
- writeS32((u8*)buf, m_base_position.Y*1000);
- os.write(buf, 4);
- writeS32((u8*)buf, m_base_position.Z*1000);
- os.write(buf, 4);
- // inventorystring
- os<<serializeString(m_inventorystring);
- return os.str();
-}
-
-std::string ItemSAO::getStaticData()
-{
- dstream<<__FUNCTION_NAME<<std::endl;
- std::ostringstream os(std::ios::binary);
- char buf[1];
- // version
- buf[0] = 0;
- os.write(buf, 1);
- // inventorystring
- os<<serializeString(m_inventorystring);
- return os.str();
-}
-
-InventoryItem * ItemSAO::createInventoryItem()
-{
- try{
- std::istringstream is(m_inventorystring, std::ios_base::binary);
- InventoryItem *item = InventoryItem::deSerialize(is);
- dstream<<__FUNCTION_NAME<<": m_inventorystring=\""
- <<m_inventorystring<<"\" -> item="<<item
- <<std::endl;
- return item;
- }
- catch(SerializationError &e)
- {
- dstream<<__FUNCTION_NAME<<": serialization error: "
- <<"m_inventorystring=\""<<m_inventorystring<<"\""<<std::endl;
- return NULL;
- }
-}
-
-
-/*
- RatSAO
-*/
-
-// Prototype
-RatSAO proto_RatSAO(NULL, 0, v3f(0,0,0));
-
-RatSAO::RatSAO(ServerEnvironment *env, u16 id, v3f pos):
- ServerActiveObject(env, id, pos),
- m_is_active(false),
- m_speed_f(0,0,0)
-{
- ServerActiveObject::registerType(getType(), create);
-
- m_oldpos = v3f(0,0,0);
- m_last_sent_position = v3f(0,0,0);
- m_yaw = 0;
- m_counter1 = 0;
- m_counter2 = 0;
- m_age = 0;
- m_touching_ground = false;
-}
-
-ServerActiveObject* RatSAO::create(ServerEnvironment *env, u16 id, v3f pos,
- const std::string &data)
-{
- std::istringstream is(data, std::ios::binary);
- char buf[1];
- // read version
- is.read(buf, 1);
- u8 version = buf[0];
- // check if version is supported
- if(version != 0)
- return NULL;
- return new RatSAO(env, id, pos);
-}
-
-void RatSAO::step(float dtime, Queue<ActiveObjectMessage> &messages,
- bool send_recommended)
-{
- assert(m_env);
-
- if(m_is_active == false)
- {
- if(m_inactive_interval.step(dtime, 0.5)==false)
- return;
- }
-
- /*
- The AI
- */
-
- /*m_age += dtime;
- if(m_age > 60)
- {
- // Die
- m_removed = true;
- return;
- }*/
-
- // Apply gravity
- m_speed_f.Y -= dtime*9.81*BS;
-
- /*
- Move around if some player is close
- */
- bool player_is_close = false;
- // Check connected players
- core::list<Player*> players = m_env->getPlayers(true);
- core::list<Player*>::Iterator i;
- for(i = players.begin();
- i != players.end(); i++)
- {
- Player *player = *i;
- v3f playerpos = player->getPosition();
- if(m_base_position.getDistanceFrom(playerpos) < BS*10.0)
- {
- player_is_close = true;
- break;
- }
- }
-
- m_is_active = player_is_close;
-
- if(player_is_close == false)
- {
- m_speed_f.X = 0;
- m_speed_f.Z = 0;
- }
- else
- {
- // Move around
- v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
- f32 speed = 2*BS;
- m_speed_f.X = speed * dir.X;
- m_speed_f.Z = speed * dir.Z;
-
- if(m_touching_ground && (m_oldpos - m_base_position).getLength()
- < dtime*speed/2)
- {
- m_counter1 -= dtime;
- if(m_counter1 < 0.0)
- {
- m_counter1 += 1.0;
- m_speed_f.Y = 5.0*BS;
- }
- }
-
- {
- m_counter2 -= dtime;
- if(m_counter2 < 0.0)
- {
- m_counter2 += (float)(myrand()%100)/100*3.0;
- m_yaw += ((float)(myrand()%200)-100)/100*180;
- m_yaw = wrapDegrees(m_yaw);
- }
- }
- }
-
- m_oldpos = m_base_position;
-
- /*
- Move it, with collision detection
- */
-
- core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
- collisionMoveResult moveresult;
- // Maximum movement without glitches
- f32 pos_max_d = BS*0.25;
- // Limit speed
- if(m_speed_f.getLength()*dtime > pos_max_d)
- m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
- v3f pos_f = getBasePosition();
- v3f pos_f_old = pos_f;
- moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
- box, dtime, pos_f, m_speed_f);
- m_touching_ground = moveresult.touching_ground;
-
- setBasePosition(pos_f);
-
- if(send_recommended == false)
- return;
-
- if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
- {
- m_last_sent_position = pos_f;
-
- std::ostringstream os(std::ios::binary);
- // command (0 = update position)
- writeU8(os, 0);
- // pos
- writeV3F1000(os, m_base_position);
- // yaw
- writeF1000(os, m_yaw);
- // create message and add to list
- ActiveObjectMessage aom(getId(), false, os.str());
- messages.push_back(aom);
- }
-}
-
-std::string RatSAO::getClientInitializationData()
-{
- std::ostringstream os(std::ios::binary);
- // version
- writeU8(os, 0);
- // pos
- writeV3F1000(os, m_base_position);
- return os.str();
-}
-
-std::string RatSAO::getStaticData()
-{
- //dstream<<__FUNCTION_NAME<<std::endl;
- std::ostringstream os(std::ios::binary);
- // version
- writeU8(os, 0);
- return os.str();
-}
-
-InventoryItem* RatSAO::createPickedUpItem()
-{
- std::istringstream is("CraftItem rat 1", std::ios_base::binary);
- InventoryItem *item = InventoryItem::deSerialize(is);
- return item;
-}
-
-/*
- Oerkki1SAO
-*/
-
-// Prototype
-Oerkki1SAO proto_Oerkki1SAO(NULL, 0, v3f(0,0,0));
-
-Oerkki1SAO::Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos):
- ServerActiveObject(env, id, pos),
- m_is_active(false),
- m_speed_f(0,0,0)
-{
- ServerActiveObject::registerType(getType(), create);
-
- m_oldpos = v3f(0,0,0);
- m_last_sent_position = v3f(0,0,0);
- m_yaw = 0;
- m_counter1 = 0;
- m_counter2 = 0;
- m_age = 0;
- m_touching_ground = false;
- m_hp = 20;
-}
-
-ServerActiveObject* Oerkki1SAO::create(ServerEnvironment *env, u16 id, v3f pos,
- const std::string &data)
-{
- std::istringstream is(data, std::ios::binary);
- // read version
- u8 version = readU8(is);
- // read hp
- u8 hp = readU8(is);
- // check if version is supported
- if(version != 0)
- return NULL;
- Oerkki1SAO *o = new Oerkki1SAO(env, id, pos);
- o->m_hp = hp;
- return o;
-}
-
-void Oerkki1SAO::step(float dtime, Queue<ActiveObjectMessage> &messages,
- bool send_recommended)
-{
- assert(m_env);
-
- if(m_is_active == false)
- {
- if(m_inactive_interval.step(dtime, 0.5)==false)
- return;
- }
-
- /*
- The AI
- */
-
- m_age += dtime;
- if(m_age > 120)
- {
- // Die
- m_removed = true;
- return;
- }
-
- // Apply gravity
- m_speed_f.Y -= dtime*9.81*BS;
-
- /*
- Move around if some player is close
- */
- bool player_is_close = false;
- v3f near_player_pos;
- // Check connected players
- core::list<Player*> players = m_env->getPlayers(true);
- core::list<Player*>::Iterator i;
- for(i = players.begin();
- i != players.end(); i++)
- {
- Player *player = *i;
- v3f playerpos = player->getPosition();
- if(m_base_position.getDistanceFrom(playerpos) < BS*15.0)
- {
- player_is_close = true;
- near_player_pos = playerpos;
- break;
- }
- }
-
- m_is_active = player_is_close;
-
- if(player_is_close == false)
- {
- m_speed_f.X = 0;
- m_speed_f.Z = 0;
- }
- else
- {
- // Move around
-
- v3f ndir = near_player_pos - m_base_position;
- ndir.Y = 0;
- ndir /= ndir.getLength();
- f32 nyaw = 180./PI*atan2(ndir.Z,ndir.X);
- if(nyaw < m_yaw - 180)
- nyaw += 360;
- else if(nyaw > m_yaw + 180)
- nyaw -= 360;
- m_yaw = 0.95*m_yaw + 0.05*nyaw;
- m_yaw = wrapDegrees(m_yaw);
-
- v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
- f32 speed = 2*BS;
- m_speed_f.X = speed * dir.X;
- m_speed_f.Z = speed * dir.Z;
-
- if(m_touching_ground && (m_oldpos - m_base_position).getLength()
- < dtime*speed/2)
- {
- m_counter1 -= dtime;
- if(m_counter1 < 0.0)
- {
- m_counter1 += 1.0;
- // Jump
- m_speed_f.Y = 5.0*BS;
- }
- }
-
- {
- m_counter2 -= dtime;
- if(m_counter2 < 0.0)
- {
- m_counter2 += (float)(myrand()%100)/100*3.0;
- //m_yaw += ((float)(myrand()%200)-100)/100*180;
- m_yaw += ((float)(myrand()%200)-100)/100*90;
- m_yaw = wrapDegrees(m_yaw);
- }
- }
- }
-
- m_oldpos = m_base_position;
-
- /*
- Move it, with collision detection
- */
-
- core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*5./3.,BS/3.);
- collisionMoveResult moveresult;
- // Maximum movement without glitches
- f32 pos_max_d = BS*0.25;
- // Limit speed
- if(m_speed_f.getLength()*dtime > pos_max_d)
- m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
- v3f pos_f = getBasePosition();
- v3f pos_f_old = pos_f;
- moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
- box, dtime, pos_f, m_speed_f);
- m_touching_ground = moveresult.touching_ground;
-
- setBasePosition(pos_f);
-
- if(send_recommended == false)
- return;
-
- if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
- {
- m_last_sent_position = pos_f;
-
- std::ostringstream os(std::ios::binary);
- // command (0 = update position)
- writeU8(os, 0);
- // pos
- writeV3F1000(os, m_base_position);
- // yaw
- writeF1000(os, m_yaw);
- // create message and add to list
- ActiveObjectMessage aom(getId(), false, os.str());
- messages.push_back(aom);
- }
-}
-
-std::string Oerkki1SAO::getClientInitializationData()
-{
- std::ostringstream os(std::ios::binary);
- // version
- writeU8(os, 0);
- // pos
- writeV3F1000(os, m_base_position);
- return os.str();
-}
-
-std::string Oerkki1SAO::getStaticData()
-{
- //dstream<<__FUNCTION_NAME<<std::endl;
- std::ostringstream os(std::ios::binary);
- // version
- writeU8(os, 0);
- // hp
- writeU8(os, m_hp);
- return os.str();
-}
-
-u16 Oerkki1SAO::punch(const std::string &toolname)
-{
- u16 amount = 5;
- if(amount < m_hp)
- {
- m_hp -= amount;
- }
- else
- {
- // Die
- m_removed = true;
- }
- return 65536/100;
-}
-
diff --git a/src/serverobject.h b/src/serverobject.h
index 955969819..c008bf93e 100644
--- a/src/serverobject.h
+++ b/src/serverobject.h
@@ -78,8 +78,7 @@ public:
same time so that the data can be combined in a single
packet.
*/
- virtual void step(float dtime, Queue<ActiveObjectMessage> &messages,
- bool send_recommended){}
+ virtual void step(float dtime, bool send_recommended){}
/*
The return value of this is passed to the client-side object
@@ -104,7 +103,8 @@ public:
If the object doesn't return an item, this will be called.
Return value is tool wear.
*/
- virtual u16 punch(const std::string &toolname){return 0;}
+ virtual u16 punch(const std::string &toolname, v3f dir)
+ {return 0;}
/*
Number of players which know about this object. Object won't be
@@ -144,6 +144,11 @@ public:
*/
v3s16 m_static_block;
+ /*
+ Queue of messages to be sent to the client
+ */
+ Queue<ActiveObjectMessage> m_messages_out;
+
protected:
// Used for creating objects based on type
typedef ServerActiveObject* (*Factory)
@@ -159,96 +164,5 @@ private:
static core::map<u16, Factory> m_types;
};
-class TestSAO : public ServerActiveObject
-{
-public:
- TestSAO(ServerEnvironment *env, u16 id, v3f pos);
- u8 getType() const
- {return ACTIVEOBJECT_TYPE_TEST;}
- static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
- const std::string &data);
- void step(float dtime, Queue<ActiveObjectMessage> &messages,
- bool send_recommended);
-private:
- float m_timer1;
- float m_age;
-};
-
-class ItemSAO : public ServerActiveObject
-{
-public:
- ItemSAO(ServerEnvironment *env, u16 id, v3f pos,
- const std::string inventorystring);
- u8 getType() const
- {return ACTIVEOBJECT_TYPE_ITEM;}
- static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
- const std::string &data);
- void step(float dtime, Queue<ActiveObjectMessage> &messages,
- bool send_recommended);
- std::string getClientInitializationData();
- std::string getStaticData();
- InventoryItem* createInventoryItem();
- InventoryItem* createPickedUpItem(){return createInventoryItem();}
-private:
- std::string m_inventorystring;
- v3f m_speed_f;
- v3f m_last_sent_position;
- IntervalLimiter m_move_interval;
-};
-
-class RatSAO : public ServerActiveObject
-{
-public:
- RatSAO(ServerEnvironment *env, u16 id, v3f pos);
- u8 getType() const
- {return ACTIVEOBJECT_TYPE_RAT;}
- static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
- const std::string &data);
- void step(float dtime, Queue<ActiveObjectMessage> &messages,
- bool send_recommended);
- std::string getClientInitializationData();
- std::string getStaticData();
- InventoryItem* createPickedUpItem();
-private:
- bool m_is_active;
- IntervalLimiter m_inactive_interval;
- v3f m_speed_f;
- v3f m_oldpos;
- v3f m_last_sent_position;
- float m_yaw;
- float m_counter1;
- float m_counter2;
- float m_age;
- bool m_touching_ground;
-};
-
-class Oerkki1SAO : public ServerActiveObject
-{
-public:
- Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos);
- u8 getType() const
- {return ACTIVEOBJECT_TYPE_OERKKI1;}
- static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
- const std::string &data);
- void step(float dtime, Queue<ActiveObjectMessage> &messages,
- bool send_recommended);
- std::string getClientInitializationData();
- std::string getStaticData();
- InventoryItem* createPickedUpItem(){return NULL;}
- u16 punch(const std::string &toolname);
-private:
- bool m_is_active;
- IntervalLimiter m_inactive_interval;
- v3f m_speed_f;
- v3f m_oldpos;
- v3f m_last_sent_position;
- float m_yaw;
- float m_counter1;
- float m_counter2;
- float m_age;
- bool m_touching_ground;
- u8 m_hp;
-};
-
#endif
diff --git a/src/test.cpp b/src/test.cpp
index 7b86750d8..7d71552a8 100644
--- a/src/test.cpp
+++ b/src/test.cpp
@@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <sstream>
#include "porting.h"
#include "content_mapnode.h"
+#include "mapsector.h"
/*
Asserts that the exception occurs
@@ -339,6 +340,12 @@ struct TestVoxelManipulator
}
};
+/*
+ NOTE: These tests became non-working then NodeContainer was removed.
+ These should be redone, utilizing some kind of a virtual
+ interface for Map (IMap would be fine).
+*/
+#if 0
struct TestMapBlock
{
class TC : public NodeContainer
@@ -641,13 +648,13 @@ struct TestMapSector
// Create one with no heightmaps
ServerMapSector sector(&parent, v2s16(1,1));
- EXCEPTION_CHECK(InvalidPositionException, sector.getBlockNoCreate(0));
- EXCEPTION_CHECK(InvalidPositionException, sector.getBlockNoCreate(1));
+ assert(sector.getBlockNoCreateNoEx(0) == 0);
+ assert(sector.getBlockNoCreateNoEx(1) == 0);
MapBlock * bref = sector.createBlankBlock(-2);
- EXCEPTION_CHECK(InvalidPositionException, sector.getBlockNoCreate(0));
- assert(sector.getBlockNoCreate(-2) == bref);
+ assert(sector.getBlockNoCreateNoEx(0) == 0);
+ assert(sector.getBlockNoCreateNoEx(-2) == bref);
//TODO: Check for AlreadyExistsException
@@ -662,6 +669,7 @@ struct TestMapSector
}
};
+#endif
struct TestSocket
{
@@ -1028,8 +1036,8 @@ void run_tests()
TEST(TestCompress);
TEST(TestMapNode);
TEST(TestVoxelManipulator);
- TEST(TestMapBlock);
- TEST(TestMapSector);
+ //TEST(TestMapBlock);
+ //TEST(TestMapSector);
if(INTERNET_SIMULATOR == false){
TEST(TestSocket);
dout_con<<"=== BEGIN RUNNING UNIT TESTS FOR CONNECTION ==="<<std::endl;