Compare commits

..

150 Commits

Author SHA1 Message Date
Perttu Ahola
1a3d25c5ad Update changelog and call this 0.3.3 2013-03-05 18:53:24 +02:00
Perttu Ahola
30cbdb0981 Check password hash validity 2013-03-05 18:49:30 +02:00
Perttu Ahola
073964a12f Update changelog and call this 0.3.2 2012-05-12 22:41:42 +03:00
Perttu Ahola
d7442aecbe Add wooden planks to creative inventory (...finally 8D) 2012-05-12 22:34:59 +03:00
Perttu Ahola
1596628850 Add #include <unistd.h> to filesys.cpp (needed by some linux distros now) 2012-05-12 22:29:26 +03:00
Perttu Ahola
bc0e5c0063 Update changelog and call this 0.3.1 2011-11-09 12:07:40 +02:00
Perttu Ahola
045e32b6ec Fix water-glass and water-lava surfaces 2011-11-08 16:17:38 +02:00
Perttu Ahola
fea55a9b87 Call this 0.3.dev-20111108 2011-11-08 02:13:29 +02:00
Perttu Ahola
763da10c7b Reset block usage timer on client only if it is very probably drawn 2011-11-08 02:13:22 +02:00
Kahrl
1c98ec94da Make Connection::Receive return the data via a SharedBuffer reference, so the caller doesn't have to choose the right buffer size in advance.
Conflicts:

	src/test.cpp
2011-11-07 11:21:42 +02:00
Kahrl
28660b4c1a utility.h: Change Buffer's interface to be more compatible with SharedBuffer's interface, connection.h: use Buffer instead of SharedBuffer in command and event queues 2011-11-07 11:19:56 +02:00
Perttu Ahola
fa72e65b59 Add new Connection test in test.cpp in case needed in the future (commented out), improve comments in test.cpp a bit 2011-11-07 11:15:43 +02:00
Perttu Ahola
7d5d676eac Infinite packet flood test for debugging the new network layer 2011-11-07 01:20:58 +02:00
Constantin Wenger
61f2cc45c2 Command-line signal handling for Windows 2011-11-06 19:24:44 +02:00
Perttu Ahola
c1d92d72e1 Make water invisible next to underwater glass 2011-11-05 23:30:27 +02:00
Perttu Ahola
4f71a9fbde Improve "compile on Windows" section in readme 2011-11-05 14:48:32 +02:00
Perttu Ahola
4142b8c352 Call this version 0.3.dev-20111104 2011-11-04 22:16:36 +02:00
Perttu Ahola
d0fdfd44c5 Add option to set water opaque (mainly for stylistic choice) 2011-11-03 23:06:57 +02:00
Perttu Ahola
f5995337e8 Fix flowing liquid spacing; water and lava next to each other will glitch a bit but it isn't as bad as this was 2011-11-03 23:04:56 +02:00
Perttu Ahola
1469196d3b Update /README.txt, remove duplicate /doc/README.txt and update CMakeLists.txt to package /README.txt 2011-11-03 21:36:42 +02:00
Perttu Ahola
e9fd3def90 Make CONTENT_IGNORE to not block the view when occlusion culling 2011-11-03 20:45:44 +02:00
Perttu Ahola
a2af490b7b Disable mipmapping because it is sometimes ugly 2011-11-03 20:17:18 +02:00
Perttu Ahola
4964daa5be Possible fix to bases of islands/hills getting culled out too early 2011-11-03 15:10:58 +02:00
Perttu Ahola
718086f383 Tune occlusion culling a bit more 2011-11-03 13:35:32 +02:00
Perttu Ahola
339b7588d2 Tune occlusion culling a bit 2011-11-03 13:35:09 +02:00
Perttu Ahola
0ac5f6a7ca Very simple occlusion culling 2011-11-03 12:48:08 +02:00
Perttu Ahola
1726b82a16 occlusion culling fix, a little reshaping of map rendering for more useful profiler output and dynamic profiler text size 2011-11-02 18:13:56 +02:00
Perttu Ahola
03db16d55b Remove trailing / or \ in path_userdata (probably fixes world deletion on Windows) 2011-11-02 13:43:00 +02:00
Perttu Ahola
0c20973c17 Add 3d cloud checkbox in main menu (and rename setting from enable_2d_clouds to enable_3d_clouds) 2011-11-02 12:50:21 +02:00
Perttu Ahola
f65d157786 Set version to 0.3.0 and update changelog 2011-11-01 16:54:01 +02:00
Perttu Ahola
899404f3b1 Fix an obvious bug in utility.h 2011-11-01 14:54:11 +02:00
Perttu Ahola
6aab526989 Attempt a workaround to the network layer segfault 2011-10-30 11:59:23 +02:00
Perttu Ahola
c349708eab Make it to compile on MSVC2010 2011-10-21 18:37:43 +03:00
Perttu Ahola
9c3e0a8040 0.3.dev-20111021 2011-10-21 18:29:13 +03:00
Perttu Ahola
7f25183936 Some tuning in m_max_packets_per_second algorithm 2011-10-21 11:52:26 +03:00
Perttu Ahola
4b6138e69b Improve Connection with threading and some kind of congestion control 2011-10-20 23:04:09 +03:00
Perttu Ahola
b6fcbc5fba Default max_simultaneous_block_sends_server_total to 2 to make network not cough too much on the fixed block sending code 2011-10-19 19:34:47 +03:00
Perttu Ahola
ed870a7237 Fix apple inventory texture 2011-10-19 02:36:46 +03:00
Perttu Ahola
3a06fb8831 Fix and tune block sending 2011-10-19 02:17:23 +03:00
Perttu Ahola
d47120aeb3 Add enable_2d_clouds setting for usage on lower-end machines 2011-10-18 23:55:55 +03:00
Perttu Ahola
9b907dd65a Try to tune fog to work well on high-end machines also 2011-10-18 21:08:31 +03:00
Perttu Ahola
28f2fdb6de Fix possible NULL dereference in MobV2CAO::step 2011-10-18 19:53:34 +03:00
Perttu Ahola
4e1055543c Tune map rendering and related diagnostics 2011-10-18 19:18:01 +03:00
Perttu Ahola
8ead29a302 set backface culling off again for torches, ladders, rails and signs 2011-10-18 18:32:35 +03:00
Perttu Ahola
fe98fe342a ...Make the the server buildable again after the last commit 2011-10-18 17:20:54 +03:00
Perttu Ahola
554f7f120c Improve rendering and fix tiling in mesh generation 2011-10-18 13:56:35 +03:00
Perttu Ahola
05ab58cd14 Automate texture listing for texture atlas making 2011-10-18 11:31:23 +03:00
Perttu Ahola
eae2d35ca5 Fix client profiler print interval 2011-10-18 10:36:52 +03:00
Perttu Ahola
85002883bd Better handling of SendFailedException in Connection 2011-10-18 03:42:23 +03:00
Perttu Ahola
22b07bdb30 Fix object duplication bug 2011-10-18 02:58:15 +03:00
Perttu Ahola
fe338745a3 Make active_block_range default to 2 2011-10-18 00:41:17 +03:00
Perttu Ahola
6ce0c61dc0 Fix possible NULL pointer access in MobV2CAO 2011-10-18 00:41:02 +03:00
Perttu Ahola
78f4142f4f Add /clearobjects 2011-10-18 00:01:50 +03:00
Perttu Ahola
ea1fda5ebc Made a scheme to get rid of the objects in the worst object flooded blocks 2011-10-17 20:57:58 +03:00
Perttu Ahola
67db77b8b3 Modify default active block range 2011-10-17 20:41:43 +03:00
Perttu Ahola
64c4d00693 F2 toggles profiler display in client 2011-10-17 20:40:55 +03:00
Perttu Ahola
6661d9be1a Attempt to fix objects getting multiplicated by objects getting deactivated in a different block than where they were loaded and then the original block, from where the static object was removed, not getting saved at unload 2011-10-17 20:19:37 +03:00
Perttu Ahola
c41f1c960b Fix minetest.conf.example a bit 2011-10-17 20:04:35 +03:00
Perttu Ahola
9a62a909bc Add a log message to SEnv and make it load objects if there are < 51 of them, to load blocks that were limited to 50 2011-10-17 19:44:28 +03:00
Perttu Ahola
93f4d2b3f1 Catch SendFailedException when replying back in Connection::Receive() 2011-10-17 18:02:26 +03:00
Perttu Ahola
558a133044 Display RTT (round trip time, ping) on client status text 2011-10-17 17:18:50 +03:00
Perttu Ahola
5037efdea9 Add some rendering statistics to profiler 2011-10-17 17:06:28 +03:00
Perttu Ahola
e9888c8e25 Workaround for blocks having a huge amount of active objects; add log messages related to active objects for investigation 2011-10-17 11:52:38 +03:00
Perttu Ahola
3daaff3a42 Remove very floody log message of MobV2SAO 2011-10-17 11:45:06 +03:00
celeron55
d39f98aeb0 Improve active object handling log output 2011-10-17 10:47:06 +03:00
celeron55
30c21b4abd Fix partly double printed debug.txt 2011-10-17 10:46:16 +03:00
Perttu Ahola
cfd19dcdb5 Fix punching of oerkkis 2011-10-17 01:58:38 +03:00
Perttu Ahola
b0481b9db1 Fix chest not working after walked away and came back 2011-10-17 01:04:22 +03:00
Perttu Ahola
5f39885975 Improve inventory debug output 2011-10-17 01:03:45 +03:00
Perttu Ahola
9ff8067426 Fix items showing up as sticks when placed in world 2011-10-17 00:08:27 +03:00
Perttu Ahola
162619a426 Fix to-transparend conversion of backgrounds of sprite image files that don't have an alpha channel 2011-10-16 23:41:43 +03:00
Perttu Ahola
2419d0029a Some more profiler stuff to get the hang on what really uses CPU 2011-10-16 22:39:35 +03:00
Perttu Ahola
b8f2dcea4d Improve debug profiler usage for investigating CPU usage of server 2011-10-16 21:16:44 +03:00
Perttu Ahola
07d000cc54 When granting or revoking privileges, notify the target player too 2011-10-16 20:03:43 +03:00
Perttu Ahola
6470743e51 Make dungeon masters not shoot the walls with no reason 2011-10-16 19:39:20 +03:00
Perttu Ahola
143dce6672 When player times out, log the action as a timeout rather than regular quitting 2011-10-16 19:38:56 +03:00
Perttu Ahola
96b2d1fd29 Check NULL pointer properly in some new code trying to log new stuff 2011-10-16 18:50:30 +03:00
Perttu Ahola
369177aa80 Better player damage prevention when falling on unloaded blocks, not involving getting stuck in there. 2011-10-16 18:45:17 +03:00
Perttu Ahola
0bf533f753 Switch more stuff to use the logging thing and fix segfault on player leave from server as introduced in a previous switch-to-logging commit 2011-10-16 16:28:12 +03:00
Perttu Ahola
67a6bc4ab5 Fix map delete on windows (concatenate paths correctly with / or \ depending on OS) 2011-10-16 16:16:47 +03:00
Perttu Ahola
ef397dca7c Update changelog (albeit a bit late) 2011-10-16 15:20:04 +03:00
Perttu Ahola
b65a5aceb0 Use the logger; also, default to not showing much crap in console. Use --info-on-stderr to enable crap. 2011-10-16 14:57:53 +03:00
Perttu Ahola
4846846a2d Initially add small and tight logging facility 2011-10-16 12:45:00 +03:00
Perttu Ahola
414c614893 Add peaceful / not peaceful distinction in mobs and the only_peaceful_mobs setting 2011-10-16 11:52:33 +03:00
Perttu Ahola
a17abae128 Update Linux build instructions in README.txt a bit and list the bat script used for releases 2011-10-16 03:08:11 +03:00
Perttu Ahola
286edd4f1e Update version number to 0.3.dev-20111016 2011-10-16 00:53:37 +03:00
Perttu Ahola
4914eb29d1 Replace M_PI with PI 2011-10-16 00:24:51 +03:00
Perttu Ahola
825953bbdc Fix some "Conditional jump or move depends on uninitialised value(s)" valgrind detections 2011-10-15 23:07:43 +03:00
Perttu Ahola
fd6452749e Resource file handling for exe icon for MinGW 2011-10-15 17:05:16 +03:00
Perttu Ahola
7c2639ddd9 Make view bobbing amount configurable 2011-10-15 16:32:24 +03:00
Perttu Ahola
3f58028d31 Make dungeon masters though and make oerkkis disappear when they get to you (because hitting them doesn't work for some unknown reason) 2011-10-15 16:04:25 +03:00
Perttu Ahola
94dfececf6 strict_protocol_version_checking setting; PROTOCOL_VERSION in clientserver.h; clean up defaultsettings.cpp and minetest.conf.example 2011-10-15 15:02:28 +03:00
Perttu Ahola
74febd5c31 Handle death and respawn better 2011-10-15 14:46:59 +03:00
Perttu Ahola
857fe0551c Set a better version number 2011-10-15 12:51:30 +03:00
Perttu Ahola
5341bf59c2 Improve mobv2 2011-10-15 12:17:21 +03:00
Perttu Ahola
43a28f04fa mobv2 2011-10-15 02:28:57 +03:00
Perttu Ahola
080002f8ed Lock mutex when accessing m_env in Server::~Server 2011-10-14 12:39:25 +03:00
Perttu Ahola
853a78681e In CMake scripts: New version number, fix MSVC stuff 2011-10-14 09:55:39 +03:00
Perttu Ahola
9e46cbf7ea Header file tweaking; mainly for speed 2011-10-12 13:53:38 +03:00
Perttu Ahola
b60b58b627 Saner block modification flag operation for not saving everything always 2011-10-12 10:53:37 +03:00
Kahrl
3e975d8f28 minetestmapper: Fix the way ylist is computed, use cStringIO instead of rolling own Bytestream, remove some artifacts when drawing underground blocks, introduce a --drawunderground switch (defaults to of), 'blocknum' renamed to 'content'. 2011-09-27 02:38:19 +02:00
Perttu Ahola
a7833cca22 Merge remote-tracking branch 'marktraceur/master' 2011-09-26 22:41:06 +03:00
Perttu Ahola
08ac3454cc minetestmapper speed tweaks (kahrl & JacobF) 2011-09-26 22:31:34 +03:00
Perttu Ahola
3ca847b4e1 Add apple color to minetestmapper and fix cactus color 2011-09-26 20:55:00 +03:00
Perttu Ahola
e7fcc08d26 Fix minetestmapper.py 2011-09-26 20:54:42 +03:00
Perttu Ahola
520b470217 Merge remote-tracking branch 'kahrl/sectors2sqlite-fix' 2011-09-26 20:01:46 +03:00
Perttu Ahola
9a7471b740 Rotate wielded tool the right way and modify axe graphics accordingly 2011-09-26 16:10:54 +03:00
Perttu Ahola
061d4b4202 Merge branch 'view_bobbing_and_vielded_tool' 2011-09-26 15:10:02 +03:00
Perttu Ahola
2ecd53ce09 Fix single-frame lag in camera yaw/pitch, tune view bobbing and add wielded tool movement when walking and tweak stuff a bit 2011-09-26 15:09:04 +03:00
Kahrl
561bb64963 Support Python 2 and 3 in sectors2sqlite.py. 2011-09-26 13:24:21 +02:00
Kahrl
d5899a53fd Fix processing of blocks below y=0 in sectors2sqlite.py. 2011-09-26 13:10:22 +02:00
Perttu Ahola
b9e680d06c Server user limit configuration option 2011-09-26 11:57:51 +03:00
Perttu Ahola
0ccc0ac927 Merge remote-tracking branch 'darkrose/master' 2011-09-26 11:57:28 +03:00
celeron55
63eca0feb2 Merge pull request #10 from joshbeck/master
Fixed null pointer dereference errors found by cppcheck
2011-09-24 00:55:05 -07:00
Joshua Beck
ae561d705f Fixed null pointer dereference errors found by cppcheck 2011-09-24 02:11:43 -05:00
Mark Holmquist
bc01ae4cbd Fixed merge issues with saplings, ready to pull now! 2011-09-23 18:19:47 -07:00
Mark Holmquist
319f43e6d2 Fixed saplings growing into trees (thanks so much, Kahrl!)
Put the random interval back to 1 in 50 chance. It's not as rare as rats, but rarer than grass.
2011-09-23 18:14:35 -07:00
Mark Holmquist
f19919546d Adding sapling texture 2011-09-23 18:13:53 -07:00
Mark Holmquist
85f119e1e6 Adding (most) of the sapling functionality. It has yet to work, since MEET_OTHER was not implemented at the time of this commit. Hopefully it will work when merged with celeron's latest. 2011-09-23 18:13:53 -07:00
darkrose
8b875d71d1 remove content_* things from map.cpp 2011-09-23 18:04:48 +10:00
Perttu Ahola
789c88509c Move PLATFORM_LIBS around to make sqlite3 link with libdl on some distros 2011-09-23 08:48:58 +03:00
Perttu Ahola
bdf54908aa Make client report a newer version number to the server than 2011-07-31 does and make the server enforce it 2011-09-22 20:47:47 +03:00
darkrose
79cb754358 added locking chest texture 2011-09-22 19:12:17 +10:00
darkrose
582e450bad added locking chests - clean patch 2011-09-22 19:11:48 +10:00
Kahrl
3e012122d1 Simplistic wielded tool lighting, added setMeshVerticesColor to utility.h and refactored some other code into calls of that 2011-09-21 18:37:29 +02:00
Kahrl
a4a2c34831 reduce view bobbing slightly 2011-09-21 15:54:06 +02:00
Kahrl
36af9bb027 Create a separate scene manager for the wielded tool. This fixes the glitchyness in large map coordinates and some depth buffer problems. (The tool doesn't bob anymore when walking, this will be fixed later.) Fix MSVC build (thanks to dannydark). 2011-09-21 01:42:52 +02:00
Kahrl
6599002149 fix a numerical problem, but tool is still jittery 2011-09-20 18:25:29 +02:00
Kahrl
cbd2bcf102 Fix jittery view bobbing at large map coordinates again. Wielded tool still has problems there 2011-09-20 18:19:26 +02:00
Kahrl
01f3ae1c50 Digging animation 2011-09-20 11:06:16 +02:00
Kahrl
eaff4616ad fix some normals 2011-09-19 17:11:53 +02:00
Kahrl
ab42549b1e Wielded tool updates, leaves and glass work now 2011-09-19 17:08:42 +02:00
Kahrl
02726f0003 Convert any inventory item into a mesh, bring back InventoryItem::getImageRay(), some const-correctness fixes 2011-09-19 06:37:24 +02:00
Kahrl
36bcbca9ac Added sprite extruder 2011-09-19 03:01:11 +02:00
Kahrl
4ed837bcfa trying some view bobbing changes 2011-09-18 17:02:30 +02:00
Kahrl
54f3796f91 Oops, up vector is needed. 2011-09-18 02:24:43 +02:00
Kahrl
ae66d611f2 This looks more like MC view bobbing, but still not even close 2011-09-18 02:17:39 +02:00
Kahrl
acfb2bb8bc Revert some changes that could lead to slower map transfer and increaed network load. 2011-09-16 18:03:58 +02:00
Kahrl
63266928a5 Made wielded tool move slightly (and smoothly) during view bobbing. Making the tool be a child node of an empty scene node instead of the camera scene node seemingly fixed the uncontrollable tool jitter, too. 2011-09-15 01:53:42 +02:00
Kahrl
fc92da4324 View bobbing is slower in the water. 2011-09-15 01:53:42 +02:00
Kahrl
524cf237b8 inventory displays tool breakage bar again 2011-09-08 17:45:39 +02:00
Kahrl
e4cb004460 trying something else... also replaced M_PI by PI everywhere 2011-09-08 16:10:44 +02:00
Kahrl
71418639d3 attempting to merge Queatz/the-wielded-tool and kahrl/viewbobbing, something doesn't work right yet 2011-09-08 14:21:56 +02:00
Kahrl
f2ec226521 minor view bobbing improvements 2011-09-08 13:34:28 +02:00
Kahrl
0931d4b7ff make it slightly less annoying :o) 2011-09-08 13:14:59 +02:00
Kahrl
ccadebabba Implemented view bobbing (testing simple lemniscate shape) 2011-09-08 13:03:55 +02:00
Kahrl
18771a39cf Commented out debug statements again 2011-09-08 01:24:47 +02:00
Kahrl
baf7da9d4a Collected and moved existing camera infrastructure from game.cpp to camera.cpp and camera.h. Introduced configuration settings 'fov' which chooses the camera's (vertical) field of view and 'view_bobbing' which currently does nothing. Other code refactored to not expect the FOV to be a build time constant. 2011-09-08 01:08:47 +02:00
Kahrl
c0b35fa429 Removed unused camera_position and camera_direction fields from Client. Moved ClientEnvironment::drawPostFx to ClientMap::renderPostFx -- this will make the camera management classes easier to write, as ClientMap already knows the camera position but ClientEnvironment doesn't and has to be told about it. This also eliminates the need for Client::getEnv(). Made the post effect color a content feature defined in content_mapnode.h. 2011-09-07 19:21:28 +02:00
JacobF
f31b0a3361 Display which tool the player is holding
And some simple animation when trying to dig...
2011-09-07 10:56:04 -04:00
101 changed files with 9422 additions and 6853 deletions

View File

@@ -7,11 +7,14 @@ endif(${CMAKE_VERSION} STREQUAL "2.8.2")
# This can be read from ${PROJECT_NAME} after project() is called
project(minetest)
# Also remember to set PROTOCOL_VERSION in clientserver.h when releasing
set(VERSION_MAJOR 0)
set(VERSION_MINOR 2)
set(VERSION_PATCH 20110922)
set(VERSION_MINOR 3)
set(VERSION_PATCH 3)
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
MESSAGE(STATUS "*** Will build version ${VERSION_STRING} ***")
# Configuration options
if(WIN32)
@@ -63,7 +66,7 @@ elseif(UNIX) # Linux, BSD etc
set(EXAMPLE_CONF_DIR "share/doc/${PROJECT_NAME}")
endif()
install(FILES "doc/README.txt" DESTINATION "${DOCDIR}")
install(FILES "README.txt" DESTINATION "${DOCDIR}")
install(FILES "doc/changelog.txt" DESTINATION "${DOCDIR}")
install(FILES "minetest.conf.example" DESTINATION "${DOCDIR}")

View File

@@ -54,12 +54,12 @@ Compiling on GNU/Linux:
-----------------------
Install dependencies. Here's an example for Debian/Ubuntu:
$ apt-get install build-essential libirrlicht-dev cmake libbz2-dev libpng12-dev libjpeg8-dev libxxf86vm-dev libgl1-mesa-dev
$ apt-get install build-essential libirrlicht-dev cmake libbz2-dev libpng12-dev libjpeg8-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev
Download source, extract (this is the URL to the latest of source repository, which might not work at all times):
$ wget https://bitbucket.org/celeron55/minetest/get/tip.tar.gz
$ tar xf tip.tar.gz
$ cd minetest
$ wget https://github.com/celeron55/minetest/tarball/master -O master.tar.gz
$ tar xf master.tar.gz
$ cd celeron55-minetest-286edd4 (or similar)
Build a version that runs directly from the source directory:
$ cmake . -DRUN_IN_PLACE=1
@@ -73,7 +73,7 @@ $ ./minetest
- If you want to install it system-wide (or are making a distribution package), you will want to use -DRUN_IN_PLACE=0
- You can build a bare server or a bare client by specifying -DBUILD_CLIENT=0 or -DBUILD_SERVER=0
- You can select between Release and Debug build by -DCMAKE_BUILD_TYPE=<Debug or Release>
- Note that the Debug build is considerably slower
- Debug build is slower, but gives much more useful output in a debugger
Compiling on Windows:
---------------------
@@ -90,16 +90,18 @@ Compiling on Windows:
http://www.winimage.com/zLibDll/index.html
* Zlib library (zlibwapi.lib and zlibwapi.dll from zlib125dll.zip):
http://www.winimage.com/zLibDll/index.html
* gettext bibrary and tools:
* Optional: gettext bibrary and tools:
http://gnuwin32.sourceforge.net/downlinks/gettext.php
- This is used for other UI languages. Feel free to leave it out.
* And, of course, Minetest-c55:
http://celeron.55.lt/~celeron55/minetest/download
- Steps:
- Select a directory called DIR hereafter in which you will operate.
- Make sure you have CMake and a compiler installed.
- Download all the other stuff to DIR and extract them into there. All those
packages contain a nice base directory in them, which should end up being
the direct subdirectories of DIR.
- Download all the other stuff to DIR and extract them into there.
("extract here", not "extract to packagename/")
- All those packages contain a nice base directory in them, which
should end up being the direct subdirectories of DIR.
- You will end up with a directory structure like this (+=dir, -=file):
-----------------
+ DIR
@@ -119,7 +121,7 @@ Compiling on Windows:
+ lib
+ include
...
+ gettext
+ gettext (optional)
+bin
+include
+lib
@@ -163,7 +165,8 @@ Compiling on Windows:
If using MSVC:
- Open the generated minetest.sln
- The project defaults to the "Debug" configuration. Make very sure to
select "Release", unless you want to debug some stuff (it's slower)
select "Release", unless you want to debug some stuff (it's slower
and might not even work at all)
- Build the ALL_BUILD project
- Build the INSTALL project
- You should now have a working game with the executable in
@@ -176,6 +179,30 @@ Compiling on Windows:
- You should now have a working game with the executable in
DIR/minetest/bin/minetest.exe
Windows releases of minetest are built using a bat script like this:
--------------------------------------------------------------------
set installpath="C:\tmp\minetest_install"
set irrlichtpath="C:\tmp\irrlicht-1.7.2"
set sourcedir=%CD%
set builddir=%sourcedir%\bvc10
mkdir %builddir%
pushd %builddir%
cmake %sourcedir% -G "Visual Studio 10" -DIRRLICHT_SOURCE_DIR=%irrlichtpath% -DRUN_IN_PLACE=1 -DCMAKE_INSTALL_PREFIX=%installpath%
"C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" ALL_BUILD.vcxproj /p:Configuration=Release
"C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" INSTALL.vcxproj /p:Configuration=Release
"C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" PACKAGE.vcxproj /p:Configuration=Release
popd
License of Minetest-c55 textures
--------------------------------
This does not apply to texture packs made by others.
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
http://creativecommons.org/licenses/by-sa/3.0/
License of Minetest-c55
-----------------------

BIN
data/chest_lock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

BIN
data/dungeon_master.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
data/fireball.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

BIN
data/sapling.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 B

After

Width:  |  Height:  |  Size: 927 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 B

After

Width:  |  Height:  |  Size: 931 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 B

After

Width:  |  Height:  |  Size: 927 B

View File

@@ -1,238 +0,0 @@
Minetest-c55
---------------
An InfiniMiner/Minecraft inspired game.
Copyright (c) 2010-2011 Perttu Ahola <celeron55@gmail.com>
Further documentation:
----------------------
- Website: http://celeron.55.lt/~celeron55/minetest/
- Wiki: http://celeron.55.lt/~celeron55/minetest/wiki/
- Forum: http://celeron.55.lt/~celeron55/minetest/forum/
This is a development version:
------------------------------
- Don't expect it to work as well as a finished game will.
- Please report any bugs to me. That way I can fix them to the next release.
- debug.txt is useful when the game crashes.
Controls:
---------
- See the in-game pause menu
- Settable in the configuration file, see the section below.
Map directory:
--------------
- Map is stored in a directory, which can be removed to generate a new map.
- There is a command-line option for it: --map-dir
- For a RUN_IN_PLACE build, it is located in:
../map
- Otherwise something like this:
Windows: C:\Documents and Settings\user\Application Data\minetest\map
Linux: ~/.minetest/map
OS X: ~/Library/Application Support/minetest/map
Configuration file:
-------------------
- An optional configuration file can be used. See minetest.conf.example.
- Path to file can be passed as a parameter to the executable:
--config <path-to-file>
- Defaults:
- If built with -DRUN_IN_PLACE=1:
../minetest.conf
../../minetest.conf
- Otherwise something like this:
Windows: C:\Documents and Settings\user\Application Data\minetest\minetest.conf
Linux: ~/.minetest/minetest.conf
OS X: ~/Library/Application Support/minetest.conf
Command-line options:
---------------------
- Use --help
Compiling on GNU/Linux:
-----------------------
Install dependencies. Here's an example for Debian/Ubuntu:
$ apt-get install build-essential libirrlicht-dev cmake libbz2-dev libpng12-dev libjpeg8-dev libxxf86vm-dev libgl1-mesa-dev
Download source, extract (this is the URL to the latest of source repository, which might not work at all times):
$ wget https://bitbucket.org/celeron55/minetest/get/tip.tar.gz
$ tar xf tip.tar.gz
$ cd minetest
Build a version that runs directly from the source directory:
$ cmake . -DRUN_IN_PLACE=1
$ make -j2
Run it:
$ cd bin
$ ./minetest
- Use cmake . -LH to see all CMake options and their current state
- If you want to install it system-wide (or are making a distribution package), you will want to use -DRUN_IN_PLACE=0
- You can build a bare server or a bare client by specifying -DBUILD_CLIENT=0 or -DBUILD_SERVER=0
- You can select between Release and Debug build by -DCMAKE_BUILD_TYPE=<Debug or Release>
- Note that the Debug build is considerably slower
Compiling on Windows:
---------------------
- You need:
* CMake:
http://www.cmake.org/cmake/resources/software.html
* MinGW or Visual Studio
http://www.mingw.org/
http://msdn.microsoft.com/en-us/vstudio/default
* Irrlicht SDK 1.7:
http://irrlicht.sourceforge.net/downloads.html
* Zlib headers (zlib125.zip)
http://www.winimage.com/zLibDll/index.html
* Zlib library (zlibwapi.lib and zlibwapi.dll from zlib125dll.zip):
http://www.winimage.com/zLibDll/index.html
* And, of course, Minetest-c55:
http://celeron.55.lt/~celeron55/minetest/download
- Steps:
- Select a directory called DIR hereafter in which you will operate.
- Make sure you have CMake and a compiler installed.
- Download all the other stuff to DIR and extract them into there. All those
packages contain a nice base directory in them, which should end up being
the direct subdirectories of DIR.
- You will end up with a directory structure like this (+=dir, -=file):
-----------------
+ DIR
- zlib-1.2.5.tar.gz
- zlib125dll.zip
- irrlicht-1.7.1.zip
- 110214175330.zip (or whatever, this is the minetest source)
+ zlib-1.2.5
- zlib.h
+ win32
...
+ zlib125dll
- readme.txt
+ dll32
...
+ irrlicht-1.7.1
+ lib
+ include
...
+ minetest
+ src
+ doc
- CMakeLists.txt
...
-----------------
- Start up the CMake GUI
- Select "Browse Source..." and select DIR/minetest
- Now, if using MSVC:
- Select "Browse Build..." and select DIR/minetest-build
- Else if using MinGW:
- Select "Browse Build..." and select DIR/minetest
- Select "Configure"
- Select your compiler
- It will warn about missing stuff, ignore that at this point. (later don't)
- Make sure the configuration is as follows
(note that the versions may differ for you):
-----------------
BUILD_CLIENT [X]
BUILD_SERVER [ ]
CMAKE_BUILD_TYPE Release
CMAKE_INSTALL_PREFIX DIR/minetest-install
IRRLICHT_SOURCE_DIR DIR/irrlicht-1.7.1
RUN_IN_PLACE [X]
WARN_ALL [ ]
ZLIB_DLL DIR/zlib125dll/dll32/zlibwapi.dll
ZLIB_INCLUDE_DIR DIR/zlib-1.2.5
ZLIB_LIBRARIES DIR/zlib125dll/dll32/zlibwapi.lib
-----------------
- Hit "Configure"
- Hit "Generate"
If using MSVC:
- Open the generated minetest.sln
- The project defaults to the "Debug" configuration. Make very sure to
select "Release", unless you want to debug some stuff (it's slower)
- Build the ALL_BUILD project
- Build the INSTALL project
- You should now have a working game with the executable in
DIR/minetest-install/bin/minetest.exe
- Additionally you may create a zip package by building the PACKAGE
project.
If using MinGW:
- Using the command line, browse to the build directory and run 'make'
(or mingw32-make or whatever it happens to be)
- You should now have a working game with the executable in
DIR/minetest/bin/minetest.exe
License of Minetest-c55
-----------------------
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.
Irrlicht
---------------
This program uses the Irrlicht Engine. http://irrlicht.sourceforge.net/
The Irrlicht Engine License
Copyright © 2002-2005 Nikolaus Gebhardt
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must
not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
JThread
---------------
This program uses the JThread library. License for JThread follows:
Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

View File

@@ -3,6 +3,46 @@ Minetest-c55 changelog
This should contain all the major changes.
For minor stuff, refer to the commit log of the repository.
0.3.3: (tagged on 2013-03-05)
- Fix a password-related vulnerability (late backport from some early 0.4)
0.3.2: (tagged on 2012-05-12)
- Include unistd.h in filesys.cpp
- Add wooden planks to creative inventory
0.3.1: (released on 2011-11-09)
- Fix frustum culling (previous versions have rendered too much stuff that is not actually visible (about 180 degrees, while should have been more like 100.))
- Add occlusion culling (improves performance a lot)
- Add “3d clouds” on/off checkbox in main menu
- Add “opaque water” on/off checkbox
- Fix some random minor stuff
- Turn mipmapping off (This makes far-away textures a bit noisier but better looking)
- Add Command-line signal handler for Windows (contributed by SpeedProg)
- Fix network layer segmentation fault introduced in 0.3.dev-20111021
- Fix water-glass and water-lava and lava-glass surfaces
0.3.0: (released on 2011-11-01)
- Some small fixes
0.3.dev-20111021:
- Modify dungeon masters to only try to shoot players
- Fix object duplication bug at block load/unload bug
- Improve network layer
0.3.dev-20111016:
- Locked chest (contributed)
- Server user limit setting (max_users)
- Wielded tool is shown in HUD (contributed)
- View bobbing (contributed)
- Saplings that drop from leaf blocks and when placed on ground will grow to trees (contributed)
- Optimized map saving (does not re-save everything all the time)
- New mob system and new mob: dungeon master
- Death/respawn screen
0.2.20110922_3:
- Fix the build for MSVC2010; also released for windows using MSVC2010.
0.2.20110922_1:
- Make client report a newer version number to the server than 2011-07-31 does and make server disallow old clients
0.2.20110922:
- Map is saved in an SQLite database file (by Queatz)
- Ladders (MarkTraceur)

View File

@@ -85,5 +85,10 @@ Furnace metadata:
Chest metadata:
TBD
Locking Chest metadata:
u16 string_len
u8[string_len] string
TBD
// END

View File

@@ -39,6 +39,8 @@
#keymap_jump = KEY_SPACE
#keymap_sneak = KEY_LSHIFT
#keymap_inventory = KEY_KEY_I
# Go down ladder / go down in fly mode / go fast in fast mode
#keymap_special1 = KEY_KEY_E
#keymap_chat = KEY_KEY_T
#keymap_rangeselect = KEY_KEY_R
#keymap_freemove = KEY_KEY_K
@@ -46,7 +48,6 @@
#keymap_frametime_graph = KEY_F1
#keymap_screenshot = KEY_F12
# Some (temporary) keys for debugging
#keymap_special1 = KEY_KEY_E
#keymap_print_debug_stacks = KEY_KEY_P
# The desired FPS
@@ -58,8 +59,8 @@
#viewing_range_nodes_max = 300
#viewing_range_nodes_min = 25
# Initial window size
screenW# = 800
screenH# = 600
#screenW = 800
#screenH = 600
# Address to connect to (#blank = start local server)
#address =
# Enable random user input, for testing
@@ -103,41 +104,54 @@ screenH# = 600
#invisible_stone = false
# Path for screenshots
#screenshot_path = .
# Amount of view bobbing (0 = no view bobbing, 1.0 = normal, 2.0 = double)
#view_bobbing_amount = 1.0
#
# Server stuff
#
# Map directory (everything in the world is stored here)
#map-#dir = /custom/map
#map-dir = /custom/map
# Message of the Day
#motd = Welcome to this awesome Minetest server!
# Maximum number of players connected simultaneously
#max_users = 20
# Set to false to allow old clients to connect
#strict_protocol_version_checking = true
# Set to true to enable creative mode (unlimited inventory)
#creative_mode = false
# Enable players getting damage and dying
#enable_damage = false
# Despawn all non-peaceful mobs
#only_peaceful_mobs = false
# A chosen map seed for a new map, leave empty for random
#fixed_map_seed =
# Gives some stuff to players at the beginning
#give_initial_stuff = false
# New users need to input this password
#default_password =
# Available privileges: build, teleport, settime, privs, shout
#default_privs = build, shout
# 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
# 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_interval = 0.2
#active_object_range = 2
#active_object_send_range_blocks = 3
#active_block_range = 2
#max_simultaneous_block_sends_per_client = 2
#max_simultaneous_block_sends_server_total = 8
#max_block_send_distance = 8
#max_block_generate_distance = 8
#max_block_send_distance = 7
#max_block_generate_distance = 5
#time_send_interval = 20
# Length of day/night cycle. 72=20min, 360=4min, 1=24hour
#time_speed = 72
#server_unload_unused_data_timeout = 60
#server_map_save_interval = 60
#full_block_send_enable_min_time_from_building = 2.0
# 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

View File

@@ -90,12 +90,12 @@ configure_file(
)
set(common_SRCS
log.cpp
content_sao.cpp
mapgen.cpp
content_inventory.cpp
content_nodemeta.cpp
content_craft.cpp
content_mapblock.cpp
content_mapnode.cpp
auth.cpp
collision.cpp
@@ -108,7 +108,6 @@ set(common_SRCS
defaultsettings.cpp
mapnode.cpp
voxel.cpp
mapblockobject.cpp
inventory.cpp
debug.cpp
serialization.cpp
@@ -131,17 +130,28 @@ set(common_SRCS
)
# This gives us the icon
if(WIN32 AND MSVC)
set(common_SRCS ${common_SRCS} winresource.rc)
if(WIN32)
if(MINGW)
ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/winresource_rc.o
COMMAND windres.exe -I${CMAKE_CURRENT_SOURCE_DIR}
-i${CMAKE_CURRENT_SOURCE_DIR}/winresource.rc
-o ${CMAKE_CURRENT_BINARY_DIR}/winresource_rc.o)
SET(common_SRCS ${common_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/winresource_rc.o)
else(MINGW) # Probably MSVC
set(common_SRCS ${common_SRCS} winresource.rc)
endif(MINGW)
endif()
# Client sources
set(minetest_SRCS
${common_SRCS}
MyBillboardSceneNode.cpp
content_mapblock.cpp
content_cao.cpp
mapblock_mesh.cpp
farmesh.cpp
keycode.cpp
camera.cpp
clouds.cpp
clientobject.cpp
guiMainMenu.cpp
@@ -151,6 +161,7 @@ set(minetest_SRCS
guiInventoryMenu.cpp
guiPauseMenu.cpp
guiPasswordChange.cpp
guiDeathScreen.cpp
client.cpp
tile.cpp
game.cpp
@@ -188,10 +199,10 @@ if(BUILD_CLIENT)
${PNG_LIBRARIES}
${X11_LIBRARIES}
${GETTEXT_LIBRARY}
${PLATFORM_LIBS}
${CLIENT_PLATFORM_LIBS}
${JTHREAD_LIBRARY}
${SQLITE3_LIBRARY}
${PLATFORM_LIBS}
${CLIENT_PLATFORM_LIBS}
)
endif(BUILD_CLIENT)
@@ -200,9 +211,9 @@ if(BUILD_SERVER)
target_link_libraries(
${PROJECT_NAME}server
${ZLIB_LIBRARIES}
${PLATFORM_LIBS}
${JTHREAD_LIBRARY}
${SQLITE3_LIBRARY}
${PLATFORM_LIBS}
)
endif(BUILD_SERVER)
@@ -216,13 +227,17 @@ if(MSVC)
# Visual Studio
# EHa enables SEH exceptions (used for catching segfaults)
set(CMAKE_CXX_FLAGS_RELEASE "/EHa /MD /O2 /Ob2 /Oi /Ot /Oy /GL /FD /MT /GS- /arch:SSE /fp:fast /D NDEBUG /D _HAS_ITERATOR_DEBUGGING=0 /TP")
set(CMAKE_CXX_FLAGS_RELEASE "/EHa /O2 /Ob2 /Oi /Ot /Oy /GL /FD /MT /GS- /arch:SSE /fp:fast /D NDEBUG /D _HAS_ITERATOR_DEBUGGING=0 /TP")
#set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/LTCG /NODEFAULTLIB:\"libcmtd.lib\" /NODEFAULTLIB:\"libcmt.lib\"")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/LTCG")
# Debug build doesn't catch exceptions by itself
# Add some optimizations because otherwise it's VERY slow
set(CMAKE_CXX_FLAGS_DEBUG "/MDd /Zi /Ob0 /Od /RTC1")
# Flags for C files (sqlite)
# /MT = Link statically with standard library stuff
set(CMAKE_C_FLAGS_RELEASE "/O2 /Ob2 /MT")
if(BUILD_SERVER)
set_target_properties(${PROJECT_NAME}server PROPERTIES

View File

@@ -0,0 +1,202 @@
// Copyright (C) 2002-2010 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "MyBillboardSceneNode.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "ICameraSceneNode.h"
namespace irr
{
namespace scene
{
//! constructor
MyBillboardSceneNode::MyBillboardSceneNode(ISceneNode* parent,
ISceneManager* mgr, s32 id,
const core::vector3df& position, const core::dimension2d<f32>& size)
: IBillboardSceneNode(parent, mgr, id, position)
{
#ifdef _DEBUG
setDebugName("MyBillboardSceneNode");
#endif
setSize(size);
indices[0] = 0;
indices[1] = 2;
indices[2] = 1;
indices[3] = 0;
indices[4] = 3;
indices[5] = 2;
video::SColor colorTop = video::SColor(0xFFFFFFFF);
video::SColor colorBottom = video::SColor(0xFFFFFFFF);
vertices[0].TCoords.set(1.0f, 1.0f);
vertices[0].Color = colorBottom;
vertices[1].TCoords.set(1.0f, 0.0f);
vertices[1].Color = colorTop;
vertices[2].TCoords.set(0.0f, 0.0f);
vertices[2].Color = colorTop;
vertices[3].TCoords.set(0.0f, 1.0f);
vertices[3].Color = colorBottom;
}
//! pre render event
void MyBillboardSceneNode::OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
//! render
void MyBillboardSceneNode::render()
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
ICameraSceneNode* camera = SceneManager->getActiveCamera();
if (!camera || !driver)
return;
// make billboard look to camera
core::vector3df pos = getAbsolutePosition();
core::vector3df campos = camera->getAbsolutePosition();
core::vector3df target = camera->getTarget();
core::vector3df up = camera->getUpVector();
core::vector3df view = target - campos;
view.normalize();
core::vector3df horizontal = up.crossProduct(view);
if ( horizontal.getLength() == 0 )
{
horizontal.set(up.Y,up.X,up.Z);
}
horizontal.normalize();
horizontal *= 0.5f * Size.Width;
core::vector3df vertical = horizontal.crossProduct(view);
vertical.normalize();
vertical *= 0.5f * Size.Height;
view *= -1.0f;
for (s32 i=0; i<4; ++i)
vertices[i].Normal = view;
vertices[0].Pos = pos + horizontal + vertical;
vertices[1].Pos = pos + horizontal - vertical;
vertices[2].Pos = pos - horizontal - vertical;
vertices[3].Pos = pos - horizontal + vertical;
// draw
if ( DebugDataVisible & scene::EDS_BBOX )
{
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
video::SMaterial m;
m.Lighting = false;
driver->setMaterial(m);
driver->draw3DBox(BBox, video::SColor(0,208,195,152));
}
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
driver->setMaterial(Material);
driver->drawIndexedTriangleList(vertices, 4, indices, 2);
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& MyBillboardSceneNode::getBoundingBox() const
{
return BBox;
}
//! sets the size of the billboard
void MyBillboardSceneNode::setSize(const core::dimension2d<f32>& size)
{
Size = size;
if (Size.Width == 0.0f)
Size.Width = 1.0f;
if (Size.Height == 0.0f )
Size.Height = 1.0f;
f32 avg = (size.Width + size.Height)/6;
BBox.MinEdge.set(-avg,-avg,-avg);
BBox.MaxEdge.set(avg,avg,avg);
}
video::SMaterial& MyBillboardSceneNode::getMaterial(u32 i)
{
return Material;
}
//! returns amount of materials used by this scene node.
u32 MyBillboardSceneNode::getMaterialCount() const
{
return 1;
}
//! gets the size of the billboard
const core::dimension2d<f32>& MyBillboardSceneNode::getSize() const
{
return Size;
}
//! Set the color of all vertices of the billboard
//! \param overallColor: the color to set
void MyBillboardSceneNode::setColor(const video::SColor & overallColor)
{
for(u32 vertex = 0; vertex < 4; ++vertex)
vertices[vertex].Color = overallColor;
}
//! Set the color of the top and bottom vertices of the billboard
//! \param topColor: the color to set the top vertices
//! \param bottomColor: the color to set the bottom vertices
void MyBillboardSceneNode::setColor(const video::SColor & topColor, const video::SColor & bottomColor)
{
vertices[0].Color = bottomColor;
vertices[1].Color = topColor;
vertices[2].Color = topColor;
vertices[3].Color = bottomColor;
}
//! Gets the color of the top and bottom vertices of the billboard
//! \param[out] topColor: stores the color of the top vertices
//! \param[out] bottomColor: stores the color of the bottom vertices
void MyBillboardSceneNode::getColor(video::SColor & topColor, video::SColor & bottomColor) const
{
bottomColor = vertices[0].Color;
topColor = vertices[1].Color;
}
void MyBillboardSceneNode::setTCoords(u32 i, core::vector2d<f32> c)
{
vertices[i].TCoords = c;
}
} // end namespace scene
} // end namespace irr

View File

@@ -0,0 +1,77 @@
// Copyright (C) 2002-2010 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_BILLBOARD_SCENE_NODE_H_INCLUDED__
#define __C_BILLBOARD_SCENE_NODE_H_INCLUDED__
#include "IBillboardSceneNode.h"
#include "S3DVertex.h"
namespace irr
{
namespace scene
{
//! Scene node which is a billboard. A billboard is like a 3d sprite: A 2d element,
//! which always looks to the camera.
class MyBillboardSceneNode : virtual public IBillboardSceneNode
{
public:
//! constructor
MyBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position, const core::dimension2d<f32>& size);
//! pre render event
virtual void OnRegisterSceneNode();
//! render
virtual void render();
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const;
//! sets the size of the billboard
virtual void setSize(const core::dimension2d<f32>& size);
//! gets the size of the billboard
virtual const core::dimension2d<f32>& getSize() const;
virtual video::SMaterial& getMaterial(u32 i);
//! returns amount of materials used by this scene node.
virtual u32 getMaterialCount() const;
//! Set the color of all vertices of the billboard
//! \param overallColor: the color to set
virtual void setColor(const video::SColor & overallColor);
//! Set the color of the top and bottom vertices of the billboard
//! \param topColor: the color to set the top vertices
//! \param bottomColor: the color to set the bottom vertices
virtual void setColor(const video::SColor & topColor, const video::SColor & bottomColor);
//! Gets the color of the top and bottom vertices of the billboard
//! \param[out] topColor: stores the color of the top vertices
//! \param[out] bottomColor: stores the color of the bottom vertices
virtual void getColor(video::SColor& topColor, video::SColor& bottomColor) const;
virtual void setTCoords(u32 i, core::vector2d<f32> c);
private:
core::dimension2d<f32> Size;
core::aabbox3d<f32> BBox;
video::SMaterial Material;
video::S3DVertex vertices[4];
u16 indices[6];
};
} // end namespace scene
} // end namespace irr
#endif

View File

@@ -38,6 +38,13 @@ static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
bool base64_is_valid(std::string const& s)
{
for(int i=0; i<s.size(); i++)
if(!is_base64(s[i])) return false;
return true;
}
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;

View File

@@ -1,4 +1,5 @@
#include <string>
bool base64_is_valid(std::string const& s);
std::string base64_encode(unsigned char const* , unsigned int len);
std::string base64_decode(std::string const& s);

903
src/camera.cpp Normal file
View File

@@ -0,0 +1,903 @@
/*
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 "camera.h"
#include "debug.h"
#include "client.h"
#include "main.h" // for g_settings
#include "map.h"
#include "player.h"
#include "tile.h"
#include <cmath>
#include <SAnimatedMesh.h>
#include "settings.h"
Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control):
m_smgr(smgr),
m_playernode(NULL),
m_headnode(NULL),
m_cameranode(NULL),
m_wieldmgr(NULL),
m_wieldnode(NULL),
m_draw_control(draw_control),
m_viewing_range_min(5.0),
m_viewing_range_max(5.0),
m_camera_position(0,0,0),
m_camera_direction(0,0,0),
m_aspect(1.0),
m_fov_x(1.0),
m_fov_y(1.0),
m_wanted_frametime(0.0),
m_added_frametime(0),
m_added_frames(0),
m_range_old(0),
m_frametime_old(0),
m_frametime_counter(0),
m_time_per_range(30. / 50), // a sane default of 30ms per 50 nodes of range
m_view_bobbing_anim(0),
m_view_bobbing_state(0),
m_view_bobbing_speed(0),
m_digging_anim(0),
m_digging_button(-1)
{
//dstream<<__FUNCTION_NAME<<std::endl;
// note: making the camera node a child of the player node
// would lead to unexpected behaviour, so we don't do that.
m_playernode = smgr->addEmptySceneNode(smgr->getRootSceneNode());
m_headnode = smgr->addEmptySceneNode(m_playernode);
m_cameranode = smgr->addCameraSceneNode(smgr->getRootSceneNode());
m_cameranode->bindTargetAndRotation(true);
// This needs to be in its own scene manager. It is drawn after
// all other 3D scene nodes and before the GUI.
m_wieldmgr = smgr->createNewSceneManager();
m_wieldmgr->addCameraSceneNode();
m_wieldnode = new ExtrudedSpriteSceneNode(m_wieldmgr->getRootSceneNode(), m_wieldmgr);
updateSettings();
}
Camera::~Camera()
{
m_wieldmgr->drop();
m_wieldnode->drop();
}
bool Camera::successfullyCreated(std::wstring& error_message)
{
if (m_playernode == NULL)
{
error_message = L"Failed to create the player scene node";
return false;
}
if (m_headnode == NULL)
{
error_message = L"Failed to create the head scene node";
return false;
}
if (m_cameranode == NULL)
{
error_message = L"Failed to create the camera scene node";
return false;
}
if (m_wieldmgr == NULL)
{
error_message = L"Failed to create the wielded item scene manager";
return false;
}
if (m_wieldnode == NULL)
{
error_message = L"Failed to create the wielded item scene node";
return false;
}
return true;
}
// Returns the fractional part of x
inline f32 my_modf(f32 x)
{
double dummy;
return modf(x, &dummy);
}
void Camera::step(f32 dtime)
{
if (m_view_bobbing_state != 0)
{
//f32 offset = dtime * m_view_bobbing_speed * 0.035;
f32 offset = dtime * m_view_bobbing_speed * 0.030;
if (m_view_bobbing_state == 2)
{
#if 0
// Animation is getting turned off
if (m_view_bobbing_anim < 0.5)
m_view_bobbing_anim -= offset;
else
m_view_bobbing_anim += offset;
if (m_view_bobbing_anim <= 0 || m_view_bobbing_anim >= 1)
{
m_view_bobbing_anim = 0;
m_view_bobbing_state = 0;
}
#endif
#if 1
// Animation is getting turned off
if(m_view_bobbing_anim < 0.25){
m_view_bobbing_anim -= offset;
} else if(m_view_bobbing_anim > 0.75){
m_view_bobbing_anim += offset;
} if(m_view_bobbing_anim < 0.5){
m_view_bobbing_anim += offset;
if(m_view_bobbing_anim > 0.5)
m_view_bobbing_anim = 0.5;
} else {
m_view_bobbing_anim -= offset;
if(m_view_bobbing_anim < 0.5)
m_view_bobbing_anim = 0.5;
}
if(m_view_bobbing_anim <= 0 || m_view_bobbing_anim >= 1 ||
fabs(m_view_bobbing_anim - 0.5) < 0.01)
{
m_view_bobbing_anim = 0;
m_view_bobbing_state = 0;
}
#endif
}
else
{
m_view_bobbing_anim = my_modf(m_view_bobbing_anim + offset);
}
}
if (m_digging_button != -1)
{
f32 offset = dtime * 3.5;
m_digging_anim += offset;
if (m_digging_anim >= 1)
{
m_digging_anim = 0;
m_digging_button = -1;
}
}
}
void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize)
{
// Set player node transformation
m_playernode->setPosition(player->getPosition());
m_playernode->setRotation(v3f(0, -1 * player->getYaw(), 0));
m_playernode->updateAbsolutePosition();
// Set head node transformation
m_headnode->setPosition(player->getEyeOffset());
m_headnode->setRotation(v3f(player->getPitch(), 0, 0));
m_headnode->updateAbsolutePosition();
// Compute relative camera position and target
v3f rel_cam_pos = v3f(0,0,0);
v3f rel_cam_target = v3f(0,0,1);
v3f rel_cam_up = v3f(0,1,0);
if (m_view_bobbing_anim != 0)
{
f32 bobfrac = my_modf(m_view_bobbing_anim * 2);
f32 bobdir = (m_view_bobbing_anim < 0.5) ? 1.0 : -1.0;
#if 1
f32 bobknob = 1.2;
f32 bobtmp = sin(pow(bobfrac, bobknob) * PI);
//f32 bobtmp2 = cos(pow(bobfrac, bobknob) * PI);
v3f bobvec = v3f(
0.3 * bobdir * sin(bobfrac * PI),
-0.28 * bobtmp * bobtmp,
0.);
//rel_cam_pos += 0.2 * bobvec;
//rel_cam_target += 0.03 * bobvec;
//rel_cam_up.rotateXYBy(0.02 * bobdir * bobtmp * PI);
float f = 1.0;
f *= g_settings->getFloat("view_bobbing_amount");
rel_cam_pos += bobvec * f;
//rel_cam_target += 0.995 * bobvec * f;
rel_cam_target += bobvec * f;
rel_cam_target.Z -= 0.005 * bobvec.Z * f;
//rel_cam_target.X -= 0.005 * bobvec.X * f;
//rel_cam_target.Y -= 0.005 * bobvec.Y * f;
rel_cam_up.rotateXYBy(-0.03 * bobdir * bobtmp * PI * f);
#else
f32 angle_deg = 1 * bobdir * sin(bobfrac * PI);
f32 angle_rad = angle_deg * PI / 180;
f32 r = 0.05;
v3f off = v3f(
r * sin(angle_rad),
r * (cos(angle_rad) - 1),
0);
rel_cam_pos += off;
//rel_cam_target += off;
rel_cam_up.rotateXYBy(angle_deg);
#endif
}
// Compute absolute camera position and target
m_headnode->getAbsoluteTransformation().transformVect(m_camera_position, rel_cam_pos);
m_headnode->getAbsoluteTransformation().rotateVect(m_camera_direction, rel_cam_target - rel_cam_pos);
v3f abs_cam_up;
m_headnode->getAbsoluteTransformation().rotateVect(abs_cam_up, rel_cam_up);
// Set camera node transformation
m_cameranode->setPosition(m_camera_position);
m_cameranode->setUpVector(abs_cam_up);
// *100.0 helps in large map coordinates
m_cameranode->setTarget(m_camera_position + 100 * m_camera_direction);
// FOV and and aspect ratio
m_aspect = (f32)screensize.X / (f32) screensize.Y;
m_fov_x = 2 * atan(0.5 * m_aspect * tan(m_fov_y));
m_cameranode->setAspectRatio(m_aspect);
m_cameranode->setFOV(m_fov_y);
// Just so big a value that everything rendered is visible
// Some more allowance that m_viewing_range_max * BS because of active objects etc.
m_cameranode->setFarValue(m_viewing_range_max * BS * 10);
// Position the wielded item
v3f wield_position = v3f(45, -35, 65);
v3f wield_rotation = v3f(-100, 110, -100);
if (m_digging_button != -1)
{
f32 digfrac = m_digging_anim;
wield_position.X -= 30 * sin(pow(digfrac, 0.8f) * PI);
wield_position.Y += 15 * sin(digfrac * 2 * PI);
wield_position.Z += 5 * digfrac;
// Euler angles are PURE EVIL, so why not use quaternions?
core::quaternion quat_begin(wield_rotation * core::DEGTORAD);
core::quaternion quat_end(v3f(90, -10, -130) * core::DEGTORAD);
core::quaternion quat_slerp;
quat_slerp.slerp(quat_begin, quat_end, sin(digfrac * PI));
quat_slerp.toEuler(wield_rotation);
wield_rotation *= core::RADTODEG;
}
else {
f32 bobfrac = my_modf(m_view_bobbing_anim);
wield_position.X -= sin(bobfrac*PI*2.0) * 3.0;
wield_position.Y += sin(my_modf(bobfrac*2.0)*PI) * 3.0;
}
m_wieldnode->setPosition(wield_position);
m_wieldnode->setRotation(wield_rotation);
m_wieldnode->updateLight(player->light);
// Render distance feedback loop
updateViewingRange(frametime);
// If the player seems to be walking on solid ground,
// view bobbing is enabled and free_move is off,
// start (or continue) the view bobbing animation.
v3f speed = player->getSpeed();
if ((hypot(speed.X, speed.Z) > BS) &&
(player->touching_ground) &&
(g_settings->getBool("view_bobbing") == true) &&
(g_settings->getBool("free_move") == false))
{
// Start animation
m_view_bobbing_state = 1;
m_view_bobbing_speed = MYMIN(speed.getLength(), 40);
}
else if (m_view_bobbing_state == 1)
{
// Stop animation
m_view_bobbing_state = 2;
m_view_bobbing_speed = 60;
}
}
void Camera::updateViewingRange(f32 frametime_in)
{
if (m_draw_control.range_all)
return;
m_added_frametime += frametime_in;
m_added_frames += 1;
// Actually this counter kind of sucks because frametime is busytime
m_frametime_counter -= frametime_in;
if (m_frametime_counter > 0)
return;
m_frametime_counter = 0.2;
/*dstream<<__FUNCTION_NAME
<<": Collected "<<m_added_frames<<" frames, total of "
<<m_added_frametime<<"s."<<std::endl;
dstream<<"m_draw_control.blocks_drawn="
<<m_draw_control.blocks_drawn
<<", m_draw_control.blocks_would_have_drawn="
<<m_draw_control.blocks_would_have_drawn
<<std::endl;*/
m_draw_control.wanted_min_range = m_viewing_range_min;
m_draw_control.wanted_max_blocks = (2.0*m_draw_control.blocks_would_have_drawn)+1;
if (m_draw_control.wanted_max_blocks < 10)
m_draw_control.wanted_max_blocks = 10;
f32 block_draw_ratio = 1.0;
if (m_draw_control.blocks_would_have_drawn != 0)
{
block_draw_ratio = (f32)m_draw_control.blocks_drawn
/ (f32)m_draw_control.blocks_would_have_drawn;
}
// Calculate the average frametime in the case that all wanted
// blocks had been drawn
f32 frametime = m_added_frametime / m_added_frames / block_draw_ratio;
m_added_frametime = 0.0;
m_added_frames = 0;
f32 wanted_frametime_change = m_wanted_frametime - frametime;
//dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;
// If needed frametime change is small, just return
// This value was 0.4 for many months until 2011-10-18 by c55;
// Let's see how this works out.
if (fabs(wanted_frametime_change) < m_wanted_frametime*0.33)
{
//dstream<<"ignoring small wanted_frametime_change"<<std::endl;
return;
}
f32 range = m_draw_control.wanted_range;
f32 new_range = range;
f32 d_range = range - m_range_old;
f32 d_frametime = frametime - m_frametime_old;
if (d_range != 0)
{
m_time_per_range = d_frametime / d_range;
}
// The minimum allowed calculated frametime-range derivative:
// Practically this sets the maximum speed of changing the range.
// The lower this value, the higher the maximum changing speed.
// A low value here results in wobbly range (0.001)
// A high value here results in slow changing range (0.0025)
// SUGG: This could be dynamically adjusted so that when
// the camera is turning, this is lower
//f32 min_time_per_range = 0.0015;
f32 min_time_per_range = 0.0010;
//f32 min_time_per_range = 0.05 / range;
if(m_time_per_range < min_time_per_range)
{
m_time_per_range = min_time_per_range;
//dstream<<"m_time_per_range="<<m_time_per_range<<" (min)"<<std::endl;
}
else
{
//dstream<<"m_time_per_range="<<m_time_per_range<<std::endl;
}
f32 wanted_range_change = wanted_frametime_change / m_time_per_range;
// Dampen the change a bit to kill oscillations
//wanted_range_change *= 0.9;
//wanted_range_change *= 0.75;
wanted_range_change *= 0.5;
//dstream<<"wanted_range_change="<<wanted_range_change<<std::endl;
// If needed range change is very small, just return
if(fabs(wanted_range_change) < 0.001)
{
//dstream<<"ignoring small wanted_range_change"<<std::endl;
return;
}
new_range += wanted_range_change;
//f32 new_range_unclamped = new_range;
new_range = MYMAX(new_range, m_viewing_range_min);
new_range = MYMIN(new_range, m_viewing_range_max);
/*dstream<<"new_range="<<new_range_unclamped
<<", clamped to "<<new_range<<std::endl;*/
m_draw_control.wanted_range = new_range;
m_range_old = new_range;
m_frametime_old = frametime;
}
void Camera::updateSettings()
{
m_viewing_range_min = g_settings->getS16("viewing_range_nodes_min");
m_viewing_range_min = MYMAX(5.0, m_viewing_range_min);
m_viewing_range_max = g_settings->getS16("viewing_range_nodes_max");
m_viewing_range_max = MYMAX(m_viewing_range_min, m_viewing_range_max);
f32 fov_degrees = g_settings->getFloat("fov");
fov_degrees = MYMAX(fov_degrees, 10.0);
fov_degrees = MYMIN(fov_degrees, 170.0);
m_fov_y = fov_degrees * PI / 180.0;
f32 wanted_fps = g_settings->getFloat("wanted_fps");
wanted_fps = MYMAX(wanted_fps, 1.0);
m_wanted_frametime = 1.0 / wanted_fps;
}
void Camera::wield(const InventoryItem* item)
{
if (item != NULL)
{
bool isCube = false;
// Try to make a MaterialItem cube.
if (std::string(item->getName()) == "MaterialItem")
{
// A block-type material
MaterialItem* mat_item = (MaterialItem*) item;
content_t content = mat_item->getMaterial();
if (content_features(content).solidness || content_features(content).visual_solidness)
{
m_wieldnode->setCube(content_features(content).tiles);
m_wieldnode->setScale(v3f(30));
isCube = true;
}
}
// If that failed, make an extruded sprite.
if (!isCube)
{
m_wieldnode->setSprite(item->getImageRaw());
m_wieldnode->setScale(v3f(40));
}
m_wieldnode->setVisible(true);
}
else
{
// Bare hands
m_wieldnode->setVisible(false);
}
}
void Camera::setDigging(s32 button)
{
if (m_digging_button == -1)
m_digging_button = button;
}
void Camera::drawWieldedTool()
{
m_wieldmgr->getVideoDriver()->clearZBuffer();
scene::ICameraSceneNode* cam = m_wieldmgr->getActiveCamera();
cam->setAspectRatio(m_cameranode->getAspectRatio());
cam->setFOV(m_cameranode->getFOV());
cam->setNearValue(0.1);
cam->setFarValue(100);
m_wieldmgr->drawAll();
}
ExtrudedSpriteSceneNode::ExtrudedSpriteSceneNode(
scene::ISceneNode* parent,
scene::ISceneManager* mgr,
s32 id,
const v3f& position,
const v3f& rotation,
const v3f& scale
):
ISceneNode(parent, mgr, id, position, rotation, scale)
{
m_meshnode = mgr->addMeshSceneNode(NULL, this, -1, v3f(0,0,0), v3f(0,0,0), v3f(1,1,1), true);
m_thickness = 0.1;
m_cubemesh = NULL;
m_is_cube = false;
m_light = LIGHT_MAX;
}
ExtrudedSpriteSceneNode::~ExtrudedSpriteSceneNode()
{
removeChild(m_meshnode);
if (m_cubemesh)
m_cubemesh->drop();
}
void ExtrudedSpriteSceneNode::setSprite(video::ITexture* texture)
{
if (texture == NULL)
{
m_meshnode->setVisible(false);
return;
}
io::path name = getExtrudedName(texture);
scene::IMeshCache* cache = SceneManager->getMeshCache();
scene::IAnimatedMesh* mesh = cache->getMeshByName(name);
if (mesh != NULL)
{
// Extruded texture has been found in cache.
m_meshnode->setMesh(mesh);
}
else
{
// Texture was not yet extruded, do it now and save in cache
mesh = extrude(texture);
if (mesh == NULL)
{
dstream << "Warning: failed to extrude sprite" << std::endl;
m_meshnode->setVisible(false);
return;
}
cache->addMesh(name, mesh);
m_meshnode->setMesh(mesh);
mesh->drop();
}
m_meshnode->setScale(v3f(1, 1, m_thickness));
m_meshnode->getMaterial(0).setTexture(0, texture);
m_meshnode->getMaterial(0).setFlag(video::EMF_LIGHTING, false);
m_meshnode->getMaterial(0).setFlag(video::EMF_BILINEAR_FILTER, false);
m_meshnode->getMaterial(0).MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
m_meshnode->setVisible(true);
m_is_cube = false;
updateLight(m_light);
}
void ExtrudedSpriteSceneNode::setCube(const TileSpec tiles[6])
{
if (m_cubemesh == NULL)
m_cubemesh = createCubeMesh();
m_meshnode->setMesh(m_cubemesh);
m_meshnode->setScale(v3f(1));
for (int i = 0; i < 6; ++i)
{
// Get the tile texture and atlas transformation
video::ITexture* atlas = tiles[i].texture.atlas;
v2f pos = tiles[i].texture.pos;
v2f size = tiles[i].texture.size;
// Set material flags and texture
video::SMaterial& material = m_meshnode->getMaterial(i);
material.setFlag(video::EMF_LIGHTING, false);
material.setFlag(video::EMF_BILINEAR_FILTER, false);
tiles[i].applyMaterialOptions(material);
material.setTexture(0, atlas);
material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
}
m_meshnode->setVisible(true);
m_is_cube = true;
updateLight(m_light);
}
void ExtrudedSpriteSceneNode::updateLight(u8 light)
{
m_light = light;
u8 li = decode_light(light);
// Set brightness one lower than incoming light
diminish_light(li);
video::SColor color(255,li,li,li);
setMeshVerticesColor(m_meshnode->getMesh(), color);
}
void ExtrudedSpriteSceneNode::removeSpriteFromCache(video::ITexture* texture)
{
scene::IMeshCache* cache = SceneManager->getMeshCache();
scene::IAnimatedMesh* mesh = cache->getMeshByName(getExtrudedName(texture));
if (mesh != NULL)
cache->removeMesh(mesh);
}
void ExtrudedSpriteSceneNode::setSpriteThickness(f32 thickness)
{
m_thickness = thickness;
if (!m_is_cube)
m_meshnode->setScale(v3f(1, 1, thickness));
}
const core::aabbox3d<f32>& ExtrudedSpriteSceneNode::getBoundingBox() const
{
return m_meshnode->getBoundingBox();
}
void ExtrudedSpriteSceneNode::OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
void ExtrudedSpriteSceneNode::render()
{
// do nothing
}
io::path ExtrudedSpriteSceneNode::getExtrudedName(video::ITexture* texture)
{
io::path path = texture->getName();
path.append("/[extruded]");
return path;
}
scene::IAnimatedMesh* ExtrudedSpriteSceneNode::extrudeARGB(u32 width, u32 height, u8* data)
{
const s32 argb_wstep = 4 * width;
const s32 alpha_threshold = 1;
scene::IMeshBuffer* buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
// Front and back
{
video::S3DVertex vertices[8] =
{
video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1),
video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0),
video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0),
video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1),
video::S3DVertex(+0.5,-0.5,+0.5, 0,0,+1, c, 1,1),
video::S3DVertex(+0.5,+0.5,+0.5, 0,0,+1, c, 1,0),
video::S3DVertex(-0.5,+0.5,+0.5, 0,0,+1, c, 0,0),
video::S3DVertex(-0.5,-0.5,+0.5, 0,0,+1, c, 0,1),
};
u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4};
buf->append(vertices, 8, indices, 12);
}
// "Interior"
// (add faces where a solid pixel is next to a transparent one)
u8* solidity = new u8[(width+2) * (height+2)];
u32 wstep = width + 2;
for (u32 y = 0; y < height + 2; ++y)
{
u8* scanline = solidity + y * wstep;
if (y == 0 || y == height + 1)
{
for (u32 x = 0; x < width + 2; ++x)
scanline[x] = 0;
}
else
{
scanline[0] = 0;
u8* argb_scanline = data + (y - 1) * argb_wstep;
for (u32 x = 0; x < width; ++x)
scanline[x+1] = (argb_scanline[x*4+3] >= alpha_threshold);
scanline[width + 1] = 0;
}
}
// without this, there would be occasional "holes" in the mesh
f32 eps = 0.01;
for (u32 y = 0; y <= height; ++y)
{
u8* scanline = solidity + y * wstep + 1;
for (u32 x = 0; x <= width; ++x)
{
if (scanline[x] && !scanline[x + wstep])
{
u32 xx = x + 1;
while (scanline[xx] && !scanline[xx + wstep])
++xx;
f32 vx1 = (x - eps) / (f32) width - 0.5;
f32 vx2 = (xx + eps) / (f32) width - 0.5;
f32 vy = 0.5 - (y - eps) / (f32) height;
f32 tx1 = x / (f32) width;
f32 tx2 = xx / (f32) width;
f32 ty = (y - 0.5) / (f32) height;
video::S3DVertex vertices[8] =
{
video::S3DVertex(vx1,vy,-0.5, 0,-1,0, c, tx1,ty),
video::S3DVertex(vx2,vy,-0.5, 0,-1,0, c, tx2,ty),
video::S3DVertex(vx2,vy,+0.5, 0,-1,0, c, tx2,ty),
video::S3DVertex(vx1,vy,+0.5, 0,-1,0, c, tx1,ty),
};
u16 indices[6] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
x = xx - 1;
}
if (!scanline[x] && scanline[x + wstep])
{
u32 xx = x + 1;
while (!scanline[xx] && scanline[xx + wstep])
++xx;
f32 vx1 = (x - eps) / (f32) width - 0.5;
f32 vx2 = (xx + eps) / (f32) width - 0.5;
f32 vy = 0.5 - (y + eps) / (f32) height;
f32 tx1 = x / (f32) width;
f32 tx2 = xx / (f32) width;
f32 ty = (y + 0.5) / (f32) height;
video::S3DVertex vertices[8] =
{
video::S3DVertex(vx1,vy,-0.5, 0,1,0, c, tx1,ty),
video::S3DVertex(vx1,vy,+0.5, 0,1,0, c, tx1,ty),
video::S3DVertex(vx2,vy,+0.5, 0,1,0, c, tx2,ty),
video::S3DVertex(vx2,vy,-0.5, 0,1,0, c, tx2,ty),
};
u16 indices[6] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
x = xx - 1;
}
}
}
for (u32 x = 0; x <= width; ++x)
{
u8* scancol = solidity + x + wstep;
for (u32 y = 0; y <= height; ++y)
{
if (scancol[y * wstep] && !scancol[y * wstep + 1])
{
u32 yy = y + 1;
while (scancol[yy * wstep] && !scancol[yy * wstep + 1])
++yy;
f32 vx = (x - eps) / (f32) width - 0.5;
f32 vy1 = 0.5 - (y - eps) / (f32) height;
f32 vy2 = 0.5 - (yy + eps) / (f32) height;
f32 tx = (x - 0.5) / (f32) width;
f32 ty1 = y / (f32) height;
f32 ty2 = yy / (f32) height;
video::S3DVertex vertices[8] =
{
video::S3DVertex(vx,vy1,-0.5, 1,0,0, c, tx,ty1),
video::S3DVertex(vx,vy1,+0.5, 1,0,0, c, tx,ty1),
video::S3DVertex(vx,vy2,+0.5, 1,0,0, c, tx,ty2),
video::S3DVertex(vx,vy2,-0.5, 1,0,0, c, tx,ty2),
};
u16 indices[6] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
y = yy - 1;
}
if (!scancol[y * wstep] && scancol[y * wstep + 1])
{
u32 yy = y + 1;
while (!scancol[yy * wstep] && scancol[yy * wstep + 1])
++yy;
f32 vx = (x + eps) / (f32) width - 0.5;
f32 vy1 = 0.5 - (y - eps) / (f32) height;
f32 vy2 = 0.5 - (yy + eps) / (f32) height;
f32 tx = (x + 0.5) / (f32) width;
f32 ty1 = y / (f32) height;
f32 ty2 = yy / (f32) height;
video::S3DVertex vertices[8] =
{
video::S3DVertex(vx,vy1,-0.5, -1,0,0, c, tx,ty1),
video::S3DVertex(vx,vy2,-0.5, -1,0,0, c, tx,ty2),
video::S3DVertex(vx,vy2,+0.5, -1,0,0, c, tx,ty2),
video::S3DVertex(vx,vy1,+0.5, -1,0,0, c, tx,ty1),
};
u16 indices[6] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
y = yy - 1;
}
}
}
// Add to mesh
scene::SMesh* mesh = new scene::SMesh();
buf->recalculateBoundingBox();
mesh->addMeshBuffer(buf);
buf->drop();
mesh->recalculateBoundingBox();
scene::SAnimatedMesh* anim_mesh = new scene::SAnimatedMesh(mesh);
mesh->drop();
return anim_mesh;
}
scene::IAnimatedMesh* ExtrudedSpriteSceneNode::extrude(video::ITexture* texture)
{
scene::IAnimatedMesh* mesh = NULL;
core::dimension2d<u32> size = texture->getSize();
video::ECOLOR_FORMAT format = texture->getColorFormat();
if (format == video::ECF_A8R8G8B8)
{
// Texture is in the correct color format, we can pass it
// to extrudeARGB right away.
void* data = texture->lock(true);
if (data == NULL)
return NULL;
mesh = extrudeARGB(size.Width, size.Height, (u8*) data);
texture->unlock();
}
else
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
video::IImage* img1 = driver->createImageFromData(format, size, texture->lock(true));
if (img1 == NULL)
return NULL;
// img1 is in the texture's color format, convert to 8-bit ARGB
video::IImage* img2 = driver->createImage(video::ECF_A8R8G8B8, size);
if (img2 != NULL)
{
img1->copyTo(img2);
img1->drop();
mesh = extrudeARGB(size.Width, size.Height, (u8*) img2->lock());
img2->unlock();
img2->drop();
}
img1->drop();
}
return mesh;
}
scene::IMesh* ExtrudedSpriteSceneNode::createCubeMesh()
{
video::SColor c(255,255,255,255);
video::S3DVertex vertices[24] =
{
// Up
video::S3DVertex(-0.5,+0.5,-0.5, 0,1,0, c, 0,1),
video::S3DVertex(-0.5,+0.5,+0.5, 0,1,0, c, 0,0),
video::S3DVertex(+0.5,+0.5,+0.5, 0,1,0, c, 1,0),
video::S3DVertex(+0.5,+0.5,-0.5, 0,1,0, c, 1,1),
// Down
video::S3DVertex(-0.5,-0.5,-0.5, 0,-1,0, c, 0,0),
video::S3DVertex(+0.5,-0.5,-0.5, 0,-1,0, c, 1,0),
video::S3DVertex(+0.5,-0.5,+0.5, 0,-1,0, c, 1,1),
video::S3DVertex(-0.5,-0.5,+0.5, 0,-1,0, c, 0,1),
// Right
video::S3DVertex(+0.5,-0.5,-0.5, 1,0,0, c, 0,1),
video::S3DVertex(+0.5,+0.5,-0.5, 1,0,0, c, 0,0),
video::S3DVertex(+0.5,+0.5,+0.5, 1,0,0, c, 1,0),
video::S3DVertex(+0.5,-0.5,+0.5, 1,0,0, c, 1,1),
// Left
video::S3DVertex(-0.5,-0.5,-0.5, -1,0,0, c, 1,1),
video::S3DVertex(-0.5,-0.5,+0.5, -1,0,0, c, 0,1),
video::S3DVertex(-0.5,+0.5,+0.5, -1,0,0, c, 0,0),
video::S3DVertex(-0.5,+0.5,-0.5, -1,0,0, c, 1,0),
// Back
video::S3DVertex(-0.5,-0.5,+0.5, 0,0,1, c, 1,1),
video::S3DVertex(+0.5,-0.5,+0.5, 0,0,1, c, 0,1),
video::S3DVertex(+0.5,+0.5,+0.5, 0,0,1, c, 0,0),
video::S3DVertex(-0.5,+0.5,+0.5, 0,0,1, c, 1,0),
// Front
video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1),
video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0),
video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0),
video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1),
};
u16 indices[6] = {0,1,2,2,3,0};
scene::SMesh* mesh = new scene::SMesh();
for (u32 i=0; i<6; ++i)
{
scene::IMeshBuffer* buf = new scene::SMeshBuffer();
buf->append(vertices + 4 * i, 4, indices, 6);
buf->recalculateBoundingBox();
mesh->addMeshBuffer(buf);
buf->drop();
}
mesh->recalculateBoundingBox();
return mesh;
}

233
src/camera.h Normal file
View File

@@ -0,0 +1,233 @@
/*
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 CAMERA_HEADER
#define CAMERA_HEADER
#include "common_irrlicht.h"
#include "inventory.h"
#include "tile.h"
#include "utility.h"
#include <ICameraSceneNode.h>
#include <IMeshCache.h>
#include <IAnimatedMesh.h>
class LocalPlayer;
class MapDrawControl;
class ExtrudedSpriteSceneNode;
/*
Client camera class, manages the player and camera scene nodes, the viewing distance
and performs view bobbing etc. It also displays the wielded tool in front of the
first-person camera.
*/
class Camera
{
public:
Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control);
~Camera();
// Get player scene node.
// This node is positioned at the player's torso (without any view bobbing),
// as given by Player::m_position. Yaw is applied but not pitch.
inline scene::ISceneNode* getPlayerNode() const
{
return m_playernode;
}
// Get head scene node.
// It has the eye transformation and pitch applied,
// but no view bobbing.
inline scene::ISceneNode* getHeadNode() const
{
return m_headnode;
}
// Get camera scene node.
// It has the eye transformation, pitch and view bobbing applied.
inline scene::ICameraSceneNode* getCameraNode() const
{
return m_cameranode;
}
// Get the camera position (in absolute scene coordinates).
// This has view bobbing applied.
inline v3f getPosition() const
{
return m_camera_position;
}
// Get the camera direction (in absolute camera coordinates).
// This has view bobbing applied.
inline v3f getDirection() const
{
return m_camera_direction;
}
// Horizontal field of view
inline f32 getFovX() const
{
return m_fov_x;
}
// Vertical field of view
inline f32 getFovY() const
{
return m_fov_y;
}
// Get maximum of getFovX() and getFovY()
inline f32 getFovMax() const
{
return MYMAX(m_fov_x, m_fov_y);
}
// Checks if the constructor was able to create the scene nodes
bool successfullyCreated(std::wstring& error_message);
// Step the camera: updates the viewing range and view bobbing.
void step(f32 dtime);
// Update the camera from the local player's position.
// frametime is used to adjust the viewing range.
void update(LocalPlayer* player, f32 frametime, v2u32 screensize);
// Render distance feedback loop
void updateViewingRange(f32 frametime_in);
// Update settings from g_settings
void updateSettings();
// Replace the wielded item mesh
void wield(const InventoryItem* item);
// Start digging animation
// Pass 0 for left click, 1 for right click
void setDigging(s32 button);
// Draw the wielded tool.
// This has to happen *after* the main scene is drawn.
// Warning: This clears the Z buffer.
void drawWieldedTool();
private:
// Scene manager and nodes
scene::ISceneManager* m_smgr;
scene::ISceneNode* m_playernode;
scene::ISceneNode* m_headnode;
scene::ICameraSceneNode* m_cameranode;
scene::ISceneManager* m_wieldmgr;
ExtrudedSpriteSceneNode* m_wieldnode;
// draw control
MapDrawControl& m_draw_control;
// viewing_range_min_nodes setting
f32 m_viewing_range_min;
// viewing_range_max_nodes setting
f32 m_viewing_range_max;
// Absolute camera position
v3f m_camera_position;
// Absolute camera direction
v3f m_camera_direction;
// Field of view and aspect ratio stuff
f32 m_aspect;
f32 m_fov_x;
f32 m_fov_y;
// Stuff for viewing range calculations
f32 m_wanted_frametime;
f32 m_added_frametime;
s16 m_added_frames;
f32 m_range_old;
f32 m_frametime_old;
f32 m_frametime_counter;
f32 m_time_per_range;
// View bobbing animation frame (0 <= m_view_bobbing_anim < 1)
f32 m_view_bobbing_anim;
// If 0, view bobbing is off (e.g. player is standing).
// If 1, view bobbing is on (player is walking).
// If 2, view bobbing is getting switched off.
s32 m_view_bobbing_state;
// Speed of view bobbing animation
f32 m_view_bobbing_speed;
// Digging animation frame (0 <= m_digging_anim < 1)
f32 m_digging_anim;
// If -1, no digging animation
// If 0, left-click digging animation
// If 1, right-click digging animation
s32 m_digging_button;
};
/*
A scene node that displays a 2D mesh extruded into the third dimension,
to add an illusion of depth.
Since this class was created to display the wielded tool of the local
player, and only tools and items are rendered like this (but not solid
content like stone and mud, which are shown as cubes), the option to
draw a textured cube instead is provided.
*/
class ExtrudedSpriteSceneNode: public scene::ISceneNode
{
public:
ExtrudedSpriteSceneNode(
scene::ISceneNode* parent,
scene::ISceneManager* mgr,
s32 id = -1,
const v3f& position = v3f(0,0,0),
const v3f& rotation = v3f(0,0,0),
const v3f& scale = v3f(1,1,1));
~ExtrudedSpriteSceneNode();
void setSprite(video::ITexture* texture);
void setCube(const TileSpec tiles[6]);
f32 getSpriteThickness() const { return m_thickness; }
void setSpriteThickness(f32 thickness);
void updateLight(u8 light);
void removeSpriteFromCache(video::ITexture* texture);
virtual const core::aabbox3d<f32>& getBoundingBox() const;
virtual void OnRegisterSceneNode();
virtual void render();
private:
scene::IMeshSceneNode* m_meshnode;
f32 m_thickness;
scene::IMesh* m_cubemesh;
bool m_is_cube;
u8 m_light;
// internal extrusion helper methods
io::path getExtrudedName(video::ITexture* texture);
scene::IAnimatedMesh* extrudeARGB(u32 width, u32 height, u8* data);
scene::IAnimatedMesh* extrude(video::ITexture* texture);
scene::IMesh* createCubeMesh();
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -113,7 +113,8 @@ enum ClientEventType
{
CE_NONE,
CE_PLAYER_DAMAGE,
CE_PLAYER_FORCE_MOVE
CE_PLAYER_FORCE_MOVE,
CE_DEATHSCREEN,
};
struct ClientEvent
@@ -129,6 +130,12 @@ struct ClientEvent
f32 pitch;
f32 yaw;
} player_force_move;
struct{
bool set_camera_point_target;
f32 camera_point_target_x;
f32 camera_point_target_y;
f32 camera_point_target_z;
} deathscreen;
};
};
@@ -183,32 +190,31 @@ class Client : public con::PeerHandler, public InventoryManager
void groundAction(u8 action, v3s16 nodepos_undersurface,
v3s16 nodepos_oversurface, u16 item);
void clickObject(u8 button, v3s16 blockpos, s16 id, u16 item);
void clickActiveObject(u8 button, u16 id, u16 item);
void clickActiveObject(u8 button, u16 id, u16 item_i);
void sendSignText(v3s16 blockpos, s16 id, std::string text);
void sendSignNodeText(v3s16 p, std::string text);
void sendInventoryAction(InventoryAction *a);
void sendChatMessage(const std::wstring &message);
void sendChangePassword(const std::wstring oldpassword,
const std::wstring newpassword);
void sendDamage(u8 damage);
void sendRespawn();
// locks envlock
void removeNode(v3s16 p);
// locks envlock
void addNode(v3s16 p, MapNode n);
void updateCamera(v3f pos, v3f dir);
void updateCamera(v3f pos, v3f dir, f32 fov);
void renderPostFx();
// Returns InvalidPositionException if not found
MapNode getNode(v3s16 p);
// Wrapper to Map
NodeMetadata* getNodeMetadata(v3s16 p);
// Get the player position, and optionally put the
// eye position in *eye_position
v3f getPlayerPosition(v3f *eye_position=NULL);
LocalPlayer* getLocalPlayer();
void setPlayerControl(PlayerControl &control);
@@ -225,14 +231,6 @@ class Client : public con::PeerHandler, public InventoryManager
Inventory* getInventory(InventoryContext *c, std::string id);
void inventoryAction(InventoryAction *a);
// Gets closest object pointed by the shootline
// Returns NULL if not found
MapBlockObject * getSelectedObject(
f32 max_d,
v3f from_pos_f_on_map,
core::line3d<f32> shootline_on_map
);
// Gets closest object pointed by the shootline
// Returns NULL if not found
ClientActiveObject * getSelectedActiveObject(
@@ -253,11 +251,11 @@ class Client : public con::PeerHandler, public InventoryManager
float getAvgRtt()
{
//JMutexAutoLock lock(m_con_mutex); //bulk comment-out
con::Peer *peer = m_con.GetPeerNoEx(PEER_ID_SERVER);
if(peer == NULL)
return 0.0;
return peer->avg_rtt;
try{
return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
} catch(con::PeerNotFoundException){
return 1337;
}
}
bool getChatMessage(std::wstring &message)
@@ -302,15 +300,8 @@ class Client : public con::PeerHandler, public InventoryManager
{
return m_access_denied_reason;
}
/*
This should only be used for calling the special drawing stuff in
ClientEnvironment
*/
ClientEnvironment * getEnv()
{
return &m_env;
}
float getRTT(void);
private:
@@ -342,9 +333,6 @@ class Client : public con::PeerHandler, public InventoryManager
IrrlichtDevice *m_device;
v3f camera_position;
v3f camera_direction;
// Server serialization version
u8 m_server_ser_ver;

View File

@@ -45,7 +45,7 @@ ClientActiveObject* ClientActiveObject::create(u8 type)
{
// If factory is not found, just return.
dstream<<"WARNING: ClientActiveObject: No factory for type="
<<type<<std::endl;
<<(int)type<<std::endl;
return NULL;
}

View File

@@ -51,6 +51,7 @@ class ClientActiveObject : public ActiveObject
virtual core::aabbox3d<f32>* getSelectionBox(){return NULL;}
virtual core::aabbox3d<f32>* getCollisionBox(){return NULL;}
virtual v3f getPosition(){return v3f(0,0,0);}
virtual bool doShowSelectionBox(){return true;}
// Step object in time
virtual void step(float dtime, ClientEnvironment *env){}
@@ -59,7 +60,7 @@ class ClientActiveObject : public ActiveObject
virtual void processMessage(const std::string &data){}
virtual std::string infoText() {return "";}
/*
This takes the return value of
ServerActiveObject::getClientInitializationData
@@ -69,6 +70,10 @@ class ClientActiveObject : public ActiveObject
// Create a certain type of ClientActiveObject
static ClientActiveObject* create(u8 type);
// If returns true, punch will not be sent to the server
virtual bool directReportPunch(const std::string &toolname, v3f dir)
{ return false; }
protected:
// Used for creating objects based on type
typedef ClientActiveObject* (*Factory)();

View File

@@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "utility.h"
#define PROTOCOL_VERSION 3
#define PROTOCOL_ID 0x4f457403
#define PASSWORD_SIZE 28 // Maximum password length. Allows for
@@ -172,6 +174,13 @@ enum ToClientCommand
string serialized item
}
*/
TOCLIENT_DEATHSCREEN = 0x37,
/*
u16 command
u8 bool set camera point target
v3f1000 camera point target (to point the death cause or whatever)
*/
};
enum ToServerCommand
@@ -320,7 +329,11 @@ enum ToServerCommand
[0] u16 TOSERVER_PLAYERITEM
[2] u16 item
*/
TOSERVER_RESPAWN=0x38,
/*
u16 TOSERVER_RESPAWN
*/
};
inline SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time)

View File

@@ -21,6 +21,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "noise.h"
#include "constants.h"
#include "debug.h"
#include "main.h" // For g_profiler and g_settings
#include "profiler.h"
#include "settings.h"
Clouds::Clouds(
scene::ISceneNode* parent,
@@ -76,6 +79,12 @@ void Clouds::render()
if(SceneManager->getSceneNodeRenderPass() != scene::ESNRP_SOLID)
return;
ScopeProfiler sp(g_profiler, "Rendering of clouds, avg", SPT_AVG);
int num_faces_to_draw = 1;
if(g_settings->getBool("enable_3d_clouds"))
num_faces_to_draw = 6;
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
driver->setMaterial(m_material);
@@ -144,7 +153,7 @@ void Clouds::render()
f32 ry = 8*BS;
f32 rz = cloud_size;
for(int i=0;i<6;i++)
for(int i=0; i<num_faces_to_draw; i++)
{
switch(i)
{

View File

@@ -23,7 +23,26 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define endSceneX(d){d->draw2DLine(v2s32(0,0),v2s32(1,0),\
video::SColor(255,30,30,30));d->endScene();}
#include <irrlicht.h>
#include <irrTypes.h>
#include <vector2d.h>
#include <vector3d.h>
#include <irrMap.h>
#include <irrList.h>
#include <irrArray.h>
#include <aabbox3d.h>
#ifndef SERVER
#include <SColor.h>
#include <IMesh.h>
#include <IImage.h>
#include <IrrlichtDevice.h>
#include <IMeshSceneNode.h>
#include <SMesh.h>
#include <ISceneManager.h>
#include <IMeshBuffer.h>
#include <SMeshBuffer.h>
#include <IGUIElement.h>
#include <IGUIEnvironment.h>
#endif
using namespace irr;
typedef core::vector3df v3f;
typedef core::vector3d<s16> v3s16;

File diff suppressed because it is too large Load Diff

View File

@@ -319,28 +319,6 @@ struct Channel
{
Channel();
~Channel();
/*
Processes a packet with the basic header stripped out.
Parameters:
packetdata: Data in packet (with no base headers)
con: The connection to which the channel is associated
(used for sending back stuff (ACKs))
peer_id: peer id of the sender of the packet in question
channelnum: channel on which the packet was sent
reliable: true if recursing into a reliable packet
*/
SharedBuffer<u8> ProcessPacket(
SharedBuffer<u8> packetdata,
Connection *con,
u16 peer_id,
u8 channelnum,
bool reliable=false);
// Returns next data from a buffer if possible
// throws a NoIncomingDataException if no data is available
// If found, sets peer_id
SharedBuffer<u8> CheckIncomingBuffers(Connection *con,
u16 &peer_id);
u16 next_outgoing_seqnum;
u16 next_incoming_seqnum;
@@ -412,78 +390,237 @@ class Peer
// with the id we have given to it
bool has_sent_with_id;
float m_sendtime_accu;
float m_max_packets_per_second;
int m_num_sent;
int m_max_num_sent;
private:
};
class Connection
/*
Connection
*/
struct OutgoingPacket
{
u16 peer_id;
u8 channelnum;
SharedBuffer<u8> data;
bool reliable;
OutgoingPacket(u16 peer_id_, u8 channelnum_, SharedBuffer<u8> data_,
bool reliable_):
peer_id(peer_id_),
channelnum(channelnum_),
data(data_),
reliable(reliable_)
{
}
};
enum ConnectionEventType{
CONNEVENT_NONE,
CONNEVENT_DATA_RECEIVED,
CONNEVENT_PEER_ADDED,
CONNEVENT_PEER_REMOVED,
};
struct ConnectionEvent
{
enum ConnectionEventType type;
u16 peer_id;
Buffer<u8> data;
bool timeout;
Address address;
ConnectionEvent(): type(CONNEVENT_NONE) {}
std::string describe()
{
switch(type){
case CONNEVENT_NONE:
return "CONNEVENT_NONE";
case CONNEVENT_DATA_RECEIVED:
return "CONNEVENT_DATA_RECEIVED";
case CONNEVENT_PEER_ADDED:
return "CONNEVENT_PEER_ADDED";
case CONNEVENT_PEER_REMOVED:
return "CONNEVENT_PEER_REMOVED";
}
return "Invalid ConnectionEvent";
}
void dataReceived(u16 peer_id_, SharedBuffer<u8> data_)
{
type = CONNEVENT_DATA_RECEIVED;
peer_id = peer_id_;
data = data_;
}
void peerAdded(u16 peer_id_, Address address_)
{
type = CONNEVENT_PEER_ADDED;
peer_id = peer_id_;
address = address_;
}
void peerRemoved(u16 peer_id_, bool timeout_, Address address_)
{
type = CONNEVENT_PEER_REMOVED;
peer_id = peer_id_;
timeout = timeout_;
address = address_;
}
};
enum ConnectionCommandType{
CONNCMD_NONE,
CONNCMD_SERVE,
CONNCMD_CONNECT,
CONNCMD_DISCONNECT,
CONNCMD_SEND,
CONNCMD_SEND_TO_ALL,
CONNCMD_DELETE_PEER,
};
struct ConnectionCommand
{
enum ConnectionCommandType type;
u16 port;
Address address;
u16 peer_id;
u8 channelnum;
Buffer<u8> data;
bool reliable;
ConnectionCommand(): type(CONNCMD_NONE) {}
void serve(u16 port_)
{
type = CONNCMD_SERVE;
port = port_;
}
void connect(Address address_)
{
type = CONNCMD_CONNECT;
address = address_;
}
void disconnect()
{
type = CONNCMD_DISCONNECT;
}
void send(u16 peer_id_, u8 channelnum_,
SharedBuffer<u8> data_, bool reliable_)
{
type = CONNCMD_SEND;
peer_id = peer_id_;
channelnum = channelnum_;
data = data_;
reliable = reliable_;
}
void sendToAll(u8 channelnum_, SharedBuffer<u8> data_, bool reliable_)
{
type = CONNCMD_SEND_TO_ALL;
channelnum = channelnum_;
data = data_;
reliable = reliable_;
}
void deletePeer(u16 peer_id_)
{
type = CONNCMD_DELETE_PEER;
peer_id = peer_id_;
}
};
class Connection: public SimpleThread
{
public:
Connection(
u32 protocol_id,
u32 max_packet_size,
float timeout,
PeerHandler *peerhandler
);
Connection(u32 protocol_id, u32 max_packet_size, float timeout);
Connection(u32 protocol_id, u32 max_packet_size, float timeout,
PeerHandler *peerhandler);
~Connection();
void setTimeoutMs(int timeout){ m_socket.setTimeoutMs(timeout); }
// Start being a server
void * Thread();
/* Interface */
ConnectionEvent getEvent();
ConnectionEvent waitEvent(u32 timeout_ms);
void putCommand(ConnectionCommand &c);
void SetTimeoutMs(int timeout){ m_bc_receive_timeout = timeout; }
void Serve(unsigned short port);
// Connect to a server
void Connect(Address address);
bool Connected();
void Disconnect();
// Sets peer_id
SharedBuffer<u8> GetFromBuffers(u16 &peer_id);
// The peer_id of sender is stored in peer_id
// Return value: I guess this always throws an exception or
// actually gets data
// May call PeerHandler methods
u32 Receive(u16 &peer_id, u8 *data, u32 datasize);
// These will automatically package the data as an original or split
u32 Receive(u16 &peer_id, SharedBuffer<u8> &data);
void SendToAll(u8 channelnum, SharedBuffer<u8> data, bool reliable);
void Send(u16 peer_id, u8 channelnum, SharedBuffer<u8> data, bool reliable);
// Send data as a packet; it will be wrapped in base header and
// optionally to a reliable packet.
void SendAsPacket(u16 peer_id, u8 channelnum,
SharedBuffer<u8> data, bool reliable);
// Sends a raw packet
void RawSend(const BufferedPacket &packet);
// May call PeerHandler methods
void RunTimeouts(float dtime);
// Can throw a PeerNotFoundException
Peer* GetPeer(u16 peer_id);
// returns NULL if failed
Peer* GetPeerNoEx(u16 peer_id);
core::list<Peer*> GetPeers();
// Calls PeerHandler::deletingPeer
// Returns false if peer was not found
bool deletePeer(u16 peer_id, bool timeout);
void SetPeerID(u16 id){ m_peer_id = id; }
void RunTimeouts(float dtime); // dummy
u16 GetPeerID(){ return m_peer_id; }
u32 GetProtocolID(){ return m_protocol_id; }
Address GetPeerAddress(u16 peer_id);
float GetPeerAvgRTT(u16 peer_id);
void DeletePeer(u16 peer_id);
private:
void putEvent(ConnectionEvent &e);
void processCommand(ConnectionCommand &c);
void send(float dtime);
void receive();
void runTimeouts(float dtime);
void serve(u16 port);
void connect(Address address);
void disconnect();
void sendToAll(u8 channelnum, SharedBuffer<u8> data, bool reliable);
void send(u16 peer_id, u8 channelnum, SharedBuffer<u8> data, bool reliable);
void sendAsPacket(u16 peer_id, u8 channelnum,
SharedBuffer<u8> data, bool reliable);
void rawSendAsPacket(u16 peer_id, u8 channelnum,
SharedBuffer<u8> data, bool reliable);
void rawSend(const BufferedPacket &packet);
Peer* getPeer(u16 peer_id);
Peer* getPeerNoEx(u16 peer_id);
core::list<Peer*> getPeers();
bool getFromBuffers(u16 &peer_id, SharedBuffer<u8> &dst);
// Returns next data from a buffer if possible
// If found, returns true; if not, false.
// If found, sets peer_id and dst
bool checkIncomingBuffers(Channel *channel, u16 &peer_id,
SharedBuffer<u8> &dst);
/*
Processes a packet with the basic header stripped out.
Parameters:
packetdata: Data in packet (with no base headers)
peer_id: peer id of the sender of the packet in question
channelnum: channel on which the packet was sent
reliable: true if recursing into a reliable packet
*/
SharedBuffer<u8> processPacket(Channel *channel,
SharedBuffer<u8> packetdata, u16 peer_id,
u8 channelnum, bool reliable);
bool deletePeer(u16 peer_id, bool timeout);
Queue<OutgoingPacket> m_outgoing_queue;
MutexedQueue<ConnectionEvent> m_event_queue;
MutexedQueue<ConnectionCommand> m_command_queue;
u32 m_protocol_id;
u32 m_max_packet_size;
float m_timeout;
UDPSocket m_socket;
u16 m_peer_id;
core::map<u16, Peer*> m_peers;
JMutex m_peers_mutex;
// For debug printing
// Backwards compatibility
PeerHandler *m_bc_peerhandler;
int m_bc_receive_timeout;
void SetPeerID(u16 id){ m_peer_id = id; }
u32 GetProtocolID(){ return m_protocol_id; }
void PrintInfo(std::ostream &out);
void PrintInfo();
std::string getDesc();
u16 m_indentation;
private:
u32 m_protocol_id;
float m_timeout;
PeerHandler *m_peerhandler;
core::map<u16, Peer*> m_peers;
u16 m_peer_id;
//bool m_waiting_new_peer_id;
u32 m_max_packet_size;
UDPSocket m_socket;
};
} // namespace

View File

@@ -44,9 +44,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PI 3.14159
// This is the same as in minecraft and everything else
#define FOV_ANGLE (PI/2.5)
// The absolute working limit is (2^15 - viewing_range).
// I really don't want to make every algorithm to check if it's
// going near the limit or not, so this is lower.

View File

@@ -20,6 +20,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_cao.h"
#include "tile.h"
#include "environment.h"
#include "settings.h"
#include <ICameraSceneNode.h>
core::map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
@@ -114,7 +116,7 @@ void TestCAO::step(float dtime, ClientEnvironment *env)
if(m_node)
{
v3f rot = m_node->getRotation();
//dstream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
//infostream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
rot.Y += dtime * 180;
m_node->setRotation(rot);
}
@@ -122,7 +124,7 @@ void TestCAO::step(float dtime, ClientEnvironment *env)
void TestCAO::processMessage(const std::string &data)
{
dstream<<"TestCAO: Got data: "<<data<<std::endl;
infostream<<"TestCAO: Got data: "<<data<<std::endl;
std::istringstream is(data, std::ios::binary);
u16 cmd;
is>>cmd;
@@ -206,6 +208,35 @@ void ItemCAO::addToScene(scene::ISceneManager *smgr)
// This is needed for changing the texture in the future
m_node->setReadOnlyMaterials(true);
updateNodePos();
/*
Update image of node
*/
// Create an inventory item to see what is its image
std::istringstream is(m_inventorystring, std::ios_base::binary);
video::ITexture *texture = NULL;
try{
InventoryItem *item = NULL;
item = InventoryItem::deSerialize(is);
infostream<<__FUNCTION_NAME<<": m_inventorystring=\""
<<m_inventorystring<<"\" -> item="<<item
<<std::endl;
if(item)
{
texture = item->getImage();
delete item;
}
}
catch(SerializationError &e)
{
infostream<<"WARNING: "<<__FUNCTION_NAME
<<": error deSerializing inventorystring \""
<<m_inventorystring<<"\""<<std::endl;
}
// Set meshbuffer texture
buf->getMaterial().setTexture(0, texture);
}
void ItemCAO::removeFromScene()
@@ -224,22 +255,7 @@ void ItemCAO::updateLight(u8 light_at_pos)
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;
}
}
setMeshVerticesColor(m_node->getMesh(), color);
}
v3s16 ItemCAO::getLightPosition()
@@ -272,7 +288,7 @@ void ItemCAO::step(float dtime, ClientEnvironment *env)
void ItemCAO::processMessage(const std::string &data)
{
dstream<<"ItemCAO: Got message"<<std::endl;
infostream<<"ItemCAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
@@ -286,7 +302,7 @@ void ItemCAO::processMessage(const std::string &data)
void ItemCAO::initialize(const std::string &data)
{
dstream<<"ItemCAO: Got init data"<<std::endl;
infostream<<"ItemCAO: Got init data"<<std::endl;
{
std::istringstream is(data, std::ios::binary);
@@ -302,49 +318,6 @@ void ItemCAO::initialize(const std::string &data)
}
updateNodePos();
/*
Update image of node
*/
if(m_node == NULL)
return;
scene::IMesh *mesh = m_node->getMesh();
if(mesh == NULL)
return;
scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
if(buf == NULL)
return;
// Create an inventory item to see what is its image
std::istringstream is(m_inventorystring, std::ios_base::binary);
video::ITexture *texture = NULL;
try{
InventoryItem *item = NULL;
item = InventoryItem::deSerialize(is);
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);
}
/*
@@ -430,22 +403,7 @@ void RatCAO::updateLight(u8 light_at_pos)
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;
}
}
setMeshVerticesColor(m_node->getMesh(), color);
}
v3s16 RatCAO::getLightPosition()
@@ -474,7 +432,7 @@ void RatCAO::step(float dtime, ClientEnvironment *env)
void RatCAO::processMessage(const std::string &data)
{
//dstream<<"RatCAO: Got message"<<std::endl;
//infostream<<"RatCAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
@@ -491,7 +449,7 @@ void RatCAO::processMessage(const std::string &data)
void RatCAO::initialize(const std::string &data)
{
//dstream<<"RatCAO: Got init data"<<std::endl;
//infostream<<"RatCAO: Got init data"<<std::endl;
{
std::istringstream is(data, std::ios::binary);
@@ -601,22 +559,7 @@ void Oerkki1CAO::updateLight(u8 light_at_pos)
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;
}
}
setMeshVerticesColor(m_node->getMesh(), color);
}
v3s16 Oerkki1CAO::getLightPosition()
@@ -649,7 +592,7 @@ void Oerkki1CAO::step(float dtime, ClientEnvironment *env)
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 &&
if(fabs(m_position.Y - playerpos.Y) < 1.5*BS &&
objectpos_2d.getDistanceFrom(playerpos_2d) < 1.5*BS)
{
if(m_attack_interval.step(dtime, 0.5))
@@ -713,7 +656,7 @@ void Oerkki1CAO::step(float dtime, ClientEnvironment *env)
void Oerkki1CAO::processMessage(const std::string &data)
{
//dstream<<"Oerkki1CAO: Got message"<<std::endl;
//infostream<<"Oerkki1CAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
@@ -728,14 +671,14 @@ void Oerkki1CAO::processMessage(const std::string &data)
}
else if(cmd == 1)
{
u16 damage = readU8(is);
//u16 damage = readU8(is);
m_damage_visual_timer = 1.0;
}
}
void Oerkki1CAO::initialize(const std::string &data)
{
//dstream<<"Oerkki1CAO: Got init data"<<std::endl;
//infostream<<"Oerkki1CAO: Got init data"<<std::endl;
{
std::istringstream is(data, std::ios::binary);
@@ -752,6 +695,18 @@ void Oerkki1CAO::initialize(const std::string &data)
updateNodePos();
}
bool Oerkki1CAO::directReportPunch(const std::string &toolname, v3f dir)
{
m_damage_visual_timer = 1.0;
m_position += dir * BS;
pos_translator.sharpen();
pos_translator.update(m_position);
updateNodePos();
return false;
}
/*
FireflyCAO
*/
@@ -833,22 +788,7 @@ void FireflyCAO::updateLight(u8 light_at_pos)
u8 li = 255;
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;
}
}
setMeshVerticesColor(m_node->getMesh(), color);
}
v3s16 FireflyCAO::getLightPosition()
@@ -877,7 +817,7 @@ void FireflyCAO::step(float dtime, ClientEnvironment *env)
void FireflyCAO::processMessage(const std::string &data)
{
//dstream<<"FireflyCAO: Got message"<<std::endl;
//infostream<<"FireflyCAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
@@ -894,7 +834,7 @@ void FireflyCAO::processMessage(const std::string &data)
void FireflyCAO::initialize(const std::string &data)
{
//dstream<<"FireflyCAO: Got init data"<<std::endl;
//infostream<<"FireflyCAO: Got init data"<<std::endl;
{
std::istringstream is(data, std::ios::binary);
@@ -910,3 +850,417 @@ void FireflyCAO::initialize(const std::string &data)
updateNodePos();
}
/*
MobV2CAO
*/
// Prototype
MobV2CAO proto_MobV2CAO;
MobV2CAO::MobV2CAO():
ClientActiveObject(0),
m_selection_box(-0.4*BS,-0.4*BS,-0.4*BS, 0.4*BS,0.8*BS,0.4*BS),
m_node(NULL),
m_position(v3f(0,10*BS,0)),
m_yaw(0),
m_walking(false),
m_walking_unset_timer(0),
m_walk_timer(0),
m_walk_frame(0),
m_damage_visual_timer(0),
m_last_light(0),
m_shooting(0),
m_shooting_unset_timer(0),
m_sprite_size(BS,BS),
m_sprite_y(0),
m_bright_shooting(false),
m_lock_full_brightness(false),
m_player_hit_timer(0)
{
ClientActiveObject::registerType(getType(), create);
m_properties = new Settings;
}
MobV2CAO::~MobV2CAO()
{
delete m_properties;
}
ClientActiveObject* MobV2CAO::create()
{
return new MobV2CAO();
}
void MobV2CAO::addToScene(scene::ISceneManager *smgr)
{
if(m_node != NULL)
return;
/*infostream<<"MobV2CAO::addToScene using texture_name="<<
m_texture_name<<std::endl;*/
std::string texture_string = "[makealpha2:128,0,0;128,128,0:";
texture_string += m_texture_name;
scene::MyBillboardSceneNode *bill = new scene::MyBillboardSceneNode(
smgr->getRootSceneNode(), smgr, -1, v3f(0,0,0), v2f(1,1));
bill->setMaterialTexture(0, g_texturesource->getTextureRaw(texture_string));
bill->setMaterialFlag(video::EMF_LIGHTING, false);
bill->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
bill->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
bill->setMaterialFlag(video::EMF_FOG_ENABLE, true);
bill->setColor(video::SColor(255,0,0,0));
bill->setVisible(false); /* Set visible when brightness is known */
bill->setSize(m_sprite_size);
if(m_sprite_type == "humanoid_1"){
const float txp = 1./192;
const float txs = txp*32;
const float typ = 1./240;
const float tys = typ*48;
bill->setTCoords(0, v2f(txs*1, tys*1));
bill->setTCoords(1, v2f(txs*1, tys*0));
bill->setTCoords(2, v2f(txs*0, tys*0));
bill->setTCoords(3, v2f(txs*0, tys*1));
} else if(m_sprite_type == "simple"){
const float txs = 1.0;
const float tys = 1.0 / m_simple_anim_frames;
bill->setTCoords(0, v2f(txs*1, tys*1));
bill->setTCoords(1, v2f(txs*1, tys*0));
bill->setTCoords(2, v2f(txs*0, tys*0));
bill->setTCoords(3, v2f(txs*0, tys*1));
} else {
infostream<<"MobV2CAO: Unknown sprite type \""<<m_sprite_type<<"\""
<<std::endl;
}
m_node = bill;
updateNodePos();
}
void MobV2CAO::removeFromScene()
{
if(m_node == NULL)
return;
m_node->drop();
m_node->remove();
m_node = NULL;
}
void MobV2CAO::updateLight(u8 light_at_pos)
{
if(m_lock_full_brightness)
light_at_pos = 15;
m_last_light = light_at_pos;
if(m_node == NULL)
return;
if(m_damage_visual_timer > 0)
return;
if(m_shooting && m_bright_shooting)
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);
m_node->setColor(color);
}
v3s16 MobV2CAO::getLightPosition()
{
return floatToInt(m_position+v3f(0,0,0), BS);
}
void MobV2CAO::updateNodePos()
{
if(m_node == NULL)
return;
m_node->setPosition(pos_translator.vect_show + v3f(0,m_sprite_y,0));
}
void MobV2CAO::step(float dtime, ClientEnvironment *env)
{
scene::MyBillboardSceneNode *bill = m_node;
if(!bill)
return;
pos_translator.translate(dtime);
if(m_sprite_type == "humanoid_1"){
scene::ICameraSceneNode* camera = m_node->getSceneManager()->getActiveCamera();
if(!camera)
return;
v3f cam_to_mob = m_node->getAbsolutePosition() - camera->getAbsolutePosition();
cam_to_mob.normalize();
int col = 0;
if(cam_to_mob.Y > 0.75)
col = 5;
else if(cam_to_mob.Y < -0.75)
col = 4;
else{
float mob_dir = atan2(cam_to_mob.Z, cam_to_mob.X) / PI * 180.;
float dir = mob_dir - m_yaw;
dir = wrapDegrees_180(dir);
//infostream<<"id="<<m_id<<" dir="<<dir<<std::endl;
if(fabs(wrapDegrees_180(dir - 0)) <= 45.1)
col = 2;
else if(fabs(wrapDegrees_180(dir - 90)) <= 45.1)
col = 3;
else if(fabs(wrapDegrees_180(dir - 180)) <= 45.1)
col = 0;
else if(fabs(wrapDegrees_180(dir + 90)) <= 45.1)
col = 1;
else
col = 4;
}
int row = 0;
if(m_shooting){
row = 3;
} else if(m_walking){
m_walk_timer += dtime;
if(m_walk_timer >= 0.5){
m_walk_frame = (m_walk_frame + 1) % 2;
m_walk_timer = 0;
}
if(m_walk_frame == 0)
row = 1;
else
row = 2;
}
const float txp = 1./192;
const float txs = txp*32;
const float typ = 1./240;
const float tys = typ*48;
bill->setTCoords(0, v2f(txs*(1+col), tys*(1+row)));
bill->setTCoords(1, v2f(txs*(1+col), tys*(0+row)));
bill->setTCoords(2, v2f(txs*(0+col), tys*(0+row)));
bill->setTCoords(3, v2f(txs*(0+col), tys*(1+row)));
} else if(m_sprite_type == "simple"){
m_walk_timer += dtime;
if(m_walk_timer >= m_simple_anim_frametime){
m_walk_frame = (m_walk_frame + 1) % m_simple_anim_frames;
m_walk_timer = 0;
}
int col = 0;
int row = m_walk_frame;
const float txs = 1.0;
const float tys = 1.0 / m_simple_anim_frames;
bill->setTCoords(0, v2f(txs*(1+col), tys*(1+row)));
bill->setTCoords(1, v2f(txs*(1+col), tys*(0+row)));
bill->setTCoords(2, v2f(txs*(0+col), tys*(0+row)));
bill->setTCoords(3, v2f(txs*(0+col), tys*(1+row)));
} else {
infostream<<"MobV2CAO::step(): Unknown sprite type \""
<<m_sprite_type<<"\""<<std::endl;
}
updateNodePos();
/* Damage local player */
if(m_player_hit_damage && m_player_hit_timer <= 0.0){
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) < m_player_hit_distance*BS &&
objectpos_2d.getDistanceFrom(playerpos_2d) < m_player_hit_distance*BS)
{
env->damageLocalPlayer(m_player_hit_damage);
m_player_hit_timer = m_player_hit_interval;
}
}
/* Run timers */
m_player_hit_timer -= dtime;
if(m_damage_visual_timer >= 0){
m_damage_visual_timer -= dtime;
if(m_damage_visual_timer <= 0){
infostream<<"id="<<m_id<<" damage visual ended"<<std::endl;
}
}
m_walking_unset_timer += dtime;
if(m_walking_unset_timer >= 1.0){
m_walking = false;
}
m_shooting_unset_timer -= dtime;
if(m_shooting_unset_timer <= 0.0){
if(m_bright_shooting){
u8 li = decode_light(m_last_light);
video::SColor color(255,li,li,li);
bill->setColor(color);
m_bright_shooting = false;
}
m_shooting = false;
}
}
void MobV2CAO::processMessage(const std::string &data)
{
//infostream<<"MobV2CAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
// Move
if(cmd == 0)
{
// pos
m_position = readV3F1000(is);
pos_translator.update(m_position);
// yaw
m_yaw = readF1000(is);
m_walking = true;
m_walking_unset_timer = 0;
updateNodePos();
}
// Damage
else if(cmd == 1)
{
//u16 damage = readU16(is);
/*u8 li = decode_light(m_last_light);
if(li >= 100)
li = 30;
else
li = 255;*/
/*video::SColor color(255,255,0,0);
m_node->setColor(color);
m_damage_visual_timer = 0.2;*/
}
// Trigger shooting
else if(cmd == 2)
{
// length
m_shooting_unset_timer = readF1000(is);
// bright?
m_bright_shooting = readU8(is);
if(m_bright_shooting){
u8 li = 255;
video::SColor color(255,li,li,li);
m_node->setColor(color);
}
m_shooting = true;
}
}
void MobV2CAO::initialize(const std::string &data)
{
//infostream<<"MobV2CAO: Got init data"<<std::endl;
{
std::istringstream is(data, std::ios::binary);
// version
u8 version = readU8(is);
// check version
if(version != 0){
infostream<<__FUNCTION_NAME<<": Invalid version"<<std::endl;
return;
}
std::ostringstream tmp_os(std::ios::binary);
decompressZlib(is, tmp_os);
std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
m_properties->parseConfigLines(tmp_is, "MobArgsEnd");
infostream<<"MobV2CAO::initialize(): got properties:"<<std::endl;
m_properties->writeLines(infostream);
m_properties->setDefault("looks", "dummy_default");
m_properties->setDefault("yaw", "0");
m_properties->setDefault("pos", "(0,0,0)");
m_properties->setDefault("player_hit_damage", "0");
m_properties->setDefault("player_hit_distance", "1.5");
m_properties->setDefault("player_hit_interval", "1.5");
setLooks(m_properties->get("looks"));
m_yaw = m_properties->getFloat("yaw");
m_position = m_properties->getV3F("pos");
m_player_hit_damage = m_properties->getS32("player_hit_damage");
m_player_hit_distance = m_properties->getFloat("player_hit_distance");
m_player_hit_interval = m_properties->getFloat("player_hit_interval");
pos_translator.init(m_position);
}
updateNodePos();
}
bool MobV2CAO::directReportPunch(const std::string &toolname, v3f dir)
{
video::SColor color(255,255,0,0);
m_node->setColor(color);
m_damage_visual_timer = 0.05;
m_position += dir * BS;
pos_translator.sharpen();
pos_translator.update(m_position);
updateNodePos();
return false;
}
void MobV2CAO::setLooks(const std::string &looks)
{
v2f selection_size = v2f(0.4, 0.4) * BS;
float selection_y = 0 * BS;
if(looks == "dungeon_master"){
m_texture_name = "dungeon_master.png";
m_sprite_type = "humanoid_1";
m_sprite_size = v2f(2, 3) * BS;
m_sprite_y = 0.85 * BS;
selection_size = v2f(0.4, 2.6) * BS;
selection_y = -0.4 * BS;
}
else if(looks == "fireball"){
m_texture_name = "fireball.png";
m_sprite_type = "simple";
m_sprite_size = v2f(1, 1) * BS;
m_simple_anim_frames = 3;
m_simple_anim_frametime = 0.1;
m_lock_full_brightness = true;
}
else{
m_texture_name = "stone.png";
m_sprite_type = "simple";
m_sprite_size = v2f(1, 1) * BS;
m_simple_anim_frames = 3;
m_simple_anim_frametime = 0.333;
selection_size = v2f(0.4, 0.4) * BS;
selection_y = 0 * BS;
}
m_selection_box = core::aabbox3d<f32>(
-selection_size.X, selection_y, -selection_size.X,
selection_size.X, selection_y+selection_size.Y,
selection_size.X);
}

View File

@@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "clientobject.h"
#include "content_object.h"
#include "utility.h" // For IntervalLimiter
class Settings;
#include "MyBillboardSceneNode.h"
/*
SmoothTranslator
@@ -31,19 +33,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
struct SmoothTranslator
{
v3f vect_old;
v3f vect_show;
v3f vect_aim;
f32 anim_counter;
f32 anim_time;
f32 anim_time_counter;
v3f vect_show;
v3f vect_aim;
SmoothTranslator():
vect_old(0,0,0),
vect_show(0,0,0),
vect_aim(0,0,0),
anim_counter(0),
anim_time(0),
anim_time_counter(0),
vect_show(0,0,0),
vect_aim(0,0,0)
anim_time_counter(0)
{}
void init(v3f vect)
@@ -51,6 +53,14 @@ struct SmoothTranslator
vect_old = vect;
vect_show = vect;
vect_aim = vect;
anim_counter = 0;
anim_time = 0;
anim_time_counter = 0;
}
void sharpen()
{
init(vect_show);
}
void update(v3f vect_new)
@@ -74,11 +84,16 @@ struct SmoothTranslator
if(anim_time > 0.001)
moveratio = anim_time_counter / anim_time;
// Move a bit less than should, to avoid oscillation
moveratio = moveratio * 0.8;
moveratio = moveratio * 0.5;
if(moveratio > 1.5)
moveratio = 1.5;
vect_show = vect_old + vect_move * moveratio;
}
bool is_moving()
{
return ((anim_time_counter / anim_time) < 1.4);
}
};
@@ -233,6 +248,9 @@ class Oerkki1CAO : public ClientActiveObject
{return pos_translator.vect_show;}
//{return m_position;}
// If returns true, punch will not be sent to the server
bool directReportPunch(const std::string &toolname, v3f dir);
private:
IntervalLimiter m_attack_interval;
core::aabbox3d<f32> m_selection_box;
@@ -286,6 +304,78 @@ class FireflyCAO : public ClientActiveObject
SmoothTranslator pos_translator;
};
/*
MobV2CAO
*/
class MobV2CAO : public ClientActiveObject
{
public:
MobV2CAO();
virtual ~MobV2CAO();
u8 getType() const
{
return ACTIVEOBJECT_TYPE_MOBV2;
}
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;}
bool doShowSelectionBox(){return false;}
// If returns true, punch will not be sent to the server
bool directReportPunch(const std::string &toolname, v3f dir);
private:
void setLooks(const std::string &looks);
IntervalLimiter m_attack_interval;
core::aabbox3d<f32> m_selection_box;
scene::MyBillboardSceneNode *m_node;
v3f m_position;
std::string m_texture_name;
float m_yaw;
SmoothTranslator pos_translator;
bool m_walking;
float m_walking_unset_timer;
float m_walk_timer;
int m_walk_frame;
float m_damage_visual_timer;
u8 m_last_light;
bool m_shooting;
float m_shooting_unset_timer;
v2f m_sprite_size;
float m_sprite_y;
bool m_bright_shooting;
std::string m_sprite_type;
int m_simple_anim_frames;
float m_simple_anim_frametime;
bool m_lock_full_brightness;
int m_player_hit_damage;
float m_player_hit_distance;
float m_player_hit_interval;
float m_player_hit_timer;
Settings *m_properties;
};
#endif

View File

@@ -297,6 +297,24 @@ InventoryItem *craft_get_result(InventoryItem **items)
}
}
// Locking Chest
{
ItemSpec specs[9];
specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot");
specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
if(checkItemCombination(items, specs))
{
return new MaterialItem(CONTENT_LOCKABLE_CHEST, 1);
}
}
// Furnace
{
ItemSpec specs[9];
@@ -487,6 +505,7 @@ void craft_set_creative_inventory(Player *player)
CONTENT_CLAY,
CONTENT_BRICK,
CONTENT_TREE,
CONTENT_WOOD,
CONTENT_LEAVES,
CONTENT_CACTUS,
CONTENT_PAPYRUS,

View File

@@ -72,8 +72,8 @@ std::string item_craft_get_image_name(const std::string &subname)
else if(subname == "firefly")
return "firefly.png";
else if(subname == "apple")
return "apple.png";
else if(subname == "apple_iron")
return "apple.png^[forcesingle";
else if(subname == "apple_iron")
return "apple_iron.png";
else
return "cloud.png"; // just something

View File

@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "main.h" // For g_settings and g_texturesource
#include "mineral.h"
#include "mapblock_mesh.h" // For MapBlock_LightColor()
#include "settings.h"
#ifndef SERVER
// Create a cuboid.
@@ -128,10 +129,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
/*
Some settings
*/
bool new_style_water = g_settings.getBool("new_style_water");
bool new_style_leaves = g_settings.getBool("new_style_leaves");
//bool smooth_lighting = g_settings.getBool("smooth_lighting");
bool invisible_stone = g_settings.getBool("invisible_stone");
bool new_style_water = g_settings->getBool("new_style_water");
bool new_style_leaves = g_settings->getBool("new_style_leaves");
//bool smooth_lighting = g_settings->getBool("smooth_lighting");
bool invisible_stone = g_settings->getBool("invisible_stone");
float node_liquid_level = 1.0;
if(new_style_water)
@@ -142,7 +143,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// New-style leaves material
video::SMaterial material_leaves1;
material_leaves1.setFlag(video::EMF_LIGHTING, false);
//material_leaves1.setFlag(video::EMF_BACK_FACE_CULLING, false);
material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false);
material_leaves1.setFlag(video::EMF_FOG_ENABLE, true);
material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
@@ -199,6 +199,18 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
g_texturesource->getTextureId("apple.png"));
material_apple.setTexture(0, pa_apple.atlas);
// Sapling material
video::SMaterial material_sapling;
material_sapling.setFlag(video::EMF_LIGHTING, false);
material_sapling.setFlag(video::EMF_BILINEAR_FILTER, false);
material_sapling.setFlag(video::EMF_FOG_ENABLE, true);
material_sapling.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
AtlasPointer pa_sapling = g_texturesource->getTexture(
g_texturesource->getTextureId("sapling.png"));
material_sapling.setTexture(0, pa_sapling.atlas);
// junglegrass material
video::SMaterial material_junglegrass;
material_junglegrass.setFlag(video::EMF_LIGHTING, false);
@@ -216,25 +228,54 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
v3s16 p(x,y,z);
MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes+p);
/*
Add torches to mesh
*/
if(n.getContent() == CONTENT_TORCH)
{
v3s16 dir = unpackDir(n.param2);
const char *texturename = "torch.png";
if(dir == v3s16(0,-1,0)){
texturename = "torch_on_floor.png";
} else if(dir == v3s16(0,1,0)){
texturename = "torch_on_ceiling.png";
// For backwards compatibility
} else if(dir == v3s16(0,0,0)){
texturename = "torch_on_floor.png";
} else {
texturename = "torch.png";
}
AtlasPointer ap = g_texturesource->getTexture(texturename);
// Set material
video::SMaterial material;
material.setFlag(video::EMF_LIGHTING, false);
material.setFlag(video::EMF_BACK_FACE_CULLING, false);
material.setFlag(video::EMF_BILINEAR_FILTER, false);
material.setFlag(video::EMF_FOG_ENABLE, true);
//material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
material.MaterialType
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
material.setTexture(0, ap.atlas);
video::SColor c(255,255,255,255);
// Wall at X+ of node
video::S3DVertex vertices[4] =
{
video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
ap.x0(), ap.y1()),
video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
ap.x1(), ap.y1()),
video::S3DVertex(BS/2,BS/2,0, 0,0,0, c,
ap.x1(), ap.y0()),
video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c,
ap.x0(), ap.y0()),
};
v3s16 dir = unpackDir(n.param2);
for(s32 i=0; i<4; i++)
{
if(dir == v3s16(1,0,0))
@@ -253,29 +294,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
}
// Set material
video::SMaterial material;
material.setFlag(video::EMF_LIGHTING, false);
material.setFlag(video::EMF_BACK_FACE_CULLING, false);
material.setFlag(video::EMF_BILINEAR_FILTER, false);
//material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
material.MaterialType
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
if(dir == v3s16(0,-1,0))
material.setTexture(0,
g_texturesource->getTextureRaw("torch_on_floor.png"));
else if(dir == v3s16(0,1,0))
material.setTexture(0,
g_texturesource->getTextureRaw("torch_on_ceiling.png"));
// For backwards compatibility
else if(dir == v3s16(0,0,0))
material.setTexture(0,
g_texturesource->getTextureRaw("torch_on_floor.png"));
else
material.setTexture(0,
g_texturesource->getTextureRaw("torch.png"));
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
collector.append(material, vertices, 4, indices, 6);
@@ -285,6 +303,18 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
*/
else if(n.getContent() == CONTENT_SIGN_WALL)
{
AtlasPointer ap = g_texturesource->getTexture("sign_wall.png");
// Set material
video::SMaterial material;
material.setFlag(video::EMF_LIGHTING, false);
material.setFlag(video::EMF_BACK_FACE_CULLING, false);
material.setFlag(video::EMF_BILINEAR_FILTER, false);
material.setFlag(video::EMF_FOG_ENABLE, true);
material.MaterialType
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
material.setTexture(0, ap.atlas);
u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
video::SColor c = MapBlock_LightColor(255, l);
@@ -292,10 +322,14 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// Wall at X+ of node
video::S3DVertex vertices[4] =
{
video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, 0,1),
video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, 1,1),
video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, 1,0),
video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, 0,0),
video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c,
ap.x0(), ap.y1()),
video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c,
ap.x1(), ap.y1()),
video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c,
ap.x1(), ap.y0()),
video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c,
ap.x0(), ap.y0()),
};
v3s16 dir = unpackDir(n.param2);
@@ -318,19 +352,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
}
// Set material
video::SMaterial material;
material.setFlag(video::EMF_LIGHTING, false);
material.setFlag(video::EMF_BACK_FACE_CULLING, false);
material.setFlag(video::EMF_BILINEAR_FILTER, false);
material.setFlag(video::EMF_FOG_ENABLE, true);
//material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
material.MaterialType
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
material.setTexture(0,
g_texturesource->getTextureRaw("sign_wall.png"));
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
collector.append(material, vertices, 4, indices, 6);
@@ -343,6 +364,9 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
assert(content_features(n).special_material);
video::SMaterial &liquid_material =
*content_features(n).special_material;
video::SMaterial &liquid_material_bfculled =
*content_features(n).special_material2;
assert(content_features(n).special_atlas);
AtlasPointer &pa_liquid1 =
*content_features(n).special_atlas;
@@ -495,10 +519,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
continue;
content_t neighbor_content = neighbor_contents[dir];
ContentFeatures &n_feat = content_features(neighbor_content);
// Don't draw face if neighbor is not air or liquid
if(neighbor_content != CONTENT_AIR
&& content_liquid(neighbor_content) == false)
// Don't draw face if neighbor is blocking the view
if(n_feat.solidness == 2)
continue;
bool neighbor_is_same_liquid = (neighbor_content == c_source
@@ -509,13 +533,15 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
if(neighbor_is_same_liquid == true
&& top_is_same_liquid == false)
continue;
// Use backface culled material if neighbor doesn't have a
// solidness of 0
video::SMaterial *current_material = &liquid_material;
if(n_feat.solidness != 0 || n_feat.visual_solidness != 0)
current_material = &liquid_material_bfculled;
video::S3DVertex vertices[4] =
{
/*video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
pa_liquid1.x0(), pa_liquid1.y1()),
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
@@ -576,17 +602,17 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// Do this to not cause glitches when two liquids are
// side-by-side
if(neighbor_is_same_liquid == false){
/*if(neighbor_is_same_liquid == false){
vertices[j].Pos.X *= 0.98;
vertices[j].Pos.Z *= 0.98;
}
}*/
vertices[j].Pos += intToFloat(p + blockpos_nodes, BS);
}
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
collector.append(liquid_material, vertices, 4, indices, 6);
collector.append(*current_material, vertices, 4, indices, 6);
}
/*
@@ -597,10 +623,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
{
video::S3DVertex vertices[4] =
{
/*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
pa_liquid1.x0(), pa_liquid1.y1()),
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
@@ -655,10 +677,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
video::S3DVertex vertices[4] =
{
/*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
pa_liquid1.x0(), pa_liquid1.y1()),
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
@@ -692,10 +710,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
{
video::S3DVertex vertices[4] =
{
/*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
pa_leaves1.x0(), pa_leaves1.y1()),
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
@@ -914,10 +928,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
video::S3DVertex vertices[4] =
{
/*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
ap.x0(), ap.y1()),
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
@@ -1021,13 +1031,13 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
video::S3DVertex vertices[4] =
{
video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
pa_papyrus.x0(), pa_papyrus.y1()),
pa_junglegrass.x0(), pa_junglegrass.y1()),
video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
pa_papyrus.x1(), pa_papyrus.y1()),
pa_junglegrass.x1(), pa_junglegrass.y1()),
video::S3DVertex(BS/2,BS/1,0, 0,0,0, c,
pa_papyrus.x1(), pa_papyrus.y0()),
pa_junglegrass.x1(), pa_junglegrass.y0()),
video::S3DVertex(-BS/2,BS/1,0, 0,0,0, c,
pa_papyrus.x0(), pa_papyrus.y0()),
pa_junglegrass.x0(), pa_junglegrass.y0()),
};
if(j == 0)
@@ -1064,9 +1074,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
}
else if(n.getContent() == CONTENT_RAIL)
{
u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
video::SColor c = MapBlock_LightColor(255, l);
bool is_rail_x [] = { false, false }; /* x-1, x+1 */
bool is_rail_z [] = { false, false }; /* z-1, z+1 */
@@ -1084,18 +1091,25 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
if(n_plus_z.getContent() == CONTENT_RAIL)
is_rail_z[1] = true;
float d = (float)BS/16;
video::S3DVertex vertices[4] =
int adjacencies = is_rail_x[0] + is_rail_x[1] + is_rail_z[0] + is_rail_z[1];
// Assign textures
const char *texturename = "rail.png";
if(adjacencies < 2)
texturename = "rail.png";
else if(adjacencies == 2)
{
video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c,
0, 1),
video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c,
1, 1),
video::S3DVertex(BS/2,-BS/2+d,BS/2, 0,0,0, c,
1, 0),
video::S3DVertex(-BS/2,-BS/2+d,BS/2, 0,0,0, c,
0, 0),
};
if((is_rail_x[0] && is_rail_x[1]) || (is_rail_z[0] && is_rail_z[1]))
texturename = "rail.png";
else
texturename = "rail_curved.png";
}
else if(adjacencies == 3)
texturename = "rail_t_junction.png";
else if(adjacencies == 4)
texturename = "rail_crossing.png";
AtlasPointer ap = g_texturesource->getTexture(texturename);
video::SMaterial material_rail;
material_rail.setFlag(video::EMF_LIGHTING, false);
@@ -1104,23 +1118,23 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
material_rail.setFlag(video::EMF_FOG_ENABLE, true);
material_rail.MaterialType
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
material_rail.setTexture(0, ap.atlas);
int adjacencies = is_rail_x[0] + is_rail_x[1] + is_rail_z[0] + is_rail_z[1];
u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
video::SColor c = MapBlock_LightColor(255, l);
// Assign textures
if(adjacencies < 2)
material_rail.setTexture(0, g_texturesource->getTextureRaw("rail.png"));
else if(adjacencies == 2)
float d = (float)BS/16;
video::S3DVertex vertices[4] =
{
if((is_rail_x[0] && is_rail_x[1]) || (is_rail_z[0] && is_rail_z[1]))
material_rail.setTexture(0, g_texturesource->getTextureRaw("rail.png"));
else
material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_curved.png"));
}
else if(adjacencies == 3)
material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_t_junction.png"));
else if(adjacencies == 4)
material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_crossing.png"));
video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c,
ap.x0(), ap.y1()),
video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c,
ap.x1(), ap.y1()),
video::S3DVertex(BS/2,-BS/2+d,BS/2, 0,0,0, c,
ap.x1(), ap.y0()),
video::S3DVertex(-BS/2,-BS/2+d,BS/2, 0,0,0, c,
ap.x0(), ap.y0()),
};
// Rotate textures
int angle = 0;
@@ -1167,6 +1181,17 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
collector.append(material_rail, vertices, 4, indices, 6);
}
else if (n.getContent() == CONTENT_LADDER) {
AtlasPointer ap = g_texturesource->getTexture("ladder.png");
// Set material
video::SMaterial material_ladder;
material_ladder.setFlag(video::EMF_LIGHTING, false);
material_ladder.setFlag(video::EMF_BACK_FACE_CULLING, false);
material_ladder.setFlag(video::EMF_BILINEAR_FILTER, false);
material_ladder.setFlag(video::EMF_FOG_ENABLE, true);
material_ladder.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
material_ladder.setTexture(0, ap.atlas);
u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
video::SColor c(255,l,l,l);
@@ -1175,10 +1200,14 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// Assume wall is at X+
video::S3DVertex vertices[4] =
{
video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, 0,1),
video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, 1,1),
video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, 1,0),
video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, 0,0),
video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c,
ap.x0(), ap.y1()),
video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c,
ap.x1(), ap.y1()),
video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c,
ap.x1(), ap.y0()),
video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c,
ap.x0(), ap.y0()),
};
v3s16 dir = unpackDir(n.param2);
@@ -1201,14 +1230,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
}
video::SMaterial material_ladder;
material_ladder.setFlag(video::EMF_LIGHTING, false);
material_ladder.setFlag(video::EMF_BACK_FACE_CULLING, false);
material_ladder.setFlag(video::EMF_BILINEAR_FILTER, false);
material_ladder.setFlag(video::EMF_FOG_ENABLE, true);
material_ladder.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
material_ladder.setTexture(0, g_texturesource->getTextureRaw("ladder.png"));
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
collector.append(material_ladder, vertices, 4, indices, 6);
@@ -1263,6 +1284,55 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
collector.append(material_apple, vertices, 4, indices, 6);
}
}
else if(n.getContent() == CONTENT_SAPLING) {
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
video::SColor c = MapBlock_LightColor(255, l);
for(u32 j=0; j<4; j++)
{
video::S3DVertex vertices[4] =
{
video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
pa_sapling.x0(), pa_sapling.y1()),
video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
pa_sapling.x1(), pa_sapling.y1()),
video::S3DVertex(BS/2,BS/1,0, 0,0,0, c,
pa_sapling.x1(), pa_sapling.y0()),
video::S3DVertex(-BS/2,BS/1,0, 0,0,0, c,
pa_sapling.x0(), pa_sapling.y0()),
};
if(j == 0)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(45);
}
else if(j == 1)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(-45);
}
else if(j == 2)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(135);
}
else if(j == 3)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(-135);
}
for(u16 i=0; i<4; i++)
{
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
}
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
collector.append(material_sapling, vertices, 4, indices, 6);
}
}
}
}
#endif

View File

@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_mapnode.h"
#include "mapnode.h"
#include "content_nodemeta.h"
#include "settings.h"
#define WATER_ALPHA 160
@@ -103,9 +104,10 @@ MapNode mapnode_translate_to_internal(MapNode n_from, u8 version)
void content_mapnode_init()
{
// Read some settings
bool new_style_water = g_settings.getBool("new_style_water");
bool new_style_leaves = g_settings.getBool("new_style_leaves");
bool invisible_stone = g_settings.getBool("invisible_stone");
bool new_style_water = g_settings->getBool("new_style_water");
bool new_style_leaves = g_settings->getBool("new_style_leaves");
bool invisible_stone = g_settings->getBool("invisible_stone");
bool opaque_water = g_settings->getBool("opaque_water");
content_t i;
ContentFeatures *f = NULL;
@@ -116,6 +118,7 @@ void content_mapnode_init()
f->setInventoryTextureCube("stone.png", "stone.png", "stone.png");
f->param_type = CPT_MINERAL;
f->is_ground_content = true;
f->often_contains_mineral = true;
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_COBBLE)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 1.0);
if(invisible_stone)
@@ -218,6 +221,7 @@ void content_mapnode_init()
i = CONTENT_JUNGLEGRASS;
f = &content_features(i);
f->setInventoryTexture("junglegrass.png");
f->used_texturenames["junglegrass.png"] = true;
f->light_propagates = true;
f->param_type = CPT_LIGHT;
//f->is_ground_content = true;
@@ -236,12 +240,16 @@ void content_mapnode_init()
if(new_style_leaves)
{
f->solidness = 0; // drawn separately, makes no faces
f->visual_solidness = 1;
f->setAllTextures("leaves.png");
f->setInventoryTextureCube("leaves.png", "leaves.png", "leaves.png");
}
else
{
f->setAllTextures("[noalpha:leaves.png");
}
f->extra_dug_item = std::string("MaterialItem2 ")+itos(CONTENT_SAPLING)+" 1";
f->extra_dug_item_rarity = 20;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setWoodLikeDiggingProperties(f->digging_properties, 0.15);
@@ -259,6 +267,7 @@ void content_mapnode_init()
i = CONTENT_PAPYRUS;
f = &content_features(i);
f->setInventoryTexture("papyrus.png");
f->used_texturenames["papyrus.png"] = true;
f->light_propagates = true;
f->param_type = CPT_LIGHT;
f->is_ground_content = true;
@@ -287,6 +296,8 @@ void content_mapnode_init()
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->solidness = 0; // drawn separately, makes no faces
f->visual_solidness = 1;
f->setAllTextures("glass.png");
f->setInventoryTextureCube("glass.png", "glass.png", "glass.png");
setWoodLikeDiggingProperties(f->digging_properties, 0.15);
@@ -299,11 +310,13 @@ void content_mapnode_init()
f->solidness = 0; // drawn separately, makes no faces
f->air_equivalent = true; // grass grows underneath
f->setInventoryTexture("fence.png");
f->used_texturenames["fence.png"] = true;
setWoodLikeDiggingProperties(f->digging_properties, 0.75);
i = CONTENT_RAIL;
f = &content_features(i);
f->setInventoryTexture("rail.png");
f->used_texturenames["rail.png"] = true;
f->light_propagates = true;
f->param_type = CPT_LIGHT;
f->is_ground_content = true;
@@ -316,6 +329,7 @@ void content_mapnode_init()
i = CONTENT_LADDER;
f = &content_features(i);
f->setInventoryTexture("ladder.png");
f->used_texturenames["ladder.png"] = true;
f->light_propagates = true;
f->param_type = CPT_LIGHT;
f->is_ground_content = true;
@@ -384,7 +398,10 @@ void content_mapnode_init()
f->liquid_alternative_flowing = CONTENT_WATER;
f->liquid_alternative_source = CONTENT_WATERSOURCE;
f->liquid_viscosity = WATER_VISC;
f->vertex_alpha = WATER_ALPHA;
#ifndef SERVER
if(!opaque_water)
f->vertex_alpha = WATER_ALPHA;
f->post_effect_color = video::SColor(64, 100, 100, 200);
if(f->special_material == NULL && g_texturesource)
{
// Flowing water material
@@ -393,12 +410,20 @@ void content_mapnode_init()
f->special_material->setFlag(video::EMF_BACK_FACE_CULLING, false);
f->special_material->setFlag(video::EMF_BILINEAR_FILTER, false);
f->special_material->setFlag(video::EMF_FOG_ENABLE, true);
f->special_material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
if(!opaque_water)
f->special_material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
AtlasPointer *pa_water1 = new AtlasPointer(g_texturesource->getTexture(
g_texturesource->getTextureId("water.png")));
f->special_material->setTexture(0, pa_water1->atlas);
// Flowing water material, backface culled
f->special_material2 = new video::SMaterial;
*f->special_material2 = *f->special_material;
f->special_material2->setFlag(video::EMF_BACK_FACE_CULLING, true);
f->special_atlas = pa_water1;
}
#endif
i = CONTENT_WATERSOURCE;
f = &content_features(i);
@@ -411,15 +436,18 @@ void content_mapnode_init()
else // old style
{
f->solidness = 1;
#ifndef SERVER
TileSpec t;
if(g_texturesource)
t.texture = g_texturesource->getTexture("water.png");
t.alpha = WATER_ALPHA;
t.material_type = MATERIAL_ALPHA_VERTEX;
if(!opaque_water){
t.alpha = WATER_ALPHA;
t.material_type = MATERIAL_ALPHA_VERTEX;
}
t.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
f->setAllTiles(t);
#endif
}
f->param_type = CPT_LIGHT;
f->light_propagates = true;
@@ -432,10 +460,13 @@ void content_mapnode_init()
f->liquid_alternative_flowing = CONTENT_WATER;
f->liquid_alternative_source = CONTENT_WATERSOURCE;
f->liquid_viscosity = WATER_VISC;
f->vertex_alpha = WATER_ALPHA;
#ifndef SERVER
if(!opaque_water)
f->vertex_alpha = WATER_ALPHA;
f->post_effect_color = video::SColor(64, 100, 100, 200);
if(f->special_material == NULL && g_texturesource)
{
// Flowing water material
// New-style water source material (mostly unused)
f->special_material = new video::SMaterial;
f->special_material->setFlag(video::EMF_LIGHTING, false);
f->special_material->setFlag(video::EMF_BACK_FACE_CULLING, false);
@@ -447,15 +478,17 @@ void content_mapnode_init()
f->special_material->setTexture(0, pa_water1->atlas);
f->special_atlas = pa_water1;
}
#endif
i = CONTENT_LAVA;
f = &content_features(i);
f->setInventoryTextureCube("lava.png", "lava.png", "lava.png");
f->used_texturenames["lava.png"] = true;
f->param_type = CPT_LIGHT;
f->light_propagates = false;
f->light_source = LIGHT_MAX-1;
f->solidness = 0; // Drawn separately, makes no faces
f->visual_solidness = 2;
f->visual_solidness = 1; // Does not completely cover block boundaries
f->walkable = false;
f->pointable = false;
f->diggable = false;
@@ -465,6 +498,8 @@ void content_mapnode_init()
f->liquid_alternative_source = CONTENT_LAVASOURCE;
f->liquid_viscosity = LAVA_VISC;
f->damage_per_second = 4*2;
#ifndef SERVER
f->post_effect_color = video::SColor(192, 255, 64, 0);
if(f->special_material == NULL && g_texturesource)
{
// Flowing lava material
@@ -474,16 +509,25 @@ void content_mapnode_init()
f->special_material->setFlag(video::EMF_BILINEAR_FILTER, false);
f->special_material->setFlag(video::EMF_FOG_ENABLE, true);
f->special_material->MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
AtlasPointer *pa_lava1 = new AtlasPointer(
g_texturesource->getTexture(
g_texturesource->getTextureId("lava.png")));
f->special_material->setTexture(0, pa_lava1->atlas);
// Flowing lava material, backface culled
f->special_material2 = new video::SMaterial;
*f->special_material2 = *f->special_material;
f->special_material2->setFlag(video::EMF_BACK_FACE_CULLING, true);
f->special_atlas = pa_lava1;
}
#endif
i = CONTENT_LAVASOURCE;
f = &content_features(i);
f->setInventoryTextureCube("lava.png", "lava.png", "lava.png");
f->used_texturenames["ladder.png"] = true;
if(new_style_water)
{
f->solidness = 0; // drawn separately, makes no faces
@@ -491,7 +535,7 @@ void content_mapnode_init()
else // old style
{
f->solidness = 2;
#ifndef SERVER
TileSpec t;
if(g_texturesource)
t.texture = g_texturesource->getTexture("lava.png");
@@ -500,6 +544,7 @@ void content_mapnode_init()
//t.material_type = MATERIAL_ALPHA_VERTEX;
//t.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
f->setAllTiles(t);
#endif
}
f->param_type = CPT_LIGHT;
f->light_propagates = false;
@@ -514,9 +559,11 @@ void content_mapnode_init()
f->liquid_alternative_source = CONTENT_LAVASOURCE;
f->liquid_viscosity = LAVA_VISC;
f->damage_per_second = 4*2;
#ifndef SERVER
f->post_effect_color = video::SColor(192, 255, 64, 0);
if(f->special_material == NULL && g_texturesource)
{
// Flowing lava material
// New-style lava source material (mostly unused)
f->special_material = new video::SMaterial;
f->special_material->setFlag(video::EMF_LIGHTING, false);
f->special_material->setFlag(video::EMF_BACK_FACE_CULLING, false);
@@ -527,12 +574,18 @@ void content_mapnode_init()
g_texturesource->getTexture(
g_texturesource->getTextureId("lava.png")));
f->special_material->setTexture(0, pa_lava1->atlas);
f->special_atlas = pa_lava1;
}
#endif
i = CONTENT_TORCH;
f = &content_features(i);
f->setInventoryTexture("torch_on_floor.png");
f->used_texturenames["torch_on_floor.png"] = true;
f->used_texturenames["torch_on_ceiling.png"] = true;
f->used_texturenames["torch_on_floor.png"] = true;
f->used_texturenames["torch.png"] = true;
f->param_type = CPT_LIGHT;
f->light_propagates = true;
f->sunlight_propagates = true;
@@ -547,6 +600,7 @@ void content_mapnode_init()
i = CONTENT_SIGN_WALL;
f = &content_features(i);
f->setInventoryTexture("sign_wall.png");
f->used_texturenames["sign_wall.png"] = true;
f->param_type = CPT_LIGHT;
f->light_propagates = true;
f->sunlight_propagates = true;
@@ -573,6 +627,20 @@ void content_mapnode_init()
f->initial_metadata = new ChestNodeMetadata();
setWoodLikeDiggingProperties(f->digging_properties, 1.0);
i = CONTENT_LOCKABLE_CHEST;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->setAllTextures("chest_side.png");
f->setTexture(0, "chest_top.png");
f->setTexture(1, "chest_top.png");
f->setTexture(5, "chest_lock.png"); // Z-
f->setInventoryTexture("chest_lock.png");
//f->setInventoryTextureCube("chest_top.png", "chest_side.png", "chest_side.png");
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
if(f->initial_metadata == NULL)
f->initial_metadata = new LockingChestNodeMetadata();
setWoodLikeDiggingProperties(f->digging_properties, 1.0);
i = CONTENT_FURNACE;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
@@ -629,10 +697,24 @@ void content_mapnode_init()
f->setInventoryTexture("nc_rb.png");
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 3.0);
i = CONTENT_SAPLING;
f = &content_features(i);
f->param_type = CPT_LIGHT;
f->setAllTextures("sapling.png");
f->setInventoryTexture("sapling.png");
f->used_texturenames["sapling.png"] = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->light_propagates = true;
f->air_equivalent = false;
f->solidness = 0; // drawn separately, makes no faces
f->walkable = false;
f->digging_properties.set("", DiggingProperties(true, 0.0, 0));
i = CONTENT_APPLE;
f = &content_features(i);
f->setInventoryTexture("apple.png");
f->used_texturenames["apple.png"] = true;
f->param_type = CPT_LIGHT;
f->light_propagates = true;
f->sunlight_propagates = true;

View File

@@ -48,6 +48,7 @@ MapNode mapnode_translate_to_internal(MapNode n_from, u8 version);
#define CONTENT_SIGN_WALL 14
#define CONTENT_CHEST 15
#define CONTENT_FURNACE 16
#define CONTENT_LOCKABLE_CHEST 17
#define CONTENT_FENCE 21
@@ -84,7 +85,7 @@ MapNode mapnode_translate_to_internal(MapNode n_from, u8 version);
#define CONTENT_NC 0x817
#define CONTENT_NC_RB 0x818
#define CONTENT_APPLE 0x819
#define CONTENT_SAPLING 0x820
#endif

View File

@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_nodemeta.h"
#include "inventory.h"
#include "content_mapnode.h"
#include "log.h"
/*
SignNodeMetadata
@@ -117,6 +118,70 @@ std::string ChestNodeMetadata::getInventoryDrawSpecString()
"list[current_player;main;0,5;8,4;]";
}
/*
LockingChestNodeMetadata
*/
// Prototype
LockingChestNodeMetadata proto_LockingChestNodeMetadata;
LockingChestNodeMetadata::LockingChestNodeMetadata()
{
NodeMetadata::registerType(typeId(), create);
m_inventory = new Inventory();
m_inventory->addList("0", 8*4);
}
LockingChestNodeMetadata::~LockingChestNodeMetadata()
{
delete m_inventory;
}
u16 LockingChestNodeMetadata::typeId() const
{
return CONTENT_LOCKABLE_CHEST;
}
NodeMetadata* LockingChestNodeMetadata::create(std::istream &is)
{
LockingChestNodeMetadata *d = new LockingChestNodeMetadata();
d->setOwner(deSerializeString(is));
d->m_inventory->deSerialize(is);
return d;
}
NodeMetadata* LockingChestNodeMetadata::clone()
{
LockingChestNodeMetadata *d = new LockingChestNodeMetadata();
*d->m_inventory = *m_inventory;
return d;
}
void LockingChestNodeMetadata::serializeBody(std::ostream &os)
{
os<<serializeString(m_text);
m_inventory->serialize(os);
}
std::string LockingChestNodeMetadata::infoText()
{
return "Locking Chest";
}
bool LockingChestNodeMetadata::nodeRemovalDisabled()
{
/*
Disable removal if chest contains something
*/
InventoryList *list = m_inventory->getList("0");
if(list == NULL)
return false;
if(list->getUsedSlots() == 0)
return false;
return true;
}
std::string LockingChestNodeMetadata::getInventoryDrawSpecString()
{
return
"invsize[8,9;]"
"list[current_name;0;0,0;8,4;]"
"list[current_player;main;0,5;8,4;]";
}
/*
FurnaceNodeMetadata
*/
@@ -223,12 +288,12 @@ bool FurnaceNodeMetadata::nodeRemovalDisabled()
}
void FurnaceNodeMetadata::inventoryModified()
{
dstream<<"Furnace inventory modification callback"<<std::endl;
infostream<<"Furnace inventory modification callback"<<std::endl;
}
bool FurnaceNodeMetadata::step(float dtime)
{
if(dtime > 60.0)
dstream<<"Furnace stepping a long time ("<<dtime<<")"<<std::endl;
infostream<<"Furnace stepping a long time ("<<dtime<<")"<<std::endl;
// Update at a fixed frequency
const float interval = 2.0;
m_step_accumulator += dtime;
@@ -238,7 +303,7 @@ bool FurnaceNodeMetadata::step(float dtime)
m_step_accumulator -= interval;
dtime = interval;
//dstream<<"Furnace step dtime="<<dtime<<std::endl;
//infostream<<"Furnace step dtime="<<dtime<<std::endl;
InventoryList *dst_list = m_inventory->getList("dst");
assert(dst_list);
@@ -270,7 +335,7 @@ bool FurnaceNodeMetadata::step(float dtime)
*/
if(m_fuel_time < m_fuel_totaltime)
{
//dstream<<"Furnace is active"<<std::endl;
//infostream<<"Furnace is active"<<std::endl;
m_fuel_time += dtime;
m_src_time += dtime;
if(m_src_time >= m_src_totaltime && m_src_totaltime > 0.001
@@ -305,7 +370,7 @@ bool FurnaceNodeMetadata::step(float dtime)
break;
}
//dstream<<"Furnace is out of fuel"<<std::endl;
//infostream<<"Furnace is out of fuel"<<std::endl;
InventoryList *fuel_list = m_inventory->getList("fuel");
assert(fuel_list);
@@ -390,7 +455,7 @@ bool FurnaceNodeMetadata::step(float dtime)
}
else
{
//dstream<<"No fuel found"<<std::endl;
//infostream<<"No fuel found"<<std::endl;
// No fuel, stop loop.
m_step_accumulator = 0;
break;

View File

@@ -62,6 +62,29 @@ class ChestNodeMetadata : public NodeMetadata
Inventory *m_inventory;
};
class LockingChestNodeMetadata : public NodeMetadata
{
public:
LockingChestNodeMetadata();
~LockingChestNodeMetadata();
virtual u16 typeId() const;
static NodeMetadata* create(std::istream &is);
virtual NodeMetadata* clone();
virtual void serializeBody(std::ostream &os);
virtual std::string infoText();
virtual Inventory* getInventory() {return m_inventory;}
virtual bool nodeRemovalDisabled();
virtual std::string getInventoryDrawSpecString();
virtual std::string getOwner(){ return m_text; }
virtual void setOwner(std::string t){ m_text = t; }
private:
Inventory *m_inventory;
std::string m_text;
};
class FurnaceNodeMetadata : public NodeMetadata
{
public:

View File

@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define ACTIVEOBJECT_TYPE_RAT 3
#define ACTIVEOBJECT_TYPE_OERKKI1 4
#define ACTIVEOBJECT_TYPE_FIREFLY 5
#define ACTIVEOBJECT_TYPE_MOBV2 6
#endif

View File

@@ -20,9 +20,30 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_sao.h"
#include "collision.h"
#include "environment.h"
#include "settings.h"
#include "profiler.h"
core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
/* Some helper functions */
// 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;
}
/*
TestSAO
*/
@@ -64,7 +85,6 @@ void TestSAO::step(float dtime, bool send_recommended)
if(m_timer1 < 0.0)
{
m_timer1 += 0.125;
//dstream<<"TestSAO: id="<<getId()<<" sending data"<<std::endl;
std::string data;
@@ -111,13 +131,15 @@ ServerActiveObject* ItemSAO::create(ServerEnvironment *env, u16 id, v3f pos,
if(version != 0)
return NULL;
std::string inventorystring = deSerializeString(is);
dstream<<"ItemSAO::create(): Creating item \""
infostream<<"ItemSAO::create(): Creating item \""
<<inventorystring<<"\""<<std::endl;
return new ItemSAO(env, id, pos, inventorystring);
}
void ItemSAO::step(float dtime, bool send_recommended)
{
ScopeProfiler sp2(g_profiler, "ItemSAO::step avg", SPT_AVG);
assert(m_env);
const float interval = 0.2;
@@ -186,7 +208,7 @@ std::string ItemSAO::getClientInitializationData()
std::string ItemSAO::getStaticData()
{
dstream<<__FUNCTION_NAME<<std::endl;
infostream<<__FUNCTION_NAME<<std::endl;
std::ostringstream os(std::ios::binary);
char buf[1];
// version
@@ -202,14 +224,14 @@ InventoryItem * ItemSAO::createInventoryItem()
try{
std::istringstream is(m_inventorystring, std::ios_base::binary);
InventoryItem *item = InventoryItem::deSerialize(is);
dstream<<__FUNCTION_NAME<<": m_inventorystring=\""
infostream<<__FUNCTION_NAME<<": m_inventorystring=\""
<<m_inventorystring<<"\" -> item="<<item
<<std::endl;
return item;
}
catch(SerializationError &e)
{
dstream<<__FUNCTION_NAME<<": serialization error: "
infostream<<__FUNCTION_NAME<<": serialization error: "
<<"m_inventorystring=\""<<m_inventorystring<<"\""<<std::endl;
return NULL;
}
@@ -217,7 +239,7 @@ InventoryItem * ItemSAO::createInventoryItem()
void ItemSAO::rightClick(Player *player)
{
dstream<<__FUNCTION_NAME<<std::endl;
infostream<<__FUNCTION_NAME<<std::endl;
InventoryItem *item = createInventoryItem();
if(item == NULL)
return;
@@ -272,6 +294,8 @@ ServerActiveObject* RatSAO::create(ServerEnvironment *env, u16 id, v3f pos,
void RatSAO::step(float dtime, bool send_recommended)
{
ScopeProfiler sp2(g_profiler, "RatSAO::step avg", SPT_AVG);
assert(m_env);
if(m_is_active == false)
@@ -404,7 +428,7 @@ std::string RatSAO::getClientInitializationData()
std::string RatSAO::getStaticData()
{
//dstream<<__FUNCTION_NAME<<std::endl;
//infostream<<__FUNCTION_NAME<<std::endl;
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
@@ -422,23 +446,6 @@ InventoryItem* RatSAO::createPickedUpItem()
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));
@@ -478,6 +485,8 @@ ServerActiveObject* Oerkki1SAO::create(ServerEnvironment *env, u16 id, v3f pos,
void Oerkki1SAO::step(float dtime, bool send_recommended)
{
ScopeProfiler sp2(g_profiler, "Oerkki1SAO::step avg", SPT_AVG);
assert(m_env);
if(m_is_active == false)
@@ -520,13 +529,14 @@ void Oerkki1SAO::step(float dtime, bool send_recommended)
Player *player = *i;
v3f playerpos = player->getPosition();
f32 dist = m_base_position.getDistanceFrom(playerpos);
if(dist < BS*1.45)
if(dist < BS*0.6)
{
m_removed = true;
return;
player_is_too_close = true;
near_player_pos = playerpos;
break;
}
else if(dist < BS*15.0)
else if(dist < BS*15.0 && !player_is_too_close)
{
player_is_close = true;
near_player_pos = playerpos;
@@ -617,7 +627,7 @@ void Oerkki1SAO::step(float dtime, bool send_recommended)
m_touching_ground = moveresult.touching_ground;
// Do collision damage
float tolerance = BS*12;
float tolerance = BS*30;
float factor = BS*0.5;
v3f speed_diff = old_speed - m_speed_f;
// Increase effect in X and Z
@@ -665,7 +675,7 @@ std::string Oerkki1SAO::getClientInitializationData()
std::string Oerkki1SAO::getStaticData()
{
//dstream<<__FUNCTION_NAME<<std::endl;
//infostream<<__FUNCTION_NAME<<std::endl;
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
@@ -674,18 +684,32 @@ std::string Oerkki1SAO::getStaticData()
return os.str();
}
u16 Oerkki1SAO::punch(const std::string &toolname, v3f dir)
u16 Oerkki1SAO::punch(const std::string &toolname, v3f dir,
const std::string &playername)
{
m_speed_f += dir*12*BS;
u16 amount = 5;
/* See tool names in inventory.h */
if(toolname == "WSword")
amount = 10;
if(toolname == "STSword")
amount = 12;
if(toolname == "SteelSword")
amount = 16;
if(toolname == "STAxe")
amount = 7;
if(toolname == "SteelAxe")
amount = 9;
if(toolname == "SteelPick")
amount = 7;
doDamage(amount);
return 65536/100;
}
void Oerkki1SAO::doDamage(u16 d)
{
dstream<<"oerkki damage: "<<d<<std::endl;
infostream<<"oerkki damage: "<<d<<std::endl;
if(d < m_hp)
{
@@ -749,6 +773,8 @@ ServerActiveObject* FireflySAO::create(ServerEnvironment *env, u16 id, v3f pos,
void FireflySAO::step(float dtime, bool send_recommended)
{
ScopeProfiler sp2(g_profiler, "FireflySAO::step avg", SPT_AVG);
assert(m_env);
if(m_is_active == false)
@@ -873,7 +899,7 @@ std::string FireflySAO::getClientInitializationData()
std::string FireflySAO::getStaticData()
{
//dstream<<__FUNCTION_NAME<<std::endl;
//infostream<<__FUNCTION_NAME<<std::endl;
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
@@ -886,3 +912,581 @@ InventoryItem* FireflySAO::createPickedUpItem()
InventoryItem *item = InventoryItem::deSerialize(is);
return item;
}
/*
MobV2SAO
*/
// Prototype
MobV2SAO proto_MobV2SAO(NULL, 0, v3f(0,0,0), NULL);
MobV2SAO::MobV2SAO(ServerEnvironment *env, u16 id, v3f pos,
Settings *init_properties):
ServerActiveObject(env, id, pos),
m_move_type("ground_nodes"),
m_speed(0,0,0),
m_last_sent_position(0,0,0),
m_oldpos(0,0,0),
m_yaw(0),
m_counter1(0),
m_counter2(0),
m_age(0),
m_touching_ground(false),
m_hp(10),
m_walk_around(false),
m_walk_around_timer(0),
m_next_pos_exists(false),
m_shoot_reload_timer(0),
m_shooting(false),
m_shooting_timer(0),
m_falling(false),
m_disturb_timer(100000),
m_random_disturb_timer(0),
m_shoot_y(0)
{
ServerActiveObject::registerType(getType(), create);
m_properties = new Settings();
if(init_properties)
m_properties->update(*init_properties);
m_properties->setV3F("pos", pos);
setPropertyDefaults();
readProperties();
}
MobV2SAO::~MobV2SAO()
{
delete m_properties;
}
ServerActiveObject* MobV2SAO::create(ServerEnvironment *env, u16 id, v3f pos,
const std::string &data)
{
std::istringstream is(data, std::ios::binary);
Settings properties;
properties.parseConfigLines(is, "MobArgsEnd");
MobV2SAO *o = new MobV2SAO(env, id, pos, &properties);
return o;
}
std::string MobV2SAO::getStaticData()
{
updateProperties();
std::ostringstream os(std::ios::binary);
m_properties->writeLines(os);
return os.str();
}
std::string MobV2SAO::getClientInitializationData()
{
//infostream<<__FUNCTION_NAME<<std::endl;
updateProperties();
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
Settings client_properties;
/*client_properties.set("version", "0");
client_properties.updateValue(*m_properties, "pos");
client_properties.updateValue(*m_properties, "yaw");
client_properties.updateValue(*m_properties, "hp");*/
// Just send everything for simplicity
client_properties.update(*m_properties);
std::ostringstream os2(std::ios::binary);
client_properties.writeLines(os2);
compressZlib(os2.str(), os);
return os.str();
}
bool checkFreePosition(Map *map, v3s16 p0, v3s16 size)
{
for(int dx=0; dx<size.X; dx++)
for(int dy=0; dy<size.Y; dy++)
for(int dz=0; dz<size.Z; dz++){
v3s16 dp(dx, dy, dz);
v3s16 p = p0 + dp;
MapNode n = map->getNodeNoEx(p);
if(n.getContent() != CONTENT_AIR)
return false;
}
return true;
}
bool checkWalkablePosition(Map *map, v3s16 p0)
{
v3s16 p = p0 + v3s16(0,-1,0);
MapNode n = map->getNodeNoEx(p);
if(n.getContent() != CONTENT_AIR)
return true;
return false;
}
bool checkFreeAndWalkablePosition(Map *map, v3s16 p0, v3s16 size)
{
if(!checkFreePosition(map, p0, size))
return false;
if(!checkWalkablePosition(map, p0))
return false;
return true;
}
static void get_random_u32_array(u32 a[], u32 len)
{
u32 i, n;
for(i=0; i<len; i++)
a[i] = i;
n = len;
while(n > 1){
u32 k = myrand() % n;
n--;
u32 temp = a[n];
a[n] = a[k];
a[k] = temp;
}
}
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
static void explodeSquare(Map *map, v3s16 p0, v3s16 size)
{
core::map<v3s16, MapBlock*> modified_blocks;
for(int dx=0; dx<size.X; dx++)
for(int dy=0; dy<size.Y; dy++)
for(int dz=0; dz<size.Z; dz++){
v3s16 dp(dx - size.X/2, dy - size.Y/2, dz - size.Z/2);
v3s16 p = p0 + dp;
MapNode n = map->getNodeNoEx(p);
if(n.getContent() == CONTENT_IGNORE)
continue;
//map->removeNodeWithEvent(p);
map->removeNodeAndUpdate(p, modified_blocks);
}
// Send a MEET_OTHER event
MapEditEvent event;
event.type = MEET_OTHER;
for(core::map<v3s16, MapBlock*>::Iterator
i = modified_blocks.getIterator();
i.atEnd() == false; i++)
{
v3s16 p = i.getNode()->getKey();
event.modified_blocks.insert(p, true);
}
map->dispatchEvent(&event);
}
void MobV2SAO::step(float dtime, bool send_recommended)
{
ScopeProfiler sp2(g_profiler, "MobV2SAO::step avg", SPT_AVG);
assert(m_env);
Map *map = &m_env->getMap();
m_age += dtime;
if(m_die_age >= 0.0 && m_age >= m_die_age){
m_removed = true;
return;
}
m_random_disturb_timer += dtime;
if(m_random_disturb_timer >= 5.0)
{
m_random_disturb_timer = 0;
// 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*16)
{
if(myrand_range(0,3) == 0){
actionstream<<"Mob id="<<m_id<<" at "
<<PP(m_base_position/BS)
<<" got randomly disturbed by "
<<player->getName()<<std::endl;
m_disturbing_player = player->getName();
m_disturb_timer = 0;
break;
}
}
}
}
Player *disturbing_player =
m_env->getPlayer(m_disturbing_player.c_str());
v3f disturbing_player_off = v3f(0,1,0);
v3f disturbing_player_norm = v3f(0,1,0);
float disturbing_player_distance = 1000000;
float disturbing_player_dir = 0;
if(disturbing_player){
disturbing_player_off =
disturbing_player->getPosition() - m_base_position;
disturbing_player_distance = disturbing_player_off.getLength();
disturbing_player_norm = disturbing_player_off;
disturbing_player_norm.normalize();
disturbing_player_dir = 180./PI*atan2(disturbing_player_norm.Z,
disturbing_player_norm.X);
}
m_disturb_timer += dtime;
if(!m_falling)
{
m_shooting_timer -= dtime;
if(m_shooting_timer <= 0.0 && m_shooting){
m_shooting = false;
std::string shoot_type = m_properties->get("shoot_type");
v3f shoot_pos(0,0,0);
shoot_pos.Y += m_properties->getFloat("shoot_y") * BS;
if(shoot_type == "fireball"){
v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
dir.Y = m_shoot_y;
dir.normalize();
v3f speed = dir * BS * 10.0;
v3f pos = m_base_position + shoot_pos;
infostream<<__FUNCTION_NAME<<": Mob id="<<m_id
<<" shooting fireball from "<<PP(pos)
<<" at speed "<<PP(speed)<<std::endl;
Settings properties;
properties.set("looks", "fireball");
properties.setV3F("speed", speed);
properties.setFloat("die_age", 5.0);
properties.set("move_type", "constant_speed");
properties.setFloat("hp", 1000);
properties.set("lock_full_brightness", "true");
properties.set("player_hit_damage", "9");
properties.set("player_hit_distance", "2");
properties.set("player_hit_interval", "1");
ServerActiveObject *obj = new MobV2SAO(m_env, 0,
pos, &properties);
//m_env->addActiveObjectAsStatic(obj);
m_env->addActiveObject(obj);
} else {
infostream<<__FUNCTION_NAME<<": Mob id="<<m_id
<<": Unknown shoot_type="<<shoot_type
<<std::endl;
}
}
m_shoot_reload_timer += dtime;
float reload_time = 15.0;
if(m_disturb_timer <= 15.0)
reload_time = 3.0;
bool shoot_without_player = false;
if(m_properties->getBool("mindless_rage"))
shoot_without_player = true;
if(!m_shooting && m_shoot_reload_timer >= reload_time &&
!m_next_pos_exists &&
(m_disturb_timer <= 60.0 || shoot_without_player))
{
m_shoot_y = 0;
if(m_disturb_timer < 60.0 && disturbing_player &&
disturbing_player_distance < 16*BS &&
fabs(disturbing_player_norm.Y) < 0.8){
m_yaw = disturbing_player_dir;
sendPosition();
m_shoot_y += disturbing_player_norm.Y;
} else {
m_shoot_y = 0.01 * myrand_range(-30,10);
}
m_shoot_reload_timer = 0.0;
m_shooting = true;
m_shooting_timer = 1.5;
{
std::ostringstream os(std::ios::binary);
// command (2 = shooting)
writeU8(os, 2);
// time
writeF1000(os, m_shooting_timer + 0.1);
// bright?
writeU8(os, true);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
}
if(m_move_type == "ground_nodes")
{
if(!m_shooting){
m_walk_around_timer -= dtime;
if(m_walk_around_timer <= 0.0){
m_walk_around = !m_walk_around;
if(m_walk_around)
m_walk_around_timer = 0.1*myrand_range(10,50);
else
m_walk_around_timer = 0.1*myrand_range(30,70);
}
}
/* Move */
if(m_next_pos_exists){
v3f pos_f = m_base_position;
v3f next_pos_f = intToFloat(m_next_pos_i, BS);
v3f v = next_pos_f - pos_f;
m_yaw = atan2(v.Z, v.X) / PI * 180;
v3f diff = next_pos_f - pos_f;
v3f dir = diff;
dir.normalize();
float speed = BS * 0.5;
if(m_falling)
speed = BS * 3.0;
dir *= dtime * speed;
bool arrived = false;
if(dir.getLength() > diff.getLength()){
dir = diff;
arrived = true;
}
pos_f += dir;
m_base_position = pos_f;
if((pos_f - next_pos_f).getLength() < 0.1 || arrived){
m_next_pos_exists = false;
}
}
v3s16 pos_i = floatToInt(m_base_position, BS);
v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5);
v3s16 pos_size_off(0,0,0);
if(m_size.X >= 2.5){
pos_size_off.X = -1;
pos_size_off.Y = -1;
}
if(!m_next_pos_exists){
/* Check whether to drop down */
if(checkFreePosition(map,
pos_i + pos_size_off + v3s16(0,-1,0), size_blocks)){
m_next_pos_i = pos_i + v3s16(0,-1,0);
m_next_pos_exists = true;
m_falling = true;
} else {
m_falling = false;
}
}
if(m_walk_around)
{
if(!m_next_pos_exists){
/* Find some position where to go next */
v3s16 dps[3*3*3];
int num_dps = 0;
for(int dx=-1; dx<=1; dx++)
for(int dy=-1; dy<=1; dy++)
for(int dz=-1; dz<=1; dz++){
if(dx == 0 && dy == 0)
continue;
if(dx != 0 && dz != 0 && dy != 0)
continue;
dps[num_dps++] = v3s16(dx,dy,dz);
}
u32 order[3*3*3];
get_random_u32_array(order, num_dps);
for(int i=0; i<num_dps; i++){
v3s16 p = dps[order[i]] + pos_i;
bool is_free = checkFreeAndWalkablePosition(map,
p + pos_size_off, size_blocks);
if(!is_free)
continue;
m_next_pos_i = p;
m_next_pos_exists = true;
break;
}
}
}
}
else if(m_move_type == "constant_speed")
{
m_base_position += m_speed * dtime;
v3s16 pos_i = floatToInt(m_base_position, BS);
v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5);
v3s16 pos_size_off(0,0,0);
if(m_size.X >= 2.5){
pos_size_off.X = -1;
pos_size_off.Y = -1;
}
bool free = checkFreePosition(map, pos_i + pos_size_off, size_blocks);
if(!free){
explodeSquare(map, pos_i, v3s16(3,3,3));
m_removed = true;
return;
}
}
else
{
errorstream<<"MobV2SAO::step(): id="<<m_id<<" unknown move_type=\""
<<m_move_type<<"\""<<std::endl;
}
if(send_recommended == false)
return;
if(m_base_position.getDistanceFrom(m_last_sent_position) > 0.05*BS)
{
sendPosition();
}
}
u16 MobV2SAO::punch(const std::string &toolname, v3f dir,
const std::string &playername)
{
assert(m_env);
Map *map = &m_env->getMap();
actionstream<<playername<<" punches mob id="<<m_id
<<" with a \""<<toolname<<"\" at "
<<PP(m_base_position/BS)<<std::endl;
m_disturb_timer = 0;
m_disturbing_player = playername;
m_next_pos_exists = false; // Cancel moving immediately
m_yaw = wrapDegrees_180(180./PI*atan2(dir.Z, dir.X) + 180.);
v3f new_base_position = m_base_position + dir * BS;
{
v3s16 pos_i = floatToInt(new_base_position, BS);
v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5);
v3s16 pos_size_off(0,0,0);
if(m_size.X >= 2.5){
pos_size_off.X = -1;
pos_size_off.Y = -1;
}
bool free = checkFreePosition(map, pos_i + pos_size_off, size_blocks);
if(free)
m_base_position = new_base_position;
}
sendPosition();
u16 amount = 2;
/* See tool names in inventory.h */
if(toolname == "WSword")
amount = 4;
if(toolname == "STSword")
amount = 6;
if(toolname == "SteelSword")
amount = 8;
if(toolname == "STAxe")
amount = 3;
if(toolname == "SteelAxe")
amount = 4;
if(toolname == "SteelPick")
amount = 3;
doDamage(amount);
return 65536/100;
}
bool MobV2SAO::isPeaceful()
{
return m_properties->getBool("is_peaceful");
}
void MobV2SAO::sendPosition()
{
m_last_sent_position = m_base_position;
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);
}
void MobV2SAO::setPropertyDefaults()
{
m_properties->setDefault("is_peaceful", "false");
m_properties->setDefault("move_type", "ground_nodes");
m_properties->setDefault("speed", "(0,0,0)");
m_properties->setDefault("age", "0");
m_properties->setDefault("yaw", "0");
m_properties->setDefault("pos", "(0,0,0)");
m_properties->setDefault("hp", "0");
m_properties->setDefault("die_age", "-1");
m_properties->setDefault("size", "(1,2)");
m_properties->setDefault("shoot_type", "fireball");
m_properties->setDefault("shoot_y", "0");
m_properties->setDefault("mindless_rage", "false");
}
void MobV2SAO::readProperties()
{
m_move_type = m_properties->get("move_type");
m_speed = m_properties->getV3F("speed");
m_age = m_properties->getFloat("age");
m_yaw = m_properties->getFloat("yaw");
m_base_position = m_properties->getV3F("pos");
m_hp = m_properties->getS32("hp");
m_die_age = m_properties->getFloat("die_age");
m_size = m_properties->getV2F("size");
}
void MobV2SAO::updateProperties()
{
m_properties->set("move_type", m_move_type);
m_properties->setV3F("speed", m_speed);
m_properties->setFloat("age", m_age);
m_properties->setFloat("yaw", m_yaw);
m_properties->setV3F("pos", m_base_position);
m_properties->setS32("hp", m_hp);
m_properties->setFloat("die_age", m_die_age);
m_properties->setV2F("size", m_size);
m_properties->setS32("version", 0);
}
void MobV2SAO::doDamage(u16 d)
{
infostream<<"MobV2 hp="<<m_hp<<" damage="<<d<<std::endl;
if(d < m_hp)
{
m_hp -= d;
}
else
{
actionstream<<"A "<<(isPeaceful()?"peaceful":"non-peaceful")
<<" mob id="<<m_id<<" dies at "<<PP(m_base_position)<<std::endl;
// Die
m_hp = 0;
m_removed = true;
}
{
std::ostringstream os(std::ios::binary);
// command (1 = damage)
writeU8(os, 1);
// amount
writeU16(os, d);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}

View File

@@ -96,7 +96,9 @@ class Oerkki1SAO : public ServerActiveObject
std::string getClientInitializationData();
std::string getStaticData();
InventoryItem* createPickedUpItem(){return NULL;}
u16 punch(const std::string &toolname, v3f dir);
u16 punch(const std::string &toolname, v3f dir,
const std::string &playername);
bool isPeaceful(){return false;}
private:
void doDamage(u16 d);
@@ -139,5 +141,59 @@ class FireflySAO : public ServerActiveObject
bool m_touching_ground;
};
class Settings;
class MobV2SAO : public ServerActiveObject
{
public:
MobV2SAO(ServerEnvironment *env, u16 id, v3f pos,
Settings *init_properties);
virtual ~MobV2SAO();
u8 getType() const
{return ACTIVEOBJECT_TYPE_MOBV2;}
static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
const std::string &data);
std::string getStaticData();
std::string getClientInitializationData();
void step(float dtime, bool send_recommended);
InventoryItem* createPickedUpItem(){return NULL;}
u16 punch(const std::string &toolname, v3f dir,
const std::string &playername);
bool isPeaceful();
private:
void sendPosition();
void setPropertyDefaults();
void readProperties();
void updateProperties();
void doDamage(u16 d);
std::string m_move_type;
v3f m_speed;
v3f m_last_sent_position;
v3f m_oldpos;
float m_yaw;
float m_counter1;
float m_counter2;
float m_age;
bool m_touching_ground;
int m_hp;
bool m_walk_around;
float m_walk_around_timer;
bool m_next_pos_exists;
v3s16 m_next_pos_i;
float m_shoot_reload_timer;
bool m_shooting;
float m_shooting_timer;
float m_die_age;
v2f m_size;
bool m_falling;
float m_disturb_timer;
std::string m_disturbing_player;
float m_random_disturb_timer;
float m_shoot_y;
Settings *m_properties;
};
#endif

View File

@@ -235,10 +235,9 @@ class PacketCounter
#if CATCH_UNHANDLED_EXCEPTIONS == 1
#define BEGIN_PORTABLE_DEBUG_EXCEPTION_HANDLER try{
#define END_PORTABLE_DEBUG_EXCEPTION_HANDLER\
#define END_PORTABLE_DEBUG_EXCEPTION_HANDLER(logstream)\
}catch(std::exception &e){\
dstream<<std::endl<<DTIME\
<<"ERROR: An unhandled exception occurred: "\
logstream<<"ERROR: An unhandled exception occurred: "\
<<e.what()<<std::endl;\
assert(0);\
}
@@ -257,24 +256,24 @@ class FatalSystemException : public BaseException
BEGIN_PORTABLE_DEBUG_EXCEPTION_HANDLER\
_set_se_translator(se_trans_func);
#define END_DEBUG_EXCEPTION_HANDLER \
END_PORTABLE_DEBUG_EXCEPTION_HANDLER
#define END_DEBUG_EXCEPTION_HANDLER(logstream) \
END_PORTABLE_DEBUG_EXCEPTION_HANDLER(logstream)
#else // Probably mingw
#define BEGIN_DEBUG_EXCEPTION_HANDLER\
BEGIN_PORTABLE_DEBUG_EXCEPTION_HANDLER
#define END_DEBUG_EXCEPTION_HANDLER\
END_PORTABLE_DEBUG_EXCEPTION_HANDLER
#define END_DEBUG_EXCEPTION_HANDLER(logstream)\
END_PORTABLE_DEBUG_EXCEPTION_HANDLER(logstream)
#endif
#else // Posix
#define BEGIN_DEBUG_EXCEPTION_HANDLER\
BEGIN_PORTABLE_DEBUG_EXCEPTION_HANDLER
#define END_DEBUG_EXCEPTION_HANDLER\
END_PORTABLE_DEBUG_EXCEPTION_HANDLER
#define END_DEBUG_EXCEPTION_HANDLER(logstream)\
END_PORTABLE_DEBUG_EXCEPTION_HANDLER(logstream)
#endif
#else
// Dummy ones
#define BEGIN_DEBUG_EXCEPTION_HANDLER
#define END_DEBUG_EXCEPTION_HANDLER
#define END_DEBUG_EXCEPTION_HANDLER(logstream)
#endif
#endif // DEBUG_HEADER

View File

@@ -17,89 +17,99 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "utility.h"
#include "settings.h"
extern Settings g_settings;
void set_default_settings()
void set_default_settings(Settings *settings)
{
// Client and server
g_settings.setDefault("port", "");
g_settings.setDefault("name", "");
g_settings.setDefault("footprints", "false");
settings->setDefault("port", "");
settings->setDefault("name", "");
settings->setDefault("footprints", "false");
// Client stuff
g_settings.setDefault("keymap_forward", "KEY_KEY_W");
g_settings.setDefault("keymap_backward", "KEY_KEY_S");
g_settings.setDefault("keymap_left", "KEY_KEY_A");
g_settings.setDefault("keymap_right", "KEY_KEY_D");
g_settings.setDefault("keymap_jump", "KEY_SPACE");
g_settings.setDefault("keymap_sneak", "KEY_LSHIFT");
g_settings.setDefault("keymap_inventory", "KEY_KEY_I");
g_settings.setDefault("keymap_chat", "KEY_KEY_T");
g_settings.setDefault("keymap_cmd", "/");
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");
settings->setDefault("keymap_forward", "KEY_KEY_W");
settings->setDefault("keymap_backward", "KEY_KEY_S");
settings->setDefault("keymap_left", "KEY_KEY_A");
settings->setDefault("keymap_right", "KEY_KEY_D");
settings->setDefault("keymap_jump", "KEY_SPACE");
settings->setDefault("keymap_sneak", "KEY_LSHIFT");
settings->setDefault("keymap_inventory", "KEY_KEY_I");
settings->setDefault("keymap_special1", "KEY_KEY_E");
settings->setDefault("keymap_chat", "KEY_KEY_T");
settings->setDefault("keymap_cmd", "/");
settings->setDefault("keymap_rangeselect", "KEY_KEY_R");
settings->setDefault("keymap_freemove", "KEY_KEY_K");
settings->setDefault("keymap_fastmove", "KEY_KEY_J");
settings->setDefault("keymap_frametime_graph", "KEY_F1");
settings->setDefault("keymap_screenshot", "KEY_F12");
settings->setDefault("keymap_toggle_profiler", "KEY_F2");
settings->setDefault("keymap_toggle_force_fog_off", "KEY_F3");
settings->setDefault("keymap_toggle_update_camera", "KEY_F4");
// Some (temporary) keys for debugging
g_settings.setDefault("keymap_special1", "KEY_KEY_E");
g_settings.setDefault("keymap_print_debug_stacks", "KEY_KEY_P");
settings->setDefault("keymap_print_debug_stacks", "KEY_KEY_P");
g_settings.setDefault("wanted_fps", "30");
g_settings.setDefault("fps_max", "60");
g_settings.setDefault("viewing_range_nodes_max", "300");
g_settings.setDefault("viewing_range_nodes_min", "15");
g_settings.setDefault("screenW", "800");
g_settings.setDefault("screenH", "600");
g_settings.setDefault("address", "");
g_settings.setDefault("random_input", "false");
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");
g_settings.setDefault("smooth_lighting", "true");
g_settings.setDefault("frametime_graph", "false");
g_settings.setDefault("enable_texture_atlas", "true");
g_settings.setDefault("texture_path", "");
g_settings.setDefault("video_driver", "opengl");
g_settings.setDefault("free_move", "false");
g_settings.setDefault("continuous_forward", "false");
g_settings.setDefault("fast_move", "false");
g_settings.setDefault("invert_mouse", "false");
g_settings.setDefault("enable_farmesh", "false");
g_settings.setDefault("enable_clouds", "true");
g_settings.setDefault("invisible_stone", "false");
g_settings.setDefault("screenshot_path", ".");
settings->setDefault("wanted_fps", "30");
settings->setDefault("fps_max", "60");
settings->setDefault("viewing_range_nodes_max", "300");
settings->setDefault("viewing_range_nodes_min", "15");
settings->setDefault("screenW", "800");
settings->setDefault("screenH", "600");
settings->setDefault("address", "");
settings->setDefault("random_input", "false");
settings->setDefault("client_unload_unused_data_timeout", "600");
settings->setDefault("enable_fog", "true");
settings->setDefault("fov", "72");
settings->setDefault("view_bobbing", "true");
settings->setDefault("new_style_water", "false");
settings->setDefault("new_style_leaves", "false");
settings->setDefault("smooth_lighting", "true");
settings->setDefault("frametime_graph", "false");
settings->setDefault("enable_texture_atlas", "true");
settings->setDefault("texture_path", "");
settings->setDefault("video_driver", "opengl");
settings->setDefault("free_move", "false");
settings->setDefault("continuous_forward", "false");
settings->setDefault("fast_move", "false");
settings->setDefault("invert_mouse", "false");
settings->setDefault("enable_farmesh", "false");
settings->setDefault("enable_clouds", "true");
settings->setDefault("invisible_stone", "false");
settings->setDefault("screenshot_path", ".");
settings->setDefault("view_bobbing_amount", "1.0");
settings->setDefault("enable_3d_clouds", "false");
settings->setDefault("opaque_water", "false");
// Server stuff
g_settings.setDefault("motd", "");
g_settings.setDefault("enable_experimental", "false");
g_settings.setDefault("creative_mode", "false");
g_settings.setDefault("enable_damage", "true");
g_settings.setDefault("give_initial_stuff", "false");
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("fixed_map_seed", "");
// "map-dir" doesn't exist by default.
settings->setDefault("motd", "");
settings->setDefault("max_users", "20");
settings->setDefault("strict_protocol_version_checking", "true");
settings->setDefault("creative_mode", "false");
settings->setDefault("enable_damage", "true");
settings->setDefault("only_peaceful_mobs", "false");
settings->setDefault("fixed_map_seed", "");
settings->setDefault("give_initial_stuff", "false");
settings->setDefault("default_password", "");
settings->setDefault("default_privs", "build, shout");
g_settings.setDefault("objectdata_interval", "0.2");
g_settings.setDefault("active_object_range", "2");
//g_settings.setDefault("max_simultaneous_block_sends_per_client", "1");
settings->setDefault("profiler_print_interval", "0");
settings->setDefault("enable_mapgen_debug_info", "false");
settings->setDefault("objectdata_interval", "0.2");
settings->setDefault("active_object_send_range_blocks", "3");
settings->setDefault("active_block_range", "2");
//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_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");
settings->setDefault("max_simultaneous_block_sends_per_client", "2");
settings->setDefault("max_simultaneous_block_sends_server_total", "8");
settings->setDefault("max_block_send_distance", "7");
settings->setDefault("max_block_generate_distance", "5");
settings->setDefault("time_send_interval", "20");
settings->setDefault("time_speed", "96");
settings->setDefault("server_unload_unused_data_timeout", "60");
settings->setDefault("server_map_save_interval", "10");
settings->setDefault("full_block_send_enable_min_time_from_building", "2.0");
settings->setDefault("enable_experimental", "false");
}

28
src/defaultsettings.h Normal file
View File

@@ -0,0 +1,28 @@
/*
Minetest-c55
Copyright (C) 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 DEFAULTSETTINGS_HEADER
#define DEFAULTSETTINGS_HEADER
class Settings;
void set_default_settings(Settings *settings);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -175,6 +175,14 @@ class ServerEnvironment : public Environment
*/
u16 addActiveObject(ServerActiveObject *object);
/*
Add an active object as a static object to the corresponding
MapBlock.
Caller allocates memory, ServerEnvironment frees memory.
Return value: true if succeeded, false if failed.
*/
bool addActiveObjectAsStatic(ServerActiveObject *object);
/*
Find out what new objects have been added to
inside a radius around a position
@@ -210,6 +218,11 @@ class ServerEnvironment : public Environment
void addActiveBlockModifier(ActiveBlockModifier *abm);
/* Other stuff */
// Clear all objects, loading and going through every MapBlock
void clearAllObjects();
private:
/*
@@ -406,9 +419,6 @@ class ClientEnvironment : public Environment
// 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;

View File

@@ -171,6 +171,7 @@ bool RecursiveDelete(std::string path)
#include <errno.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
std::vector<DirListNode> GetDirListing(std::string pathstring)
{
@@ -279,7 +280,7 @@ bool RecursiveDeleteContent(std::string path)
{
if(trim(list[i].name) == "." || trim(list[i].name) == "..")
continue;
std::string childpath = path + "/" + list[i].name;
std::string childpath = path + DIR_DELIM + list[i].name;
bool r = RecursiveDelete(childpath);
if(r == false)
{
@@ -299,7 +300,7 @@ bool CreateAllDirs(std::string path)
while(!PathExists(basepath))
{
tocreate.push_back(basepath);
pos = basepath.rfind('/');
pos = basepath.rfind(DIR_DELIM_C);
if(pos == std::string::npos)
return false;
basepath = basepath.substr(0,pos);

View File

@@ -24,6 +24,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <vector>
#include "exceptions.h"
#ifdef _WIN32 // WINDOWS
#define DIR_DELIM "\\"
#define DIR_DELIM_C '\\'
#else // POSIX
#define DIR_DELIM "/"
#define DIR_DELIM_C '/'
#endif
namespace fs
{

File diff suppressed because it is too large Load Diff

179
src/guiDeathScreen.cpp Normal file
View File

@@ -0,0 +1,179 @@
/*
Minetest-c55
Copyright (C) 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 "guiDeathScreen.h"
#include "debug.h"
#include "serialization.h"
#include <string>
#include <IGUICheckBox.h>
#include <IGUIEditBox.h>
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "gettext.h"
#include "client.h"
GUIDeathScreen::GUIDeathScreen(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr, IRespawnInitiator *respawner
):
GUIModalMenu(env, parent, id, menumgr),
m_respawner(respawner),
m_screensize(1,1)
{
}
GUIDeathScreen::~GUIDeathScreen()
{
removeChildren();
delete m_respawner;
}
void GUIDeathScreen::removeChildren()
{
const core::list<gui::IGUIElement*> &children = getChildren();
core::list<gui::IGUIElement*> children_copy;
for(core::list<gui::IGUIElement*>::ConstIterator
i = children.begin(); i != children.end(); i++)
{
children_copy.push_back(*i);
}
for(core::list<gui::IGUIElement*>::Iterator
i = children_copy.begin();
i != children_copy.end(); i++)
{
(*i)->remove();
}
}
void GUIDeathScreen::regenerateGui(v2u32 screensize)
{
m_screensize = screensize;
/*
Remove stuff
*/
removeChildren();
/*
Calculate new sizes and positions
*/
core::rect<s32> rect(
screensize.X/2 - 500/2,
screensize.Y/2 - 200/2,
screensize.X/2 + 500/2,
screensize.Y/2 + 200/2
);
DesiredRect = rect;
recalculateAbsolutePosition(false);
v2s32 size = rect.getSize();
/*
Add stuff
*/
changeCtype("");
{
core::rect<s32> rect(0, 0, 400, 50);
rect = rect + v2s32(size.X/2-400/2, size.Y/2-50/2-25);
Environment->addStaticText(wgettext("You died."), rect, false,
true, this, 256);
}
{
core::rect<s32> rect(0, 0, 140, 30);
rect = rect + v2s32(size.X/2-140/2, size.Y/2-30/2+25);
gui::IGUIElement *e =
Environment->addButton(rect, this, 257,
wgettext("Respawn"));
Environment->setFocus(e);
}
changeCtype("C");
}
void GUIDeathScreen::drawMenu()
{
gui::IGUISkin* skin = Environment->getSkin();
if (!skin)
return;
video::IVideoDriver* driver = Environment->getVideoDriver();
{
video::SColor color(180,50,0,0);
driver->draw2DRectangle(color,
core::rect<s32>(0,0,m_screensize.X,m_screensize.Y), NULL);
}
{
video::SColor bgcolor(50,0,0,0);
driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
}
gui::IGUIElement::draw();
}
bool GUIDeathScreen::OnEvent(const SEvent& event)
{
if(event.EventType==EET_KEY_INPUT_EVENT)
{
if(event.KeyInput.Key==KEY_ESCAPE && event.KeyInput.PressedDown)
{
respawn();
quitMenu();
return true;
}
if(event.KeyInput.Key==KEY_RETURN && event.KeyInput.PressedDown)
{
respawn();
quitMenu();
return true;
}
}
if(event.EventType==EET_GUI_EVENT)
{
if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
&& isVisible())
{
if(!canTakeFocus(event.GUIEvent.Element))
{
dstream<<"GUIDeathScreen: Not allowing focus change."
<<std::endl;
// Returning true disables focus change
return true;
}
}
if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED)
{
switch(event.GUIEvent.Caller->getID())
{
case 257:
respawn();
quitMenu();
return true;
}
}
}
return Parent ? Parent->OnEvent(event) : false;
}
void GUIDeathScreen::respawn()
{
m_respawner->respawn();
}

60
src/guiDeathScreen.h Normal file
View File

@@ -0,0 +1,60 @@
/*
Minetest-c55
Copyright (C) 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 GUIMESSAGEMENU_HEADER
#define GUIMESSAGEMENU_HEADER
#include "common_irrlicht.h"
#include "modalMenu.h"
#include "utility.h"
#include <string>
class IRespawnInitiator
{
public:
virtual void respawn() = 0;
};
class GUIDeathScreen : public GUIModalMenu
{
public:
GUIDeathScreen(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr, IRespawnInitiator *respawner);
~GUIDeathScreen();
void removeChildren();
/*
Remove and re-add (or reposition) stuff
*/
void regenerateGui(v2u32 screensize);
void drawMenu();
bool OnEvent(const SEvent& event);
void respawn();
private:
IRespawnInitiator *m_respawner;
v2u32 m_screensize;
};
#endif

View File

@@ -22,6 +22,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "constants.h"
#include "keycode.h"
#include "strfnd.h"
#include <IGUICheckBox.h>
#include <IGUIEditBox.h>
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "log.h"
void drawInventoryItem(video::IVideoDriver *driver,
gui::IGUIFont *font,
@@ -321,11 +327,11 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
if(amount >= 0)
{
v2s32 p(event.MouseInput.X, event.MouseInput.Y);
//dstream<<"Mouse down at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
//infostream<<"Mouse down at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
ItemSpec s = getItemAtPos(p);
if(s.isValid())
{
dstream<<"Mouse down on "<<s.inventoryname
infostream<<"Mouse down on "<<s.inventoryname
<<"/"<<s.listname<<" "<<s.i<<std::endl;
if(m_selected_item)
{
@@ -340,15 +346,15 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
InventoryList *list_to =
inv_to->getList(s.listname);
if(list_from == NULL)
dstream<<"from list doesn't exist"<<std::endl;
infostream<<"from list doesn't exist"<<std::endl;
if(list_to == NULL)
dstream<<"to list doesn't exist"<<std::endl;
infostream<<"to list doesn't exist"<<std::endl;
// Indicates whether source slot completely empties
bool source_empties = false;
if(list_from && list_to
&& list_from->getItem(m_selected_item->i) != NULL)
{
dstream<<"Handing IACTION_MOVE to manager"<<std::endl;
infostream<<"Handing IACTION_MOVE to manager"<<std::endl;
IMoveAction *a = new IMoveAction();
a->count = amount;
a->from_inv = m_selected_item->inventoryname;
@@ -403,7 +409,7 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
{
if(!canTakeFocus(event.GUIEvent.Element))
{
dstream<<"GUIInventoryMenu: Not allowing focus change."
infostream<<"GUIInventoryMenu: Not allowing focus change."
<<std::endl;
// Returning true disables focus change
return true;
@@ -469,7 +475,7 @@ v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
while(f.atend() == false)
{
std::string type = trim(f.next("["));
//dstream<<"type="<<type<<std::endl;
//infostream<<"type="<<type<<std::endl;
if(type == "list")
{
std::string name = f.next(";");
@@ -480,7 +486,7 @@ v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
s32 pos_y = stoi(f.next(";"));
s32 geom_x = stoi(f.next(","));
s32 geom_y = stoi(f.next(";"));
dstream<<"list name="<<name<<", subname="<<subname
infostream<<"list name="<<name<<", subname="<<subname
<<", pos=("<<pos_x<<","<<pos_y<<")"
<<", geom=("<<geom_x<<","<<geom_y<<")"
<<std::endl;
@@ -493,14 +499,14 @@ v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
{
invsize.X = stoi(f.next(","));
invsize.Y = stoi(f.next(";"));
dstream<<"invsize ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl;
infostream<<"invsize ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl;
f.next("]");
}
else
{
// Ignore others
std::string ts = f.next("]");
dstream<<"Unknown DrawSpec: type="<<type<<", data=\""<<ts<<"\""
infostream<<"Unknown DrawSpec: type="<<type<<", data=\""<<ts<<"\""
<<std::endl;
}
}

View File

@@ -24,6 +24,12 @@
#include "serialization.h"
#include "main.h"
#include <string>
#include <IGUICheckBox.h>
#include <IGUIEditBox.h>
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "settings.h"
GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id, IMenuManager *menumgr) :
@@ -340,20 +346,20 @@ void GUIKeyChangeMenu::drawMenu()
bool GUIKeyChangeMenu::acceptInput()
{
g_settings.set("keymap_forward", key_forward.sym());
g_settings.set("keymap_backward", key_backward.sym());
g_settings.set("keymap_left", key_left.sym());
g_settings.set("keymap_right", key_right.sym());
g_settings.set("keymap_jump", key_jump.sym());
g_settings.set("keymap_sneak", key_sneak.sym());
g_settings.set("keymap_inventory", key_inventory.sym());
g_settings.set("keymap_chat", key_chat.sym());
g_settings.set("keymap_cmd", key_cmd.sym());
g_settings.set("keymap_rangeselect", key_range.sym());
g_settings.set("keymap_freemove", key_fly.sym());
g_settings.set("keymap_fastmove", key_fast.sym());
g_settings.set("keymap_special1", key_use.sym());
g_settings.set("keymap_print_debug_stacks", key_dump.sym());
g_settings->set("keymap_forward", key_forward.sym());
g_settings->set("keymap_backward", key_backward.sym());
g_settings->set("keymap_left", key_left.sym());
g_settings->set("keymap_right", key_right.sym());
g_settings->set("keymap_jump", key_jump.sym());
g_settings->set("keymap_sneak", key_sneak.sym());
g_settings->set("keymap_inventory", key_inventory.sym());
g_settings->set("keymap_chat", key_chat.sym());
g_settings->set("keymap_cmd", key_cmd.sym());
g_settings->set("keymap_rangeselect", key_range.sym());
g_settings->set("keymap_freemove", key_fly.sym());
g_settings->set("keymap_fastmove", key_fast.sym());
g_settings->set("keymap_special1", key_use.sym());
g_settings->set("keymap_print_debug_stacks", key_dump.sym());
clearKeyCache();
return true;
}

View File

@@ -22,7 +22,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "debug.h"
#include "serialization.h"
#include <string>
#include <IGUICheckBox.h>
#include <IGUIEditBox.h>
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "gettext.h"
@@ -76,6 +80,8 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
bool enable_damage;
bool fancy_trees;
bool smooth_lighting;
bool clouds_3d;
bool opaque_water;
// Client options
{
@@ -113,6 +119,20 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
else
smooth_lighting = m_data->smooth_lighting;
}
{
gui::IGUIElement *e = getElementFromId(GUI_ID_3D_CLOUDS_CB);
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
clouds_3d = ((gui::IGUICheckBox*)e)->isChecked();
else
clouds_3d = m_data->clouds_3d;
}
{
gui::IGUIElement *e = getElementFromId(GUI_ID_OPAQUE_WATER_CB);
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
opaque_water = ((gui::IGUICheckBox*)e)->isChecked();
else
opaque_water = m_data->opaque_water;
}
// Server options
{
@@ -238,10 +258,22 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
}
{
core::rect<s32> rect(0, 0, 250, 30);
rect += topleft_client + v2s32(35, 150+30);
rect += topleft_client + v2s32(35, 150+20);
Environment->addCheckBox(smooth_lighting, rect, this, GUI_ID_SMOOTH_LIGHTING_CB,
wgettext("Smooth Lighting"));
}
{
core::rect<s32> rect(0, 0, 250, 30);
rect += topleft_client + v2s32(35, 150+40);
Environment->addCheckBox(clouds_3d, rect, this, GUI_ID_3D_CLOUDS_CB,
wgettext("3D Clouds"));
}
{
core::rect<s32> rect(0, 0, 250, 30);
rect += topleft_client + v2s32(35, 150+60);
Environment->addCheckBox(opaque_water, rect, this, GUI_ID_OPAQUE_WATER_CB,
wgettext("Opaque water"));
}
// Start game button
{
core::rect<s32> rect(0, 0, 180, 30);
@@ -358,15 +390,25 @@ void GUIMainMenu::acceptInput()
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
m_data->enable_damage = ((gui::IGUICheckBox*)e)->isChecked();
}
{
gui::IGUIElement *e = getElementFromId(GUI_ID_FANCYTREE_CB);
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
m_data->fancy_trees = ((gui::IGUICheckBox*)e)->isChecked();
}
{
gui::IGUIElement *e = getElementFromId(GUI_ID_SMOOTH_LIGHTING_CB);
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
m_data->smooth_lighting = ((gui::IGUICheckBox*)e)->isChecked();
}
{
gui::IGUIElement *e = getElementFromId(GUI_ID_FANCYTREE_CB);
gui::IGUIElement *e = getElementFromId(GUI_ID_3D_CLOUDS_CB);
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
m_data->fancy_trees = ((gui::IGUICheckBox*)e)->isChecked();
m_data->clouds_3d = ((gui::IGUICheckBox*)e)->isChecked();
}
{
gui::IGUIElement *e = getElementFromId(GUI_ID_OPAQUE_WATER_CB);
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
m_data->opaque_water = ((gui::IGUICheckBox*)e)->isChecked();
}
m_accepted = true;

View File

@@ -35,6 +35,8 @@ enum
GUI_ID_PORT_INPUT,
GUI_ID_FANCYTREE_CB,
GUI_ID_SMOOTH_LIGHTING_CB,
GUI_ID_3D_CLOUDS_CB,
GUI_ID_OPAQUE_WATER_CB,
GUI_ID_DAMAGE_CB,
GUI_ID_CREATIVE_CB,
GUI_ID_JOIN_GAME_BUTTON,
@@ -64,6 +66,8 @@ struct MainMenuData
std::wstring password;
bool fancy_trees;
bool smooth_lighting;
bool clouds_3d;
bool opaque_water;
// Server options
bool creative_mode;
bool enable_damage;

View File

@@ -21,6 +21,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "debug.h"
#include "serialization.h"
#include <string>
#include <IGUICheckBox.h>
#include <IGUIEditBox.h>
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "gettext.h"

View File

@@ -20,6 +20,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "debug.h"
#include "serialization.h"
#include <string>
#include <IGUICheckBox.h>
#include <IGUIEditBox.h>
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "gettext.h"

View File

@@ -23,6 +23,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "porting.h"
#include "config.h"
#include "main.h"
#include <IGUICheckBox.h>
#include <IGUIEditBox.h>
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "gettext.h"

View File

@@ -21,6 +21,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "debug.h"
#include "serialization.h"
#include <string>
#include <IGUICheckBox.h>
#include <IGUIEditBox.h>
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "gettext.h"

View File

@@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_inventory.h"
#include "content_sao.h"
#include "player.h"
#include "log.h"
/*
InventoryItem
@@ -97,7 +98,7 @@ InventoryItem* InventoryItem::deSerialize(std::istream &is)
{
std::string inventorystring;
std::getline(is, inventorystring, '|');
return new MapBlockObjectItem(inventorystring);
throw SerializationError("MBOItem not supported anymore");
}
else if(name == "CraftItem")
{
@@ -117,7 +118,7 @@ InventoryItem* InventoryItem::deSerialize(std::istream &is)
}
else
{
dstream<<"Unknown InventoryItem name=\""<<name<<"\""<<std::endl;
infostream<<"Unknown InventoryItem name=\""<<name<<"\""<<std::endl;
throw SerializationError("Unknown InventoryItem name");
}
}
@@ -158,7 +159,7 @@ InventoryItem *MaterialItem::createCookResult() const
*/
#ifndef SERVER
video::ITexture * CraftItem::getImage()
video::ITexture * CraftItem::getImage() const
{
if(g_texturesource == NULL)
return NULL;
@@ -219,77 +220,6 @@ bool CraftItem::use(ServerEnvironment *env, Player *player)
return false;
}
/*
MapBlockObjectItem DEPRECATED
TODO: Remove
*/
#ifndef SERVER
video::ITexture * MapBlockObjectItem::getImage()
{
if(m_inventorystring.substr(0,3) == "Rat")
return g_texturesource->getTextureRaw("rat.png");
if(m_inventorystring.substr(0,4) == "Sign")
return g_texturesource->getTextureRaw("sign.png");
return NULL;
}
#endif
std::string MapBlockObjectItem::getText()
{
if(m_inventorystring.substr(0,3) == "Rat")
return "";
if(m_inventorystring.substr(0,4) == "Sign")
return "";
return "obj";
}
MapBlockObject * MapBlockObjectItem::createObject
(v3f pos, f32 player_yaw, f32 player_pitch)
{
std::istringstream is(m_inventorystring);
std::string name;
std::getline(is, name, ' ');
if(name == "None")
{
return NULL;
}
else if(name == "Sign")
{
std::string text;
std::getline(is, text, '|');
SignObject *obj = new SignObject(NULL, -1, pos);
obj->setText(text);
obj->setYaw(-player_yaw);
return obj;
}
else if(name == "Rat")
{
RatObject *obj = new RatObject(NULL, -1, pos);
return obj;
}
else if(name == "ItemObj")
{
/*
Now we are an inventory item containing the serialization
string of an object that contains the serialization
string of an inventory item. Fuck this.
*/
//assert(0);
dstream<<__FUNCTION_NAME<<": WARNING: Ignoring ItemObj "
<<"because an item-object should never be inside "
<<"an object-item."<<std::endl;
return NULL;
}
else
{
return NULL;
}
}
/*
Inventory
*/
@@ -809,51 +739,56 @@ InventoryAction * InventoryAction::deSerialize(std::istream &is)
return a;
}
static std::string describeC(const struct InventoryContext *c)
{
if(c->current_player == NULL)
return "current_player=NULL";
else
return std::string("current_player=") + c->current_player->getName();
}
void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr)
{
#if 1
/*dstream<<"from_inv="<<from_inv<<" to_inv="<<to_inv<<std::endl;
dstream<<"from_list="<<from_list<<" to_list="<<to_list<<std::endl;
dstream<<"from_i="<<from_i<<" to_i="<<to_i<<std::endl;*/
Inventory *inv_from = mgr->getInventory(c, from_inv);
Inventory *inv_to = mgr->getInventory(c, to_inv);
if(!inv_from || !inv_to)
{
dstream<<__FUNCTION_NAME<<": Operation not allowed "
<<"(inventories not found)"<<std::endl;
if(!inv_from){
infostream<<"IMoveAction::apply(): FAIL: source inventory not found: "
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
<<", to_inv=\""<<to_inv<<"\""<<std::endl;
return;
}
if(!inv_to){
infostream<<"IMoveAction::apply(): FAIL: destination inventory not found: "
"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
<<", to_inv=\""<<to_inv<<"\""<<std::endl;
return;
}
InventoryList *list_from = inv_from->getList(from_list);
InventoryList *list_to = inv_to->getList(to_list);
/*dstream<<"list_from="<<list_from<<" list_to="<<list_to
<<std::endl;*/
/*if(list_from)
dstream<<" list_from->getItem(from_i)="<<list_from->getItem(from_i)
<<std::endl;
if(list_to)
dstream<<" list_to->getItem(to_i)="<<list_to->getItem(to_i)
<<std::endl;*/
/*
If a list doesn't exist or the source item doesn't exist
*/
if(!list_from || !list_to)
{
dstream<<__FUNCTION_NAME<<": Operation not allowed "
<<"(a list doesn't exist)"
<<std::endl;
if(!list_from){
infostream<<"IMoveAction::apply(): FAIL: source list not found: "
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
<<", from_list=\""<<from_list<<"\""<<std::endl;
return;
}
if(!list_to){
infostream<<"IMoveAction::apply(): FAIL: destination list not found: "
<<"context=["<<describeC(c)<<"], to_inv=\""<<to_inv<<"\""
<<", to_list=\""<<to_list<<"\""<<std::endl;
return;
}
if(list_from->getItem(from_i) == NULL)
{
dstream<<__FUNCTION_NAME<<": Operation not allowed "
<<"(the source item doesn't exist)"
<<std::endl;
infostream<<"IMoveAction::apply(): FAIL: source item not found: "
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
<<", from_list=\""<<from_list<<"\""
<<" from_i="<<from_i<<std::endl;
return;
}
/*
@@ -861,8 +796,9 @@ void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr)
*/
if(inv_from == inv_to && list_from == list_to && from_i == to_i)
{
dstream<<__FUNCTION_NAME<<": Operation not allowed "
<<"(source and the destination slots are the same)"<<std::endl;
infostream<<"IMoveAction::apply(): FAIL: source and destination slots "
<<"are the same: inv=\""<<from_inv<<"\" list=\""<<from_list
<<"\" i="<<from_i<<std::endl;
return;
}
@@ -903,7 +839,16 @@ void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr)
mgr->inventoryModified(c, from_inv);
if(from_inv != to_inv)
mgr->inventoryModified(c, to_inv);
#endif
infostream<<"IMoveAction::apply(): moved at "
<<"["<<describeC(c)<<"]"
<<" from inv=\""<<from_inv<<"\""
<<" list=\""<<from_list<<"\""
<<" i="<<from_i
<<" to inv=\""<<to_inv<<"\""
<<" list=\""<<to_list<<"\""
<<" i="<<to_i
<<std::endl;
}
/*

View File

@@ -29,7 +29,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
#include "common_irrlicht.h"
#include "debug.h"
#include "mapblockobject.h"
#include "main.h" // For g_materials
#include "mapnode.h" // For content_t
@@ -53,8 +52,12 @@ class InventoryItem
// Shall make an exact clone of the item
virtual InventoryItem* clone() = 0;
#ifndef SERVER
// Shall return an image to show in the GUI (or NULL)
virtual video::ITexture * getImage() { return NULL; }
// Return the name of the image for this item
virtual std::string getBasename() const { return ""; }
// Shall return an image of the item (or NULL)
virtual video::ITexture * getImage() const { return NULL; }
// Shall return an image of the item without embellishments (or NULL)
virtual video::ITexture * getImageRaw() const { return getImage(); }
#endif
// Shall return a text to show in the GUI
virtual std::string getText() { return ""; }
@@ -149,10 +152,9 @@ class MaterialItem : public InventoryItem
return new MaterialItem(m_content, m_count);
}
#ifndef SERVER
video::ITexture * getImage()
video::ITexture * getImage() const
{
return content_features(m_content).inventory_texture;
return NULL;
}
#endif
std::string getText()
@@ -193,56 +195,6 @@ class MaterialItem : public InventoryItem
content_t m_content;
};
//TODO: Remove
class MapBlockObjectItem : public InventoryItem
{
public:
MapBlockObjectItem(std::string inventorystring):
InventoryItem(1)
{
m_inventorystring = inventorystring;
}
/*
Implementation interface
*/
virtual const char* getName() const
{
return "MBOItem";
}
virtual void serialize(std::ostream &os) const
{
std::string sane_string(m_inventorystring);
str_replace_char(sane_string, '|', '?');
os<<getName();
os<<" ";
os<<sane_string;
os<<"|";
}
virtual InventoryItem* clone()
{
return new MapBlockObjectItem(m_inventorystring);
}
#ifndef SERVER
video::ITexture * getImage();
#endif
std::string getText();
/*
Special methods
*/
std::string getInventoryString()
{
return m_inventorystring;
}
MapBlockObject * createObject(v3f pos, f32 player_yaw, f32 player_pitch);
private:
std::string m_inventorystring;
};
/*
An item that is used as a mid-product when crafting.
Subnames:
@@ -276,7 +228,7 @@ class CraftItem : public InventoryItem
return new CraftItem(m_subname, m_count);
}
#ifndef SERVER
video::ITexture * getImage();
video::ITexture * getImage() const;
#endif
std::string getText()
{
@@ -353,40 +305,43 @@ class ToolItem : public InventoryItem
return new ToolItem(m_toolname, m_wear);
}
#ifndef SERVER
video::ITexture * getImage()
std::string getBasename() const {
if(m_toolname == "WPick")
return "tool_woodpick.png";
else if(m_toolname == "STPick")
return "tool_stonepick.png";
else if(m_toolname == "SteelPick")
return "tool_steelpick.png";
else if(m_toolname == "MesePick")
return "tool_mesepick.png";
else if(m_toolname == "WShovel")
return "tool_woodshovel.png";
else if(m_toolname == "STShovel")
return "tool_stoneshovel.png";
else if(m_toolname == "SteelShovel")
return "tool_steelshovel.png";
else if(m_toolname == "WAxe")
return "tool_woodaxe.png";
else if(m_toolname == "STAxe")
return "tool_stoneaxe.png";
else if(m_toolname == "SteelAxe")
return "tool_steelaxe.png";
else if(m_toolname == "WSword")
return "tool_woodsword.png";
else if(m_toolname == "STSword")
return "tool_stonesword.png";
else if(m_toolname == "SteelSword")
return "tool_steelsword.png";
else
return "cloud.png";
}
video::ITexture * getImage() const
{
if(g_texturesource == NULL)
return NULL;
std::string basename;
if(m_toolname == "WPick")
basename = "tool_woodpick.png";
else if(m_toolname == "STPick")
basename = "tool_stonepick.png";
else if(m_toolname == "SteelPick")
basename = "tool_steelpick.png";
else if(m_toolname == "MesePick")
basename = "tool_mesepick.png";
else if(m_toolname == "WShovel")
basename = "tool_woodshovel.png";
else if(m_toolname == "STShovel")
basename = "tool_stoneshovel.png";
else if(m_toolname == "SteelShovel")
basename = "tool_steelshovel.png";
else if(m_toolname == "WAxe")
basename = "tool_woodaxe.png";
else if(m_toolname == "STAxe")
basename = "tool_stoneaxe.png";
else if(m_toolname == "SteelAxe")
basename = "tool_steelaxe.png";
else if(m_toolname == "WSword")
basename = "tool_woodsword.png";
else if(m_toolname == "STSword")
basename = "tool_stonesword.png";
else if(m_toolname == "SteelSword")
basename = "tool_steelsword.png";
else
basename = "cloud.png";
std::string basename = getBasename();
/*
Calculate a progress value with sane amount of
@@ -401,6 +356,14 @@ class ToolItem : public InventoryItem
return g_texturesource->getTextureRaw(os.str());
}
video::ITexture * getImageRaw() const
{
if(g_texturesource == NULL)
return NULL;
return g_texturesource->getTextureRaw(getBasename());
}
#endif
std::string getText()
{

View File

@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "keycode.h"
#include "main.h" // For g_settings
#include "exceptions.h"
#include "settings.h"
class UnknownKeycode : public BaseException
{
@@ -334,7 +335,7 @@ KeyPress getKeySetting(const char *settingname)
if(n)
return n->getValue();
g_key_setting_cache.insert(settingname,
g_settings.get(settingname).c_str());
g_settings->get(settingname).c_str());
return g_key_setting_cache.find(settingname)->getValue();
}

144
src/log.cpp Normal file
View File

@@ -0,0 +1,144 @@
/*
Minetest-c55
Copyright (C) 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 "log.h"
#include <map>
#include <list>
#include <sstream>
#include "threads.h"
#include "debug.h"
#include "gettime.h"
std::list<ILogOutput*> log_outputs[LMT_NUM_VALUES];
std::map<threadid_t, std::string> log_threadnames;
void log_add_output(ILogOutput *out, enum LogMessageLevel lev)
{
log_outputs[lev].push_back(out);
}
void log_add_output_maxlev(ILogOutput *out, enum LogMessageLevel lev)
{
for(int i=0; i<=lev; i++)
log_outputs[i].push_back(out);
}
void log_add_output_all_levs(ILogOutput *out)
{
for(int i=0; i<LMT_NUM_VALUES; i++)
log_outputs[i].push_back(out);
}
void log_register_thread(const std::string &name)
{
threadid_t id = get_current_thread_id();
log_threadnames[id] = name;
}
static std::string get_lev_string(enum LogMessageLevel lev)
{
switch(lev){
case LMT_ERROR:
return "ERROR";
case LMT_ACTION:
return "ACTION";
case LMT_INFO:
return "INFO";
case LMT_VERBOSE:
return "VERBOSE";
case LMT_NUM_VALUES:
break;
}
return "(unknown level)";
}
void log_printline(enum LogMessageLevel lev, const std::string &text)
{
std::string threadname = "(unknown thread)";
std::map<threadid_t, std::string>::const_iterator i;
i = log_threadnames.find(get_current_thread_id());
if(i != log_threadnames.end())
threadname = i->second;
std::string levelname = get_lev_string(lev);
std::ostringstream os(std::ios_base::binary);
os<<getTimestamp()<<": "<<levelname<<"["<<threadname<<"]: "<<text;
for(std::list<ILogOutput*>::iterator i = log_outputs[lev].begin();
i != log_outputs[lev].end(); i++){
ILogOutput *out = *i;
out->printLog(os.str());
out->printLog(lev, text);
}
}
class Logbuf : public std::streambuf
{
public:
Logbuf(enum LogMessageLevel lev):
m_lev(lev)
{
}
~Logbuf()
{
}
int overflow(int c)
{
bufchar(c);
return c;
}
std::streamsize xsputn(const char *s, std::streamsize n)
{
for(int i=0; i<n; i++)
bufchar(s[i]);
return n;
}
void printbuf()
{
log_printline(m_lev, m_buf);
}
void bufchar(char c)
{
if(c == '\n' || c == '\r'){
if(m_buf != "")
printbuf();
m_buf = "";
return;
}
m_buf += c;
}
private:
enum LogMessageLevel m_lev;
std::string m_buf;
};
Logbuf errorbuf(LMT_ERROR);
Logbuf actionbuf(LMT_ACTION);
Logbuf infobuf(LMT_INFO);
Logbuf verbosebuf(LMT_VERBOSE);
std::ostream errorstream(&errorbuf);
std::ostream actionstream(&actionbuf);
std::ostream infostream(&infobuf);
std::ostream verbosestream(&verbosebuf);

69
src/log.h Normal file
View File

@@ -0,0 +1,69 @@
/*
Minetest-c55
Copyright (C) 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 LOG_HEADER
#define LOG_HEADER
#include <string>
/*
Use this for logging everything.
If you need to explicitly print something, use dstream or cout or cerr.
*/
enum LogMessageLevel {
LMT_ERROR, /* Something failed ("invalid map data on disk, block (2,2,1)") */
LMT_ACTION, /* In-game actions ("celeron55 placed block at (12,4,-5)") */
LMT_INFO, /* More deep info ("saving map on disk (only_modified=true)") */
LMT_VERBOSE, /* Flood-style ("loaded block (2,2,2) from disk") */
LMT_NUM_VALUES,
};
class ILogOutput
{
public:
/* line: Full line with timestamp, level and thread */
virtual void printLog(const std::string &line){};
/* line: Only actual printed text */
virtual void printLog(enum LogMessageLevel lev, const std::string &line){};
};
void log_add_output(ILogOutput *out, enum LogMessageLevel lev);
void log_add_output_maxlev(ILogOutput *out, enum LogMessageLevel lev);
void log_add_output_all_levs(ILogOutput *out);
void log_register_thread(const std::string &name);
void log_printline(enum LogMessageLevel lev, const std::string &text);
#define LOGLINEF(lev, ...)\
{\
char buf[10000];\
snprintf(buf, 10000, __VA_ARGS__);\
log_printline(lev, buf);\
}
extern std::ostream errorstream;
extern std::ostream actionstream;
extern std::ostream infostream;
extern std::ostream verbosestream;
#endif

View File

@@ -411,10 +411,13 @@ Doing currently:
//#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
#include "irrlicht.h" // createDevice
#include "main.h"
#include "mainmenumanager.h"
#include <iostream>
#include <fstream>
#include <locale.h>
#include "main.h"
#include "common_irrlicht.h"
#include "debug.h"
#include "test.h"
@@ -431,8 +434,11 @@ Doing currently:
#include "game.h"
#include "keycode.h"
#include "tile.h"
#include "defaultsettings.h"
#include "gettext.h"
#include "settings.h"
#include "profiler.h"
#include "log.h"
// This makes textures
ITextureSource *g_texturesource = NULL;
@@ -441,25 +447,23 @@ ITextureSource *g_texturesource = NULL;
Settings.
These are loaded from the config file.
*/
Settings g_settings;
// This is located in defaultsettings.cpp
extern void set_default_settings();
Settings main_settings;
Settings *g_settings = &main_settings;
// Global profiler
Profiler g_profiler;
Profiler main_profiler;
Profiler *g_profiler = &main_profiler;
/*
Random stuff
*/
/*
GUI Stuff
mainmenumanager.h
*/
gui::IGUIEnvironment* guienv = NULL;
gui::IGUIStaticText *guiroot = NULL;
MainMenuManager g_menumgr;
bool noMenuActive()
@@ -468,7 +472,6 @@ bool noMenuActive()
}
// Passed to menus to allow disconnecting and exiting
MainGameCallback *g_gamecallback = NULL;
/*
@@ -477,19 +480,17 @@ MainGameCallback *g_gamecallback = NULL;
// Connection
std::ostream *dout_con_ptr = &dummyout;
std::ostream *derr_con_ptr = &dstream_no_stderr;
//std::ostream *dout_con_ptr = &dstream_no_stderr;
//std::ostream *derr_con_ptr = &dstream_no_stderr;
//std::ostream *dout_con_ptr = &dstream;
//std::ostream *derr_con_ptr = &dstream;
std::ostream *derr_con_ptr = &verbosestream;
//std::ostream *dout_con_ptr = &infostream;
//std::ostream *derr_con_ptr = &errorstream;
// Server
std::ostream *dout_server_ptr = &dstream;
std::ostream *derr_server_ptr = &dstream;
std::ostream *dout_server_ptr = &infostream;
std::ostream *derr_server_ptr = &errorstream;
// Client
std::ostream *dout_client_ptr = &dstream;
std::ostream *derr_client_ptr = &dstream;
std::ostream *dout_client_ptr = &infostream;
std::ostream *derr_client_ptr = &errorstream;
/*
gettime.h implementation
@@ -581,7 +582,6 @@ class MyEventReceiver : public IEventReceiver
}
else
{
//dstream<<"MyEventReceiver: mouse input"<<std::endl;
left_active = event.MouseInput.isLeftPressed();
middle_active = event.MouseInput.isMiddlePressed();
right_active = event.MouseInput.isRightPressed();
@@ -1024,7 +1024,7 @@ void SpeedTests()
u32 dtime = timer.stop();
u32 per_ms = n / dtime;
std::cout<<"Done. "<<dtime<<"ms, "
dstream<<"Done. "<<dtime<<"ms, "
<<per_ms<<"/ms"<<std::endl;
}
}
@@ -1076,12 +1076,37 @@ void drawMenuBackground(video::IVideoDriver* driver)
}
}
class StderrLogOutput: public ILogOutput
{
public:
/* line: Full line with timestamp, level and thread */
void printLog(const std::string &line)
{
std::cerr<<line<<std::endl;
}
} main_stderr_log_out;
class DstreamNoStderrLogOutput: public ILogOutput
{
public:
/* line: Full line with timestamp, level and thread */
void printLog(const std::string &line)
{
dstream_no_stderr<<line<<std::endl;
}
} main_dstream_no_stderr_log_out;
int main(int argc, char *argv[])
{
/*
Initialization
*/
log_add_output_maxlev(&main_stderr_log_out, LMT_ACTION);
log_add_output_all_levs(&main_dstream_no_stderr_log_out);
log_register_thread("main");
// Set locale. This is for forcing '.' as the decimal point.
std::locale::global(std::locale("C"));
// This enables printing all characters in bitmap font
@@ -1108,6 +1133,7 @@ int main(int argc, char *argv[])
allowed_options.insert("dstream-on-stderr", ValueSpec(VALUETYPE_FLAG));
#endif
allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG));
allowed_options.insert("info-on-stderr", ValueSpec(VALUETYPE_FLAG));
Settings cmd_args;
@@ -1149,6 +1175,9 @@ int main(int argc, char *argv[])
if(cmd_args.getFlag("dstream-on-stderr") == false)
disable_stderr = true;
#endif
if(cmd_args.getFlag("info-on-stderr"))
log_add_output(&main_stderr_log_out, LMT_INFO);
porting::signal_handler_init();
bool &kill = *porting::signal_handler_killstatus();
@@ -1159,13 +1188,13 @@ int main(int argc, char *argv[])
// Create user data directory
fs::CreateDir(porting::path_userdata);
init_gettext((porting::path_data+"/../locale").c_str());
init_gettext((porting::path_data+DIR_DELIM+".."+DIR_DELIM+"locale").c_str());
// Initialize debug streams
#ifdef RUN_IN_PLACE
std::string debugfile = DEBUGFILE;
#else
std::string debugfile = porting::path_userdata+"/"+DEBUGFILE;
std::string debugfile = porting::path_userdata+DIR_DELIM+DEBUGFILE;
#endif
debugstreams_init(disable_stderr, debugfile.c_str());
// Initialize debug stacks
@@ -1180,7 +1209,7 @@ int main(int argc, char *argv[])
BEGIN_DEBUG_EXCEPTION_HANDLER
// Print startup message
dstream<<DTIME<<PROJECT_NAME
actionstream<<PROJECT_NAME<<
" with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST
<<", "<<BUILD_INFO
<<std::endl;
@@ -1190,7 +1219,7 @@ int main(int argc, char *argv[])
*/
// Initialize default settings
set_default_settings();
set_default_settings(g_settings);
// Initialize sockets
sockets_init();
@@ -1205,10 +1234,10 @@ int main(int argc, char *argv[])
if(cmd_args.exists("config"))
{
bool r = g_settings.readConfigFile(cmd_args.get("config").c_str());
bool r = g_settings->readConfigFile(cmd_args.get("config").c_str());
if(r == false)
{
dstream<<"Could not read configuration from \""
errorstream<<"Could not read configuration from \""
<<cmd_args.get("config")<<"\""<<std::endl;
return 1;
}
@@ -1217,14 +1246,16 @@ int main(int argc, char *argv[])
else
{
core::array<std::string> filenames;
filenames.push_back(porting::path_userdata + "/minetest.conf");
filenames.push_back(porting::path_userdata +
DIR_DELIM + "minetest.conf");
#ifdef RUN_IN_PLACE
filenames.push_back(porting::path_userdata + "/../minetest.conf");
filenames.push_back(porting::path_userdata +
DIR_DELIM + ".." + DIR_DELIM + "minetest.conf");
#endif
for(u32 i=0; i<filenames.size(); i++)
{
bool r = g_settings.readConfigFile(filenames[i].c_str());
bool r = g_settings->readConfigFile(filenames[i].c_str());
if(r)
{
configpath = filenames[i];
@@ -1249,6 +1280,9 @@ int main(int argc, char *argv[])
// Initial call with g_texturesource not set.
init_mapnode();
// Must be called before g_texturesource is created
// (for texture atlas making)
init_mineral();
/*
Run unit tests
@@ -1275,17 +1309,17 @@ int main(int argc, char *argv[])
u16 port = 30000;
if(cmd_args.exists("port"))
port = cmd_args.getU16("port");
else if(g_settings.exists("port"))
port = g_settings.getU16("port");
else if(g_settings->exists("port"))
port = g_settings->getU16("port");
if(port == 0)
port = 30000;
// Map directory
std::string map_dir = porting::path_userdata+"/world";
std::string map_dir = porting::path_userdata+DIR_DELIM+"world";
if(cmd_args.exists("map-dir"))
map_dir = cmd_args.get("map-dir");
else if(g_settings.exists("map-dir"))
map_dir = g_settings.get("map-dir");
else if(g_settings->exists("map-dir"))
map_dir = g_settings->get("map-dir");
// Run dedicated server if asked to
if(cmd_args.getFlag("server"))
@@ -1319,10 +1353,10 @@ int main(int argc, char *argv[])
}
else
{
address = g_settings.get("address");
address = g_settings->get("address");
}
std::string playername = g_settings.get("name");
std::string playername = g_settings->get("name");
/*
Device initialization
@@ -1331,14 +1365,14 @@ int main(int argc, char *argv[])
// Resolution selection
bool fullscreen = false;
u16 screenW = g_settings.getU16("screenW");
u16 screenH = g_settings.getU16("screenH");
u16 screenW = g_settings->getU16("screenW");
u16 screenH = g_settings->getU16("screenH");
// Determine driver
video::E_DRIVER_TYPE driverType;
std::string driverstring = g_settings.get("video_driver");
std::string driverstring = g_settings->get("video_driver");
if(driverstring == "null")
driverType = video::EDT_NULL;
@@ -1354,7 +1388,7 @@ int main(int argc, char *argv[])
driverType = video::EDT_OPENGL;
else
{
dstream<<"WARNING: Invalid video_driver specified; defaulting "
errorstream<<"WARNING: Invalid video_driver specified; defaulting "
"to opengl"<<std::endl;
driverType = video::EDT_OPENGL;
}
@@ -1373,6 +1407,21 @@ int main(int argc, char *argv[])
if (device == 0)
return 1; // could not create selected driver.
/*
Continue initialization
*/
video::IVideoDriver* driver = device->getVideoDriver();
// Disable mipmaps (because some of them look ugly)
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
/*
This changes the minimum allowed number of vertices in a VBO.
Default is 500.
*/
//driver->setMinHardwareBufferVertexCount(50);
// Set the window caption
device->setWindowCaption(L"Minetest [Main Menu]");
@@ -1397,7 +1446,7 @@ int main(int argc, char *argv[])
device->setResizable(true);
bool random_input = g_settings.getBool("random_input")
bool random_input = g_settings->getBool("random_input")
|| cmd_args.getFlag("random-input");
InputHandler *input = NULL;
if(random_input)
@@ -1405,18 +1454,6 @@ int main(int argc, char *argv[])
else
input = new RealInputHandler(device, &receiver);
/*
Continue initialization
*/
//video::IVideoDriver* driver = device->getVideoDriver();
/*
This changes the minimum allowed number of vertices in a VBO.
Default is 500.
*/
//driver->setMinHardwareBufferVertexCount(50);
scene::ISceneManager* smgr = device->getSceneManager();
guienv = device->getGUIEnvironment();
@@ -1425,14 +1462,14 @@ int main(int argc, char *argv[])
if(font)
skin->setFont(font);
else
dstream<<"WARNING: Font file was not found."
errorstream<<"WARNING: Font file was not found."
" Using default font."<<std::endl;
// If font was not found, this will get us one
font = skin->getFont();
assert(font);
u32 text_height = font->getDimension(L"Hello, world!").Height;
dstream<<"text_height="<<text_height<<std::endl;
infostream<<"text_height="<<text_height<<std::endl;
//skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,0,0,0));
skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,255,255,255));
@@ -1446,7 +1483,6 @@ int main(int argc, char *argv[])
*/
init_mapnode(); // Second call with g_texturesource set
init_mineral();
/*
GUI stuff
@@ -1508,10 +1544,12 @@ int main(int argc, char *argv[])
menudata.address = narrow_to_wide(address);
menudata.name = narrow_to_wide(playername);
menudata.port = narrow_to_wide(itos(port));
menudata.fancy_trees = g_settings.getBool("new_style_leaves");
menudata.smooth_lighting = g_settings.getBool("smooth_lighting");
menudata.creative_mode = g_settings.getBool("creative_mode");
menudata.enable_damage = g_settings.getBool("enable_damage");
menudata.fancy_trees = g_settings->getBool("new_style_leaves");
menudata.smooth_lighting = g_settings->getBool("smooth_lighting");
menudata.clouds_3d = g_settings->getBool("enable_3d_clouds");
menudata.opaque_water = g_settings->getBool("opaque_water");
menudata.creative_mode = g_settings->getBool("creative_mode");
menudata.enable_damage = g_settings->getBool("enable_damage");
GUIMainMenu *menu =
new GUIMainMenu(guienv, guiroot, -1,
@@ -1520,7 +1558,7 @@ int main(int argc, char *argv[])
if(error_message != L"")
{
dstream<<"WARNING: error_message = "
errorstream<<"error_message = "
<<wide_to_narrow(error_message)<<std::endl;
GUIMessageMenu *menu2 =
@@ -1532,7 +1570,7 @@ int main(int argc, char *argv[])
video::IVideoDriver* driver = device->getVideoDriver();
dstream<<"Created main menu"<<std::endl;
infostream<<"Created main menu"<<std::endl;
while(device->run() && kill == false)
{
@@ -1557,7 +1595,7 @@ int main(int argc, char *argv[])
if(device->run() == false || kill == true)
break;
dstream<<"Dropping main menu"<<std::endl;
infostream<<"Dropping main menu"<<std::endl;
menu->drop();
@@ -1574,16 +1612,18 @@ int main(int argc, char *argv[])
password = translatePassword(playername, menudata.password);
//dstream<<"Main: password hash: '"<<password<<"'"<<std::endl;
//infostream<<"Main: password hash: '"<<password<<"'"<<std::endl;
address = wide_to_narrow(menudata.address);
int newport = stoi(wide_to_narrow(menudata.port));
if(newport != 0)
port = newport;
g_settings.set("new_style_leaves", itos(menudata.fancy_trees));
g_settings.set("smooth_lighting", itos(menudata.smooth_lighting));
g_settings.set("creative_mode", itos(menudata.creative_mode));
g_settings.set("enable_damage", itos(menudata.enable_damage));
g_settings->set("new_style_leaves", itos(menudata.fancy_trees));
g_settings->set("smooth_lighting", itos(menudata.smooth_lighting));
g_settings->set("enable_3d_clouds", itos(menudata.clouds_3d));
g_settings->set("opaque_water", itos(menudata.opaque_water));
g_settings->set("creative_mode", itos(menudata.creative_mode));
g_settings->set("enable_damage", itos(menudata.enable_damage));
// NOTE: These are now checked server side; no need to do it
// here, so let's not do it here.
@@ -1602,12 +1642,12 @@ int main(int argc, char *argv[])
}*/
// Save settings
g_settings.set("name", playername);
g_settings.set("address", address);
g_settings.set("port", itos(port));
g_settings->set("name", playername);
g_settings->set("address", address);
g_settings->set("port", itos(port));
// Update configuration file
if(configpath != "")
g_settings.updateConfigFile(configpath.c_str());
g_settings->updateConfigFile(configpath.c_str());
// Continue to game
break;
@@ -1641,12 +1681,12 @@ int main(int argc, char *argv[])
} //try
catch(con::PeerNotFoundException &e)
{
dstream<<DTIME<<"Connection error (timed out?)"<<std::endl;
errorstream<<"Connection error (timed out?)"<<std::endl;
error_message = L"Connection error (timed out?)";
}
catch(SocketException &e)
{
dstream<<DTIME<<"Socket error (port already in use?)"<<std::endl;
errorstream<<"Socket error (port already in use?)"<<std::endl;
error_message = L"Socket error (port already in use?)";
}
#ifdef NDEBUG
@@ -1655,7 +1695,7 @@ int main(int argc, char *argv[])
std::string narrow_message = "Some exception, what()=\"";
narrow_message += e.what();
narrow_message += "\"";
dstream<<DTIME<<narrow_message<<std::endl;
errorstream<<narrow_message<<std::endl;
error_message = narrow_to_wide(narrow_message);
}
#endif
@@ -1669,7 +1709,7 @@ int main(int argc, char *argv[])
*/
device->drop();
END_DEBUG_EXCEPTION_HANDLER
END_DEBUG_EXCEPTION_HANDLER(errorstream)
debugstreams_deinit();

View File

@@ -21,16 +21,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MAIN_HEADER
// Settings
#include "utility.h"
extern Settings g_settings;
class Settings;
extern Settings *g_settings;
// This makes and maps textures
class ITextureSource;
extern ITextureSource *g_texturesource;
// Global profiler
#include "profiler.h"
extern Profiler g_profiler;
class Profiler;
extern Profiler *g_profiler;
// Debug streams
@@ -50,105 +50,5 @@ extern std::ostream *derr_server_ptr;
#define dout_server (*dout_server_ptr)
#define derr_server (*derr_server_ptr)
/*
All kinds of stuff that needs to be exposed from main.cpp
*/
#include "modalMenu.h"
#include "guiPauseMenu.h" //For IGameCallback
extern gui::IGUIEnvironment* guienv;
extern gui::IGUIStaticText *guiroot;
// Handler for the modal menus
class MainMenuManager : public IMenuManager
{
public:
virtual void createdMenu(GUIModalMenu *menu)
{
for(core::list<GUIModalMenu*>::Iterator
i = m_stack.begin();
i != m_stack.end(); i++)
{
assert(*i != menu);
}
if(m_stack.size() != 0)
(*m_stack.getLast())->setVisible(false);
m_stack.push_back(menu);
}
virtual void deletingMenu(GUIModalMenu *menu)
{
// Remove all entries if there are duplicates
bool removed_entry;
do{
removed_entry = false;
for(core::list<GUIModalMenu*>::Iterator
i = m_stack.begin();
i != m_stack.end(); i++)
{
if(*i == menu)
{
m_stack.erase(i);
removed_entry = true;
break;
}
}
}while(removed_entry);
/*core::list<GUIModalMenu*>::Iterator i = m_stack.getLast();
assert(*i == menu);
m_stack.erase(i);*/
if(m_stack.size() != 0)
(*m_stack.getLast())->setVisible(true);
}
u32 menuCount()
{
return m_stack.size();
}
core::list<GUIModalMenu*> m_stack;
};
extern MainMenuManager g_menumgr;
extern bool noMenuActive();
class MainGameCallback : public IGameCallback
{
public:
MainGameCallback(IrrlichtDevice *a_device):
disconnect_requested(false),
changepassword_requested(false),
device(a_device)
{
}
virtual void exitToOS()
{
device->closeDevice();
}
virtual void disconnect()
{
disconnect_requested = true;
}
virtual void changePassword()
{
changepassword_requested = true;
}
bool disconnect_requested;
bool changepassword_requested;
IrrlichtDevice *device;
};
extern MainGameCallback *g_gamecallback;
#endif

124
src/mainmenumanager.h Normal file
View File

@@ -0,0 +1,124 @@
/*
Minetest-c55
Copyright (C) 2010 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 MAINMENUMANAGER_HEADER
#define MAINMENUMANAGER_HEADER
/*
All kinds of stuff that needs to be exposed from main.cpp
*/
#include "debug.h" // assert
#include "modalMenu.h"
#include "guiPauseMenu.h" //For IGameCallback
extern gui::IGUIEnvironment* guienv;
extern gui::IGUIStaticText *guiroot;
// Handler for the modal menus
class MainMenuManager : public IMenuManager
{
public:
virtual void createdMenu(GUIModalMenu *menu)
{
for(core::list<GUIModalMenu*>::Iterator
i = m_stack.begin();
i != m_stack.end(); i++)
{
assert(*i != menu);
}
if(m_stack.size() != 0)
(*m_stack.getLast())->setVisible(false);
m_stack.push_back(menu);
}
virtual void deletingMenu(GUIModalMenu *menu)
{
// Remove all entries if there are duplicates
bool removed_entry;
do{
removed_entry = false;
for(core::list<GUIModalMenu*>::Iterator
i = m_stack.begin();
i != m_stack.end(); i++)
{
if(*i == menu)
{
m_stack.erase(i);
removed_entry = true;
break;
}
}
}while(removed_entry);
/*core::list<GUIModalMenu*>::Iterator i = m_stack.getLast();
assert(*i == menu);
m_stack.erase(i);*/
if(m_stack.size() != 0)
(*m_stack.getLast())->setVisible(true);
}
u32 menuCount()
{
return m_stack.size();
}
core::list<GUIModalMenu*> m_stack;
};
extern MainMenuManager g_menumgr;
extern bool noMenuActive();
class MainGameCallback : public IGameCallback
{
public:
MainGameCallback(IrrlichtDevice *a_device):
disconnect_requested(false),
changepassword_requested(false),
device(a_device)
{
}
virtual void exitToOS()
{
device->closeDevice();
}
virtual void disconnect()
{
disconnect_requested = true;
}
virtual void changePassword()
{
changepassword_requested = true;
}
bool disconnect_requested;
bool changepassword_requested;
IrrlichtDevice *device;
};
extern MainGameCallback *g_gamecallback;
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -157,6 +157,10 @@ class Map /*: public NodeContainer*/
// Returns NULL if not found
MapBlock * getBlockNoCreateNoEx(v3s16 p);
/* Server overrides */
virtual MapBlock * emergeBlock(v3s16 p, bool allow_generate=true)
{ return getBlockNoCreateNoEx(p); }
// Returns InvalidPositionException if not found
bool isNodeUnderground(v3s16 p);
@@ -205,7 +209,7 @@ class Map /*: public NodeContainer*/
These handle lighting but not faces.
*/
void addNodeAndUpdate(v3s16 p, MapNode n,
core::map<v3s16, MapBlock*> &modified_blocks);
core::map<v3s16, MapBlock*> &modified_blocks, std::string &player_name);
void removeNodeAndUpdate(v3s16 p,
core::map<v3s16, MapBlock*> &modified_blocks);
@@ -379,6 +383,7 @@ class ServerMap : public Map
void verifyDatabase();
// Get an integer suitable for a block
static sqlite3_int64 getBlockAsInteger(const v3s16 pos);
static v3s16 getIntegerAsBlock(sqlite3_int64 i);
// Returns true if the database file does not exist
bool loadFromFolders();
@@ -390,6 +395,8 @@ class ServerMap : public Map
void save(bool only_changed);
//void loadAll();
void listAllLoadableBlocks(core::list<v3s16> &dst);
// Saves map seed and possibly other stuff
void saveMapMeta();
void loadMapMeta();
@@ -454,6 +461,7 @@ class ServerMap : public Map
sqlite3 *m_database;
sqlite3_stmt *m_database_read;
sqlite3_stmt *m_database_write;
sqlite3_stmt *m_database_list;
};
/*
@@ -518,11 +526,12 @@ class ClientMap : public Map, public scene::ISceneNode
ISceneNode::drop();
}
void updateCamera(v3f pos, v3f dir)
void updateCamera(v3f pos, v3f dir, f32 fov)
{
JMutexAutoLock lock(m_camera_mutex);
m_camera_position = pos;
m_camera_direction = dir;
m_camera_fov = fov;
}
/*
@@ -552,6 +561,8 @@ class ClientMap : public Map, public scene::ISceneNode
void renderMap(video::IVideoDriver* driver, s32 pass);
void renderPostFx();
/*
Methods for setting temporary modifications to nodes for
drawing.
@@ -601,6 +612,7 @@ class ClientMap : public Map, public scene::ISceneNode
v3f m_camera_position;
v3f m_camera_direction;
f32 m_camera_fov;
JMutex m_camera_mutex;
core::map<v2s16, bool> m_last_drawn_sectors;

View File

@@ -36,7 +36,6 @@ MapBlock::MapBlock(Map *parent, v3s16 pos, bool dummy):
m_lighting_expired(true),
m_day_night_differs(false),
m_generated(false),
m_objects(this),
m_timestamp(BLOCK_TIMESTAMP_UNDEFINED),
m_usage_timer(0)
{
@@ -434,17 +433,6 @@ void MapBlock::copyFrom(VoxelManipulator &dst)
getPosRelative(), data_size);
}
void MapBlock::stepObjects(float dtime, bool server, u32 daynight_ratio)
{
/*
Step objects
*/
m_objects.step(dtime, server, daynight_ratio);
setChangedFlag();
}
void MapBlock::updateDayNightDiff()
{
if(data == NULL)
@@ -817,10 +805,9 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
void MapBlock::serializeDiskExtra(std::ostream &os, u8 version)
{
// Versions up from 9 have block objects.
// Versions up from 9 have block objects. (DEPRECATED)
if(version >= 9)
{
//serializeObjects(os, version); // DEPRECATED
// count=0
writeU16(os, 0);
}
@@ -841,11 +828,17 @@ void MapBlock::serializeDiskExtra(std::ostream &os, u8 version)
void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version)
{
/*
Versions up from 9 have block objects.
Versions up from 9 have block objects. (DEPRECATED)
*/
if(version >= 9)
{
updateObjects(is, version, NULL, 0);
u16 count = readU16(is);
// Not supported and length not known if count is not 0
if(count != 0){
dstream<<"WARNING: MapBlock::deSerializeDiskExtra(): "
<<"Ignoring stuff coming at and after MBOs"<<std::endl;
return;
}
}
/*

View File

@@ -29,7 +29,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "exceptions.h"
#include "serialization.h"
#include "constants.h"
#include "mapblockobject.h"
#include "voxel.h"
#include "nodemetadata.h"
#include "staticobject.h"
@@ -225,8 +224,10 @@ class MapBlock /*: public NodeContainer*/
void setLightingExpired(bool expired)
{
m_lighting_expired = expired;
raiseModified(MOD_STATE_WRITE_NEEDED);
if(expired != m_lighting_expired){
m_lighting_expired = expired;
raiseModified(MOD_STATE_WRITE_NEEDED);
}
}
bool getLightingExpired()
{
@@ -239,8 +240,10 @@ class MapBlock /*: public NodeContainer*/
}
void setGenerated(bool b)
{
raiseModified(MOD_STATE_WRITE_NEEDED);
m_generated = b;
if(b != m_generated){
raiseModified(MOD_STATE_WRITE_NEEDED);
m_generated = b;
}
}
bool isValid()
@@ -419,68 +422,6 @@ class MapBlock /*: public NodeContainer*/
// Copies data from VoxelManipulator getPosRelative()
void copyFrom(VoxelManipulator &dst);
/*
MapBlockObject stuff
DEPRECATED
*/
/*void serializeObjects(std::ostream &os, u8 version)
{
m_objects.serialize(os, version);
}*/
// If smgr!=NULL, new objects are added to the scene
void updateObjects(std::istream &is, u8 version,
scene::ISceneManager *smgr, u32 daynight_ratio)
{
m_objects.update(is, version, smgr, daynight_ratio);
raiseModified(MOD_STATE_WRITE_NEEDED);
}
void clearObjects()
{
m_objects.clear();
raiseModified(MOD_STATE_WRITE_NEEDED);
}
void addObject(MapBlockObject *object)
throw(ContainerFullException, AlreadyExistsException)
{
m_objects.add(object);
raiseModified(MOD_STATE_WRITE_NEEDED);
}
void removeObject(s16 id)
{
m_objects.remove(id);
raiseModified(MOD_STATE_WRITE_NEEDED);
}
MapBlockObject * getObject(s16 id)
{
return m_objects.get(id);
}
JMutexAutoLock * getObjectLock()
{
return m_objects.getLock();
}
/*
Moves objects, deletes objects and spawns new objects
*/
void stepObjects(float dtime, bool server, u32 daynight_ratio);
// origin is relative to block
void getObjects(v3f origin, f32 max_d,
core::array<DistanceSortedObject> &dest)
{
m_objects.getObjects(origin, max_d, dest);
}
s32 getObjectCount()
{
return m_objects.getCount();
}
#ifndef SERVER // Only on client
/*
Methods for setting temporary modifications to nodes for
@@ -684,9 +625,6 @@ class MapBlock /*: public NodeContainer*/
bool m_generated;
// DEPRECATED
MapBlockObjectList m_objects;
#ifndef SERVER // Only on client
/*
Set to true if the mesh has been ordered to be updated

View File

@@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h"
#include "main.h" // For g_settings and g_texturesource
#include "content_mapblock.h"
#include "settings.h"
#include "profiler.h"
void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
{
@@ -425,7 +427,8 @@ void getTileInfo(
// This is hackish
content_t content0 = getNodeContent(p, n0, temp_mods);
content_t content1 = getNodeContent(p + face_dir, n1, temp_mods);
u8 mf = face_contents(content0, content1);
bool equivalent = false;
u8 mf = face_contents(content0, content1, &equivalent);
if(mf == 0)
{
@@ -448,6 +451,10 @@ void getTileInfo(
face_dir_corrected = -face_dir;
}
// eg. water and glass
if(equivalent)
tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
if(smooth_lighting == false)
{
lights[0] = lights[1] = lights[2] = lights[3] =
@@ -491,10 +498,10 @@ void updateFastFaceRow(
u16 continuous_tiles_count = 0;
bool makes_face;
bool makes_face = false;
v3s16 p_corrected;
v3s16 face_dir_corrected;
u8 lights[4];
u8 lights[4] = {0,0,0,0};
TileSpec tile;
getTileInfo(blockpos_nodes, p, face_dir, daynight_ratio,
vmanip, temp_mods, smooth_lighting,
@@ -526,7 +533,7 @@ void updateFastFaceRow(
next_tile);
if(next_makes_face == makes_face
&& next_p_corrected == p_corrected
&& next_p_corrected == p_corrected + translate_dir
&& next_face_dir_corrected == face_dir_corrected
&& next_lights[0] == lights[0]
&& next_lights[1] == lights[1]
@@ -536,6 +543,29 @@ void updateFastFaceRow(
{
next_is_different = false;
}
else{
/*if(makes_face){
g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
next_makes_face != makes_face ? 1 : 0);
g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
(next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
next_face_dir_corrected != face_dir_corrected ? 1 : 0);
g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
(next_lights[0] != lights[0] ||
next_lights[0] != lights[0] ||
next_lights[0] != lights[0] ||
next_lights[0] != lights[0]) ? 1 : 0);
g_profiler->add("Meshgen: diff: !(next_tile == tile)",
!(next_tile == tile) ? 1 : 0);
}*/
}
/*g_profiler->add("Meshgen: Total faces checked", 1);
if(makes_face)
g_profiler->add("Meshgen: Total makes_face checked", 1);*/
} else {
/*if(makes_face)
g_profiler->add("Meshgen: diff: last position", 1);*/
}
continuous_tiles_count++;
@@ -567,6 +597,8 @@ void updateFastFaceRow(
v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
// Center point of face (kind of)
v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
if(continuous_tiles_count != 1)
sp += translate_dir_f;
v3f scale(1,1,1);
if(translate_dir.X != 0)
@@ -585,6 +617,11 @@ void updateFastFaceRow(
makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
sp, face_dir_corrected, scale,
posRelative_f, dest);
g_profiler->avg("Meshgen: faces drawn by tiling", 0);
for(int i=1; i<continuous_tiles_count; i++){
g_profiler->avg("Meshgen: faces drawn by tiling", 1);
}
}
continuous_tiles_count = 0;
@@ -619,9 +656,9 @@ scene::SMesh* makeMapBlockMesh(MeshMakeData *data)
/*
Some settings
*/
//bool new_style_water = g_settings.getBool("new_style_water");
//bool new_style_leaves = g_settings.getBool("new_style_leaves");
bool smooth_lighting = g_settings.getBool("smooth_lighting");
//bool new_style_water = g_settings->getBool("new_style_water");
//bool new_style_leaves = g_settings->getBool("new_style_leaves");
bool smooth_lighting = g_settings->getBool("smooth_lighting");
/*
We are including the faces of the trailing edges of the block.
@@ -706,10 +743,13 @@ scene::SMesh* makeMapBlockMesh(MeshMakeData *data)
video::SMaterial material;
material.setFlag(video::EMF_LIGHTING, false);
material.setFlag(video::EMF_BACK_FACE_CULLING, true);
material.setFlag(video::EMF_BILINEAR_FILTER, false);
material.setFlag(video::EMF_FOG_ENABLE, true);
//material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
//material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
material.MaterialType
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
for(u32 i=0; i<fastfaces_new.size(); i++)
{

View File

@@ -1,939 +0,0 @@
/*
Minetest-c55
Copyright (C) 2010 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.
*/
// This file contains the DEPRECATED MapBlockObject system
#include "mapblockobject.h"
#include "mapblock.h"
// For object wrapping
#include "map.h"
#include "inventory.h"
#include "utility.h"
#include "mapblock.h"
/*
MapBlockObject
*/
// This is here because it uses the MapBlock
v3f MapBlockObject::getAbsolutePos()
{
if(m_block == NULL)
return m_pos;
// getPosRelative gets nodepos relative to map origin
v3f blockpos = intToFloat(m_block->getPosRelative(), BS);
return blockpos + m_pos;
}
void MapBlockObject::setBlockChanged()
{
if(m_block)
m_block->setChangedFlag();
}
/*
MovingObject
*/
v3f MovingObject::getAbsoluteShowPos()
{
if(m_block == NULL)
return m_pos;
// getPosRelative gets nodepos relative to map origin
v3f blockpos = intToFloat(m_block->getPosRelative(), BS);
return blockpos + m_showpos;
}
void MovingObject::move(float dtime, v3f acceleration)
{
DSTACKF("%s: typeid=%i, pos=(%f,%f,%f), speed=(%f,%f,%f)"
", dtime=%f, acc=(%f,%f,%f)",
__FUNCTION_NAME,
getTypeId(),
m_pos.X, m_pos.Y, m_pos.Z,
m_speed.X, m_speed.Y, m_speed.Z,
dtime,
acceleration.X, acceleration.Y, acceleration.Z
);
v3s16 oldpos_i = floatToInt(m_pos, BS);
if(m_block->isValidPosition(oldpos_i) == false)
{
// Should have wrapped, cancelling further movement.
return;
}
// No collisions if there is no collision box
if(m_collision_box == NULL)
{
m_speed += dtime * acceleration;
m_pos += m_speed * dtime;
return;
}
// Set insane speed to zero
// Otherwise there will be divides by zero and other silly stuff
if(m_speed.getLength() > 1000.0*BS)
m_speed = v3f(0,0,0);
// Limit speed to a reasonable value
float speed_limit = 20.0*BS;
if(m_speed.getLength() > speed_limit)
m_speed = m_speed * (speed_limit / m_speed.getLength());
v3f position = m_pos;
v3f oldpos = position;
/*std::cout<<"oldpos_i=("<<oldpos_i.X<<","<<oldpos_i.Y<<","
<<oldpos_i.Z<<")"<<std::endl;*/
// Maximum time increment (for collision detection etc)
// Allow 0.1 blocks per increment
// time = distance / speed
// NOTE: In the loop below collisions are detected at 0.15*BS radius
float speedlength = m_speed.getLength();
f32 dtime_max_increment;
if(fabs(speedlength) > 0.001)
dtime_max_increment = 0.05*BS / speedlength;
else
dtime_max_increment = 0.5;
m_touching_ground = false;
u32 loopcount = 0;
do
{
loopcount++;
f32 dtime_part;
if(dtime > dtime_max_increment)
dtime_part = dtime_max_increment;
else
dtime_part = dtime;
dtime -= dtime_part;
// Begin of dtime limited code
m_speed += acceleration * dtime_part;
position += m_speed * dtime_part;
/*
Collision detection
*/
v3s16 pos_i = floatToInt(position, BS);
// The loop length is limited to the object moving a distance
f32 d = (float)BS * 0.15;
core::aabbox3d<f32> objectbox(
m_collision_box->MinEdge + position,
m_collision_box->MaxEdge + position
);
core::aabbox3d<f32> objectbox_old(
m_collision_box->MinEdge + oldpos,
m_collision_box->MaxEdge + oldpos
);
//TODO: Get these ranges from somewhere
for(s16 y = oldpos_i.Y - 1; y <= oldpos_i.Y + 2; y++)
for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++)
for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++)
{
try{
MapNode n = m_block->getNodeParent(v3s16(x,y,z));
if(content_features(n).walkable == false)
continue;
}
catch(InvalidPositionException &e)
{
// Doing nothing here will block the object from
// walking over map borders
}
core::aabbox3d<f32> nodebox = getNodeBox(v3s16(x,y,z), BS);
// See if the object is touching ground
if(
fabs(nodebox.MaxEdge.Y-objectbox.MinEdge.Y) < d
&& nodebox.MaxEdge.X-d > objectbox.MinEdge.X
&& nodebox.MinEdge.X+d < objectbox.MaxEdge.X
&& nodebox.MaxEdge.Z-d > objectbox.MinEdge.Z
&& nodebox.MinEdge.Z+d < objectbox.MaxEdge.Z
){
m_touching_ground = true;
}
if(objectbox.intersectsWithBox(nodebox))
{
v3f dirs[3] = {
v3f(0,0,1), // back
v3f(0,1,0), // top
v3f(1,0,0), // right
};
for(u16 i=0; i<3; i++)
{
f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[i]);
f32 nodemin = nodebox.MinEdge.dotProduct(dirs[i]);
f32 playermax = objectbox.MaxEdge.dotProduct(dirs[i]);
f32 playermin = objectbox.MinEdge.dotProduct(dirs[i]);
f32 playermax_old = objectbox_old.MaxEdge.dotProduct(dirs[i]);
f32 playermin_old = objectbox_old.MinEdge.dotProduct(dirs[i]);
bool main_edge_collides =
((nodemax > playermin && nodemax <= playermin_old + d
&& m_speed.dotProduct(dirs[i]) < 0)
||
(nodemin < playermax && nodemin >= playermax_old - d
&& m_speed.dotProduct(dirs[i]) > 0));
bool other_edges_collide = true;
for(u16 j=0; j<3; j++)
{
if(j == i)
continue;
f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[j]);
f32 nodemin = nodebox.MinEdge.dotProduct(dirs[j]);
f32 playermax = objectbox.MaxEdge.dotProduct(dirs[j]);
f32 playermin = objectbox.MinEdge.dotProduct(dirs[j]);
if(!(nodemax - d > playermin && nodemin + d < playermax))
{
other_edges_collide = false;
break;
}
}
if(main_edge_collides && other_edges_collide)
{
m_speed -= m_speed.dotProduct(dirs[i]) * dirs[i];
position -= position.dotProduct(dirs[i]) * dirs[i];
position += oldpos.dotProduct(dirs[i]) * dirs[i];
}
}
} // if(objectbox.intersectsWithBox(nodebox))
} // for y
} // End of dtime limited loop
while(dtime > 0.001);
m_pos = position;
}
void MovingObject::simpleMove(float dtime)
{
m_pos_animation_time_counter += dtime;
m_pos_animation_counter += dtime;
v3f movevector = m_pos - m_oldpos;
f32 moveratio;
if(m_pos_animation_time < 0.001)
moveratio = 1.0;
else
moveratio = m_pos_animation_counter / m_pos_animation_time;
if(moveratio > 1.5)
moveratio = 1.5;
m_showpos = m_oldpos + movevector * moveratio;
}
#ifndef SERVER
/*
RatObject
*/
void RatObject::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();
}
#endif
/*
ItemObject
*/
#ifndef SERVER
void ItemObject::addToScene(scene::ISceneManager *smgr)
{
if(m_node != NULL)
return;
//video::IVideoDriver* driver = smgr->getVideoDriver();
// Get image of item for showing
video::ITexture *texture = getItemImage();
/*
Create a mesh
*/
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/2,0, 0,0,0, c, 0,1),
video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 1,1),
video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 1,0),
video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 0,0),*/
video::S3DVertex(BS/3,-BS/2,0, 0,0,0, c, 0,1),
video::S3DVertex(-BS/3,-BS/2,0, 0,0,0, c, 1,1),
video::S3DVertex(-BS/3,-BS/2+BS*2/3,0, 0,0,0, c, 1,0),
video::S3DVertex(BS/3,-BS/2+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, texture);
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
}
m_node = smgr->addMeshSceneNode(mesh, NULL);
// Set it to use the materials of the meshbuffers directly.
// This is needed for changing the texture in the future
((scene::IMeshSceneNode*)m_node)->setReadOnlyMaterials(true);
mesh->drop();
updateSceneNode();
}
video::ITexture * ItemObject::getItemImage()
{
/*
Create an inventory item to see what is its image
*/
video::ITexture *texture = NULL;
InventoryItem *item = createInventoryItem();
if(item)
texture = item->getImage();
if(item)
delete item;
return texture;
}
#endif
InventoryItem * ItemObject::createInventoryItem()
{
try{
std::istringstream is(m_itemstring, std::ios_base::binary);
InventoryItem *item = InventoryItem::deSerialize(is);
dstream<<__FUNCTION_NAME<<": m_itemstring=\""
<<m_itemstring<<"\" -> item="<<item
<<std::endl;
return item;
}
catch(SerializationError &e)
{
dstream<<__FUNCTION_NAME<<": serialization error: "
<<"m_itemstring=\""<<m_itemstring<<"\""<<std::endl;
return NULL;
}
}
/*
PlayerObject
*/
#ifndef SERVER
void PlayerObject::addToScene(scene::ISceneManager *smgr)
{
if(m_node != NULL)
return;
video::IVideoDriver* driver = smgr->getVideoDriver();
// Attach a simple mesh to the player for showing an image
scene::SMesh *mesh = new scene::SMesh();
{ // Front
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, driver->getTexture(getTexturePath("player.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;
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
}
{ // Back
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, 1,1),
video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,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("player_back.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_REF;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
}
m_node = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
updateNodePos();
}
#endif
/*
MapBlockObjectList
*/
MapBlockObjectList::MapBlockObjectList(MapBlock *block):
m_block(block)
{
m_mutex.Init();
}
MapBlockObjectList::~MapBlockObjectList()
{
clear();
}
/*
The serialization format:
[0] u16 number of entries
[2] entries (id, typeId, parameters)
*/
void MapBlockObjectList::serialize(std::ostream &os, u8 version)
{
JMutexAutoLock lock(m_mutex);
u8 buf[2];
writeU16(buf, m_objects.size());
os.write((char*)buf, 2);
for(core::map<s16, MapBlockObject*>::Iterator
i = m_objects.getIterator();
i.atEnd() == false; i++)
{
i.getNode()->getValue()->serialize(os, version);
}
}
void MapBlockObjectList::update(std::istream &is, u8 version,
scene::ISceneManager *smgr, u32 daynight_ratio)
{
JMutexAutoLock lock(m_mutex);
/*
Collect all existing ids to a set.
As things are updated, they are removed from this.
All remaining ones are deleted.
*/
core::map<s16, bool> ids_to_delete;
for(core::map<s16, MapBlockObject*>::Iterator
i = m_objects.getIterator();
i.atEnd() == false; i++)
{
ids_to_delete.insert(i.getNode()->getKey(), true);
}
u8 buf[6];
is.read((char*)buf, 2);
u16 count = readU16(buf);
for(u16 i=0; i<count; i++)
{
// Read id
is.read((char*)buf, 2);
s16 id = readS16(buf);
// Read position
// stored as x1000/BS v3s16
is.read((char*)buf, 6);
v3s16 pos_i = readV3S16(buf);
v3f pos((f32)pos_i.X/1000*BS,
(f32)pos_i.Y/1000*BS,
(f32)pos_i.Z/1000*BS);
// Read typeId
is.read((char*)buf, 2);
u16 type_id = readU16(buf);
bool create_new = false;
// Find an object with the id
core::map<s16, MapBlockObject*>::Node *n;
n = m_objects.find(id);
// If no entry is found for id
if(n == NULL)
{
// Insert dummy pointer node
m_objects.insert(id, NULL);
// Get node
n = m_objects.find(id);
// A new object will be created at this node
create_new = true;
}
// If type_id differs
else if(n->getValue()->getTypeId() != type_id)
{
// Delete old object
delete n->getValue();
// A new object will be created at this node
create_new = true;
}
MapBlockObject *obj = NULL;
if(create_new)
{
/*dstream<<"MapBlockObjectList adding new object"
" id="<<id
<<std::endl;*/
if(type_id == MAPBLOCKOBJECT_TYPE_SIGN)
{
obj = new SignObject(m_block, id, pos);
}
else if(type_id == MAPBLOCKOBJECT_TYPE_RAT)
{
obj = new RatObject(m_block, id, pos);
}
else if(type_id == MAPBLOCKOBJECT_TYPE_ITEM)
{
obj = new ItemObject(m_block, id, pos);
}
else
{
// This is fatal because we cannot know the length
// of the object's data
throw SerializationError
("MapBlockObjectList::update(): Unknown MapBlockObject type");
}
if(smgr != NULL)
//obj->addToScene(smgr, daynight_ratio);
obj->addToScene(smgr);
n->setValue(obj);
}
else
{
obj = n->getValue();
obj->updatePos(pos);
/*if(daynight_ratio != m_last_update_daynight_ratio)
{
obj->removeFromScene();
obj->addToScene(smgr, daynight_ratio);
}*/
}
// Now there is an object in obj.
// Update it.
obj->update(is, version);
/*
Update light on client
*/
if(smgr != NULL)
{
u8 light = LIGHT_MAX;
try{
v3s16 relpos_i = floatToInt(obj->m_pos, BS);
MapNode n = m_block->getNodeParent(relpos_i);
light = n.getLightBlend(daynight_ratio);
}
catch(InvalidPositionException &e) {}
obj->updateLight(light);
}
// Remove from deletion list
if(ids_to_delete.find(id) != NULL)
ids_to_delete.remove(id);
}
// Delete all objects whose ids_to_delete remain in ids_to_delete
for(core::map<s16, bool>::Iterator
i = ids_to_delete.getIterator();
i.atEnd() == false; i++)
{
s16 id = i.getNode()->getKey();
/*dstream<<"MapBlockObjectList deleting object"
" id="<<id
<<std::endl;*/
MapBlockObject *obj = m_objects[id];
obj->removeFromScene();
delete obj;
m_objects.remove(id);
}
m_last_update_daynight_ratio = daynight_ratio;
}
s16 MapBlockObjectList::getFreeId() throw(ContainerFullException)
{
s16 id = 0;
for(;;)
{
if(m_objects.find(id) == NULL)
return id;
if(id == 32767)
throw ContainerFullException
("MapBlockObjectList doesn't fit more objects");
id++;
}
}
void MapBlockObjectList::add(MapBlockObject *object)
throw(ContainerFullException, AlreadyExistsException)
{
if(object == NULL)
{
dstream<<"MapBlockObjectList::add(): NULL object"<<std::endl;
return;
}
JMutexAutoLock lock(m_mutex);
// Create unique id if id==-1
if(object->m_id == -1)
{
object->m_id = getFreeId();
}
if(m_objects.find(object->m_id) != NULL)
{
dstream<<"MapBlockObjectList::add(): "
"object with same id already exists"<<std::endl;
throw AlreadyExistsException
("MapBlockObjectList already has given id");
}
object->m_block = m_block;
/*v3f p = object->m_pos;
dstream<<"MapBlockObjectList::add(): "
<<"m_block->getPos()=("
<<m_block->getPos().X<<","
<<m_block->getPos().Y<<","
<<m_block->getPos().Z<<")"
<<" inserting object with id="<<object->m_id
<<" pos="
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
<<std::endl;*/
m_objects.insert(object->m_id, object);
}
void MapBlockObjectList::clear()
{
JMutexAutoLock lock(m_mutex);
for(core::map<s16, MapBlockObject*>::Iterator
i = m_objects.getIterator();
i.atEnd() == false; i++)
{
MapBlockObject *obj = i.getNode()->getValue();
//FIXME: This really shouldn't be NULL at any time,
// but this condition was added because it was.
if(obj != NULL)
{
obj->removeFromScene();
delete obj;
}
}
m_objects.clear();
}
void MapBlockObjectList::remove(s16 id)
{
JMutexAutoLock lock(m_mutex);
core::map<s16, MapBlockObject*>::Node *n;
n = m_objects.find(id);
if(n == NULL)
return;
n->getValue()->removeFromScene();
delete n->getValue();
m_objects.remove(id);
}
MapBlockObject * MapBlockObjectList::get(s16 id)
{
core::map<s16, MapBlockObject*>::Node *n;
n = m_objects.find(id);
if(n == NULL)
return NULL;
else
return n->getValue();
}
void MapBlockObjectList::step(float dtime, bool server, u32 daynight_ratio)
{
DSTACK(__FUNCTION_NAME);
JMutexAutoLock lock(m_mutex);
core::map<s16, bool> ids_to_delete;
{
DSTACKF("%s: stepping objects", __FUNCTION_NAME);
for(core::map<s16, MapBlockObject*>::Iterator
i = m_objects.getIterator();
i.atEnd() == false; i++)
{
MapBlockObject *obj = i.getNode()->getValue();
DSTACKF("%s: stepping object type %i", __FUNCTION_NAME,
obj->getTypeId());
if(server)
{
// Update light
u8 light = LIGHT_MAX;
try{
v3s16 relpos_i = floatToInt(obj->m_pos, BS);
MapNode n = m_block->getNodeParent(relpos_i);
light = n.getLightBlend(daynight_ratio);
}
catch(InvalidPositionException &e) {}
obj->updateLight(light);
bool to_delete = obj->serverStep(dtime, daynight_ratio);
if(to_delete)
ids_to_delete.insert(obj->m_id, true);
}
else
{
obj->clientStep(dtime);
}
}
}
{
DSTACKF("%s: deleting objects", __FUNCTION_NAME);
// Delete objects in delete queue
for(core::map<s16, bool>::Iterator
i = ids_to_delete.getIterator();
i.atEnd() == false; i++)
{
s16 id = i.getNode()->getKey();
MapBlockObject *obj = m_objects[id];
obj->removeFromScene();
delete obj;
m_objects.remove(id);
}
}
/*
Wrap objects on server
*/
if(server == false)
return;
{
DSTACKF("%s: object wrap loop", __FUNCTION_NAME);
for(core::map<s16, MapBlockObject*>::Iterator
i = m_objects.getIterator();
i.atEnd() == false; i++)
{
MapBlockObject *obj = i.getNode()->getValue();
v3s16 pos_i = floatToInt(obj->m_pos, BS);
if(m_block->isValidPosition(pos_i))
{
// No wrap
continue;
}
bool impossible = wrapObject(obj);
if(impossible)
{
// No wrap
continue;
}
// Restart find
i = m_objects.getIterator();
}
}
}
bool MapBlockObjectList::wrapObject(MapBlockObject *object)
{
DSTACK(__FUNCTION_NAME);
// No lock here; this is called so that the lock is already locked.
//JMutexAutoLock lock(m_mutex);
assert(object->m_block == m_block);
assert(m_objects.find(object->m_id) != NULL);
assert(m_objects[object->m_id] == object);
Map *map = m_block->getParent();
// Calculate blockpos on map
v3s16 oldblock_pos_i_on_map = m_block->getPosRelative();
v3f pos_f_on_oldblock = object->m_pos;
v3s16 pos_i_on_oldblock = floatToInt(pos_f_on_oldblock, BS);
v3s16 pos_i_on_map = pos_i_on_oldblock + oldblock_pos_i_on_map;
v3s16 pos_blocks_on_map = getNodeBlockPos(pos_i_on_map);
// Get new block
MapBlock *newblock;
try{
newblock = map->getBlockNoCreate(pos_blocks_on_map);
}
catch(InvalidPositionException &e)
{
// Couldn't find block -> not wrapping
/*dstream<<"WARNING: Wrapping object not possible: "
<<"could not find new block"
<<"("<<pos_blocks_on_map.X
<<","<<pos_blocks_on_map.Y
<<","<<pos_blocks_on_map.Z
<<")"<<std::endl;*/
/*dstream<<"pos_f_on_oldblock=("
<<pos_f_on_oldblock.X<<","
<<pos_f_on_oldblock.Y<<","
<<pos_f_on_oldblock.Z<<")"
<<std::endl;*/
return true;
}
if(newblock == m_block)
{
dstream<<"WARNING: Wrapping object not possible: "
"newblock == oldblock"<<std::endl;
return true;
}
// Calculate position on new block
v3f oldblock_pos_f_on_map = intToFloat(oldblock_pos_i_on_map, BS);
v3s16 newblock_pos_i_on_map = newblock->getPosRelative();
v3f newblock_pos_f_on_map = intToFloat(newblock_pos_i_on_map, BS);
v3f pos_f_on_newblock = pos_f_on_oldblock
- newblock_pos_f_on_map + oldblock_pos_f_on_map;
// Remove object from this block
m_objects.remove(object->m_id);
// Add object to new block
object->m_pos = pos_f_on_newblock;
object->m_id = -1;
object->m_block = NULL;
newblock->addObject(object);
//dstream<<"NOTE: Wrapped object"<<std::endl;
return false;
}
void MapBlockObjectList::getObjects(v3f origin, f32 max_d,
core::array<DistanceSortedObject> &dest)
{
for(core::map<s16, MapBlockObject*>::Iterator
i = m_objects.getIterator();
i.atEnd() == false; i++)
{
MapBlockObject *obj = i.getNode()->getValue();
f32 d = (obj->getRelativeShowPos() - origin).getLength();
if(d > max_d)
continue;
DistanceSortedObject dso(obj, d);
dest.push_back(dso);
}
}
//END

File diff suppressed because it is too large Load Diff

View File

@@ -80,7 +80,7 @@ static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d)
}
#endif
static void make_tree(VoxelManipulator &vmanip, v3s16 p0, bool is_apple_tree)
void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0, bool is_apple_tree)
{
MapNode treenode(CONTENT_TREE);
MapNode leavesnode(CONTENT_LEAVES);
@@ -1405,6 +1405,7 @@ bool get_have_sand(u64 seed, v2s16 p2d)
*/
void add_random_objects(MapBlock *block)
{
#if 0
for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
{
@@ -1465,6 +1466,7 @@ void add_random_objects(MapBlock *block)
}
}
block->setChangedFlag();
#endif
}
void make_block(BlockMakeData *data)

View File

@@ -40,6 +40,9 @@ namespace mapgen
// Add objects according to block content
void add_random_objects(MapBlock *block);
// Add a tree
void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0, bool is_apple_tree);
/*
These are used by FarMesh

View File

@@ -19,7 +19,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h"
#include "mapnode.h"
#ifndef SERVER
#include "tile.h"
#endif
#include "porting.h"
#include <string>
#include "mineral.h"
@@ -31,12 +33,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
ContentFeatures::~ContentFeatures()
{
delete initial_metadata;
#ifndef SERVER
delete special_material;
delete special_atlas;
#endif
}
#ifndef SERVER
void ContentFeatures::setTexture(u16 i, std::string name, u8 alpha)
{
used_texturenames[name] = true;
if(g_texturesource)
{
tiles[i].texture = g_texturesource->getTexture(name);
@@ -81,6 +88,7 @@ void ContentFeatures::setInventoryTextureCube(std::string top,
imgname_full += right;
inventory_texture = g_texturesource->getTextureRaw(imgname_full);
}
#endif
struct ContentFeatures g_content_features[MAX_CONTENT+1];
@@ -118,7 +126,8 @@ void init_mapnode()
/*
Initialize content feature table
*/
#ifndef SERVER
/*
Set initial material type to same in all tiles, so that the
same material can be used in more stuff.
@@ -140,6 +149,7 @@ void init_mapnode()
for(u16 j=0; j<6; j++)
f->tiles[j].material_type = initial_material_type;
}
#endif
/*
Initially set every block to be shown as an unknown block.
@@ -154,6 +164,9 @@ void init_mapnode()
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
}
// Make CONTENT_IGNORE to not block the view when occlusion culling
content_features(CONTENT_IGNORE).solidness = 0;
/*
Initialize mapnode content
*/
@@ -161,6 +174,57 @@ void init_mapnode()
}
/*
Nodes make a face if contents differ and solidness differs.
Return value:
0: No face
1: Face uses m1's content
2: Face uses m2's content
equivalent: Whether the blocks share the same face (eg. water and glass)
*/
u8 face_contents(content_t m1, content_t m2, bool *equivalent)
{
*equivalent = false;
if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
return 0;
bool contents_differ = (m1 != m2);
// Contents don't differ for different forms of same liquid
if(content_liquid(m1) && content_liquid(m2)
&& make_liquid_flowing(m1) == make_liquid_flowing(m2))
contents_differ = false;
u8 c1 = content_solidness(m1);
u8 c2 = content_solidness(m2);
bool solidness_differs = (c1 != c2);
bool makes_face = contents_differ && solidness_differs;
if(makes_face == false)
return 0;
if(c1 == 0)
c1 = content_features(m1).visual_solidness;
if(c2 == 0)
c2 = content_features(m2).visual_solidness;
if(c1 == c2){
*equivalent = true;
// If same solidness, liquid takes precense
if(content_features(m1).liquid_type != LIQUID_NONE)
return 1;
if(content_features(m2).liquid_type != LIQUID_NONE)
return 2;
}
if(c1 > c2)
return 1;
else
return 2;
}
v3s16 facedir_rotate(u8 facedir, v3s16 dir)
{
/*
@@ -184,6 +248,7 @@ v3s16 facedir_rotate(u8 facedir, v3s16 dir)
return newdir;
}
#ifndef SERVER
TileSpec MapNode::getTile(v3s16 dir)
{
if(content_features(*this).param_type == CPT_FACEDIR_SIMPLE)
@@ -235,6 +300,7 @@ TileSpec MapNode::getTile(v3s16 dir)
return spec;
}
#endif
u8 MapNode::getMineral()
{

View File

@@ -23,11 +23,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <iostream>
#include "common_irrlicht.h"
#include "light.h"
#include "utility.h"
#include "exceptions.h"
#include "serialization.h"
#include "tile.h"
#include "materials.h"
#ifndef SERVER
#include "tile.h"
#endif
/*
Naming scheme:
@@ -101,9 +102,7 @@ class NodeMetadata;
struct ContentFeatures
{
// Type of MapNode::param1
ContentParamType param_type;
#ifndef SERVER
/*
0: up
1: down
@@ -115,7 +114,23 @@ struct ContentFeatures
TileSpec tiles[6];
video::ITexture *inventory_texture;
// Used currently for flowing liquids
u8 vertex_alpha;
// Post effect color, drawn when the camera is inside the node.
video::SColor post_effect_color;
// Special irrlicht material, used sometimes
video::SMaterial *special_material;
video::SMaterial *special_material2;
AtlasPointer *special_atlas;
#endif
// List of all block textures that have been used (value is dummy)
// Exists on server too for cleaner code in content_mapnode.cpp
core::map<std::string, bool> used_texturenames;
// Type of MapNode::param1
ContentParamType param_type;
// True for all ground-like things like stone and mud, false for eg. trees
bool is_ground_content;
bool light_propagates;
@@ -141,11 +156,19 @@ struct ContentFeatures
// If true, node is equivalent to air. Torches are, air is. Water is not.
// Is used for example to check whether a mud block can have grass on.
bool air_equivalent;
// Whether this content type often contains mineral.
// Used for texture atlas creation.
// Currently only enabled for CONTENT_STONE.
bool often_contains_mineral;
// Inventory item string as which the node appears in inventory when dug.
// Mineral overrides this.
std::string dug_item;
// Extra dug item and its rarity
std::string extra_dug_item;
s32 extra_dug_item_rarity;
// Initial metadata is cloned from this
NodeMetadata *initial_metadata;
@@ -158,11 +181,6 @@ struct ContentFeatures
// 1 giving almost instantaneous propagation and 7 being
// the slowest possible
u8 liquid_viscosity;
// Used currently for flowing liquids
u8 vertex_alpha;
// Special irrlicht material, used sometimes
video::SMaterial *special_material;
AtlasPointer *special_atlas;
// Amount of light the node emits
u8 light_source;
@@ -176,8 +194,16 @@ struct ContentFeatures
void reset()
{
param_type = CPT_NONE;
#ifndef SERVER
inventory_texture = NULL;
vertex_alpha = 255;
post_effect_color = video::SColor(0, 0, 0, 0);
special_material = NULL;
special_material2 = NULL;
special_atlas = NULL;
#endif
param_type = CPT_NONE;
is_ground_content = false;
light_propagates = false;
sunlight_propagates = false;
@@ -191,14 +217,12 @@ struct ContentFeatures
liquid_type = LIQUID_NONE;
wall_mounted = false;
air_equivalent = false;
often_contains_mineral = false;
dug_item = "";
initial_metadata = NULL;
liquid_alternative_flowing = CONTENT_IGNORE;
liquid_alternative_source = CONTENT_IGNORE;
liquid_viscosity = 0;
vertex_alpha = 255;
special_material = NULL;
special_atlas = NULL;
light_source = 0;
digging_properties.clear();
damage_per_second = 0;
@@ -215,6 +239,12 @@ struct ContentFeatures
Quickhands for simple materials
*/
#ifdef SERVER
void setTexture(u16 i, std::string name, u8 alpha=255)
{}
void setAllTextures(std::string name, u8 alpha=255)
{}
#else
void setTexture(u16 i, std::string name, u8 alpha=255);
void setAllTextures(std::string name, u8 alpha=255)
@@ -226,7 +256,9 @@ struct ContentFeatures
// Force inventory texture too
setInventoryTexture(name);
}
#endif
#ifndef SERVER
void setTile(u16 i, const TileSpec &tile)
{
tiles[i] = tile;
@@ -238,11 +270,20 @@ struct ContentFeatures
setTile(i, tile);
}
}
#endif
#ifdef SERVER
void setInventoryTexture(std::string imgname)
{}
void setInventoryTextureCube(std::string top,
std::string left, std::string right)
{}
#else
void setInventoryTexture(std::string imgname);
void setInventoryTextureCube(std::string top,
std::string left, std::string right);
#endif
};
/*
@@ -338,30 +379,9 @@ inline bool content_buildable_to(content_t m)
0: No face
1: Face uses m1's content
2: Face uses m2's content
equivalent: Whether the blocks share the same face (eg. water and glass)
*/
inline u8 face_contents(content_t m1, content_t m2)
{
if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
return 0;
bool contents_differ = (m1 != m2);
// Contents don't differ for different forms of same liquid
if(content_liquid(m1) && content_liquid(m2)
&& make_liquid_flowing(m1) == make_liquid_flowing(m2))
contents_differ = false;
bool solidness_differs = (content_solidness(m1) != content_solidness(m2));
bool makes_face = contents_differ && solidness_differs;
if(makes_face == false)
return 0;
if(content_solidness(m1) > content_solidness(m2))
return 1;
else
return 2;
}
u8 face_contents(content_t m1, content_t m2, bool *equivalent);
/*
Packs directions like (1,0,0), (1,-1,0)
@@ -625,6 +645,7 @@ struct MapNode
}
// In mapnode.cpp
#ifndef SERVER
/*
Get tile of a face of the node.
dir: direction of face
@@ -632,6 +653,7 @@ struct MapNode
which must be obeyed so that the texture atlas can be used.
*/
TileSpec getTile(v3s16 dir);
#endif
/*
Gets mineral content of node, if there is any.

View File

@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "inventory.h"
#include <sstream>
#include "content_mapnode.h"
#include "log.h"
/*
NodeMetadata
@@ -55,7 +56,7 @@ NodeMetadata* NodeMetadata::deSerialize(std::istream &is)
if(n == NULL)
{
// If factory is not found, just return.
dstream<<"WARNING: NodeMetadata: No factory for typeId="
infostream<<"WARNING: NodeMetadata: No factory for typeId="
<<id<<std::endl;
return NULL;
}
@@ -71,7 +72,7 @@ NodeMetadata* NodeMetadata::deSerialize(std::istream &is)
}
catch(SerializationError &e)
{
dstream<<"WARNING: NodeMetadata: ignoring SerializationError"<<std::endl;
infostream<<"WARNING: NodeMetadata: ignoring SerializationError"<<std::endl;
return NULL;
}
}
@@ -138,7 +139,7 @@ void NodeMetadataList::deSerialize(std::istream &is)
if(version > 1)
{
dstream<<__FUNCTION_NAME<<": version "<<version<<" not supported"
infostream<<__FUNCTION_NAME<<": version "<<version<<" not supported"
<<std::endl;
throw SerializationError("NodeMetadataList::deSerialize");
}
@@ -165,7 +166,7 @@ void NodeMetadataList::deSerialize(std::istream &is)
if(m_data.find(p))
{
dstream<<"WARNING: NodeMetadataList::deSerialize(): "
infostream<<"WARNING: NodeMetadataList::deSerialize(): "
<<"already set data at position"
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<"): Ignoring."
<<std::endl;

View File

@@ -65,6 +65,9 @@ class NodeMetadata
// Used to make custom inventory menus.
// See format in guiInventoryMenu.cpp.
virtual std::string getInventoryDrawSpecString(){return "";}
// primarily used for locking chests, but others can play too
virtual std::string getOwner(){ return std::string(""); }
virtual void setOwner(std::string t){ }
protected:
static void registerType(u16 id, Factory f);

View File

@@ -22,12 +22,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "connection.h"
#include "constants.h"
#include "utility.h"
#ifndef SERVER
#include <ITextSceneNode.h>
#endif
#include "settings.h"
Player::Player():
touching_ground(false),
in_water(false),
in_water_stable(false),
is_climbing(false),
swimming_up(false),
inventory_backup(NULL),
craftresult_is_preview(true),
@@ -330,21 +334,10 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
/*
Calculate new position
*/
if(is_frozen) {
// Still move very slowly so as not to feel all completely stuck
position += m_speed * dtime * 0.001;
}
else {
position += m_speed * dtime;
}
position += m_speed * dtime;
/*
If the player enters an unloaded chunk this is set to true.
*/
is_frozen = false;
// Skip collision detection if a special movement mode is used
bool free_move = g_settings.getBool("free_move");
bool free_move = g_settings->getBool("free_move");
if(free_move)
{
setPosition(position);
@@ -500,6 +493,8 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z
<<"):"<<std::endl;*/
bool standing_on_unloaded = false;
/*
Go through every node around the player
*/
@@ -507,6 +502,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++)
for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++)
{
bool is_unloaded = false;
try{
// Player collides into walkable nodes
if(content_walkable(map.getNode(v3s16(x,y,z)).getContent()) == false)
@@ -514,11 +510,9 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
}
catch(InvalidPositionException &e)
{
if(!is_frozen) {
// freeze when entering unloaded areas
is_frozen = true;
}
continue;
is_unloaded = true;
// Doing nothing here will block the player from
// walking over map borders
}
core::aabbox3d<f32> nodebox = getNodeBox(v3s16(x,y,z), BS);
@@ -541,6 +535,8 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
&& nodebox.MinEdge.Z+d < playerbox.MaxEdge.Z
){
touching_ground = true;
if(is_unloaded)
standing_on_unloaded = true;
}
// If player doesn't intersect with node, ignore node.
@@ -722,7 +718,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
if(collision_info)
{
// Report fall collision
if(old_speed.Y < m_speed.Y - 0.1)
if(old_speed.Y < m_speed.Y - 0.1 && !standing_on_unloaded)
{
CollisionInfo info;
info.t = COLLISION_FALL;
@@ -754,9 +750,9 @@ void LocalPlayer::applyControl(float dtime)
v3f speed = v3f(0,0,0);
bool free_move = g_settings.getBool("free_move");
bool fast_move = g_settings.getBool("fast_move");
bool continuous_forward = g_settings.getBool("continuous_forward");
bool free_move = g_settings->getBool("free_move");
bool fast_move = g_settings->getBool("fast_move");
bool continuous_forward = g_settings->getBool("continuous_forward");
if(free_move || is_climbing)
{

View File

@@ -67,12 +67,17 @@ class Player
return floatToInt(m_position + v3f(0,BS+BS/2,0), BS);
}
v3f getEyePosition()
v3f getEyeOffset()
{
// This is at the height of the eyes of the current figure
// return m_position + v3f(0, BS+BS/2, 0);
// return v3f(0, BS+BS/2, 0);
// This is more like in minecraft
return m_position + v3f(0,BS+(5*BS)/8,0);
return v3f(0,BS+(5*BS)/8,0);
}
v3f getEyePosition()
{
return m_position + getEyeOffset();
}
virtual void setPosition(const v3f &position)
@@ -121,7 +126,10 @@ class Player
virtual bool isLocal() const = 0;
virtual void updateLight(u8 light_at_pos) {};
virtual void updateLight(u8 light_at_pos)
{
light = light_at_pos;
}
// NOTE: Use peer_id == 0 for disconnected
/*virtual bool isClientConnected() { return false; }
@@ -142,8 +150,9 @@ class Player
bool in_water_stable;
bool is_climbing;
bool swimming_up;
bool is_frozen;
u8 light;
Inventory inventory;
// Actual inventory is backed up here when creative mode is used
Inventory *inventory_backup;
@@ -261,25 +270,14 @@ class RemotePlayer : public Player, public scene::ISceneNode
virtual void updateLight(u8 light_at_pos)
{
Player::updateLight(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();
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;
}
}
setMeshVerticesColor(m_node->getMesh(), color);
}
void move(f32 dtime, Map &map, f32 pos_max_d);
@@ -356,7 +354,7 @@ class LocalPlayer : public Player
{
return true;
}
void move(f32 dtime, Map &map, f32 pos_max_d,
core::list<CollisionInfo> *collision_info);
void move(f32 dtime, Map &map, f32 pos_max_d);

View File

@@ -75,10 +75,45 @@ void signal_handler_init(void)
}
#else // _WIN32
#include <signal.h>
#include <windows.h>
BOOL WINAPI event_handler(DWORD sig)
{
switch(sig)
{
case CTRL_C_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
if(g_killed == false)
{
dstream<<DTIME<<"INFO: event_handler(): "
<<"Ctrl+C, Close Event, Logoff Event or Shutdown Event, shutting down."<<std::endl;
dstream<<DTIME<<"INFO: event_handler(): "
<<"Printing debug stacks"<<std::endl;
debug_stacks_print();
g_killed = true;
}
else
{
(void)signal(SIGINT, SIG_DFL);
}
break;
case CTRL_BREAK_EVENT:
break;
}
return TRUE;
}
void signal_handler_init(void)
{
// No-op
dstream<<"signal_handler_init()"<<std::endl;
SetConsoleCtrlHandler( (PHANDLER_ROUTINE)event_handler,TRUE);
}
#endif
@@ -87,8 +122,8 @@ void signal_handler_init(void)
Path mangler
*/
std::string path_data = "../data";
std::string path_userdata = "../";
std::string path_data = ".." DIR_DELIM "data";
std::string path_userdata = "..";
void pathRemoveFile(char *path, char delim)
{
@@ -127,10 +162,10 @@ void initializePaths()
pathRemoveFile(buf, '\\');
// Use "./bin/../data"
path_data = std::string(buf) + "/../data";
path_data = std::string(buf) + DIR_DELIM ".." DIR_DELIM "data";
// Use "./bin/../"
path_userdata = std::string(buf) + "/../";
// Use "./bin/.."
path_userdata = std::string(buf) + DIR_DELIM "..";
/*
Linux
@@ -149,7 +184,7 @@ void initializePaths()
path_data = std::string(buf) + "/../data";
// Use "./bin/../"
path_userdata = std::string(buf) + "/../";
path_userdata = std::string(buf) + "/..";
/*
OS X
@@ -160,7 +195,7 @@ void initializePaths()
dstream<<"WARNING: Relative path not properly supported on OS X and FreeBSD"
<<std::endl;
path_data = std::string("../data");
path_userdata = std::string("../");
path_userdata = std::string("..");
#endif
@@ -188,13 +223,13 @@ void initializePaths()
pathRemoveFile(buf, '\\');
// Use "./bin/../data"
path_data = std::string(buf) + "/../data";
path_data = std::string(buf) + DIR_DELIM ".." DIR_DELIM "data";
//path_data = std::string(buf) + "/../share/" + PROJECT_NAME;
// Use "C:\Documents and Settings\user\Application Data\<PROJECT_NAME>"
len = GetEnvironmentVariable("APPDATA", buf, buflen);
assert(len < buflen);
path_userdata = std::string(buf) + "/" + PROJECT_NAME;
path_userdata = std::string(buf) + DIR_DELIM + PROJECT_NAME;
/*
Linux

View File

@@ -38,42 +38,83 @@ class Profiler
m_mutex.Init();
}
void add(const std::string &name, u32 duration)
void add(const std::string &name, float value)
{
JMutexAutoLock lock(m_mutex);
core::map<std::string, u32>::Node *n = m_data.find(name);
if(n == NULL)
{
m_data[name] = duration;
/* No average shall have been used; mark add used as -2 */
core::map<std::string, int>::Node *n = m_avgcounts.find(name);
if(n == NULL)
m_avgcounts[name] = -2;
else{
if(n->getValue() == -1)
n->setValue(-2);
assert(n->getValue() == -2);
}
}
else
{
n->setValue(n->getValue()+duration);
core::map<std::string, float>::Node *n = m_data.find(name);
if(n == NULL)
m_data[name] = value;
else
n->setValue(n->getValue() + value);
}
}
void avg(const std::string &name, float value)
{
JMutexAutoLock lock(m_mutex);
{
core::map<std::string, int>::Node *n = m_avgcounts.find(name);
if(n == NULL)
m_avgcounts[name] = 1;
else{
/* No add shall have been used */
assert(n->getValue() != -2);
if(n->getValue() <= 0)
n->setValue(1);
else
n->setValue(n->getValue() + 1);
}
}
{
core::map<std::string, float>::Node *n = m_data.find(name);
if(n == NULL)
m_data[name] = value;
else
n->setValue(n->getValue() + value);
}
}
void clear()
{
JMutexAutoLock lock(m_mutex);
for(core::map<std::string, u32>::Iterator
for(core::map<std::string, float>::Iterator
i = m_data.getIterator();
i.atEnd() == false; i++)
{
i.getNode()->setValue(0);
}
m_avgcounts.clear();
}
void print(std::ostream &o)
{
JMutexAutoLock lock(m_mutex);
for(core::map<std::string, u32>::Iterator
for(core::map<std::string, float>::Iterator
i = m_data.getIterator();
i.atEnd() == false; i++)
{
std::string name = i.getNode()->getKey();
o<<name<<": ";
int avgcount = 1;
core::map<std::string, int>::Node *n = m_avgcounts.find(name);
if(n){
if(n->getValue() >= 1)
avgcount = n->getValue();
}
o<<" "<<name<<": ";
s32 clampsize = 40;
s32 space = clampsize-name.size();
s32 space = clampsize - name.size();
for(s32 j=0; j<space; j++)
{
if(j%2 == 0 && j < space - 1)
@@ -81,32 +122,42 @@ class Profiler
else
o<<" ";
}
o<<i.getNode()->getValue();
o<<(i.getNode()->getValue() / avgcount);
o<<std::endl;
}
}
private:
JMutex m_mutex;
core::map<std::string, u32> m_data;
core::map<std::string, float> m_data;
core::map<std::string, int> m_avgcounts;
};
enum ScopeProfilerType{
SPT_ADD,
SPT_AVG
};
class ScopeProfiler
{
public:
ScopeProfiler(Profiler *profiler, const std::string &name):
ScopeProfiler(Profiler *profiler, const std::string &name,
enum ScopeProfilerType type = SPT_ADD):
m_profiler(profiler),
m_name(name),
m_timer(NULL)
m_timer(NULL),
m_type(type)
{
if(m_profiler)
m_timer = new TimeTaker(m_name.c_str());
}
// name is copied
ScopeProfiler(Profiler *profiler, const char *name):
ScopeProfiler(Profiler *profiler, const char *name,
enum ScopeProfilerType type = SPT_ADD):
m_profiler(profiler),
m_name(name),
m_timer(NULL)
m_timer(NULL),
m_type(type)
{
if(m_profiler)
m_timer = new TimeTaker(m_name.c_str());
@@ -115,9 +166,18 @@ class ScopeProfiler
{
if(m_timer)
{
u32 duration = m_timer->stop(true);
if(m_profiler)
m_profiler->add(m_name, duration);
float duration_ms = m_timer->stop(true);
float duration = duration_ms / 1000.0;
if(m_profiler){
switch(m_type){
case SPT_ADD:
m_profiler->add(m_name, duration);
break;
case SPT_AVG:
m_profiler->avg(m_name, duration);
break;
}
}
delete m_timer;
}
}
@@ -125,6 +185,7 @@ class ScopeProfiler
Profiler *m_profiler;
std::string m_name;
TimeTaker *m_timer;
enum ScopeProfilerType m_type;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "environment.h"
#include "common_irrlicht.h"
#include <string>
#include "utility.h"
#include "porting.h"
#include "map.h"
#include "inventory.h"
@@ -450,11 +449,7 @@ class Server : public con::PeerHandler, public MapEventReceiver,
}
// Saves g_settings to configpath given at initialization
void saveConfig()
{
if(m_configpath != "")
g_settings.updateConfigFile(m_configpath.c_str());
}
void saveConfig();
void setIpBanned(const std::string &ip, const std::string &name)
{
@@ -473,10 +468,14 @@ class Server : public con::PeerHandler, public MapEventReceiver,
return m_banmanager.getBanDescription(ip_or_name);
}
con::Peer* getPeerNoEx(u16 peer_id)
Address getPeerAddress(u16 peer_id)
{
return m_con.GetPeerNoEx(peer_id);
return m_con.GetPeerAddress(peer_id);
}
// Envlock and conlock should be locked when calling this
void notifyPlayer(const char *name, const std::wstring msg);
void notifyPlayers(const std::wstring msg);
private:
@@ -493,6 +492,8 @@ class Server : public con::PeerHandler, public MapEventReceiver,
static void SendHP(con::Connection &con, u16 peer_id, u8 hp);
static void SendAccessDenied(con::Connection &con, u16 peer_id,
const std::wstring &reason);
static void SendDeathscreen(con::Connection &con, u16 peer_id,
bool set_camera_point_target, v3f camera_point_target);
/*
Non-static send methods
@@ -531,6 +532,9 @@ class Server : public con::PeerHandler, public MapEventReceiver,
Something random
*/
void HandlePlayerHP(Player *player, s16 damage);
void RespawnPlayer(Player *player);
void UpdateCrafting(u16 peer_id);
// When called, connection mutex should be locked

View File

@@ -18,6 +18,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "servercommand.h"
#include "utility.h"
#include "settings.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
void cmd_status(std::wostringstream &os,
ServerCommandContext *ctx)
@@ -93,10 +96,31 @@ void cmd_grantrevoke(std::wostringstream &os,
std::string playername = wide_to_narrow(ctx->parms[1]);
u64 privs = ctx->server->getPlayerAuthPrivs(playername);
if(ctx->parms[0] == L"grant")
if(ctx->parms[0] == L"grant"){
privs |= newprivs;
else
actionstream<<ctx->player->getName()<<" grants "
<<wide_to_narrow(ctx->parms[2])<<" to "
<<playername<<std::endl;
std::wstring msg;
msg += narrow_to_wide(ctx->player->getName());
msg += L" granted you the privilege \"";
msg += ctx->parms[2];
msg += L"\"";
ctx->server->notifyPlayer(playername.c_str(), msg);
} else {
privs &= ~newprivs;
actionstream<<ctx->player->getName()<<" revokes "
<<wide_to_narrow(ctx->parms[2])<<" from "
<<playername<<std::endl;
std::wstring msg;
msg += narrow_to_wide(ctx->player->getName());
msg += L" revoked from you the privilege \"";
msg += ctx->parms[2];
msg += L"\"";
ctx->server->notifyPlayer(playername.c_str(), msg);
}
ctx->server->setPlayerAuthPrivs(playername, privs);
@@ -122,6 +146,9 @@ void cmd_time(std::wostringstream &os,
u32 time = stoi(wide_to_narrow(ctx->parms[1]));
ctx->server->setTimeOfDay(time);
os<<L"-!- time_of_day changed.";
actionstream<<ctx->player->getName()<<" sets time "
<<time<<std::endl;
}
void cmd_shutdown(std::wostringstream &os,
@@ -133,8 +160,9 @@ void cmd_shutdown(std::wostringstream &os,
return;
}
dstream<<DTIME<<" Server: Operator requested shutdown."
<<std::endl;
actionstream<<ctx->player->getName()
<<" shuts down server"<<std::endl;
ctx->server->requestShutdown();
os<<L"*** Server shutting down (operator request)";
@@ -155,7 +183,10 @@ void cmd_setting(std::wostringstream &os,
std::string confline = wide_to_narrow(ctx->paramstring);
g_settings.parseConfigLine(confline);
actionstream<<ctx->player->getName()
<<" sets: "<<confline<<std::endl;
g_settings->parseConfigLine(confline);
ctx->server->saveConfig();
@@ -185,6 +216,11 @@ void cmd_teleport(std::wostringstream &os,
}
v3f dest(stoi(coords[0])*10, stoi(coords[1])*10, stoi(coords[2])*10);
actionstream<<ctx->player->getName()<<" teleports from "
<<PP(ctx->player->getPosition()/BS)<<" to "
<<PP(dest/BS)<<std::endl;
ctx->player->setPosition(dest);
ctx->server->SendMovePlayer(ctx->player);
@@ -214,17 +250,19 @@ void cmd_banunban(std::wostringstream &os, ServerCommandContext *ctx)
os<<L"-!- No such player";
return;
}
try{
Address address = ctx->server->getPeerAddress(player->peer_id);
std::string ip_string = address.serializeString();
ctx->server->setIpBanned(ip_string, player->getName());
os<<L"-!- Banned "<<narrow_to_wide(ip_string)<<L"|"
<<narrow_to_wide(player->getName());
con::Peer *peer = ctx->server->getPeerNoEx(player->peer_id);
if(peer == NULL)
{
actionstream<<ctx->player->getName()<<" bans "
<<player->getName()<<" / "<<ip_string<<std::endl;
} catch(con::PeerNotFoundException){
dstream<<__FUNCTION_NAME<<": peer was not found"<<std::endl;
return;
}
std::string ip_string = peer->address.serializeString();
ctx->server->setIpBanned(ip_string, player->getName());
os<<L"-!- Banned "<<narrow_to_wide(ip_string)<<L"|"
<<narrow_to_wide(player->getName());
}
else
{
@@ -232,9 +270,41 @@ void cmd_banunban(std::wostringstream &os, ServerCommandContext *ctx)
std::string desc = ctx->server->getBanDescription(ip_or_name);
ctx->server->unsetIpBanned(ip_or_name);
os<<L"-!- Unbanned "<<narrow_to_wide(desc);
actionstream<<ctx->player->getName()<<" unbans "
<<ip_or_name<<std::endl;
}
}
void cmd_clearobjects(std::wostringstream &os,
ServerCommandContext *ctx)
{
if((ctx->privs & PRIV_SERVER) ==0)
{
os<<L"-!- You don't have permission to do that";
return;
}
actionstream<<ctx->player->getName()
<<" clears all objects"<<std::endl;
{
std::wstring msg;
msg += L"Clearing all objects. This may take long.";
msg += L" You may experience a timeout. (by ";
msg += narrow_to_wide(ctx->player->getName());
msg += L")";
ctx->server->notifyPlayers(msg);
}
ctx->env->clearAllObjects();
actionstream<<"object clearing done"<<std::endl;
os<<L"*** cleared all objects";
ctx->flags |= SEND_TO_OTHERS;
}
std::wstring processServerCommand(ServerCommandContext *ctx)
{
@@ -260,45 +330,28 @@ std::wstring processServerCommand(ServerCommandContext *ctx)
os<<L" ban unban";
}
else if(ctx->parms[0] == L"status")
{
cmd_status(os, ctx);
}
else if(ctx->parms[0] == L"privs")
{
cmd_privs(os, ctx);
}
else if(ctx->parms[0] == L"grant" || ctx->parms[0] == L"revoke")
{
cmd_grantrevoke(os, ctx);
}
else if(ctx->parms[0] == L"time")
{
cmd_time(os, ctx);
}
else if(ctx->parms[0] == L"shutdown")
{
cmd_shutdown(os, ctx);
}
else if(ctx->parms[0] == L"setting")
{
cmd_setting(os, ctx);
}
else if(ctx->parms[0] == L"teleport")
{
cmd_teleport(os, ctx);
}
else if(ctx->parms[0] == L"ban" || ctx->parms[0] == L"unban")
{
cmd_banunban(os, ctx);
}
else if(ctx->parms[0] == L"me")
{
cmd_me(os, ctx);
}
else if(ctx->parms[0] == L"clearobjects")
cmd_clearobjects(os, ctx);
else
{
os<<L"-!- Invalid command: " + ctx->parms[0];
}
return os.str();
}

View File

@@ -70,18 +70,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "config.h"
#include "mineral.h"
#include "filesys.h"
#include "defaultsettings.h"
#include "settings.h"
#include "profiler.h"
#include "log.h"
/*
Settings.
These are loaded from the config file.
*/
Settings g_settings;
extern void set_default_settings();
Settings main_settings;
Settings *g_settings = &main_settings;
// Global profiler
Profiler g_profiler;
Profiler main_profiler;
Profiler *g_profiler = &main_profiler;
// A dummy thing
ITextureSource *g_texturesource = NULL;
@@ -92,15 +95,15 @@ ITextureSource *g_texturesource = NULL;
// Connection
std::ostream *dout_con_ptr = &dummyout;
std::ostream *derr_con_ptr = &dstream_no_stderr;
std::ostream *derr_con_ptr = &verbosestream;
// Server
std::ostream *dout_server_ptr = &dstream;
std::ostream *derr_server_ptr = &dstream;
std::ostream *dout_server_ptr = &infostream;
std::ostream *derr_server_ptr = &errorstream;
// Client
std::ostream *dout_client_ptr = &dstream;
std::ostream *derr_client_ptr = &dstream;
std::ostream *dout_client_ptr = &infostream;
std::ostream *derr_client_ptr = &errorstream;
/*
gettime.h implementation
@@ -114,12 +117,37 @@ u32 getTimeMs()
return porting::getTimeMs();
}
class StderrLogOutput: public ILogOutput
{
public:
/* line: Full line with timestamp, level and thread */
void printLog(const std::string &line)
{
std::cerr<<line<<std::endl;
}
} main_stderr_log_out;
class DstreamNoStderrLogOutput: public ILogOutput
{
public:
/* line: Full line with timestamp, level and thread */
void printLog(const std::string &line)
{
dstream_no_stderr<<line<<std::endl;
}
} main_dstream_no_stderr_log_out;
int main(int argc, char *argv[])
{
/*
Initialization
*/
log_add_output_maxlev(&main_stderr_log_out, LMT_ACTION);
log_add_output_all_levs(&main_dstream_no_stderr_log_out);
log_register_thread("main");
// Set locale. This is for forcing '.' as the decimal point.
std::locale::global(std::locale("C"));
// This enables printing all characters in bitmap font
@@ -147,7 +175,7 @@ int main(int argc, char *argv[])
#ifdef RUN_IN_PLACE
std::string debugfile = DEBUGFILE;
#else
std::string debugfile = porting::path_userdata+"/"+DEBUGFILE;
std::string debugfile = porting::path_userdata+DIR_DELIM+DEBUGFILE;
#endif
debugstreams_init(disable_stderr, debugfile.c_str());
// Initialize debug stacks
@@ -162,7 +190,7 @@ int main(int argc, char *argv[])
BEGIN_DEBUG_EXCEPTION_HANDLER
// Print startup message
dstream<<DTIME<<PROJECT_NAME <<
actionstream<<PROJECT_NAME<<
" with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST
<<", "<<BUILD_INFO
<<std::endl;
@@ -183,6 +211,7 @@ int main(int argc, char *argv[])
allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG));
allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG));
allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING));
allowed_options.insert("info-on-stderr", ValueSpec(VALUETYPE_FLAG));
Settings cmd_args;
@@ -215,13 +244,15 @@ int main(int argc, char *argv[])
return cmd_args.getFlag("help") ? 0 : 1;
}
if(cmd_args.getFlag("info-on-stderr"))
log_add_output(&main_stderr_log_out, LMT_INFO);
/*
Basic initialization
*/
// Initialize default settings
set_default_settings();
set_default_settings(g_settings);
// Initialize sockets
sockets_init();
@@ -236,10 +267,10 @@ int main(int argc, char *argv[])
if(cmd_args.exists("config"))
{
bool r = g_settings.readConfigFile(cmd_args.get("config").c_str());
bool r = g_settings->readConfigFile(cmd_args.get("config").c_str());
if(r == false)
{
dstream<<"Could not read configuration from \""
errorstream<<"Could not read configuration from \""
<<cmd_args.get("config")<<"\""<<std::endl;
return 1;
}
@@ -248,14 +279,16 @@ int main(int argc, char *argv[])
else
{
core::array<std::string> filenames;
filenames.push_back(porting::path_userdata + "/minetest.conf");
filenames.push_back(porting::path_userdata +
DIR_DELIM + "minetest.conf");
#ifdef RUN_IN_PLACE
filenames.push_back(porting::path_userdata + "/../minetest.conf");
filenames.push_back(porting::path_userdata +
DIR_DELIM + ".." + DIR_DELIM + "minetest.conf");
#endif
for(u32 i=0; i<filenames.size(); i++)
{
bool r = g_settings.readConfigFile(filenames[i].c_str());
bool r = g_settings->readConfigFile(filenames[i].c_str());
if(r)
{
configpath = filenames[i];
@@ -305,9 +338,9 @@ int main(int argc, char *argv[])
{
port = cmd_args.getU16("port");
}
else if(g_settings.exists("port") && g_settings.getU16("port") != 0)
else if(g_settings->exists("port") && g_settings->getU16("port") != 0)
{
port = g_settings.getU16("port");
port = g_settings->getU16("port");
}
else
{
@@ -316,11 +349,11 @@ int main(int argc, char *argv[])
}
// Figure out path to map
std::string map_dir = porting::path_userdata+"/world";
std::string map_dir = porting::path_userdata+DIR_DELIM+"world";
if(cmd_args.exists("map-dir"))
map_dir = cmd_args.get("map-dir");
else if(g_settings.exists("map-dir"))
map_dir = g_settings.get("map-dir");
else if(g_settings->exists("map-dir"))
map_dir = g_settings->get("map-dir");
// Create server
Server server(map_dir.c_str(), configpath);
@@ -332,10 +365,10 @@ int main(int argc, char *argv[])
} //try
catch(con::PeerNotFoundException &e)
{
dstream<<DTIME<<"Connection timed out."<<std::endl;
errorstream<<"Connection timed out."<<std::endl;
}
END_DEBUG_EXCEPTION_HANDLER
END_DEBUG_EXCEPTION_HANDLER(errorstream)
debugstreams_deinit();

View File

@@ -104,12 +104,15 @@ class ServerActiveObject : public ActiveObject
If the object doesn't return an item, this will be called.
Return value is tool wear.
*/
virtual u16 punch(const std::string &toolname, v3f dir)
virtual u16 punch(const std::string &toolname, v3f dir,
const std::string &playername)
{return 0;}
/*
*/
virtual void rightClick(Player *player){}
virtual bool isPeaceful(){return true;}
/*
Number of players which know about this object. Object won't be

658
src/settings.h Normal file
View File

@@ -0,0 +1,658 @@
/*
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 SETTINGS_HEADER
#define SETTINGS_HEADER
#include "common_irrlicht.h"
#include <string>
#include <jthread.h>
#include <jmutex.h>
#include <jmutexautolock.h>
#include "strfnd.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include "debug.h"
#include "utility.h"
#include "log.h"
enum ValueType
{
VALUETYPE_STRING,
VALUETYPE_FLAG // Doesn't take any arguments
};
struct ValueSpec
{
ValueSpec(ValueType a_type, const char *a_help=NULL)
{
type = a_type;
help = a_help;
}
ValueType type;
const char *help;
};
class Settings
{
public:
Settings()
{
m_mutex.Init();
}
void writeLines(std::ostream &os)
{
JMutexAutoLock lock(m_mutex);
for(core::map<std::string, std::string>::Iterator
i = m_settings.getIterator();
i.atEnd() == false; i++)
{
std::string name = i.getNode()->getKey();
std::string value = i.getNode()->getValue();
os<<name<<" = "<<value<<"\n";
}
}
bool parseConfigLine(const std::string &line)
{
JMutexAutoLock lock(m_mutex);
std::string trimmedline = trim(line);
// Ignore comments
if(trimmedline[0] == '#')
return true;
//infostream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
Strfnd sf(trim(line));
std::string name = sf.next("=");
name = trim(name);
if(name == "")
return true;
std::string value = sf.next("\n");
value = trim(value);
/*infostream<<"Config name=\""<<name<<"\" value=\""
<<value<<"\""<<std::endl;*/
m_settings[name] = value;
return true;
}
void parseConfigLines(std::istream &is, const std::string &endstring)
{
for(;;){
if(is.eof())
break;
std::string line;
std::getline(is, line);
std::string trimmedline = trim(line);
if(endstring != ""){
if(trimmedline == endstring)
break;
}
parseConfigLine(line);
}
}
// Returns false on EOF
bool parseConfigObject(std::istream &is)
{
if(is.eof())
return false;
/*
NOTE: This function might be expanded to allow multi-line
settings.
*/
std::string line;
std::getline(is, line);
//infostream<<"got line: \""<<line<<"\""<<std::endl;
return parseConfigLine(line);
}
/*
Read configuration file
Returns true on success
*/
bool readConfigFile(const char *filename)
{
std::ifstream is(filename);
if(is.good() == false)
{
errorstream<<"Error opening configuration file \""
<<filename<<"\""<<std::endl;
return false;
}
infostream<<"Parsing configuration file: \""
<<filename<<"\""<<std::endl;
while(parseConfigObject(is));
return true;
}
/*
Reads a configuration object from stream (usually a single line)
and adds it to dst.
Preserves comments and empty lines.
Settings that were added to dst are also added to updated.
key of updated is setting name, value of updated is dummy.
Returns false on EOF
*/
bool getUpdatedConfigObject(std::istream &is,
core::list<std::string> &dst,
core::map<std::string, bool> &updated)
{
JMutexAutoLock lock(m_mutex);
if(is.eof())
return false;
// NOTE: This function will be expanded to allow multi-line settings
std::string line;
std::getline(is, line);
std::string trimmedline = trim(line);
std::string line_end = "";
if(is.eof() == false)
line_end = "\n";
// Ignore comments
if(trimmedline[0] == '#')
{
dst.push_back(line+line_end);
return true;
}
Strfnd sf(trim(line));
std::string name = sf.next("=");
name = trim(name);
if(name == "")
{
dst.push_back(line+line_end);
return true;
}
std::string value = sf.next("\n");
value = trim(value);
if(m_settings.find(name))
{
std::string newvalue = m_settings[name];
if(newvalue != value)
{
infostream<<"Changing value of \""<<name<<"\" = \""
<<value<<"\" -> \""<<newvalue<<"\""
<<std::endl;
}
dst.push_back(name + " = " + newvalue + line_end);
updated[name] = true;
}
return true;
}
/*
Updates configuration file
Returns true on success
*/
bool updateConfigFile(const char *filename)
{
infostream<<"Updating configuration file: \""
<<filename<<"\""<<std::endl;
core::list<std::string> objects;
core::map<std::string, bool> updated;
// Read and modify stuff
{
std::ifstream is(filename);
if(is.good() == false)
{
infostream<<"updateConfigFile():"
" Error opening configuration file"
" for reading: \""
<<filename<<"\""<<std::endl;
}
else
{
while(getUpdatedConfigObject(is, objects, updated));
}
}
JMutexAutoLock lock(m_mutex);
// Write stuff back
{
std::ofstream os(filename);
if(os.good() == false)
{
errorstream<<"Error opening configuration file"
" for writing: \""
<<filename<<"\""<<std::endl;
return false;
}
/*
Write updated stuff
*/
for(core::list<std::string>::Iterator
i = objects.begin();
i != objects.end(); i++)
{
os<<(*i);
}
/*
Write stuff that was not already in the file
*/
for(core::map<std::string, std::string>::Iterator
i = m_settings.getIterator();
i.atEnd() == false; i++)
{
if(updated.find(i.getNode()->getKey()))
continue;
std::string name = i.getNode()->getKey();
std::string value = i.getNode()->getValue();
infostream<<"Adding \""<<name<<"\" = \""<<value<<"\""
<<std::endl;
os<<name<<" = "<<value<<"\n";
}
}
return true;
}
/*
NOTE: Types of allowed_options are ignored
returns true on success
*/
bool parseCommandLine(int argc, char *argv[],
core::map<std::string, ValueSpec> &allowed_options)
{
int i=1;
for(;;)
{
if(i >= argc)
break;
std::string argname = argv[i];
if(argname.substr(0, 2) != "--")
{
errorstream<<"Invalid command-line parameter \""
<<argname<<"\": --<option> expected."<<std::endl;
return false;
}
i++;
std::string name = argname.substr(2);
core::map<std::string, ValueSpec>::Node *n;
n = allowed_options.find(name);
if(n == NULL)
{
errorstream<<"Unknown command-line parameter \""
<<argname<<"\""<<std::endl;
return false;
}
ValueType type = n->getValue().type;
std::string value = "";
if(type == VALUETYPE_FLAG)
{
value = "true";
}
else
{
if(i >= argc)
{
errorstream<<"Invalid command-line parameter \""
<<name<<"\": missing value"<<std::endl;
return false;
}
value = argv[i];
i++;
}
infostream<<"Valid command-line parameter: \""
<<name<<"\" = \""<<value<<"\""
<<std::endl;
set(name, value);
}
return true;
}
void set(std::string name, std::string value)
{
JMutexAutoLock lock(m_mutex);
m_settings[name] = value;
}
void set(std::string name, const char *value)
{
JMutexAutoLock lock(m_mutex);
m_settings[name] = value;
}
void setDefault(std::string name, std::string value)
{
JMutexAutoLock lock(m_mutex);
m_defaults[name] = value;
}
bool exists(std::string name)
{
JMutexAutoLock lock(m_mutex);
return (m_settings.find(name) || m_defaults.find(name));
}
std::string get(std::string name)
{
JMutexAutoLock lock(m_mutex);
core::map<std::string, std::string>::Node *n;
n = m_settings.find(name);
if(n == NULL)
{
n = m_defaults.find(name);
if(n == NULL)
{
infostream<<"Settings: Setting not found: \""
<<name<<"\""<<std::endl;
throw SettingNotFoundException("Setting not found");
}
}
return n->getValue();
}
bool getBool(std::string name)
{
return is_yes(get(name));
}
bool getFlag(std::string name)
{
try
{
return getBool(name);
}
catch(SettingNotFoundException &e)
{
return false;
}
}
// Asks if empty
bool getBoolAsk(std::string name, std::string question, bool def)
{
// If it is in settings
if(exists(name))
return getBool(name);
std::string s;
char templine[10];
std::cout<<question<<" [y/N]: ";
std::cin.getline(templine, 10);
s = templine;
if(s == "")
return def;
return is_yes(s);
}
float getFloat(std::string name)
{
return stof(get(name));
}
u16 getU16(std::string name)
{
return stoi(get(name), 0, 65535);
}
u16 getU16Ask(std::string name, std::string question, u16 def)
{
// If it is in settings
if(exists(name))
return getU16(name);
std::string s;
char templine[10];
std::cout<<question<<" ["<<def<<"]: ";
std::cin.getline(templine, 10);
s = templine;
if(s == "")
return def;
return stoi(s, 0, 65535);
}
s16 getS16(std::string name)
{
return stoi(get(name), -32768, 32767);
}
s32 getS32(std::string name)
{
return stoi(get(name));
}
v3f getV3F(std::string name)
{
v3f value;
Strfnd f(get(name));
f.next("(");
value.X = stof(f.next(","));
value.Y = stof(f.next(","));
value.Z = stof(f.next(")"));
return value;
}
v2f getV2F(std::string name)
{
v2f value;
Strfnd f(get(name));
f.next("(");
value.X = stof(f.next(","));
value.Y = stof(f.next(")"));
return value;
}
u64 getU64(std::string name)
{
u64 value = 0;
std::string s = get(name);
std::istringstream ss(s);
ss>>value;
return value;
}
void setBool(std::string name, bool value)
{
if(value)
set(name, "true");
else
set(name, "false");
}
void setS32(std::string name, s32 value)
{
set(name, itos(value));
}
void setFloat(std::string name, float value)
{
set(name, ftos(value));
}
void setV3F(std::string name, v3f value)
{
std::ostringstream os;
os<<"("<<value.X<<","<<value.Y<<","<<value.Z<<")";
set(name, os.str());
}
void setV2F(std::string name, v2f value)
{
std::ostringstream os;
os<<"("<<value.X<<","<<value.Y<<")";
set(name, os.str());
}
void setU64(std::string name, u64 value)
{
std::ostringstream os;
os<<value;
set(name, os.str());
}
void clear()
{
JMutexAutoLock lock(m_mutex);
m_settings.clear();
m_defaults.clear();
}
void updateValue(Settings &other, const std::string &name)
{
JMutexAutoLock lock(m_mutex);
if(&other == this)
return;
try{
std::string val = other.get(name);
m_settings[name] = val;
} catch(SettingNotFoundException &e){
}
return;
}
void update(Settings &other)
{
JMutexAutoLock lock(m_mutex);
JMutexAutoLock lock2(other.m_mutex);
if(&other == this)
return;
for(core::map<std::string, std::string>::Iterator
i = other.m_settings.getIterator();
i.atEnd() == false; i++)
{
m_settings[i.getNode()->getKey()] = i.getNode()->getValue();
}
for(core::map<std::string, std::string>::Iterator
i = other.m_defaults.getIterator();
i.atEnd() == false; i++)
{
m_defaults[i.getNode()->getKey()] = i.getNode()->getValue();
}
return;
}
Settings & operator+=(Settings &other)
{
JMutexAutoLock lock(m_mutex);
JMutexAutoLock lock2(other.m_mutex);
if(&other == this)
return *this;
for(core::map<std::string, std::string>::Iterator
i = other.m_settings.getIterator();
i.atEnd() == false; i++)
{
m_settings.insert(i.getNode()->getKey(),
i.getNode()->getValue());
}
for(core::map<std::string, std::string>::Iterator
i = other.m_defaults.getIterator();
i.atEnd() == false; i++)
{
m_defaults.insert(i.getNode()->getKey(),
i.getNode()->getValue());
}
return *this;
}
Settings & operator=(Settings &other)
{
JMutexAutoLock lock(m_mutex);
JMutexAutoLock lock2(other.m_mutex);
if(&other == this)
return *this;
clear();
(*this) += other;
return *this;
}
private:
core::map<std::string, std::string> m_settings;
core::map<std::string, std::string> m_defaults;
// All methods that access m_settings/m_defaults directly should lock this.
JMutex m_mutex;
};
#endif

View File

@@ -97,7 +97,7 @@ void Address::Resolve(const char *name)
freeaddrinfo(resolved);
}
std::string Address::serializeString()
std::string Address::serializeString() const
{
unsigned int a, b, c, d;
a = (m_address & 0xFF000000)>>24;

View File

@@ -97,7 +97,7 @@ class Address
void setPort(unsigned short port);
void print(std::ostream *s) const;
void print() const;
std::string serializeString();
std::string serializeString() const;
private:
unsigned int m_address;
unsigned short m_port;

View File

@@ -32,6 +32,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "porting.h"
#include "content_mapnode.h"
#include "mapsector.h"
#include "settings.h"
#include "log.h"
/*
Asserts that the exception occurs
@@ -48,9 +50,9 @@ struct TestUtilities
{
void Run()
{
/*dstream<<"wrapDegrees(100.0) = "<<wrapDegrees(100.0)<<std::endl;
dstream<<"wrapDegrees(720.5) = "<<wrapDegrees(720.5)<<std::endl;
dstream<<"wrapDegrees(-0.5) = "<<wrapDegrees(-0.5)<<std::endl;*/
/*infostream<<"wrapDegrees(100.0) = "<<wrapDegrees(100.0)<<std::endl;
infostream<<"wrapDegrees(720.5) = "<<wrapDegrees(720.5)<<std::endl;
infostream<<"wrapDegrees(-0.5) = "<<wrapDegrees(-0.5)<<std::endl;*/
assert(fabs(wrapDegrees(100.0) - 100.0) < 0.001);
assert(fabs(wrapDegrees(720.5) - 0.5) < 0.001);
assert(fabs(wrapDegrees(-0.5) - (-0.5)) < 0.001);
@@ -111,13 +113,13 @@ struct TestCompress
std::string str_out = os.str();
dstream<<"str_out.size()="<<str_out.size()<<std::endl;
dstream<<"TestCompress: 1,5,5,1 -> ";
infostream<<"str_out.size()="<<str_out.size()<<std::endl;
infostream<<"TestCompress: 1,5,5,1 -> ";
for(u32 i=0; i<str_out.size(); i++)
{
dstream<<(u32)str_out[i]<<",";
infostream<<(u32)str_out[i]<<",";
}
dstream<<std::endl;
infostream<<std::endl;
assert(str_out.size() == 10);
@@ -138,12 +140,12 @@ struct TestCompress
decompress(is, os2, 0);
std::string str_out2 = os2.str();
dstream<<"decompress: ";
infostream<<"decompress: ";
for(u32 i=0; i<str_out2.size(); i++)
{
dstream<<(u32)str_out2[i]<<",";
infostream<<(u32)str_out2[i]<<",";
}
dstream<<std::endl;
infostream<<std::endl;
assert(str_out2.size() == fromdata.getSize());
@@ -167,13 +169,13 @@ struct TestCompress
std::string str_out = os.str();
dstream<<"str_out.size()="<<str_out.size()<<std::endl;
dstream<<"TestCompress: 1,5,5,1 -> ";
infostream<<"str_out.size()="<<str_out.size()<<std::endl;
infostream<<"TestCompress: 1,5,5,1 -> ";
for(u32 i=0; i<str_out.size(); i++)
{
dstream<<(u32)str_out[i]<<",";
infostream<<(u32)str_out[i]<<",";
}
dstream<<std::endl;
infostream<<std::endl;
/*assert(str_out.size() == 10);
@@ -194,12 +196,12 @@ struct TestCompress
decompress(is, os2, SER_FMT_VER_HIGHEST);
std::string str_out2 = os2.str();
dstream<<"decompress: ";
infostream<<"decompress: ";
for(u32 i=0; i<str_out2.size(); i++)
{
dstream<<(u32)str_out2[i]<<",";
infostream<<(u32)str_out2[i]<<",";
}
dstream<<std::endl;
infostream<<std::endl;
assert(str_out2.size() == fromdata.getSize());
@@ -257,12 +259,12 @@ struct TestVoxelManipulator
assert(aa.size() == results.size());
dstream<<"Result of diff:"<<std::endl;
infostream<<"Result of diff:"<<std::endl;
for(core::list<VoxelArea>::Iterator
i = aa.begin(); i != aa.end(); i++)
{
i->print(dstream);
dstream<<std::endl;
i->print(infostream);
infostream<<std::endl;
s32 j = results.linear_search(*i);
assert(j != -1);
@@ -276,27 +278,27 @@ struct TestVoxelManipulator
VoxelManipulator v;
v.print(dstream);
v.print(infostream);
dstream<<"*** Setting (-1,0,-1)=2 ***"<<std::endl;
infostream<<"*** Setting (-1,0,-1)=2 ***"<<std::endl;
v.setNodeNoRef(v3s16(-1,0,-1), MapNode(2));
v.print(dstream);
v.print(infostream);
assert(v.getNode(v3s16(-1,0,-1)).getContent() == 2);
dstream<<"*** Reading from inexistent (0,0,-1) ***"<<std::endl;
infostream<<"*** Reading from inexistent (0,0,-1) ***"<<std::endl;
EXCEPTION_CHECK(InvalidPositionException, v.getNode(v3s16(0,0,-1)));
v.print(dstream);
v.print(infostream);
dstream<<"*** Adding area ***"<<std::endl;
infostream<<"*** Adding area ***"<<std::endl;
v.addArea(a);
v.print(dstream);
v.print(infostream);
assert(v.getNode(v3s16(-1,0,-1)).getContent() == 2);
EXCEPTION_CHECK(InvalidPositionException, v.getNode(v3s16(0,1,1)));
@@ -342,12 +344,12 @@ struct TestVoxelManipulator
p++;
}
v.print(dstream, VOXELPRINT_WATERPRESSURE);
v.print(infostream, VOXELPRINT_WATERPRESSURE);
core::map<v3s16, u8> active_nodes;
v.updateAreaWaterPressure(area, active_nodes);
v.print(dstream, VOXELPRINT_WATERPRESSURE);
v.print(infostream, VOXELPRINT_WATERPRESSURE);
//s16 highest_y = -32768;
/*
@@ -364,8 +366,8 @@ struct TestVoxelManipulator
//v.flowWater(active_nodes, 0, true, 1000);
v.flowWater(active_nodes, 0, false, 1000);
dstream<<"Final result of flowWater:"<<std::endl;
v.print(dstream, VOXELPRINT_WATERPRESSURE);
infostream<<"Final result of flowWater:"<<std::endl;
v.print(infostream, VOXELPRINT_WATERPRESSURE);
#endif
//assert(0);
@@ -764,15 +766,15 @@ struct TestConnection
assert(readU8(&p1.data[6]) == channel);
assert(readU8(&p1.data[7]) == data1[0]);
//dstream<<"initial data1[0]="<<((u32)data1[0]&0xff)<<std::endl;
//infostream<<"initial data1[0]="<<((u32)data1[0]&0xff)<<std::endl;
SharedBuffer<u8> p2 = con::makeReliablePacket(data1, seqnum);
/*dstream<<"p2.getSize()="<<p2.getSize()<<", data1.getSize()="
/*infostream<<"p2.getSize()="<<p2.getSize()<<", data1.getSize()="
<<data1.getSize()<<std::endl;
dstream<<"readU8(&p2[3])="<<readU8(&p2[3])
infostream<<"readU8(&p2[3])="<<readU8(&p2[3])
<<" p2[3]="<<((u32)p2[3]&0xff)<<std::endl;
dstream<<"data1[0]="<<((u32)data1[0]&0xff)<<std::endl;*/
infostream<<"data1[0]="<<((u32)data1[0]&0xff)<<std::endl;*/
assert(p2.getSize() == 3 + data1.getSize());
assert(readU8(&p2[0]) == TYPE_RELIABLE);
@@ -790,14 +792,14 @@ struct TestConnection
}
void peerAdded(con::Peer *peer)
{
dstream<<"Handler("<<name<<")::peerAdded(): "
infostream<<"Handler("<<name<<")::peerAdded(): "
"id="<<peer->id<<std::endl;
last_id = peer->id;
count++;
}
void deletingPeer(con::Peer *peer, bool timeout)
{
dstream<<"Handler("<<name<<")::deletingPeer(): "
infostream<<"Handler("<<name<<")::deletingPeer(): "
"id="<<peer->id
<<", timeout="<<timeout<<std::endl;
last_id = peer->id;
@@ -817,17 +819,20 @@ struct TestConnection
/*
Test some real connections
NOTE: This mostly tests the legacy interface.
*/
u32 proto_id = 0xad26846a;
Handler hand_server("server");
Handler hand_client("client");
dstream<<"** Creating server Connection"<<std::endl;
infostream<<"** Creating server Connection"<<std::endl;
con::Connection server(proto_id, 512, 5.0, &hand_server);
server.Serve(30001);
dstream<<"** Creating client Connection"<<std::endl;
infostream<<"** Creating client Connection"<<std::endl;
con::Connection client(proto_id, 512, 5.0, &hand_client);
assert(hand_server.count == 0);
@@ -836,24 +841,43 @@ struct TestConnection
sleep_ms(50);
Address server_address(127,0,0,1, 30001);
dstream<<"** running client.Connect()"<<std::endl;
infostream<<"** running client.Connect()"<<std::endl;
client.Connect(server_address);
sleep_ms(50);
// Client should not have added client yet
assert(hand_client.count == 0);
try
{
u16 peer_id;
SharedBuffer<u8> data;
infostream<<"** running client.Receive()"<<std::endl;
u32 size = client.Receive(peer_id, data);
infostream<<"** Client received: peer_id="<<peer_id
<<", size="<<size
<<std::endl;
}
catch(con::NoIncomingDataException &e)
{
}
// Client should have added server now
assert(hand_client.count == 1);
assert(hand_client.last_id == 1);
// But server should not have added client
// Server should not have added client yet
assert(hand_server.count == 0);
sleep_ms(50);
try
{
u16 peer_id;
u8 data[100];
dstream<<"** running server.Receive()"<<std::endl;
u32 size = server.Receive(peer_id, data, 100);
dstream<<"** Server received: peer_id="<<peer_id
SharedBuffer<u8> data;
infostream<<"** running server.Receive()"<<std::endl;
u32 size = server.Receive(peer_id, data);
infostream<<"** Server received: peer_id="<<peer_id
<<", size="<<size
<<std::endl;
}
@@ -877,10 +901,10 @@ struct TestConnection
try
{
u16 peer_id;
u8 data[100];
dstream<<"** running client.Receive()"<<std::endl;
u32 size = client.Receive(peer_id, data, 100);
dstream<<"** Client received: peer_id="<<peer_id
SharedBuffer<u8> data;
infostream<<"** running client.Receive()"<<std::endl;
u32 size = client.Receive(peer_id, data);
infostream<<"** Client received: peer_id="<<peer_id
<<", size="<<size
<<std::endl;
}
@@ -895,57 +919,61 @@ struct TestConnection
try
{
u16 peer_id;
u8 data[100];
dstream<<"** running server.Receive()"<<std::endl;
u32 size = server.Receive(peer_id, data, 100);
dstream<<"** Server received: peer_id="<<peer_id
SharedBuffer<u8> data;
infostream<<"** running server.Receive()"<<std::endl;
u32 size = server.Receive(peer_id, data);
infostream<<"** Server received: peer_id="<<peer_id
<<", size="<<size
<<std::endl;
}
catch(con::NoIncomingDataException &e)
{
}
#if 1
/*
Simple send-receive test
*/
{
/*u8 data[] = "Hello World!";
u32 datasize = sizeof(data);*/
SharedBuffer<u8> data = SharedBufferFromString("Hello World!");
dstream<<"** running client.Send()"<<std::endl;
infostream<<"** running client.Send()"<<std::endl;
client.Send(PEER_ID_SERVER, 0, data, true);
sleep_ms(50);
u16 peer_id;
u8 recvdata[100];
dstream<<"** running server.Receive()"<<std::endl;
u32 size = server.Receive(peer_id, recvdata, 100);
dstream<<"** Server received: peer_id="<<peer_id
SharedBuffer<u8> recvdata;
infostream<<"** running server.Receive()"<<std::endl;
u32 size = server.Receive(peer_id, recvdata);
infostream<<"** Server received: peer_id="<<peer_id
<<", size="<<size
<<", data="<<*data
<<std::endl;
assert(memcmp(*data, recvdata, data.getSize()) == 0);
assert(memcmp(*data, *recvdata, data.getSize()) == 0);
}
#endif
u16 peer_id_client = 2;
#if 0
/*
Send consequent packets in different order
Not compatible with new Connection, thus commented out.
*/
{
/*
Send consequent packets in different order
*/
//u8 data1[] = "hello1";
//u8 data2[] = "hello2";
SharedBuffer<u8> data1 = SharedBufferFromString("hello1");
SharedBuffer<u8> data2 = SharedBufferFromString("Hello2");
Address client_address =
server.GetPeer(peer_id_client)->address;
server.GetPeerAddress(peer_id_client);
dstream<<"*** Sending packets in wrong order (2,1,2)"
infostream<<"*** Sending packets in wrong order (2,1,2)"
<<std::endl;
u8 chn = 0;
con::Channel *ch = &server.GetPeer(peer_id_client)->channels[chn];
con::Channel *ch = &server.getPeer(peer_id_client)->channels[chn];
u16 sn = ch->next_outgoing_seqnum;
ch->next_outgoing_seqnum = sn+1;
server.Send(peer_id_client, chn, data2, true);
@@ -956,52 +984,94 @@ struct TestConnection
sleep_ms(50);
dstream<<"*** Receiving the packets"<<std::endl;
infostream<<"*** Receiving the packets"<<std::endl;
u16 peer_id;
u8 recvdata[20];
SharedBuffer<u8> recvdata;
u32 size;
dstream<<"** running client.Receive()"<<std::endl;
infostream<<"** running client.Receive()"<<std::endl;
peer_id = 132;
size = client.Receive(peer_id, recvdata, 20);
dstream<<"** Client received: peer_id="<<peer_id
size = client.Receive(peer_id, recvdata);
infostream<<"** Client received: peer_id="<<peer_id
<<", size="<<size
<<", data="<<recvdata
<<", data="<<*recvdata
<<std::endl;
assert(size == data1.getSize());
assert(memcmp(*data1, recvdata, data1.getSize()) == 0);
assert(memcmp(*data1, *recvdata, data1.getSize()) == 0);
assert(peer_id == PEER_ID_SERVER);
dstream<<"** running client.Receive()"<<std::endl;
infostream<<"** running client.Receive()"<<std::endl;
peer_id = 132;
size = client.Receive(peer_id, recvdata, 20);
dstream<<"** Client received: peer_id="<<peer_id
size = client.Receive(peer_id, recvdata);
infostream<<"** Client received: peer_id="<<peer_id
<<", size="<<size
<<", data="<<recvdata
<<", data="<<*recvdata
<<std::endl;
assert(size == data2.getSize());
assert(memcmp(*data2, recvdata, data2.getSize()) == 0);
assert(memcmp(*data2, *recvdata, data2.getSize()) == 0);
assert(peer_id == PEER_ID_SERVER);
bool got_exception = false;
try
{
dstream<<"** running client.Receive()"<<std::endl;
infostream<<"** running client.Receive()"<<std::endl;
peer_id = 132;
size = client.Receive(peer_id, recvdata, 20);
dstream<<"** Client received: peer_id="<<peer_id
size = client.Receive(peer_id, recvdata);
infostream<<"** Client received: peer_id="<<peer_id
<<", size="<<size
<<", data="<<recvdata
<<", data="<<*recvdata
<<std::endl;
}
catch(con::NoIncomingDataException &e)
{
dstream<<"** No incoming data for client"<<std::endl;
infostream<<"** No incoming data for client"<<std::endl;
got_exception = true;
}
assert(got_exception);
}
#endif
#if 0
/*
Send large amounts of packets (infinite test)
Commented out because of infinity.
*/
{
infostream<<"Sending large amounts of packets (infinite test)"<<std::endl;
int sendcount = 0;
for(;;){
int datasize = myrand_range(0,5)==0?myrand_range(100,10000):myrand_range(0,100);
infostream<<"datasize="<<datasize<<std::endl;
SharedBuffer<u8> data1(datasize);
for(u16 i=0; i<datasize; i++)
data1[i] = i/4;
int sendtimes = myrand_range(1,10);
for(int i=0; i<sendtimes; i++){
server.Send(peer_id_client, 0, data1, true);
sendcount++;
}
infostream<<"sendcount="<<sendcount<<std::endl;
//int receivetimes = myrand_range(1,20);
int receivetimes = 20;
for(int i=0; i<receivetimes; i++){
SharedBuffer<u8> recvdata;
u16 peer_id = 132;
u16 size = 0;
bool received = false;
try{
size = client.Receive(peer_id, recvdata);
received = true;
}catch(con::NoIncomingDataException &e){
}
}
}
}
#endif
/*
Send a large packet
*/
{
const int datasize = 30000;
SharedBuffer<u8> data1(datasize);
@@ -1009,37 +1079,50 @@ struct TestConnection
data1[i] = i/4;
}
dstream<<"Sending data (size="<<datasize<<"):";
infostream<<"Sending data (size="<<datasize<<"):";
for(int i=0; i<datasize && i<20; i++){
if(i%2==0) DEBUGPRINT(" ");
DEBUGPRINT("%.2X", ((int)((const char*)*data1)[i])&0xff);
}
if(datasize>20)
dstream<<"...";
dstream<<std::endl;
infostream<<"...";
infostream<<std::endl;
server.Send(peer_id_client, 0, data1, true);
sleep_ms(50);
sleep_ms(3000);
u8 recvdata[datasize + 1000];
dstream<<"** running client.Receive()"<<std::endl;
SharedBuffer<u8> recvdata;
infostream<<"** running client.Receive()"<<std::endl;
u16 peer_id = 132;
u16 size = client.Receive(peer_id, recvdata, datasize + 1000);
dstream<<"** Client received: peer_id="<<peer_id
u16 size = 0;
bool received = false;
u32 timems0 = porting::getTimeMs();
for(;;){
if(porting::getTimeMs() - timems0 > 5000)
break;
try{
size = client.Receive(peer_id, recvdata);
received = true;
}catch(con::NoIncomingDataException &e){
}
sleep_ms(10);
}
assert(received);
infostream<<"** Client received: peer_id="<<peer_id
<<", size="<<size
<<std::endl;
dstream<<"Received data (size="<<size<<"):";
infostream<<"Received data (size="<<size<<"):";
for(int i=0; i<size && i<20; i++){
if(i%2==0) DEBUGPRINT(" ");
DEBUGPRINT("%.2X", ((int)((const char*)recvdata)[i])&0xff);
DEBUGPRINT("%.2X", ((int)(recvdata[i]))&0xff);
}
if(size>20)
dstream<<"...";
dstream<<std::endl;
infostream<<"...";
infostream<<std::endl;
assert(memcmp(*data1, recvdata, data1.getSize()) == 0);
assert(memcmp(*data1, *recvdata, data1.getSize()) == 0);
assert(peer_id == PEER_ID_SERVER);
}
@@ -1056,14 +1139,14 @@ struct TestConnection
#define TEST(X)\
{\
X x;\
dstream<<"Running " #X <<std::endl;\
infostream<<"Running " #X <<std::endl;\
x.Run();\
}
void run_tests()
{
DSTACK(__FUNCTION_NAME);
dstream<<"run_tests() started"<<std::endl;
infostream<<"run_tests() started"<<std::endl;
TEST(TestUtilities);
TEST(TestSettings);
TEST(TestCompress);
@@ -1077,6 +1160,6 @@ void run_tests()
TEST(TestConnection);
dout_con<<"=== END RUNNING UNIT TESTS FOR CONNECTION ==="<<std::endl;
}
dstream<<"run_tests() passed"<<std::endl;
infostream<<"run_tests() passed"<<std::endl;
}

View File

@@ -22,6 +22,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "main.h" // for g_settings
#include "filesys.h"
#include "utility.h"
#include "settings.h"
#include <ICameraSceneNode.h>
#include "log.h"
#include "mapnode.h" // For texture atlas making
#include "mineral.h" // For texture atlas making
/*
A cache from texture name to texture path
@@ -112,10 +117,10 @@ std::string getTexturePath(const std::string &filename)
/*
Check from texture_path
*/
std::string texture_path = g_settings.get("texture_path");
std::string texture_path = g_settings->get("texture_path");
if(texture_path != "")
{
std::string testpath = texture_path + '/' + filename;
std::string testpath = texture_path + DIR_DELIM + filename;
// Check all filename extensions. Returns "" if not found.
fullpath = getImagePath(testpath);
}
@@ -157,10 +162,10 @@ TextureSource::TextureSource(IrrlichtDevice *device):
m_name_to_id[""] = 0;
// Build main texture atlas
if(g_settings.getBool("enable_texture_atlas"))
if(g_settings->getBool("enable_texture_atlas"))
buildMainAtlas();
else
dstream<<"INFO: Not building texture atlas."<<std::endl;
infostream<<"Not building texture atlas."<<std::endl;
}
TextureSource::~TextureSource()
@@ -177,7 +182,7 @@ void TextureSource::processQueue()
GetRequest<std::string, u32, u8, u8>
request = m_get_texture_queue.pop();
dstream<<"INFO: TextureSource::processQueue(): "
infostream<<"TextureSource::processQueue(): "
<<"got texture request with "
<<"name=\""<<request.key<<"\""
<<std::endl;
@@ -194,7 +199,7 @@ void TextureSource::processQueue()
u32 TextureSource::getTextureId(const std::string &name)
{
//dstream<<"INFO: getTextureId(): \""<<name<<"\""<<std::endl;
//infostream<<"getTextureId(): \""<<name<<"\""<<std::endl;
{
/*
@@ -218,7 +223,7 @@ u32 TextureSource::getTextureId(const std::string &name)
}
else
{
dstream<<"INFO: getTextureId(): Queued: name=\""<<name<<"\""<<std::endl;
infostream<<"getTextureId(): Queued: name=\""<<name<<"\""<<std::endl;
// We're gonna ask the result to be put into here
ResultQueue<std::string, u32, u8, u8> result_queue;
@@ -226,7 +231,7 @@ u32 TextureSource::getTextureId(const std::string &name)
// Throw a request in
m_get_texture_queue.add(name, 0, 0, &result_queue);
dstream<<"INFO: Waiting for texture from main thread, name=\""
infostream<<"Waiting for texture from main thread, name=\""
<<name<<"\""<<std::endl;
try
@@ -242,12 +247,12 @@ u32 TextureSource::getTextureId(const std::string &name)
}
catch(ItemNotFoundException &e)
{
dstream<<"WARNING: Waiting for texture timed out."<<std::endl;
infostream<<"Waiting for texture timed out."<<std::endl;
return 0;
}
}
dstream<<"WARNING: getTextureId(): Failed"<<std::endl;
infostream<<"getTextureId(): Failed"<<std::endl;
return 0;
}
@@ -276,12 +281,12 @@ video::IImage* generate_image_from_scratch(std::string name,
*/
u32 TextureSource::getTextureIdDirect(const std::string &name)
{
//dstream<<"INFO: getTextureIdDirect(): name=\""<<name<<"\""<<std::endl;
//infostream<<"getTextureIdDirect(): name=\""<<name<<"\""<<std::endl;
// Empty name means texture 0
if(name == "")
{
dstream<<"INFO: getTextureIdDirect(): name is empty"<<std::endl;
infostream<<"getTextureIdDirect(): name is empty"<<std::endl;
return 0;
}
@@ -290,7 +295,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
*/
if(get_current_thread_id() != m_main_thread)
{
dstream<<"ERROR: TextureSource::getTextureIdDirect() "
errorstream<<"TextureSource::getTextureIdDirect() "
"called not from main thread"<<std::endl;
return 0;
}
@@ -305,13 +310,13 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
n = m_name_to_id.find(name);
if(n != NULL)
{
dstream<<"INFO: getTextureIdDirect(): \""<<name
infostream<<"getTextureIdDirect(): \""<<name
<<"\" found in cache"<<std::endl;
return n->getValue();
}
}
dstream<<"INFO: getTextureIdDirect(): \""<<name
infostream<<"getTextureIdDirect(): \""<<name
<<"\" NOT found in cache. Creating it."<<std::endl;
/*
@@ -346,13 +351,13 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
{
// Construct base name
base_image_name = name.substr(0, last_separator_position);
/*dstream<<"INFO: getTextureIdDirect(): Calling itself recursively"
/*infostream<<"getTextureIdDirect(): Calling itself recursively"
" to get base image of \""<<name<<"\" = \""
<<base_image_name<<"\""<<std::endl;*/
base_image_id = getTextureIdDirect(base_image_name);
}
//dstream<<"base_image_id="<<base_image_id<<std::endl;
//infostream<<"base_image_id="<<base_image_id<<std::endl;
video::IVideoDriver* driver = m_device->getVideoDriver();
assert(driver);
@@ -375,7 +380,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
if(image == NULL)
{
dstream<<"WARNING: getTextureIdDirect(): NULL image in "
infostream<<"getTextureIdDirect(): NULL image in "
<<"cache: \""<<base_image_name<<"\""
<<std::endl;
}
@@ -394,7 +399,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
core::rect<s32>(pos_from, dim) // from
);
/*dstream<<"INFO: getTextureIdDirect(): Loaded \""
/*infostream<<"getTextureIdDirect(): Loaded \""
<<base_image_name<<"\" from image cache"
<<std::endl;*/
}
@@ -406,12 +411,12 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
*/
std::string last_part_of_name = name.substr(last_separator_position+1);
//dstream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl;
//infostream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl;
// Generate image according to part of name
if(generate_image(last_part_of_name, baseimg, m_device) == false)
{
dstream<<"INFO: getTextureIdDirect(): "
infostream<<"getTextureIdDirect(): "
"failed to generate \""<<last_part_of_name<<"\""
<<std::endl;
}
@@ -419,7 +424,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
// If no resulting image, print a warning
if(baseimg == NULL)
{
dstream<<"WARNING: getTextureIdDirect(): baseimg is NULL (attempted to"
infostream<<"getTextureIdDirect(): baseimg is NULL (attempted to"
" create texture \""<<name<<"\""<<std::endl;
}
@@ -448,7 +453,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
m_atlaspointer_cache.push_back(nap);
m_name_to_id.insert(name, id);
/*dstream<<"INFO: getTextureIdDirect(): "
/*infostream<<"getTextureIdDirect(): "
<<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;*/
return id;
@@ -460,7 +465,7 @@ std::string TextureSource::getTextureName(u32 id)
if(id >= m_atlaspointer_cache.size())
{
dstream<<"WARNING: TextureSource::getTextureName(): id="<<id
infostream<<"TextureSource::getTextureName(): id="<<id
<<" >= m_atlaspointer_cache.size()="
<<m_atlaspointer_cache.size()<<std::endl;
return "";
@@ -482,7 +487,7 @@ AtlasPointer TextureSource::getTexture(u32 id)
void TextureSource::buildMainAtlas()
{
dstream<<"TextureSource::buildMainAtlas()"<<std::endl;
infostream<<"TextureSource::buildMainAtlas()"<<std::endl;
//return; // Disable (for testing)
@@ -498,58 +503,68 @@ void TextureSource::buildMainAtlas()
//assert(atlas_img);
if(atlas_img == NULL)
{
dstream<<"TextureSource::buildMainAtlas(): Failed to create atlas "
errorstream<<"TextureSource::buildMainAtlas(): Failed to create atlas "
"image; not building texture atlas."<<std::endl;
return;
}
/*
A list of stuff to include in the texture atlas.
It is a single-dimensional texture atlas due to the need to tile
textures.
It should contain as much of the stuff shown in game as possible,
to minimize texture changes.
It fills up quickly, so do not add anything that isn't contained
in most MapBlocks. E.g. mese isn't suitable but stone is.
Grab list of stuff to include in the texture atlas from the
main content features
*/
core::array<std::string> sourcelist;
core::map<std::string, bool> sourcelist;
sourcelist.push_back("stone.png");
sourcelist.push_back("mud.png");
sourcelist.push_back("sand.png");
sourcelist.push_back("grass.png");
sourcelist.push_back("grass_footsteps.png");
sourcelist.push_back("tree.png");
sourcelist.push_back("tree_top.png");
sourcelist.push_back("water.png");
sourcelist.push_back("leaves.png");
sourcelist.push_back("glass.png");
sourcelist.push_back("mud.png^grass_side.png");
sourcelist.push_back("cobble.png");
sourcelist.push_back("mossycobble.png");
sourcelist.push_back("gravel.png");
sourcelist.push_back("jungletree.png");
sourcelist.push_back("stone.png^mineral_coal.png");
sourcelist.push_back("stone.png^mineral_iron.png");
for(u16 j=0; j<MAX_CONTENT+1; j++)
{
if(j == CONTENT_IGNORE || j == CONTENT_AIR)
continue;
ContentFeatures *f = &content_features(j);
for(core::map<std::string, bool>::Iterator
i = f->used_texturenames.getIterator();
i.atEnd() == false; i++)
{
std::string name = i.getNode()->getKey();
sourcelist[name] = true;
if(f->often_contains_mineral){
for(int k=1; k<MINERAL_COUNT; k++){
std::string mineraltexture = mineral_block_texture(k);
std::string fulltexture = name + "^" + mineraltexture;
sourcelist[fulltexture] = true;
}
}
}
}
infostream<<"Creating texture atlas out of textures: ";
for(core::map<std::string, bool>::Iterator
i = sourcelist.getIterator();
i.atEnd() == false; i++)
{
std::string name = i.getNode()->getKey();
infostream<<"\""<<name<<"\" ";
}
infostream<<std::endl;
// Padding to disallow texture bleeding
s32 padding = 16;
s32 column_width = 256;
s32 column_padding = 16;
/*
First pass: generate almost everything
*/
core::position2d<s32> pos_in_atlas(0,0);
pos_in_atlas.Y += padding;
pos_in_atlas.Y = padding;
for(u32 i=0; i<sourcelist.size(); i++)
for(core::map<std::string, bool>::Iterator
i = sourcelist.getIterator();
i.atEnd() == false; i++)
{
std::string name = sourcelist[i];
std::string name = i.getNode()->getKey();
/*video::IImage *img = driver->createImageFromFile(
getTexturePath(name.c_str()).c_str());
@@ -567,7 +582,7 @@ void TextureSource::buildMainAtlas()
video::IImage *img2 = generate_image_from_scratch(name, m_device);
if(img2 == NULL)
{
dstream<<"WARNING: TextureSource::buildMainAtlas(): Couldn't generate texture atlas: Couldn't generate image \""<<name<<"\""<<std::endl;
infostream<<"TextureSource::buildMainAtlas(): Couldn't generate texture atlas: Couldn't generate image \""<<name<<"\""<<std::endl;
continue;
}
@@ -578,25 +593,31 @@ void TextureSource::buildMainAtlas()
if(dim.Width > max_size_in_atlas.Width
|| dim.Height > max_size_in_atlas.Height)
{
dstream<<"INFO: TextureSource::buildMainAtlas(): Not adding "
infostream<<"TextureSource::buildMainAtlas(): Not adding "
<<"\""<<name<<"\" because image is large"<<std::endl;
continue;
}
// Stop making atlas if atlas is full
// Wrap columns and stop making atlas if atlas is full
if(pos_in_atlas.Y + dim.Height > atlas_dim.Height)
{
dstream<<"WARNING: TextureSource::buildMainAtlas(): "
<<"Atlas is full, not adding more textures."
<<std::endl;
break;
if(pos_in_atlas.X > (s32)atlas_dim.Width - 256 - padding){
errorstream<<"TextureSource::buildMainAtlas(): "
<<"Atlas is full, not adding more textures."
<<std::endl;
break;
}
pos_in_atlas.Y = padding;
pos_in_atlas.X += column_width + column_padding;
}
dstream<<"INFO: TextureSource::buildMainAtlas(): Adding \""<<name
infostream<<"TextureSource::buildMainAtlas(): Adding \""<<name
<<"\" to texture atlas"<<std::endl;
// Tile it a few times in the X direction
u16 xwise_tiling = 16;
u16 xwise_tiling = column_width / dim.Width;
if(xwise_tiling > 16) // Limit to 16 (more gives no benefit)
xwise_tiling = 16;
for(u32 j=0; j<xwise_tiling; j++)
{
// Copy the copy to the atlas
@@ -624,7 +645,7 @@ void TextureSource::buildMainAtlas()
dst_y = -y0 + pos_in_atlas.Y-1;
src_y = pos_in_atlas.Y;
}
s32 x = x0 + pos_in_atlas.X * dim.Width;
s32 x = x0 + pos_in_atlas.X;
video::SColor c = atlas_img->getPixel(x, src_y);
atlas_img->setPixel(x,dst_y,c);
}
@@ -665,27 +686,33 @@ void TextureSource::buildMainAtlas()
/*
Second pass: set texture pointer in generated AtlasPointers
*/
for(u32 i=0; i<sourcelist.size(); i++)
for(core::map<std::string, bool>::Iterator
i = sourcelist.getIterator();
i.atEnd() == false; i++)
{
std::string name = sourcelist[i];
std::string name = i.getNode()->getKey();
if(m_name_to_id.find(name) == NULL)
continue;
u32 id = m_name_to_id[name];
//dstream<<"id of name "<<name<<" is "<<id<<std::endl;
//infostream<<"id of name "<<name<<" is "<<id<<std::endl;
m_atlaspointer_cache[id].a.atlas = t;
}
/*
Write image to file so that it can be inspected
*/
/*driver->writeImageToFile(atlas_img,
getTexturePath("main_atlas.png").c_str());*/
/*std::string atlaspath = porting::path_userdata
+ DIR_DELIM + "generated_texture_atlas.png";
infostream<<"Removing and writing texture atlas for inspection to "
<<atlaspath<<std::endl;
fs::RecursiveDelete(atlaspath);
driver->writeImageToFile(atlas_img, atlaspath.c_str());*/
}
video::IImage* generate_image_from_scratch(std::string name,
IrrlichtDevice *device)
{
/*dstream<<"INFO: generate_image_from_scratch(): "
/*infostream<<"generate_image_from_scratch(): "
"\""<<name<<"\""<<std::endl;*/
video::IVideoDriver* driver = device->getVideoDriver();
@@ -710,7 +737,7 @@ video::IImage* generate_image_from_scratch(std::string name,
}
}
/*dstream<<"INFO: generate_image_from_scratch(): "
/*infostream<<"generate_image_from_scratch(): "
<<"last_separator_position="<<last_separator_position
<<std::endl;*/
@@ -723,7 +750,7 @@ video::IImage* generate_image_from_scratch(std::string name,
{
// Construct base name
base_image_name = name.substr(0, last_separator_position);
/*dstream<<"INFO: generate_image_from_scratch(): Calling itself recursively"
/*infostream<<"generate_image_from_scratch(): Calling itself recursively"
" to get base image of \""<<name<<"\" = \""
<<base_image_name<<"\""<<std::endl;*/
baseimg = generate_image_from_scratch(base_image_name, device);
@@ -735,12 +762,12 @@ video::IImage* generate_image_from_scratch(std::string name,
*/
std::string last_part_of_name = name.substr(last_separator_position+1);
//dstream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl;
//infostream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl;
// Generate image according to part of name
if(generate_image(last_part_of_name, baseimg, device) == false)
{
dstream<<"INFO: generate_image_from_scratch(): "
infostream<<"generate_image_from_scratch(): "
"failed to generate \""<<last_part_of_name<<"\""
<<std::endl;
return NULL;
@@ -760,20 +787,20 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
{
// A normal texture; load it from a file
std::string path = getTexturePath(part_of_name.c_str());
/*dstream<<"INFO: generate_image(): Loading path \""<<path
/*infostream<<"generate_image(): Loading path \""<<path
<<"\""<<std::endl;*/
video::IImage *image = driver->createImageFromFile(path.c_str());
if(image == NULL)
{
dstream<<"WARNING: generate_image(): Could not load image \""
infostream<<"generate_image(): Could not load image \""
<<part_of_name<<"\" from path \""<<path<<"\""
<<" while building texture"<<std::endl;
//return false;
dstream<<"WARNING: generate_image(): Creating a dummy"
infostream<<"generate_image(): Creating a dummy"
<<" image for \""<<part_of_name<<"\""<<std::endl;
// Just create a dummy image
@@ -798,7 +825,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
// If base image is NULL, load as base.
if(baseimg == NULL)
{
//dstream<<"INFO: Setting "<<part_of_name<<" as base"<<std::endl;
//infostream<<"Setting "<<part_of_name<<" as base"<<std::endl;
/*
Copy it this way to get an alpha channel.
Otherwise images with alpha cannot be blitted on
@@ -812,7 +839,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
// Else blit on base.
else
{
//dstream<<"INFO: Blitting "<<part_of_name<<" on base"<<std::endl;
//infostream<<"Blitting "<<part_of_name<<" on base"<<std::endl;
// Size of the copied area
core::dimension2d<u32> dim = image->getDimension();
//core::dimension2d<u32> dim(16,16);
@@ -833,7 +860,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
{
// A special texture modification
dstream<<"INFO: generate_image(): generating special "
infostream<<"generate_image(): generating special "
<<"modification \""<<part_of_name<<"\""
<<std::endl;
@@ -856,7 +883,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
{
if(baseimg == NULL)
{
dstream<<"WARNING: generate_image(): baseimg==NULL "
infostream<<"generate_image(): baseimg==NULL "
<<"for part_of_name=\""<<part_of_name
<<"\", cancelling."<<std::endl;
return false;
@@ -950,7 +977,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
sf.next(":");
u32 w0 = stoi(sf.next("x"));
u32 h0 = stoi(sf.next(":"));
dstream<<"INFO: combined w="<<w0<<" h="<<h0<<std::endl;
infostream<<"combined w="<<w0<<" h="<<h0<<std::endl;
core::dimension2d<u32> dim(w0,h0);
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
while(sf.atend() == false)
@@ -958,7 +985,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
u32 x = stoi(sf.next(","));
u32 y = stoi(sf.next("="));
std::string filename = sf.next(":");
dstream<<"INFO: Adding \""<<filename
infostream<<"Adding \""<<filename
<<"\" to combined ("<<x<<","<<y<<")"
<<std::endl;
video::IImage *img = driver->createImageFromFile(
@@ -966,7 +993,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
if(img)
{
core::dimension2d<u32> dim = img->getDimension();
dstream<<"INFO: Size "<<dim.Width
infostream<<"Size "<<dim.Width
<<"x"<<dim.Height<<std::endl;
core::position2d<s32> pos_base(x, y);
video::IImage *img2 =
@@ -981,7 +1008,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
}
else
{
dstream<<"WARNING: img==NULL"<<std::endl;
infostream<<"img==NULL"<<std::endl;
}
}
}
@@ -993,7 +1020,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
{
if(baseimg == NULL)
{
dstream<<"WARNING: generate_image(): baseimg==NULL "
infostream<<"generate_image(): baseimg==NULL "
<<"for part_of_name=\""<<part_of_name
<<"\", cancelling."<<std::endl;
return false;
@@ -1013,7 +1040,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
{
if(baseimg != NULL)
{
dstream<<"WARNING: generate_image(): baseimg!=NULL "
infostream<<"generate_image(): baseimg!=NULL "
<<"for part_of_name=\""<<part_of_name
<<"\", cancelling."<<std::endl;
return false;
@@ -1023,14 +1050,14 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
std::string path = getTexturePath(filename.c_str());
dstream<<"INFO: generate_image(): Loading path \""<<path
infostream<<"generate_image(): Loading path \""<<path
<<"\""<<std::endl;
video::IImage *image = driver->createImageFromFile(path.c_str());
if(image == NULL)
{
dstream<<"WARNING: generate_image(): Loading path \""
infostream<<"generate_image(): Loading path \""
<<path<<"\" failed"<<std::endl;
}
else
@@ -1052,6 +1079,122 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
image->drop();
}
}
/*
"[makealpha:R,G,B:filename.png"
Use an image with converting one color to transparent.
*/
else if(part_of_name.substr(0,11) == "[makealpha:")
{
if(baseimg != NULL)
{
infostream<<"generate_image(): baseimg!=NULL "
<<"for part_of_name=\""<<part_of_name
<<"\", cancelling."<<std::endl;
return false;
}
Strfnd sf(part_of_name.substr(11));
u32 r1 = stoi(sf.next(","));
u32 g1 = stoi(sf.next(","));
u32 b1 = stoi(sf.next(":"));
std::string filename = sf.next("");
std::string path = getTexturePath(filename.c_str());
infostream<<"generate_image(): Loading path \""<<path
<<"\""<<std::endl;
video::IImage *image = driver->createImageFromFile(path.c_str());
if(image == NULL)
{
infostream<<"generate_image(): Loading path \""
<<path<<"\" failed"<<std::endl;
}
else
{
core::dimension2d<u32> dim = image->getDimension();
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
// Blit
image->copyTo(baseimg);
image->drop();
for(u32 y=0; y<dim.Height; y++)
for(u32 x=0; x<dim.Width; x++)
{
video::SColor c = baseimg->getPixel(x,y);
u32 r = c.getRed();
u32 g = c.getGreen();
u32 b = c.getBlue();
if(!(r == r1 && g == g1 && b == b1))
continue;
c.setAlpha(0);
baseimg->setPixel(x,y,c);
}
}
}
/*
"[makealpha2:R,G,B;R2,G2,B2:filename.png"
Use an image with converting two colors to transparent.
*/
else if(part_of_name.substr(0,12) == "[makealpha2:")
{
if(baseimg != NULL)
{
infostream<<"generate_image(): baseimg!=NULL "
<<"for part_of_name=\""<<part_of_name
<<"\", cancelling."<<std::endl;
return false;
}
Strfnd sf(part_of_name.substr(12));
u32 r1 = stoi(sf.next(","));
u32 g1 = stoi(sf.next(","));
u32 b1 = stoi(sf.next(";"));
u32 r2 = stoi(sf.next(","));
u32 g2 = stoi(sf.next(","));
u32 b2 = stoi(sf.next(":"));
std::string filename = sf.next("");
std::string path = getTexturePath(filename.c_str());
infostream<<"generate_image(): Loading path \""<<path
<<"\""<<std::endl;
video::IImage *image = driver->createImageFromFile(path.c_str());
if(image == NULL)
{
infostream<<"generate_image(): Loading path \""
<<path<<"\" failed"<<std::endl;
}
else
{
core::dimension2d<u32> dim = image->getDimension();
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
// Blit
image->copyTo(baseimg);
image->drop();
for(u32 y=0; y<dim.Height; y++)
for(u32 x=0; x<dim.Width; x++)
{
video::SColor c = baseimg->getPixel(x,y);
u32 r = c.getRed();
u32 g = c.getGreen();
u32 b = c.getBlue();
if(!(r == r1 && g == g1 && b == b1) &&
!(r == r2 && g == g2 && b == b2))
continue;
c.setAlpha(0);
baseimg->setPixel(x,y,c);
}
}
}
/*
[inventorycube{topimage{leftimage{rightimage
In every subimage, replace ^ with &.
@@ -1064,7 +1207,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
{
if(baseimg != NULL)
{
dstream<<"WARNING: generate_image(): baseimg!=NULL "
infostream<<"generate_image(): baseimg!=NULL "
<<"for part_of_name=\""<<part_of_name
<<"\", cancelling."<<std::endl;
return false;
@@ -1082,7 +1225,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
{
dstream<<"WARNING: generate_image(): EVDF_RENDER_TO_TARGET"
infostream<<"generate_image(): EVDF_RENDER_TO_TARGET"
" not supported. Creating fallback image"<<std::endl;
baseimg = generate_image_from_scratch(
imagename_top, device);
@@ -1091,7 +1234,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
u32 w0 = 64;
u32 h0 = 64;
//dstream<<"INFO: inventorycube w="<<w0<<" h="<<h0<<std::endl;
//infostream<<"inventorycube w="<<w0<<" h="<<h0<<std::endl;
core::dimension2d<u32> dim(w0,h0);
// Generate images for the faces of the cube
@@ -1193,7 +1336,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
}
else
{
dstream<<"WARNING: generate_image(): Invalid "
infostream<<"generate_image(): Invalid "
" modification: \""<<part_of_name<<"\""<<std::endl;
}
}

View File

@@ -283,9 +283,9 @@ struct TileSpec
TileSpec():
texture(0),
alpha(255),
material_type(MATERIAL_ALPHA_NONE),
//material_type(MATERIAL_ALPHA_NONE),
// Use this so that leaves don't need a separate material
//material_type(MATERIAL_ALPHA_SIMPLE),
material_type(MATERIAL_ALPHA_SIMPLE),
material_flags(
//0 // <- DEBUG, Use the one below
MATERIAL_FLAG_BACKFACE_CULLING
@@ -304,7 +304,7 @@ struct TileSpec
}
// Sets everything else except the texture in the material
void applyMaterialOptions(video::SMaterial &material)
void applyMaterialOptions(video::SMaterial &material) const
{
if(alpha != 255 && material_type != MATERIAL_ALPHA_VERTEX)
dstream<<"WARNING: TileSpec: alpha != 255 "

View File

@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gettime.h"
#include "sha1.h"
#include "base64.h"
#include "log.h"
TimeTaker::TimeTaker(const char *name, u32 *result)
{
@@ -47,7 +48,7 @@ u32 TimeTaker::stop(bool quiet)
else
{
if(quiet == false)
std::cout<<m_name<<" took "<<dtime<<"ms"<<std::endl;
infostream<<m_name<<" took "<<dtime<<"ms"<<std::endl;
}
m_running = false;
return dtime;
@@ -156,14 +157,50 @@ void mysrand(unsigned seed)
next = seed;
}
int myrand_range(int min, int max)
{
if(max-min > MYRAND_MAX)
{
errorstream<<"WARNING: myrand_range: max-min > MYRAND_MAX"<<std::endl;
assert(0);
}
if(min > max)
{
assert(0);
return max;
}
return (myrand()%(max-min+1))+min;
}
#ifndef SERVER
// Sets the color of all vertices in the mesh
void setMeshVerticesColor(scene::IMesh* mesh, video::SColor& color)
{
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;
}
}
}
#endif
/*
blockpos: position of block in block coordinates
camera_pos: position of camera in nodes
camera_dir: an unit vector pointing to camera direction
range: viewing range
*/
bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range,
f32 *distance_ptr)
bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
f32 camera_fov, f32 range, f32 *distance_ptr)
{
v3s16 blockpos_nodes = blockpos_b * MAP_BLOCKSIZE;
@@ -199,22 +236,21 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range,
// If block is (nearly) touching the camera, don't
// bother validating further (that is, render it anyway)
if(d > block_max_radius * 1.5)
{
// Cosine of the angle between the camera direction
// and the block direction (camera_dir is an unit vector)
f32 cosangle = dforward / d;
// Compensate for the size of the block
// (as the block has to be shown even if it's a bit off FOV)
// This is an estimate.
cosangle += block_max_radius / dforward;
if(d < block_max_radius)
return true;
// Cosine of the angle between the camera direction
// and the block direction (camera_dir is an unit vector)
f32 cosangle = dforward / d;
// Compensate for the size of the block
// (as the block has to be shown even if it's a bit off FOV)
// This is an estimate, plus an arbitary factor
cosangle += block_max_radius / d * 0.5;
// If block is not in the field of view, skip it
//if(cosangle < cos(FOV_ANGLE/2))
if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
return false;
}
// If block is not in the field of view, skip it
if(cosangle < cos(camera_fov / 2))
return false;
return true;
}

View File

@@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <jthread.h>
#include <jmutex.h>
#include <jmutexautolock.h>
#include <cstring>
#include "common_irrlicht.h"
#include "debug.h"
@@ -221,13 +222,13 @@ inline u16 readU16(std::istream &is)
return readU16((u8*)buf);
}
inline void writeU32(std::ostream &os, u16 p)
inline void writeU32(std::ostream &os, u32 p)
{
char buf[4];
writeU16((u8*)buf, p);
os.write(buf, 4);
}
inline u16 readU32(std::istream &is)
inline u32 readU32(std::istream &is)
{
char buf[4];
is.read(buf, 4);
@@ -342,26 +343,59 @@ template <typename T>
class Buffer
{
public:
Buffer()
{
m_size = 0;
data = NULL;
}
Buffer(unsigned int size)
{
m_size = size;
data = new T[size];
if(size != 0)
data = new T[size];
else
data = NULL;
}
Buffer(const Buffer &buffer)
{
m_size = buffer.m_size;
data = new T[buffer.m_size];
memcpy(data, buffer.data, buffer.m_size);
if(m_size != 0)
{
data = new T[buffer.m_size];
memcpy(data, buffer.data, buffer.m_size);
}
else
data = NULL;
}
Buffer(T *t, unsigned int size)
{
m_size = size;
data = new T[size];
memcpy(data, t, size);
if(size != 0)
{
data = new T[size];
memcpy(data, t, size);
}
else
data = NULL;
}
~Buffer()
{
delete[] data;
drop();
}
Buffer& operator=(const Buffer &buffer)
{
if(this == &buffer)
return *this;
drop();
m_size = buffer.m_size;
if(m_size != 0)
{
data = new T[buffer.m_size];
memcpy(data, buffer.data, buffer.m_size);
}
else
data = NULL;
return *this;
}
T & operator[](unsigned int i) const
{
@@ -376,6 +410,11 @@ class Buffer
return m_size;
}
private:
void drop()
{
if(data)
delete[] data;
}
T *data;
unsigned int m_size;
};
@@ -470,6 +509,10 @@ class SharedBuffer
{
return m_size;
}
operator Buffer<T>() const
{
return Buffer<T>(data, m_size);
}
private:
void drop()
{
@@ -553,6 +596,11 @@ class TimeTaker
u32 *m_result;
};
#ifndef SERVER
// Sets the color of all vertices in the mesh
void setMeshVerticesColor(scene::IMesh* mesh, video::SColor& color);
#endif
// Calculates the borders of a "d-radius" cube
inline void getFacePositions(core::list<v3s16> &list, u16 d)
{
@@ -804,6 +852,35 @@ inline float wrapDegrees(float f)
return f;
}
/* Wrap to 0...360 */
inline float wrapDegrees_0_360(float f)
{
// Take examples of f=10, f=720.5, f=-0.5, f=-360.5
// This results in
// 10, 720, -1, -361
int i = floor(f);
// 0, 2, 0, -1
int l = i / 360;
// Wrap to 0...360
// 0, 2, -1, -2
if(i < 0)
l -= 1;
// 0, 720, 0, -360
int k = l * 360;
// 10, 0.5, -0.5, -0.5
f -= float(k);
return f;
}
/* Wrap to -180...180 */
inline float wrapDegrees_180(float f)
{
f += 180;
f = wrapDegrees_0_360(f);
f -= 180;
return f;
}
inline std::string lowercase(const std::string &s)
{
std::string s2;
@@ -935,557 +1012,6 @@ class SimpleThread : public JThread
}
};
/*
Config stuff
*/
enum ValueType
{
VALUETYPE_STRING,
VALUETYPE_FLAG // Doesn't take any arguments
};
struct ValueSpec
{
ValueSpec(ValueType a_type, const char *a_help=NULL)
{
type = a_type;
help = a_help;
}
ValueType type;
const char *help;
};
class Settings
{
public:
Settings()
{
m_mutex.Init();
}
void writeLines(std::ostream &os)
{
JMutexAutoLock lock(m_mutex);
for(core::map<std::string, std::string>::Iterator
i = m_settings.getIterator();
i.atEnd() == false; i++)
{
std::string name = i.getNode()->getKey();
std::string value = i.getNode()->getValue();
os<<name<<" = "<<value<<"\n";
}
}
bool parseConfigLine(const std::string &line)
{
JMutexAutoLock lock(m_mutex);
std::string trimmedline = trim(line);
// Ignore comments
if(trimmedline[0] == '#')
return true;
//dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
Strfnd sf(trim(line));
std::string name = sf.next("=");
name = trim(name);
if(name == "")
return true;
std::string value = sf.next("\n");
value = trim(value);
/*dstream<<"Config name=\""<<name<<"\" value=\""
<<value<<"\""<<std::endl;*/
m_settings[name] = value;
return true;
}
// Returns false on EOF
bool parseConfigObject(std::istream &is)
{
if(is.eof())
return false;
/*
NOTE: This function might be expanded to allow multi-line
settings.
*/
std::string line;
std::getline(is, line);
//dstream<<"got line: \""<<line<<"\""<<std::endl;
return parseConfigLine(line);
}
/*
Read configuration file
Returns true on success
*/
bool readConfigFile(const char *filename)
{
std::ifstream is(filename);
if(is.good() == false)
{
dstream<<"Error opening configuration file \""
<<filename<<"\""<<std::endl;
return false;
}
dstream<<"Parsing configuration file: \""
<<filename<<"\""<<std::endl;
while(parseConfigObject(is));
return true;
}
/*
Reads a configuration object from stream (usually a single line)
and adds it to dst.
Preserves comments and empty lines.
Settings that were added to dst are also added to updated.
key of updated is setting name, value of updated is dummy.
Returns false on EOF
*/
bool getUpdatedConfigObject(std::istream &is,
core::list<std::string> &dst,
core::map<std::string, bool> &updated)
{
JMutexAutoLock lock(m_mutex);
if(is.eof())
return false;
// NOTE: This function will be expanded to allow multi-line settings
std::string line;
std::getline(is, line);
std::string trimmedline = trim(line);
std::string line_end = "";
if(is.eof() == false)
line_end = "\n";
// Ignore comments
if(trimmedline[0] == '#')
{
dst.push_back(line+line_end);
return true;
}
Strfnd sf(trim(line));
std::string name = sf.next("=");
name = trim(name);
if(name == "")
{
dst.push_back(line+line_end);
return true;
}
std::string value = sf.next("\n");
value = trim(value);
if(m_settings.find(name))
{
std::string newvalue = m_settings[name];
if(newvalue != value)
{
dstream<<"Changing value of \""<<name<<"\" = \""
<<value<<"\" -> \""<<newvalue<<"\""
<<std::endl;
}
dst.push_back(name + " = " + newvalue + line_end);
updated[name] = true;
}
return true;
}
/*
Updates configuration file
Returns true on success
*/
bool updateConfigFile(const char *filename)
{
dstream<<"Updating configuration file: \""
<<filename<<"\""<<std::endl;
core::list<std::string> objects;
core::map<std::string, bool> updated;
// Read and modify stuff
{
std::ifstream is(filename);
if(is.good() == false)
{
dstream<<"INFO: updateConfigFile():"
" Error opening configuration file"
" for reading: \""
<<filename<<"\""<<std::endl;
}
else
{
while(getUpdatedConfigObject(is, objects, updated));
}
}
JMutexAutoLock lock(m_mutex);
// Write stuff back
{
std::ofstream os(filename);
if(os.good() == false)
{
dstream<<"Error opening configuration file"
" for writing: \""
<<filename<<"\""<<std::endl;
return false;
}
/*
Write updated stuff
*/
for(core::list<std::string>::Iterator
i = objects.begin();
i != objects.end(); i++)
{
os<<(*i);
}
/*
Write stuff that was not already in the file
*/
for(core::map<std::string, std::string>::Iterator
i = m_settings.getIterator();
i.atEnd() == false; i++)
{
if(updated.find(i.getNode()->getKey()))
continue;
std::string name = i.getNode()->getKey();
std::string value = i.getNode()->getValue();
dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
<<std::endl;
os<<name<<" = "<<value<<"\n";
}
}
return true;
}
/*
NOTE: Types of allowed_options are ignored
returns true on success
*/
bool parseCommandLine(int argc, char *argv[],
core::map<std::string, ValueSpec> &allowed_options)
{
int i=1;
for(;;)
{
if(i >= argc)
break;
std::string argname = argv[i];
if(argname.substr(0, 2) != "--")
{
dstream<<"Invalid command-line parameter \""
<<argname<<"\": --<option> expected."<<std::endl;
return false;
}
i++;
std::string name = argname.substr(2);
core::map<std::string, ValueSpec>::Node *n;
n = allowed_options.find(name);
if(n == NULL)
{
dstream<<"Unknown command-line parameter \""
<<argname<<"\""<<std::endl;
return false;
}
ValueType type = n->getValue().type;
std::string value = "";
if(type == VALUETYPE_FLAG)
{
value = "true";
}
else
{
if(i >= argc)
{
dstream<<"Invalid command-line parameter \""
<<name<<"\": missing value"<<std::endl;
return false;
}
value = argv[i];
i++;
}
dstream<<"Valid command-line parameter: \""
<<name<<"\" = \""<<value<<"\""
<<std::endl;
set(name, value);
}
return true;
}
void set(std::string name, std::string value)
{
JMutexAutoLock lock(m_mutex);
m_settings[name] = value;
}
void set(std::string name, const char *value)
{
JMutexAutoLock lock(m_mutex);
m_settings[name] = value;
}
void setDefault(std::string name, std::string value)
{
JMutexAutoLock lock(m_mutex);
m_defaults[name] = value;
}
bool exists(std::string name)
{
JMutexAutoLock lock(m_mutex);
return (m_settings.find(name) || m_defaults.find(name));
}
std::string get(std::string name)
{
JMutexAutoLock lock(m_mutex);
core::map<std::string, std::string>::Node *n;
n = m_settings.find(name);
if(n == NULL)
{
n = m_defaults.find(name);
if(n == NULL)
{
dstream<<"INFO: Settings: Setting not found: \""
<<name<<"\""<<std::endl;
throw SettingNotFoundException("Setting not found");
}
}
return n->getValue();
}
bool getBool(std::string name)
{
return is_yes(get(name));
}
bool getFlag(std::string name)
{
try
{
return getBool(name);
}
catch(SettingNotFoundException &e)
{
return false;
}
}
// Asks if empty
bool getBoolAsk(std::string name, std::string question, bool def)
{
// If it is in settings
if(exists(name))
return getBool(name);
std::string s;
char templine[10];
std::cout<<question<<" [y/N]: ";
std::cin.getline(templine, 10);
s = templine;
if(s == "")
return def;
return is_yes(s);
}
float getFloat(std::string name)
{
return stof(get(name));
}
u16 getU16(std::string name)
{
return stoi(get(name), 0, 65535);
}
u16 getU16Ask(std::string name, std::string question, u16 def)
{
// If it is in settings
if(exists(name))
return getU16(name);
std::string s;
char templine[10];
std::cout<<question<<" ["<<def<<"]: ";
std::cin.getline(templine, 10);
s = templine;
if(s == "")
return def;
return stoi(s, 0, 65535);
}
s16 getS16(std::string name)
{
return stoi(get(name), -32768, 32767);
}
s32 getS32(std::string name)
{
return stoi(get(name));
}
v3f getV3F(std::string name)
{
v3f value;
Strfnd f(get(name));
f.next("(");
value.X = stof(f.next(","));
value.Y = stof(f.next(","));
value.Z = stof(f.next(")"));
return value;
}
u64 getU64(std::string name)
{
u64 value = 0;
std::string s = get(name);
std::istringstream ss(s);
ss>>value;
return value;
}
void setBool(std::string name, bool value)
{
if(value)
set(name, "true");
else
set(name, "false");
}
void setS32(std::string name, s32 value)
{
set(name, itos(value));
}
void setFloat(std::string name, float value)
{
set(name, ftos(value));
}
void setV3F(std::string name, v3f value)
{
std::ostringstream os;
os<<"("<<value.X<<","<<value.Y<<","<<value.Z<<")";
set(name, os.str());
}
void setU64(std::string name, u64 value)
{
std::ostringstream os;
os<<value;
set(name, os.str());
}
void clear()
{
JMutexAutoLock lock(m_mutex);
m_settings.clear();
m_defaults.clear();
}
Settings & operator+=(Settings &other)
{
JMutexAutoLock lock(m_mutex);
JMutexAutoLock lock2(other.m_mutex);
if(&other == this)
return *this;
for(core::map<std::string, std::string>::Iterator
i = other.m_settings.getIterator();
i.atEnd() == false; i++)
{
m_settings.insert(i.getNode()->getKey(),
i.getNode()->getValue());
}
for(core::map<std::string, std::string>::Iterator
i = other.m_defaults.getIterator();
i.atEnd() == false; i++)
{
m_defaults.insert(i.getNode()->getKey(),
i.getNode()->getValue());
}
return *this;
}
Settings & operator=(Settings &other)
{
JMutexAutoLock lock(m_mutex);
JMutexAutoLock lock2(other.m_mutex);
if(&other == this)
return *this;
clear();
(*this) += other;
return *this;
}
private:
core::map<std::string, std::string> m_settings;
core::map<std::string, std::string> m_defaults;
// All methods that access m_settings/m_defaults directly should lock this.
JMutex m_mutex;
};
/*
FIFO queue (well, actually a FILO also)
*/
@@ -1746,27 +1272,14 @@ int myrand(void);
void mysrand(unsigned seed);
#define MYRAND_MAX 32767
inline int myrand_range(int min, int max)
{
if(max-min > MYRAND_MAX)
{
dstream<<"WARNING: myrand_range: max-min > MYRAND_MAX"<<std::endl;
assert(0);
}
if(min > max)
{
assert(0);
return max;
}
return (myrand()%(max-min+1))+min;
}
int myrand_range(int min, int max);
/*
Miscellaneous functions
*/
bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range,
f32 *distance_ptr=NULL);
bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
f32 camera_fov, f32 range, f32 *distance_ptr=NULL);
/*
Queue with unique values with fast checking of value existence

View File

@@ -24,7 +24,7 @@ f 128 79 0 # CONTENT_CHEST
80d 219 202 178 # CONTENT_MOSSYCOBBLE
80e 78 154 6 # CONTENT_GRAVEL
80f 204 0 0 # CONTENT_SANDSTONE
810 211 215 207 # CONTENT_CACTUS
810 0 215 0 # CONTENT_CACTUS
811 170 50 25 # CONTENT_BRICK
812 104 78 42 # CONTENT_CLAY
813 58 105 18 # CONTENT_PAPYRUS
@@ -33,3 +33,4 @@ f 128 79 0 # CONTENT_CHEST
816 62 101 25 # CONTENT_JUNGLEGRASS
817 255 153 255 # CONTENT_NC
818 102 50 255 # CONTENT_NC_RB
819 200 0 0 # CONTENT_APPLE

172
util/minetestmapper.py Executable file → Normal file
View File

@@ -29,10 +29,9 @@ import time
import getopt
import sys
import array
import cStringIO
from PIL import Image, ImageDraw, ImageFont, ImageColor
CONTENT_WATER = [2, 9]
TRANSLATION_TABLE = {
1: 0x800, # CONTENT_GRASS
4: 0x801, # CONTENT_TREE
@@ -88,9 +87,19 @@ def int_to_hex4(i):
def getBlockAsInteger(p):
return p[2]*16777216 + p[1]*4096 + p[0]
def getIntegerAsBlock(i):
return i%4096, int(i/4096)%4096, int(i/16777216)%4096
def unsignedToSigned(i, max_positive):
if i < max_positive:
return i
else:
return i - 2*max_positive
def getIntegerAsBlock(i):
x = unsignedToSigned(i % 4096, 2048)
i = int((i - x) / 4096)
y = unsignedToSigned(i % 4096, 2048)
i = int((i - y) / 4096)
z = unsignedToSigned(i % 4096, 2048)
return x,y,z
def limit(i, l, h):
if(i > h):
@@ -101,14 +110,15 @@ def limit(i, l, h):
def usage():
print "TODO: Help"
print("TODO: Help")
try:
opts, args = getopt.getopt(sys.argv[1:], "hi:o:", ["help", "input=",
"output=", "bgcolor=", "scalecolor=", "origincolor=",
"playercolor=", "draworigin", "drawplayers", "drawscale"])
except getopt.GetoptError, err:
"playercolor=", "draworigin", "drawplayers", "drawscale",
"drawunderground"])
except getopt.GetoptError as err:
# print help information and exit:
print str(err) # will print something like "option -a not recognized"
print(str(err)) # will print something like "option -a not recognized"
usage()
sys.exit(2)
@@ -122,6 +132,7 @@ playercolor = "red"
drawscale = False
drawplayers = False
draworigin = False
drawunderground = False
sector_xmin = -1500 / 16
sector_xmax = 1500 / 16
@@ -151,6 +162,8 @@ for o, a in opts:
drawplayers = True
elif o == "--draworigin":
draworigin = True
elif o == "--drawunderground":
drawunderground = True
else:
assert False, "unhandled option"
@@ -160,9 +173,9 @@ if path[-1:] != "/" and path[-1:] != "\\":
# Load color information for the blocks.
colors = {}
try:
f = file("colors.txt")
f = file("colors.txt")
except IOError:
f = file(os.path.join(os.path.dirname(__file__), "colors.txt"))
f = file(os.path.join(os.path.dirname(__file__), "colors.txt"))
for line in f:
values = string.split(line)
colors[int(values[0], 16)] = (
@@ -190,7 +203,7 @@ if os.path.exists(path + "map.sqlite"):
if not r:
break
x, y, z = getIntegerAsBlock (r[0])
x, y, z = getIntegerAsBlock(r[0])
if x < sector_xmin or x > sector_xmax:
continue
@@ -223,6 +236,9 @@ if os.path.exists(path + "sectors"):
xlist.append(x)
zlist.append(z)
# Get rid of doubles
xlist, zlist = zip(*sorted(set(zip(xlist, zlist))))
minx = min(xlist)
minz = min(zlist)
maxx = max(xlist)
@@ -231,7 +247,7 @@ maxz = max(zlist)
w = (maxx - minx) * 16 + 16
h = (maxz - minz) * 16 + 16
print "w=" + str(w) + " h=" + str(h)
print("w=" + str(w) + " h=" + str(h))
im = Image.new("RGB", (w + border, h + border), bgcolor)
draw = ImageDraw.Draw(im)
@@ -241,12 +257,15 @@ stuff = {}
starttime = time.time()
CONTENT_WATER = 2
def data_is_air(d):
def content_is_water(d):
return d in [2, 9]
def content_is_air(d):
return d in [126, 127, 254]
def read_blocknum(mapdata, version, datapos):
def read_content(mapdata, version, datapos):
if version == 20:
if mapdata[datapos] < 0x80:
return mapdata[datapos]
@@ -258,7 +277,7 @@ def read_blocknum(mapdata, version, datapos):
raise Exception("Unsupported map format: " + str(version))
def read_mapdata(f, version, pixellist, water):
def read_mapdata(f, version, pixellist, water, day_night_differs):
global stuff # oh my :-)
dec_o = zlib.decompressobj()
@@ -270,34 +289,35 @@ def read_mapdata(f, version, pixellist, water):
f.close()
if(len(mapdata) < 4096):
print "bad: " + xhex + "/" + zhex + "/" + yhex + " " + \
str(len(mapdata))
print("bad: " + xhex + "/" + zhex + "/" + yhex + " " + \
str(len(mapdata)))
else:
chunkxpos = xpos * 16
chunkypos = ypos * 16
chunkzpos = zpos * 16
blocknum = 0
content = 0
datapos = 0
for (x, z) in reversed(pixellist):
for y in reversed(range(16)):
datapos = x + y * 16 + z * 256
blocknum = read_blocknum(mapdata, version, datapos)
if not data_is_air(blocknum) and blocknum in colors:
if blocknum in CONTENT_WATER:
water[(x, z)] += 1
# Add dummy stuff for drawing sea without seabed
stuff[(chunkxpos + x, chunkzpos + z)] = (
chunkypos + y, blocknum, water[(x, z)])
else:
pixellist.remove((x, z))
# Memorize information on the type and height of
# the block and for drawing the picture.
stuff[(chunkxpos + x, chunkzpos + z)] = (
chunkypos + y, blocknum, water[(x, z)])
break
elif not data_is_air(blocknum) and blocknum not in colors:
print "strange block: %s/%s/%s x: %d y: %d z: %d \
block id: %x" % (xhex, zhex, yhex, x, y, z, blocknum)
content = read_content(mapdata, version, datapos)
if content_is_air(content):
pass
elif content_is_water(content):
water[(x, z)] += 1
# Add dummy stuff for drawing sea without seabed
stuff[(chunkxpos + x, chunkzpos + z)] = (
chunkypos + y, content, water[(x, z)], day_night_differs)
elif content in colors:
# Memorize information on the type and height of
# the block and for drawing the picture.
stuff[(chunkxpos + x, chunkzpos + z)] = (
chunkypos + y, content, water[(x, z)], day_night_differs)
pixellist.remove((x, z))
break
else:
print("strange block: %s/%s/%s x: %d y: %d z: %d \
block id: %x" % (xhex, zhex, yhex, x, y, z, content))
# Go through all sectors.
for n in range(len(xlist)):
@@ -337,8 +357,9 @@ for n in range(len(xlist)):
sectortype = ""
if cur:
ps = getBlockAsInteger((xpos, 0, zpos))
cur.execute("SELECT `pos` FROM `blocks` WHERE `pos`>=? AND `pos`<?", (ps, ps + 4096))
psmin = getBlockAsInteger((xpos, -2048, zpos))
psmax = getBlockAsInteger((xpos, 2047, zpos))
cur.execute("SELECT `pos` FROM `blocks` WHERE `pos`>=? AND `pos`<=? AND (`pos` - ?) % 4096 = 0", (psmin, psmax, psmin))
while True:
r = cur.fetchone()
if not r:
@@ -383,72 +404,39 @@ for n in range(len(xlist)):
water[(x, z)] = 0
# Go through the Y axis from top to bottom.
ylist2 = []
for ypos in reversed(ylist):
yhex = int_to_hex4(ypos)
filename = ""
if sectortype == "sqlite":
ps = getBlockAsInteger((xpos, ypos, zpos))
cur.execute("SELECT `data` FROM `blocks` WHERE `pos`==? LIMIT 1", (ps,))
r = cur.fetchone()
if not r:
continue
filename = "mtm_tmp"
f = file(filename, 'wb')
f.write(r[0])
f.close()
f = cStringIO.StringIO(r[0])
else:
if sectortype == "old":
filename = path + "sectors/" + sector1 + "/" + yhex.lower()
else:
filename = path + "sectors2/" + sector2 + "/" + yhex.lower()
f = file(filename, "rb")
f = file(filename, "rb")
# Let's just memorize these even though it's not really necessary.
version = ord(f.read(1))
flags = f.read(1)
# Checking day and night differs -flag
if not ord(flags) & 2:
ylist2.append((ypos, filename))
f.close()
continue
day_night_differs = ((ord(flags) & 2) != 0)
read_mapdata(f, version, pixellist, water)
read_mapdata(f, version, pixellist, water, day_night_differs)
# After finding all the pixels in the sector, we can move on to
# the next sector without having to continue the Y axis.
if(len(pixellist) == 0):
break
if len(pixellist) > 0:
for (ypos, filename) in ylist2:
ps = getBlockAsInteger((xpos, ypos, zpos))
cur.execute("SELECT `data` FROM `blocks` WHERE `pos`==? LIMIT 1", (ps,))
r = cur.fetchone()
if not r:
continue
filename = "mtm_tmp"
f = file(filename, 'wb')
f.write(r[0])
f.close()
f = file(filename, "rb")
version = ord(f.read(1))
flags = f.read(1)
read_mapdata(f, version, pixellist, water)
# After finding all the pixels in the sector, we can move on
# to the next sector without having to continue the Y axis.
if(len(pixellist) == 0):
break
print "Drawing image"
print("Drawing image")
# Drawing the picture
starttime = time.time()
n = 0
@@ -474,18 +462,29 @@ for (x, z) in stuff.iterkeys():
n += 1
(r, g, b) = colors[stuff[(x, z)][1]]
dnd = stuff[(x, z)][3] # day/night differs?
if not dnd and not drawunderground:
if stuff[(x, z)][2] > 0: # water
(r, g, b) = colors[CONTENT_WATER]
else:
continue
# Comparing heights of a couple of adjacent blocks and changing
# brightness accordingly.
try:
c = stuff[(x, z)][1]
c1 = stuff[(x - 1, z)][1]
c2 = stuff[(x, z + 1)][1]
c = stuff[(x, z)][1]
if c1 not in CONTENT_WATER and c2 not in CONTENT_WATER and \
c not in CONTENT_WATER:
y1 = stuff[(x - 1, z)][0]
y2 = stuff[(x, z + 1)][0]
dnd1 = stuff[(x - 1, z)][3]
dnd2 = stuff[(x, z + 1)][3]
if not dnd:
d = -69
elif not content_is_water(c1) and not content_is_water(c2) and \
not content_is_water(c):
y = stuff[(x, z)][0]
y1 = stuff[(x - 1, z)][0] if dnd1 else y
y2 = stuff[(x, z + 1)][0] if dnd2 else y
d = ((y - y1) + (y - y2)) * 12
else:
d = 0
@@ -542,10 +541,10 @@ if drawplayers:
p = string.split(line)
if p[0] == "name":
name = p[2]
print filename + ": name = " + name
print(filename + ": name = " + name)
if p[0] == "position":
position = string.split(p[2][1:-1], ",")
print filename + ": position = " + p[2]
print(filename + ": position = " + p[2])
if len(name) > 0 and len(position) == 3:
x = (int(float(position[0]) / 10 - minx * 16))
z = int(h - (float(position[2]) / 10 - minz * 16))
@@ -557,8 +556,5 @@ if drawplayers:
except OSError:
pass
if os.path.isfile("mtm_tmp"):
os.remove("mtm_tmp")
print "Saving"
print("Saving")
im.save(output)

Some files were not shown because too many files have changed in this diff Show More