aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShadowNinja <shadowninja@minetest.net>2017-06-03 14:55:10 -0400
committerShadowNinja <shadowninja@minetest.net>2017-06-03 14:55:10 -0400
commitcaecdb681c428c1aab9c0f7eec2570c0460f995c (patch)
treee5115982ea59bbf2343ba9b35bc4a0cfbb56f407 /src
parent81d56b94919dceb7b2e51d70b21a7ca22f852bd5 (diff)
parent80dc961d24e1964e25d57039ddb2ba639f9f4d22 (diff)
downloadminetest-caecdb681c428c1aab9c0f7eec2570c0460f995c.tar.gz
minetest-caecdb681c428c1aab9c0f7eec2570c0460f995c.tar.bz2
minetest-caecdb681c428c1aab9c0f7eec2570c0460f995c.zip
Merge 0.4.16 into stable-0.4
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt51
-rw-r--r--src/activeobject.h14
-rw-r--r--src/ban.h2
-rw-r--r--src/camera.cpp48
-rw-r--r--src/camera.h32
-rw-r--r--src/cavegen.cpp146
-rw-r--r--src/cavegen.h71
-rw-r--r--src/cguittfont/CGUITTFont.cpp4
-rw-r--r--src/cguittfont/CGUITTFont.h7
-rw-r--r--src/chat.cpp27
-rw-r--r--src/chat.h11
-rw-r--r--src/client.cpp597
-rw-r--r--src/client.h250
-rw-r--r--src/client/CMakeLists.txt1
-rw-r--r--src/client/clientlauncher.cpp108
-rw-r--r--src/client/clientlauncher.h37
-rw-r--r--src/client/inputhandler.cpp119
-rw-r--r--src/client/inputhandler.h360
-rw-r--r--src/client/joystick_controller.cpp108
-rw-r--r--src/client/joystick_controller.h9
-rw-r--r--src/client/keys.h15
-rw-r--r--src/client/tile.cpp224
-rw-r--r--src/client/tile.h137
-rw-r--r--src/clientenvironment.cpp847
-rw-r--r--src/clientenvironment.h195
-rw-r--r--src/clientiface.cpp45
-rw-r--r--src/clientiface.h29
-rw-r--r--src/clientmap.cpp193
-rw-r--r--src/clientmap.h21
-rw-r--r--src/clientmedia.cpp16
-rw-r--r--src/clientmedia.h7
-rw-r--r--src/clientobject.cpp9
-rw-r--r--src/clientobject.h40
-rw-r--r--src/clientsimpleobject.h7
-rw-r--r--src/cloudparams.h33
-rw-r--r--src/clouds.cpp90
-rw-r--r--src/clouds.h54
-rw-r--r--src/collision.cpp8
-rw-r--r--src/constants.h8
-rw-r--r--src/content_abm.cpp8
-rw-r--r--src/content_abm.h1
-rw-r--r--src/content_cao.cpp194
-rw-r--r--src/content_cao.h30
-rw-r--r--src/content_cso.cpp16
-rw-r--r--src/content_mapblock.cpp2897
-rw-r--r--src/content_mapblock.h123
-rw-r--r--src/content_sao.cpp751
-rw-r--r--src/content_sao.h202
-rw-r--r--src/craftdef.cpp3
-rw-r--r--src/craftdef.h11
-rw-r--r--src/database-dummy.h10
-rw-r--r--src/database-files.cpp179
-rw-r--r--src/database-files.h46
-rw-r--r--src/database-leveldb.h7
-rw-r--r--src/database-postgresql.cpp471
-rw-r--r--src/database-postgresql.h115
-rw-r--r--src/database-redis.cpp15
-rw-r--r--src/database-redis.h5
-rw-r--r--src/database-sqlite3.cpp401
-rw-r--r--src/database-sqlite3.h163
-rw-r--r--src/database.cpp4
-rw-r--r--src/database.h32
-rw-r--r--src/defaultsettings.cpp253
-rw-r--r--src/defaultsettings.h1
-rw-r--r--src/drawscene.cpp125
-rw-r--r--src/drawscene.h6
-rw-r--r--src/dungeongen.cpp126
-rw-r--r--src/dungeongen.h8
-rw-r--r--src/emerge.cpp23
-rw-r--r--src/emerge.h3
-rw-r--r--src/environment.cpp2733
-rw-r--r--src/environment.h542
-rw-r--r--src/exceptions.h9
-rw-r--r--src/face_position_cache.cpp110
-rw-r--r--src/face_position_cache.h44
-rw-r--r--src/filecache.h10
-rw-r--r--src/fontengine.cpp26
-rw-r--r--src/game.cpp2021
-rw-r--r--src/game.h129
-rw-r--r--src/gamedef.h41
-rw-r--r--src/gameparams.h3
-rw-r--r--src/genericobject.cpp26
-rw-r--r--src/genericobject.h12
-rw-r--r--src/gettime.h29
-rw-r--r--src/gmp/CMakeLists.txt7
-rw-r--r--src/gmp/mini-gmp.c4130
-rw-r--r--src/gmp/mini-gmp.h256
-rw-r--r--src/guiChatConsole.cpp22
-rw-r--r--src/guiChatConsole.h4
-rw-r--r--src/guiEngine.cpp40
-rw-r--r--src/guiEngine.h14
-rw-r--r--src/guiFileSelectMenu.cpp21
-rw-r--r--src/guiFileSelectMenu.h29
-rw-r--r--src/guiFormSpecMenu.cpp363
-rw-r--r--src/guiFormSpecMenu.h177
-rw-r--r--src/guiKeyChangeMenu.cpp26
-rw-r--r--src/guiKeyChangeMenu.h18
-rw-r--r--src/guiPasswordChange.cpp173
-rw-r--r--src/guiPasswordChange.h23
-rw-r--r--src/guiTable.cpp2
-rw-r--r--src/guiTable.h11
-rw-r--r--src/guiVolumeChange.cpp63
-rw-r--r--src/httpfetch.cpp22
-rw-r--r--src/httpfetch.h23
-rw-r--r--src/hud.cpp73
-rw-r--r--src/hud.h14
-rw-r--r--src/intlGUIEditBox.cpp39
-rw-r--r--src/intlGUIEditBox.h2
-rw-r--r--src/inventory.cpp114
-rw-r--r--src/inventory.h21
-rw-r--r--src/inventorymanager.cpp7
-rw-r--r--src/irr_aabb3d.h1
-rw-r--r--src/irr_v2d.h1
-rw-r--r--src/irr_v3d.h1
-rw-r--r--src/irrlicht_changes/static_text.cpp4
-rw-r--r--src/irrlichttypes_bloated.h1
-rw-r--r--src/irrlichttypes_extrabloated.h1
-rw-r--r--src/itemdef.cpp117
-rw-r--r--src/itemdef.h35
-rw-r--r--src/itemgroup.h6
-rw-r--r--src/itemstackmetadata.cpp43
-rw-r--r--src/itemstackmetadata.h35
-rw-r--r--src/jsoncpp/json/CMakeLists.txt7
-rw-r--r--src/jsoncpp/json/UPDATING16
-rw-r--r--src/jsoncpp/json/json.h1914
-rw-r--r--src/jsoncpp/json/jsoncpp.cpp4367
-rw-r--r--src/keycode.cpp8
-rw-r--r--src/keycode.h7
-rw-r--r--src/light.cpp351
-rw-r--r--src/light.h31
-rw-r--r--src/localplayer.cpp638
-rw-r--r--src/localplayer.h77
-rw-r--r--src/lua/CMakeLists.txt77
-rw-r--r--src/lua/COPYRIGHT34
-rw-r--r--src/lua/src/CMakeLists.txt54
-rw-r--r--src/lua/src/lapi.c1087
-rw-r--r--src/lua/src/lapi.h16
-rw-r--r--src/lua/src/lauxlib.c653
-rw-r--r--src/lua/src/lauxlib.h174
-rw-r--r--src/lua/src/lbaselib.c653
-rw-r--r--src/lua/src/lcode.c839
-rw-r--r--src/lua/src/lcode.h76
-rw-r--r--src/lua/src/ldblib.c397
-rw-r--r--src/lua/src/ldebug.c638
-rw-r--r--src/lua/src/ldebug.h33
-rw-r--r--src/lua/src/ldo.c518
-rw-r--r--src/lua/src/ldo.h57
-rw-r--r--src/lua/src/ldump.c164
-rw-r--r--src/lua/src/lfunc.c174
-rw-r--r--src/lua/src/lfunc.h34
-rw-r--r--src/lua/src/lgc.c711
-rw-r--r--src/lua/src/lgc.h110
-rw-r--r--src/lua/src/linit.c38
-rw-r--r--src/lua/src/liolib.c553
-rw-r--r--src/lua/src/llex.c467
-rw-r--r--src/lua/src/llex.h81
-rw-r--r--src/lua/src/llimits.h128
-rw-r--r--src/lua/src/lmathlib.c263
-rw-r--r--src/lua/src/lmem.c86
-rw-r--r--src/lua/src/lmem.h49
-rw-r--r--src/lua/src/loadlib.c666
-rw-r--r--src/lua/src/lobject.c214
-rw-r--r--src/lua/src/lobject.h381
-rw-r--r--src/lua/src/lopcodes.c102
-rw-r--r--src/lua/src/lopcodes.h268
-rw-r--r--src/lua/src/loslib.c243
-rw-r--r--src/lua/src/lparser.c1339
-rw-r--r--src/lua/src/lparser.h82
-rw-r--r--src/lua/src/lstate.c214
-rw-r--r--src/lua/src/lstate.h169
-rw-r--r--src/lua/src/lstring.c111
-rw-r--r--src/lua/src/lstring.h31
-rw-r--r--src/lua/src/lstrlib.c869
-rw-r--r--src/lua/src/ltable.c588
-rw-r--r--src/lua/src/ltable.h40
-rw-r--r--src/lua/src/ltablib.c287
-rw-r--r--src/lua/src/ltm.c75
-rw-r--r--src/lua/src/ltm.h54
-rw-r--r--src/lua/src/lua.c392
-rw-r--r--src/lua/src/lua.h388
-rw-r--r--src/lua/src/luac.c200
-rw-r--r--src/lua/src/luaconf.h763
-rw-r--r--src/lua/src/lualib.h53
-rw-r--r--src/lua/src/lundump.c227
-rw-r--r--src/lua/src/lundump.h36
-rw-r--r--src/lua/src/lvm.c763
-rw-r--r--src/lua/src/lvm.h36
-rw-r--r--src/lua/src/lzio.c82
-rw-r--r--src/lua/src/lzio.h67
-rw-r--r--src/lua/src/print.c227
-rw-r--r--src/main.cpp69
-rw-r--r--src/mainmenumanager.h6
-rw-r--r--src/map.cpp934
-rw-r--r--src/map.h72
-rw-r--r--src/map_settings_manager.cpp13
-rw-r--r--src/mapblock.cpp39
-rw-r--r--src/mapblock.h123
-rw-r--r--src/mapblock_mesh.cpp827
-rw-r--r--src/mapblock_mesh.h120
-rw-r--r--src/mapgen.cpp204
-rw-r--r--src/mapgen.h33
-rw-r--r--src/mapgen_flat.cpp19
-rw-r--r--src/mapgen_flat.h11
-rw-r--r--src/mapgen_fractal.cpp5
-rw-r--r--src/mapgen_fractal.h11
-rw-r--r--src/mapgen_singlenode.cpp4
-rw-r--r--src/mapgen_singlenode.h10
-rw-r--r--src/mapgen_v5.cpp91
-rw-r--r--src/mapgen_v5.h22
-rw-r--r--src/mapgen_v6.cpp117
-rw-r--r--src/mapgen_v6.h3
-rw-r--r--src/mapgen_v7.cpp120
-rw-r--r--src/mapgen_v7.h17
-rw-r--r--src/mapgen_valleys.cpp32
-rw-r--r--src/mapgen_valleys.h9
-rw-r--r--src/mapnode.cpp66
-rw-r--r--src/mapnode.h25
-rw-r--r--src/mesh.cpp162
-rw-r--r--src/mesh.h31
-rw-r--r--src/mesh_generator_thread.cpp335
-rw-r--r--src/mesh_generator_thread.h135
-rw-r--r--src/metadata.cpp108
-rw-r--r--src/metadata.h61
-rw-r--r--src/mg_biome.cpp15
-rw-r--r--src/mg_biome.h8
-rw-r--r--src/mg_decoration.cpp5
-rw-r--r--src/mg_decoration.h3
-rw-r--r--src/mg_ore.cpp6
-rw-r--r--src/mg_ore.h3
-rw-r--r--src/mg_schematic.cpp23
-rw-r--r--src/mg_schematic.h12
-rw-r--r--src/minimap.cpp223
-rw-r--r--src/minimap.h28
-rw-r--r--src/modalMenu.h10
-rw-r--r--src/modifiedstate.h1
-rw-r--r--src/mods.cpp295
-rw-r--r--src/mods.h85
-rw-r--r--src/nameidmapping.cpp12
-rw-r--r--src/nameidmapping.h34
-rw-r--r--src/network/clientopcodes.cpp12
-rw-r--r--src/network/clientopcodes.h2
-rw-r--r--src/network/clientpackethandler.cpp127
-rw-r--r--src/network/connection.cpp22
-rw-r--r--src/network/connection.h18
-rw-r--r--src/network/networkpacket.cpp8
-rw-r--r--src/network/networkpacket.h11
-rw-r--r--src/network/networkprotocol.h45
-rw-r--r--src/network/serveropcodes.cpp8
-rw-r--r--src/network/serveropcodes.h2
-rw-r--r--src/network/serverpackethandler.cpp180
-rw-r--r--src/nodedef.cpp746
-rw-r--r--src/nodedef.h221
-rw-r--r--src/nodemetadata.cpp103
-rw-r--r--src/nodemetadata.h35
-rw-r--r--src/object_properties.cpp6
-rw-r--r--src/object_properties.h2
-rw-r--r--src/particles.cpp278
-rw-r--r--src/particles.h33
-rw-r--r--src/pathfinder.cpp76
-rw-r--r--src/player.h1
-rw-r--r--src/porting.cpp63
-rw-r--r--src/porting.h168
-rw-r--r--src/profiler.cpp30
-rw-r--r--src/profiler.h77
-rw-r--r--src/raycast.cpp89
-rw-r--r--src/raycast.h38
-rw-r--r--src/reflowscan.cpp5
-rw-r--r--src/remoteplayer.cpp88
-rw-r--r--src/remoteplayer.h36
-rw-r--r--src/rollback_interface.cpp12
-rw-r--r--src/script/CMakeLists.txt7
-rw-r--r--src/script/common/c_content.cpp472
-rw-r--r--src/script/common/c_content.h35
-rw-r--r--src/script/common/c_converter.cpp4
-rw-r--r--src/script/common/c_converter.h2
-rw-r--r--src/script/cpp_api/CMakeLists.txt1
-rw-r--r--src/script/cpp_api/s_async.cpp33
-rw-r--r--src/script/cpp_api/s_async.h25
-rw-r--r--src/script/cpp_api/s_base.cpp45
-rw-r--r--src/script/cpp_api/s_base.h17
-rw-r--r--src/script/cpp_api/s_client.cpp230
-rw-r--r--src/script/cpp_api/s_client.h63
-rw-r--r--src/script/cpp_api/s_entity.cpp22
-rw-r--r--src/script/cpp_api/s_entity.h4
-rw-r--r--src/script/cpp_api/s_env.cpp12
-rw-r--r--src/script/cpp_api/s_item.cpp35
-rw-r--r--src/script/cpp_api/s_mainmenu.cpp8
-rw-r--r--src/script/cpp_api/s_node.cpp27
-rw-r--r--src/script/cpp_api/s_node.h1
-rw-r--r--src/script/cpp_api/s_player.h14
-rw-r--r--src/script/cpp_api/s_security.cpp187
-rw-r--r--src/script/cpp_api/s_security.h2
-rw-r--r--src/script/lua_api/CMakeLists.txt10
-rw-r--r--src/script/lua_api/l_areastore.cpp4
-rw-r--r--src/script/lua_api/l_areastore.h7
-rw-r--r--src/script/lua_api/l_base.cpp26
-rw-r--r--src/script/lua_api/l_base.h16
-rw-r--r--src/script/lua_api/l_camera.cpp202
-rw-r--r--src/script/lua_api/l_camera.h44
-rw-r--r--src/script/lua_api/l_client.cpp356
-rw-r--r--src/script/lua_api/l_client.h98
-rw-r--r--src/script/lua_api/l_craft.cpp2
-rw-r--r--src/script/lua_api/l_env.cpp109
-rw-r--r--src/script/lua_api/l_env.h14
-rw-r--r--src/script/lua_api/l_internal.h14
-rw-r--r--src/script/lua_api/l_inventory.cpp12
-rw-r--r--src/script/lua_api/l_inventory.h2
-rw-r--r--src/script/lua_api/l_item.cpp66
-rw-r--r--src/script/lua_api/l_item.h7
-rw-r--r--src/script/lua_api/l_itemstackmeta.cpp120
-rw-r--r--src/script/lua_api/l_itemstackmeta.h59
-rw-r--r--src/script/lua_api/l_localplayer.cpp358
-rw-r--r--src/script/lua_api/l_localplayer.h85
-rw-r--r--src/script/lua_api/l_mainmenu.cpp76
-rw-r--r--src/script/lua_api/l_mainmenu.h10
-rw-r--r--src/script/lua_api/l_mapgen.cpp20
-rw-r--r--src/script/lua_api/l_mapgen.h3
-rw-r--r--src/script/lua_api/l_metadata.cpp266
-rw-r--r--src/script/lua_api/l_metadata.h75
-rw-r--r--src/script/lua_api/l_minimap.cpp227
-rw-r--r--src/script/lua_api/l_minimap.h65
-rw-r--r--src/script/lua_api/l_nodemeta.cpp330
-rw-r--r--src/script/lua_api/l_nodemeta.h48
-rw-r--r--src/script/lua_api/l_nodetimer.cpp4
-rw-r--r--src/script/lua_api/l_nodetimer.h9
-rw-r--r--src/script/lua_api/l_noise.cpp10
-rw-r--r--src/script/lua_api/l_noise.h37
-rw-r--r--src/script/lua_api/l_object.cpp271
-rw-r--r--src/script/lua_api/l_object.h67
-rw-r--r--src/script/lua_api/l_particles.cpp29
-rw-r--r--src/script/lua_api/l_server.cpp79
-rw-r--r--src/script/lua_api/l_server.h17
-rw-r--r--src/script/lua_api/l_settings.cpp85
-rw-r--r--src/script/lua_api/l_settings.h43
-rw-r--r--src/script/lua_api/l_sound.cpp53
-rw-r--r--src/script/lua_api/l_sound.h36
-rw-r--r--src/script/lua_api/l_storage.cpp147
-rw-r--r--src/script/lua_api/l_storage.h63
-rw-r--r--src/script/lua_api/l_util.cpp137
-rw-r--r--src/script/lua_api/l_util.h24
-rw-r--r--src/script/lua_api/l_vmanip.cpp49
-rw-r--r--src/script/lua_api/l_vmanip.h9
-rw-r--r--src/script/scripting_client.cpp88
-rw-r--r--src/script/scripting_client.h46
-rw-r--r--src/script/scripting_mainmenu.cpp29
-rw-r--r--src/script/scripting_mainmenu.h7
-rw-r--r--src/script/scripting_server.cpp (renamed from src/script/scripting_game.cpp)37
-rw-r--r--src/script/scripting_server.h (renamed from src/script/scripting_game.h)12
-rw-r--r--src/serialization.h6
-rw-r--r--src/server.cpp601
-rw-r--r--src/server.h91
-rw-r--r--src/serverenvironment.cpp2317
-rw-r--r--src/serverenvironment.h438
-rw-r--r--src/serverlist.cpp22
-rw-r--r--src/serverlist.h39
-rw-r--r--src/serverobject.h12
-rw-r--r--src/settings.cpp29
-rw-r--r--src/settings.h37
-rw-r--r--src/settings_translation_file.cpp269
-rw-r--r--src/shader.cpp6
-rw-r--r--src/sky.cpp10
-rw-r--r--src/sky.h77
-rw-r--r--src/sound.h82
-rw-r--r--src/sound_openal.cpp97
-rw-r--r--src/threading/event.cpp2
-rw-r--r--src/threading/event.h10
-rw-r--r--src/threading/mutex.cpp9
-rw-r--r--src/threading/mutex.h2
-rw-r--r--src/threading/semaphore.h14
-rw-r--r--src/threading/thread.cpp17
-rw-r--r--src/threading/thread.h1
-rw-r--r--src/tileanimation.cpp131
-rw-r--r--src/tileanimation.h62
-rw-r--r--src/tool.cpp29
-rw-r--r--src/tool.h8
-rw-r--r--src/touchscreengui.cpp6
-rw-r--r--src/touchscreengui.h115
-rw-r--r--src/treegen.cpp12
-rw-r--r--src/treegen.h2
-rw-r--r--src/unittest/test.cpp20
-rw-r--r--src/unittest/test.h4
-rw-r--r--src/unittest/test_connection.cpp2
-rw-r--r--src/unittest/test_mapnode.cpp3
-rw-r--r--src/unittest/test_nodedef.cpp5
-rw-r--r--src/unittest/test_noderesolver.cpp2
-rw-r--r--src/unittest/test_objdef.cpp4
-rw-r--r--src/unittest/test_player.cpp52
-rw-r--r--src/unittest/test_profiler.cpp3
-rw-r--r--src/unittest/test_threading.cpp2
-rw-r--r--src/unittest/test_voxelalgorithms.cpp59
-rw-r--r--src/util/basic_macros.h12
-rw-r--r--src/util/cpp11.h32
-rw-r--r--src/util/cpp11_container.h16
-rw-r--r--src/util/directiontables.h56
-rw-r--r--src/util/hex.h13
-rw-r--r--src/util/mathconstants.h7
-rw-r--r--src/util/numeric.cpp94
-rw-r--r--src/util/numeric.h104
-rw-r--r--src/util/pointedthing.cpp75
-rw-r--r--src/util/pointedthing.h40
-rw-r--r--src/util/serialize.cpp49
-rw-r--r--src/util/serialize.h7
-rw-r--r--src/util/sha1.h33
-rw-r--r--src/util/sha2.h107
-rw-r--r--src/util/sha256.c5
-rw-r--r--src/util/srp.cpp2
-rw-r--r--src/util/string.cpp8
-rw-r--r--src/util/string.h38
-rw-r--r--src/util/thread.h21
-rw-r--r--src/util/timetaker.cpp27
-rw-r--r--src/util/timetaker.h14
-rw-r--r--src/voxel.cpp12
-rw-r--r--src/voxel.h4
-rw-r--r--src/voxelalgorithms.cpp739
-rw-r--r--src/voxelalgorithms.h100
-rw-r--r--src/wieldmesh.cpp244
-rw-r--r--src/wieldmesh.h89
417 files changed, 23196 insertions, 42395 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3aa645df9..7c1a4eee0 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -156,26 +156,6 @@ if(ENABLE_FREETYPE)
endif()
endif(ENABLE_FREETYPE)
-# LuaJIT
-option(ENABLE_LUAJIT "Enable LuaJIT support" TRUE)
-set(USE_LUAJIT FALSE)
-if(ENABLE_LUAJIT)
- find_package(LuaJIT)
- if(LUAJIT_FOUND)
- set(USE_LUAJIT TRUE)
- endif(LUAJIT_FOUND)
-else()
- message (STATUS "LuaJIT detection disabled! (ENABLE_LUAJIT=0)")
-endif()
-if(NOT USE_LUAJIT)
- message(STATUS "LuaJIT not found, using bundled Lua.")
- set(LUA_LIBRARY "lua")
- set(LUA_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/lua/src")
- add_subdirectory(lua)
-endif()
-
-find_package(GMP REQUIRED)
-
option(ENABLE_CURSES "Enable ncurses console" TRUE)
set(USE_CURSES FALSE)
@@ -253,7 +233,6 @@ endif(ENABLE_REDIS)
find_package(SQLite3 REQUIRED)
-find_package(Json REQUIRED)
OPTION(ENABLE_SPATIAL "Enable SpatialIndex AreaStore backend" TRUE)
set(USE_SPATIAL FALSE)
@@ -284,6 +263,8 @@ if(WIN32)
set(PLATFORM_LIBS dbghelp.lib ${PLATFORM_LIBS})
# Surpress some useless warnings
add_definitions ( /D "_CRT_SECURE_NO_DEPRECATE" /W1 )
+ # Get M_PI to work
+ add_definitions(/D "_USE_MATH_DEFINES")
else() # Probably MinGW = GCC
set(PLATFORM_LIBS "")
endif()
@@ -396,6 +377,7 @@ set(common_SRCS
convert_json.cpp
craftdef.cpp
database-dummy.cpp
+ database-files.cpp
database-leveldb.cpp
database-postgresql.cpp
database-redis.cpp
@@ -406,6 +388,7 @@ set(common_SRCS
dungeongen.cpp
emerge.cpp
environment.cpp
+ face_position_cache.cpp
filesys.cpp
genericobject.cpp
gettext.cpp
@@ -413,6 +396,7 @@ set(common_SRCS
inventory.cpp
inventorymanager.cpp
itemdef.cpp
+ itemstackmetadata.cpp
light.cpp
log.cpp
map.cpp
@@ -428,6 +412,7 @@ set(common_SRCS
mapgen_valleys.cpp
mapnode.cpp
mapsector.cpp
+ metadata.cpp
mg_biome.cpp
mg_decoration.cpp
mg_ore.cpp
@@ -447,10 +432,12 @@ set(common_SRCS
quicktune.cpp
reflowscan.cpp
remoteplayer.cpp
+ raycast.cpp
rollback.cpp
rollback_interface.cpp
serialization.cpp
server.cpp
+ serverenvironment.cpp
serverlist.cpp
serverobject.cpp
settings.cpp
@@ -459,6 +446,7 @@ set(common_SRCS
staticobject.cpp
subgame.cpp
terminal_chat_console.cpp
+ tileanimation.cpp
tool.cpp
treegen.cpp
version.cpp
@@ -506,6 +494,7 @@ set(client_SRCS
${client_irrlicht_changes_SRCS}
camera.cpp
client.cpp
+ clientenvironment.cpp
clientmap.cpp
clientmedia.cpp
clientobject.cpp
@@ -535,6 +524,7 @@ set(client_SRCS
main.cpp
mapblock_mesh.cpp
mesh.cpp
+ mesh_generator_thread.cpp
minimap.cpp
particles.cpp
shader.cpp
@@ -722,7 +712,11 @@ if(MSVC)
# EHa enables SEH exceptions (used for catching segfaults)
set(CMAKE_CXX_FLAGS_RELEASE "/EHa /Ox /GL /FD /MT /GS- /Zi /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 /OPT:REF /OPT:ICF")
+ set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/LTCG /INCREMENTAL:NO /DEBUG /OPT:REF /OPT:ICF")
+
+
+ set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
+
set(CMAKE_CXX_FLAGS_SEMIDEBUG "/MDd /Zi /Ob0 /O1 /RTC1")
@@ -760,18 +754,22 @@ else()
set(OTHER_FLAGS "${OTHER_FLAGS} -mthreads -fexceptions")
endif()
- set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG ${RELEASE_WARNING_FLAGS} ${WARNING_FLAGS} ${OTHER_FLAGS} -ffast-math -Wall -pipe -funroll-loops")
- if(APPLE)
+ set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG ${RELEASE_WARNING_FLAGS} ${WARNING_FLAGS} ${OTHER_FLAGS} -Wall -pipe -funroll-loops")
+ if(CMAKE_SYSTEM_NAME MATCHES "(Darwin|FreeBSD)")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os")
else()
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -fomit-frame-pointer")
- endif(APPLE)
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -ffast-math -fomit-frame-pointer")
+ endif(CMAKE_SYSTEM_NAME MATCHES "(Darwin|FreeBSD)")
set(CMAKE_CXX_FLAGS_SEMIDEBUG "-g -O1 -Wall -Wabi ${WARNING_FLAGS} ${OTHER_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -Wabi ${WARNING_FLAGS} ${OTHER_FLAGS}")
if(USE_GPROF)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg")
endif()
+
+ if(MINGW)
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mwindows")
+ endif()
endif()
@@ -887,4 +885,3 @@ endif()
if (BUILD_CLIENT AND USE_FREETYPE)
add_subdirectory(cguittfont)
endif()
-
diff --git a/src/activeobject.h b/src/activeobject.h
index 48f078d3f..f349ddef3 100644
--- a/src/activeobject.h
+++ b/src/activeobject.h
@@ -28,9 +28,9 @@ enum ActiveObjectType {
ACTIVEOBJECT_TYPE_TEST = 1,
// Deprecated stuff
ACTIVEOBJECT_TYPE_ITEM = 2,
- ACTIVEOBJECT_TYPE_RAT = 3,
- ACTIVEOBJECT_TYPE_OERKKI1 = 4,
- ACTIVEOBJECT_TYPE_FIREFLY = 5,
+// ACTIVEOBJECT_TYPE_RAT = 3,
+// ACTIVEOBJECT_TYPE_OERKKI1 = 4,
+// ACTIVEOBJECT_TYPE_FIREFLY = 5,
ACTIVEOBJECT_TYPE_MOBV2 = 6,
// End deprecated stuff
ACTIVEOBJECT_TYPE_LUAENTITY = 7,
@@ -43,7 +43,7 @@ enum ActiveObjectType {
struct ActiveObjectMessage
{
- ActiveObjectMessage(u16 id_, bool reliable_=true, std::string data_=""):
+ ActiveObjectMessage(u16 id_, bool reliable_=true, const std::string &data_ = "") :
id(id_),
reliable(reliable_),
datastring(data_)
@@ -64,7 +64,7 @@ public:
m_id(id)
{
}
-
+
u16 getId()
{
return m_id;
@@ -76,8 +76,8 @@ public:
}
virtual ActiveObjectType getType() const = 0;
- virtual bool getCollisionBox(aabb3f *toset) = 0;
- virtual bool collideWithObjects() = 0;
+ virtual bool getCollisionBox(aabb3f *toset) const = 0;
+ virtual bool collideWithObjects() const = 0;
protected:
u16 m_id; // 0 is invalid, "no id"
};
diff --git a/src/ban.h b/src/ban.h
index d1a49cb15..e35bd0e10 100644
--- a/src/ban.h
+++ b/src/ban.h
@@ -41,12 +41,12 @@ public:
void add(const std::string &ip, const std::string &name);
void remove(const std::string &ip_or_name);
bool isModified();
+
private:
Mutex m_mutex;
std::string m_banfilepath;
StringMap m_ips;
bool m_modified;
-
};
#endif
diff --git a/src/camera.cpp b/src/camera.cpp
index 43980db1c..52a42a3a9 100644
--- a/src/camera.cpp
+++ b/src/camera.cpp
@@ -27,21 +27,20 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "wieldmesh.h"
#include "noise.h" // easeCurve
-#include "gamedef.h"
#include "sound.h"
#include "event.h"
#include "profiler.h"
#include "util/numeric.h"
-#include "util/mathconstants.h"
#include "constants.h"
#include "fontengine.h"
+#include "script/scripting_client.h"
#define CAMERA_OFFSET_STEP 200
#include "nodedef.h"
Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
- IGameDef *gamedef):
+ Client *client):
m_playernode(NULL),
m_headnode(NULL),
m_cameranode(NULL),
@@ -50,7 +49,7 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
m_wieldnode(NULL),
m_draw_control(draw_control),
- m_gamedef(gamedef),
+ m_client(client),
m_camera_position(0,0,0),
m_camera_direction(0,0,0),
@@ -88,7 +87,7 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
m_wieldmgr = smgr->createNewSceneManager();
m_wieldmgr->addCameraSceneNode();
m_wieldnode = new WieldMeshSceneNode(m_wieldmgr->getRootSceneNode(), m_wieldmgr, -1, false);
- m_wieldnode->setItem(ItemStack(), m_gamedef);
+ m_wieldnode->setItem(ItemStack(), m_client);
m_wieldnode->drop(); // m_wieldmgr grabbed it
/* TODO: Add a callback function so these can be updated when a setting
@@ -104,7 +103,6 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
m_cache_view_bobbing_amount = g_settings->getFloat("view_bobbing_amount");
m_cache_fov = g_settings->getFloat("fov");
m_cache_zoom_fov = g_settings->getFloat("zoom_fov");
- m_cache_view_bobbing = g_settings->getBool("view_bobbing");
m_nametags.clear();
}
@@ -128,6 +126,10 @@ bool Camera::successfullyCreated(std::string &error_message)
} else {
error_message.clear();
}
+
+ if (g_settings->getBool("enable_client_modding")) {
+ m_client->getScript()->on_camera_ready(this);
+ }
return error_message.empty();
}
@@ -151,7 +153,7 @@ void Camera::step(f32 dtime)
m_wield_change_timer = MYMIN(m_wield_change_timer + dtime, 0.125);
if (m_wield_change_timer >= 0 && was_under_zero)
- m_wieldnode->setItem(m_wield_item_next, m_gamedef);
+ m_wieldnode->setItem(m_wield_item_next, m_client);
if (m_view_bobbing_state != 0)
{
@@ -189,7 +191,7 @@ void Camera::step(f32 dtime)
(was > 0.5f && m_view_bobbing_anim <= 0.5f));
if(step) {
MtEvent *e = new SimpleTriggerEvent("ViewBobbingStep");
- m_gamedef->event()->put(e);
+ m_client->event()->put(e);
}
}
}
@@ -210,10 +212,10 @@ void Camera::step(f32 dtime)
if(m_digging_button == 0)
{
MtEvent *e = new SimpleTriggerEvent("CameraPunchLeft");
- m_gamedef->event()->put(e);
+ m_client->event()->put(e);
} else if(m_digging_button == 1) {
MtEvent *e = new SimpleTriggerEvent("CameraPunchRight");
- m_gamedef->event()->put(e);
+ m_client->event()->put(e);
}
}
}
@@ -282,8 +284,8 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
v3f rel_cam_target = v3f(0,0,1);
v3f rel_cam_up = v3f(0,1,0);
- if (m_view_bobbing_anim != 0 && m_camera_mode < CAMERA_MODE_THIRD)
- {
+ if (m_cache_view_bobbing_amount != 0.0f && m_view_bobbing_anim != 0.0f &&
+ m_camera_mode < CAMERA_MODE_THIRD) {
f32 bobfrac = my_modf(m_view_bobbing_anim * 2);
f32 bobdir = (m_view_bobbing_anim < 0.5) ? 1.0 : -1.0;
@@ -352,7 +354,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
my_cp.Y = m_camera_position.Y + (m_camera_direction.Y*-i);
// Prevent camera positioned inside nodes
- INodeDefManager *nodemgr = m_gamedef->ndef();
+ INodeDefManager *nodemgr = m_client->ndef();
MapNode n = c_env.getClientMap().getNodeNoEx(floatToInt(my_cp, BS));
const ContentFeatures& features = nodemgr->get(n);
if(features.walkable)
@@ -390,13 +392,12 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
// Get FOV
f32 fov_degrees;
- if (player->getPlayerControl().zoom && m_gamedef->checkLocalPrivilege("zoom")) {
+ if (player->getPlayerControl().zoom && m_client->checkLocalPrivilege("zoom")) {
fov_degrees = m_cache_zoom_fov;
} else {
fov_degrees = m_cache_fov;
}
- fov_degrees = MYMAX(fov_degrees, 10.0);
- fov_degrees = MYMIN(fov_degrees, 170.0);
+ fov_degrees = rangelim(fov_degrees, 7.0, 160.0);
// FOV and aspect ratio
m_aspect = (f32) porting::getWindowSize().X / (f32) porting::getWindowSize().Y;
@@ -407,9 +408,12 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
m_cameranode->setAspectRatio(m_aspect);
m_cameranode->setFOV(m_fov_y);
+ float wieldmesh_offset_Y = -35 + player->getPitch() * 0.05;
+ wieldmesh_offset_Y = rangelim(wieldmesh_offset_Y, -52, -32);
+
// Position the wielded item
//v3f wield_position = v3f(45, -35, 65);
- v3f wield_position = v3f(55, -35, 65);
+ v3f wield_position = v3f(55, wieldmesh_offset_Y, 65);
//v3f wield_rotation = v3f(-100, 120, -100);
v3f wield_rotation = v3f(-100, 120, -100);
wield_position.Y += fabs(m_wield_change_timer)*320 - 40;
@@ -467,9 +471,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
const bool swimming = (movement_XZ || player->swimming_vertical) && player->in_liquid;
const bool climbing = movement_Y && player->is_climbing;
if ((walking || swimming || climbing) &&
- m_cache_view_bobbing &&
- (!g_settings->getBool("free_move") || !m_gamedef->checkLocalPrivilege("fly")))
- {
+ (!g_settings->getBool("free_move") || !m_client->checkLocalPrivilege("fly"))) {
// Start animation
m_view_bobbing_state = 1;
m_view_bobbing_speed = MYMIN(speed.getLength(), 70);
@@ -501,7 +503,8 @@ void Camera::setDigging(s32 button)
void Camera::wield(const ItemStack &item)
{
- if (item.name != m_wield_item_next.name) {
+ if (item.name != m_wield_item_next.name ||
+ item.metadata != m_wield_item_next.metadata) {
m_wield_item_next = item;
if (m_wield_change_timer > 0)
m_wield_change_timer = -m_wield_change_timer;
@@ -555,9 +558,10 @@ void Camera::drawNametags()
f32 transformed_pos[4] = { pos.X, pos.Y, pos.Z, 1.0f };
trans.multiplyWith1x4Matrix(transformed_pos);
if (transformed_pos[3] > 0) {
+ std::string nametag_colorless = unescape_enriched(nametag->nametag_text);
core::dimension2d<u32> textsize =
g_fontengine->getFont()->getDimension(
- utf8_to_wide(nametag->nametag_text).c_str());
+ utf8_to_wide(nametag_colorless).c_str());
f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
core::reciprocal(transformed_pos[3]);
v2u32 screensize = m_driver->getScreenSize();
diff --git a/src/camera.h b/src/camera.h
index cb0e9686d..1e4800cba 100644
--- a/src/camera.h
+++ b/src/camera.h
@@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class LocalPlayer;
struct MapDrawControl;
-class IGameDef;
+class Client;
class WieldMeshSceneNode;
struct Nametag {
@@ -61,25 +61,9 @@ class Camera
{
public:
Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
- IGameDef *gamedef);
+ Client *client);
~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
@@ -161,6 +145,12 @@ public:
m_camera_mode = CAMERA_MODE_FIRST;
}
+ // Set the current camera mode
+ inline void setCameraMode(CameraMode mode)
+ {
+ m_camera_mode = mode;
+ }
+
//read the current camera mode
inline CameraMode getCameraMode()
{
@@ -172,8 +162,7 @@ public:
void removeNametag(Nametag *nametag);
- std::list<Nametag *> *getNametags()
- { return &m_nametags; }
+ const std::list<Nametag *> &getNametags() { return m_nametags; }
void drawNametags();
@@ -189,7 +178,7 @@ private:
// draw control
MapDrawControl& m_draw_control;
- IGameDef *m_gamedef;
+ Client *m_client;
video::IVideoDriver *m_driver;
// Absolute camera position
@@ -232,7 +221,6 @@ private:
f32 m_cache_view_bobbing_amount;
f32 m_cache_fov;
f32 m_cache_zoom_fov;
- bool m_cache_view_bobbing;
std::list<Nametag *> m_nametags;
};
diff --git a/src/cavegen.cpp b/src/cavegen.cpp
index bb6aa25a6..dbed79951 100644
--- a/src/cavegen.cpp
+++ b/src/cavegen.cpp
@@ -74,19 +74,23 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm,
noise_cave2->perlinMap3D(nmin.X, nmin.Y - 1, nmin.Z);
v3s16 em = vm->m_area.getExtent();
- u32 index2d = 0;
+ u32 index2d = 0; // Biomemap index
for (s16 z = nmin.Z; z <= nmax.Z; z++)
for (s16 x = nmin.X; x <= nmax.X; x++, index2d++) {
bool column_is_open = false; // Is column open to overground
bool is_under_river = false; // Is column under river water
- bool is_tunnel = false; // Is tunnel or tunnel floor
+ bool is_under_tunnel = false; // Is tunnel or is under tunnel
+ // Indexes at column top
u32 vi = vm->m_area.index(x, nmax.Y, z);
u32 index3d = (z - nmin.Z) * m_zstride_1d + m_csize.Y * m_ystride +
- (x - nmin.X);
+ (x - nmin.X); // 3D noise index
// Biome of column
Biome *biome = (Biome *)m_bmgr->getRaw(biomemap[index2d]);
-
+ u16 depth_top = biome->depth_top;
+ u16 base_filler = depth_top + biome->depth_filler;
+ u16 depth_riverbed = biome->depth_riverbed;
+ u16 nplaced = 0;
// Don't excavate the overgenerated stone at nmax.Y + 1,
// this creates a 'roof' over the tunnel, preventing light in
// tunnels at mapchunk borders when generating mapchunks upwards.
@@ -112,20 +116,34 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm,
if (d1 * d2 > m_cave_width && m_ndef->get(c).is_ground_content) {
// In tunnel and ground content, excavate
vm->m_data[vi] = MapNode(CONTENT_AIR);
- is_tunnel = true;
- } else {
- // Not in tunnel or not ground content
- if (is_tunnel && column_is_open &&
- (c == biome->c_filler || c == biome->c_stone)) {
- // Tunnel entrance floor
- if (is_under_river)
+ is_under_tunnel = true;
+ } else if (column_is_open && is_under_tunnel &&
+ (c == biome->c_stone || c == biome->c_filler)) {
+ // Tunnel entrance floor, place biome surface nodes
+ if (is_under_river) {
+ if (nplaced < depth_riverbed) {
vm->m_data[vi] = MapNode(biome->c_riverbed);
- else
- vm->m_data[vi] = MapNode(biome->c_top);
+ nplaced++;
+ } else {
+ // Disable top/filler placement
+ column_is_open = false;
+ is_under_river = false;
+ is_under_tunnel = false;
+ }
+ } else if (nplaced < depth_top) {
+ vm->m_data[vi] = MapNode(biome->c_top);
+ nplaced++;
+ } else if (nplaced < base_filler) {
+ vm->m_data[vi] = MapNode(biome->c_filler);
+ nplaced++;
+ } else {
+ // Disable top/filler placement
+ column_is_open = false;
+ is_under_tunnel = false;
}
-
+ } else {
+ // Not tunnel or tunnel entrance floor
column_is_open = false;
- is_tunnel = false;
}
}
}
@@ -133,6 +151,104 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm,
////
+//// CavernsNoise
+////
+
+CavernsNoise::CavernsNoise(
+ INodeDefManager *nodedef, v3s16 chunksize, NoiseParams *np_cavern,
+ s32 seed, float cavern_limit, float cavern_taper, float cavern_threshold)
+{
+ assert(nodedef);
+
+ m_ndef = nodedef;
+
+ m_csize = chunksize;
+ m_cavern_limit = cavern_limit;
+ m_cavern_taper = cavern_taper;
+ m_cavern_threshold = cavern_threshold;
+
+ m_ystride = m_csize.X;
+ m_zstride_1d = m_csize.X * (m_csize.Y + 1);
+
+ // Noise is created using 1-down overgeneration
+ // A Nx-by-1-by-Nz-sized plane is at the bottom of the desired for
+ // re-carving the solid overtop placed for blocking sunlight
+ noise_cavern = new Noise(np_cavern, seed, m_csize.X, m_csize.Y + 1, m_csize.Z);
+
+ c_water_source = m_ndef->getId("mapgen_water_source");
+ if (c_water_source == CONTENT_IGNORE)
+ c_water_source = CONTENT_AIR;
+
+ c_lava_source = m_ndef->getId("mapgen_lava_source");
+ if (c_lava_source == CONTENT_IGNORE)
+ c_lava_source = CONTENT_AIR;
+}
+
+
+CavernsNoise::~CavernsNoise()
+{
+ delete noise_cavern;
+}
+
+
+bool CavernsNoise::generateCaverns(MMVManip *vm, v3s16 nmin, v3s16 nmax)
+{
+ assert(vm);
+
+ // Calculate noise
+ noise_cavern->perlinMap3D(nmin.X, nmin.Y - 1, nmin.Z);
+
+ // Cache cavern_amp values
+ float *cavern_amp = new float[m_csize.Y + 1];
+ u8 cavern_amp_index = 0; // Index zero at column top
+ for (s16 y = nmax.Y; y >= nmin.Y - 1; y--, cavern_amp_index++) {
+ cavern_amp[cavern_amp_index] =
+ MYMIN((m_cavern_limit - y) / (float)m_cavern_taper, 1.0f);
+ }
+
+ //// Place nodes
+ bool near_cavern = false;
+ v3s16 em = vm->m_area.getExtent();
+ u32 index2d = 0;
+
+ for (s16 z = nmin.Z; z <= nmax.Z; z++)
+ for (s16 x = nmin.X; x <= nmax.X; x++, index2d++) {
+ // Reset cave_amp index to column top
+ cavern_amp_index = 0;
+ // Initial voxelmanip index at column top
+ u32 vi = vm->m_area.index(x, nmax.Y, z);
+ // Initial 3D noise index at column top
+ u32 index3d = (z - nmin.Z) * m_zstride_1d + m_csize.Y * m_ystride +
+ (x - nmin.X);
+ // Don't excavate the overgenerated stone at node_max.Y + 1,
+ // this creates a 'roof' over the cavern, preventing light in
+ // caverns at mapchunk borders when generating mapchunks upwards.
+ // This 'roof' is excavated when the mapchunk above is generated.
+ for (s16 y = nmax.Y; y >= nmin.Y - 1; y--,
+ index3d -= m_ystride,
+ vm->m_area.add_y(em, vi, -1),
+ cavern_amp_index++) {
+ content_t c = vm->m_data[vi].getContent();
+ float n_absamp_cavern = fabs(noise_cavern->result[index3d]) *
+ cavern_amp[cavern_amp_index];
+ // Disable CavesRandomWalk at a safe distance from caverns
+ // to avoid excessively spreading liquids in caverns.
+ if (n_absamp_cavern > m_cavern_threshold - 0.1f) {
+ near_cavern = true;
+ if (n_absamp_cavern > m_cavern_threshold &&
+ m_ndef->get(c).is_ground_content)
+ vm->m_data[vi] = MapNode(CONTENT_AIR);
+ }
+ }
+ }
+
+ delete[] cavern_amp;
+
+ return near_cavern;
+}
+
+
+////
//// CavesRandomWalk
////
diff --git a/src/cavegen.h b/src/cavegen.h
index 2bf503d47..a1140594e 100644
--- a/src/cavegen.h
+++ b/src/cavegen.h
@@ -37,11 +37,12 @@ class GenerateNotifier;
TODO(hmmmm): Remove dependency on biomes
TODO(hmmmm): Find alternative to overgeneration as solution for sunlight issue
*/
-class CavesNoiseIntersection {
+class CavesNoiseIntersection
+{
public:
CavesNoiseIntersection(INodeDefManager *nodedef, BiomeManager *biomemgr,
- v3s16 chunksize, NoiseParams *np_cave1, NoiseParams *np_cave2,
- s32 seed, float cave_width);
+ v3s16 chunksize, NoiseParams *np_cave1, NoiseParams *np_cave2,
+ s32 seed, float cave_width);
~CavesNoiseIntersection();
void generateCaves(MMVManip *vm, v3s16 nmin, v3s16 nmax, u8 *biomemap);
@@ -63,6 +64,38 @@ private:
};
/*
+ CavernsNoise is a cave digging algorithm
+*/
+class CavernsNoise
+{
+public:
+ CavernsNoise(INodeDefManager *nodedef, v3s16 chunksize, NoiseParams *np_cavern,
+ s32 seed, float cavern_limit, float cavern_taper,
+ float cavern_threshold);
+ ~CavernsNoise();
+
+ bool generateCaverns(MMVManip *vm, v3s16 nmin, v3s16 nmax);
+
+private:
+ INodeDefManager *m_ndef;
+
+ // configurable parameters
+ v3s16 m_csize;
+ float m_cavern_limit;
+ float m_cavern_taper;
+ float m_cavern_threshold;
+
+ // intermediate state variables
+ u16 m_ystride;
+ u16 m_zstride_1d;
+
+ Noise *noise_cavern;
+
+ content_t c_water_source;
+ content_t c_lava_source;
+};
+
+/*
CavesRandomWalk is an implementation of a cave-digging algorithm that
operates on the principle of a "random walk" to approximate the stochiastic
activity of cavern development.
@@ -75,7 +108,8 @@ private:
This algorithm is very fast, executing in less than 1ms on average for an
80x80x80 chunk of map on a modern processor.
*/
-class CavesRandomWalk {
+class CavesRandomWalk
+{
public:
MMVManip *vm;
INodeDefManager *ndef;
@@ -120,18 +154,16 @@ public:
// ndef is a mandatory parameter.
// If gennotify is NULL, generation events are not logged.
- CavesRandomWalk(INodeDefManager *ndef,
- GenerateNotifier *gennotify = NULL,
- s32 seed = 0,
- int water_level = 1,
- content_t water_source = CONTENT_IGNORE,
- content_t lava_source = CONTENT_IGNORE);
+ CavesRandomWalk(INodeDefManager *ndef, GenerateNotifier *gennotify = NULL,
+ s32 seed = 0, int water_level = 1,
+ content_t water_source = CONTENT_IGNORE,
+ content_t lava_source = CONTENT_IGNORE);
// vm and ps are mandatory parameters.
// If heightmap is NULL, the surface level at all points is assumed to
// be water_level.
void makeCave(MMVManip *vm, v3s16 nmin, v3s16 nmax, PseudoRandom *ps,
- bool is_large_cave, int max_stone_height, s16 *heightmap);
+ bool is_large_cave, int max_stone_height, s16 *heightmap);
private:
void makeTunnel(bool dirswitch);
@@ -153,7 +185,8 @@ private:
tl;dr,
*** DO NOT TOUCH THIS CLASS UNLESS YOU KNOW WHAT YOU ARE DOING ***
*/
-class CavesV6 {
+class CavesV6
+{
public:
MMVManip *vm;
INodeDefManager *ndef;
@@ -192,18 +225,16 @@ public:
// ndef is a mandatory parameter.
// If gennotify is NULL, generation events are not logged.
- CavesV6(INodeDefManager *ndef,
- GenerateNotifier *gennotify = NULL,
- int water_level = 1,
- content_t water_source = CONTENT_IGNORE,
- content_t lava_source = CONTENT_IGNORE);
+ CavesV6(INodeDefManager *ndef, GenerateNotifier *gennotify = NULL,
+ int water_level = 1, content_t water_source = CONTENT_IGNORE,
+ content_t lava_source = CONTENT_IGNORE);
// vm, ps, and ps2 are mandatory parameters.
// If heightmap is NULL, the surface level at all points is assumed to
// be water_level.
- void makeCave(MMVManip *vm, v3s16 nmin, v3s16 nmax,
- PseudoRandom *ps, PseudoRandom *ps2,
- bool is_large_cave, int max_stone_height, s16 *heightmap = NULL);
+ void makeCave(MMVManip *vm, v3s16 nmin, v3s16 nmax, PseudoRandom *ps,
+ PseudoRandom *ps2, bool is_large_cave, int max_stone_height,
+ s16 *heightmap = NULL);
private:
void makeTunnel(bool dirswitch);
diff --git a/src/cguittfont/CGUITTFont.cpp b/src/cguittfont/CGUITTFont.cpp
index c2d37c6c0..bd4e700de 100644
--- a/src/cguittfont/CGUITTFont.cpp
+++ b/src/cguittfont/CGUITTFont.cpp
@@ -512,9 +512,11 @@ CGUITTGlyphPage* CGUITTFont::createGlyphPage(const u8& pixel_mode)
if (page_texture_size.Width > max_texture_size.Width || page_texture_size.Height > max_texture_size.Height)
page_texture_size = max_texture_size;
- if (!page->createPageTexture(pixel_mode, page_texture_size))
+ if (!page->createPageTexture(pixel_mode, page_texture_size)) {
// TODO: add error message?
+ delete page;
return 0;
+ }
if (page)
{
diff --git a/src/cguittfont/CGUITTFont.h b/src/cguittfont/CGUITTFont.h
index 0aa540c5c..77c9e34f8 100644
--- a/src/cguittfont/CGUITTFont.h
+++ b/src/cguittfont/CGUITTFont.h
@@ -125,6 +125,10 @@ namespace gui
bool flgmip = driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
+#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8
+ bool flgcpy = driver->getTextureCreationFlag(video::ETCF_ALLOW_MEMORY_COPY);
+ driver->setTextureCreationFlag(video::ETCF_ALLOW_MEMORY_COPY, true);
+#endif
// Set the texture color format.
switch (pixel_mode)
@@ -140,6 +144,9 @@ namespace gui
// Restore our texture creation flags.
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, flgmip);
+#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8
+ driver->setTextureCreationFlag(video::ETCF_ALLOW_MEMORY_COPY, flgcpy);
+#endif
return texture ? true : false;
}
diff --git a/src/chat.cpp b/src/chat.cpp
index 46555b3dc..ade3fefd3 100644
--- a/src/chat.cpp
+++ b/src/chat.cpp
@@ -77,11 +77,6 @@ u32 ChatBuffer::getLineCount() const
return m_unformatted.size();
}
-u32 ChatBuffer::getScrollback() const
-{
- return m_scrollback;
-}
-
const ChatLine& ChatBuffer::getLine(u32 index) const
{
assert(index < getLineCount()); // pre-condition
@@ -336,7 +331,7 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
while (frag_length < remaining_in_input &&
frag_length < remaining_in_output)
{
- if (isspace(line.text.getString()[in_pos + frag_length]))
+ if (iswspace(line.text.getString()[in_pos + frag_length]))
space_pos = frag_length;
++frag_length;
}
@@ -386,7 +381,7 @@ s32 ChatBuffer::getBottomScrollPos() const
-ChatPrompt::ChatPrompt(std::wstring prompt, u32 history_limit):
+ChatPrompt::ChatPrompt(const std::wstring &prompt, u32 history_limit):
m_prompt(prompt),
m_line(L""),
m_history(),
@@ -493,9 +488,9 @@ void ChatPrompt::nickCompletion(const std::list<std::string>& names, bool backwa
{
// no previous nick completion is active
prefix_start = prefix_end = m_cursor;
- while (prefix_start > 0 && !isspace(m_line[prefix_start-1]))
+ while (prefix_start > 0 && !iswspace(m_line[prefix_start-1]))
--prefix_start;
- while (prefix_end < m_line.size() && !isspace(m_line[prefix_end]))
+ while (prefix_end < m_line.size() && !iswspace(m_line[prefix_end]))
++prefix_end;
if (prefix_start == prefix_end)
return;
@@ -524,7 +519,7 @@ void ChatPrompt::nickCompletion(const std::list<std::string>& names, bool backwa
u32 replacement_index = 0;
if (!initial)
{
- while (word_end < m_line.size() && !isspace(m_line[word_end]))
+ while (word_end < m_line.size() && !iswspace(m_line[word_end]))
++word_end;
std::wstring word = m_line.substr(prefix_start, word_end - prefix_start);
@@ -543,7 +538,7 @@ void ChatPrompt::nickCompletion(const std::list<std::string>& names, bool backwa
}
}
std::wstring replacement = completions[replacement_index];
- if (word_end < m_line.size() && isspace(word_end))
+ if (word_end < m_line.size() && iswspace(m_line[word_end]))
++word_end;
// replace existing word with replacement word,
@@ -598,17 +593,17 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco
case CURSOROP_SCOPE_WORD:
if (dir == CURSOROP_DIR_RIGHT) {
// skip one word to the right
- while (new_cursor < length && isspace(m_line[new_cursor]))
+ while (new_cursor < length && iswspace(m_line[new_cursor]))
new_cursor++;
- while (new_cursor < length && !isspace(m_line[new_cursor]))
+ while (new_cursor < length && !iswspace(m_line[new_cursor]))
new_cursor++;
- while (new_cursor < length && isspace(m_line[new_cursor]))
+ while (new_cursor < length && iswspace(m_line[new_cursor]))
new_cursor++;
} else {
// skip one word to the left
- while (new_cursor >= 1 && isspace(m_line[new_cursor - 1]))
+ while (new_cursor >= 1 && iswspace(m_line[new_cursor - 1]))
new_cursor--;
- while (new_cursor >= 1 && !isspace(m_line[new_cursor - 1]))
+ while (new_cursor >= 1 && !iswspace(m_line[new_cursor - 1]))
new_cursor--;
}
break;
diff --git a/src/chat.h b/src/chat.h
index 11061fd39..b7c6b74b9 100644
--- a/src/chat.h
+++ b/src/chat.h
@@ -38,14 +38,14 @@ struct ChatLine
// message text
EnrichedString text;
- ChatLine(std::wstring a_name, std::wstring a_text):
+ ChatLine(const std::wstring &a_name, const std::wstring &a_text):
age(0.0),
name(a_name),
text(a_text)
{
}
- ChatLine(EnrichedString a_name, EnrichedString a_text):
+ ChatLine(const EnrichedString &a_name, const EnrichedString &a_text):
age(0.0),
name(a_name),
text(a_text)
@@ -86,8 +86,6 @@ public:
// Get number of lines currently in buffer.
u32 getLineCount() const;
- // Get scrollback size, maximum number of lines in buffer.
- u32 getScrollback() const;
// Get reference to i-th chat line.
const ChatLine& getLine(u32 index) const;
@@ -148,7 +146,7 @@ private:
class ChatPrompt
{
public:
- ChatPrompt(std::wstring prompt, u32 history_limit);
+ ChatPrompt(const std::wstring &prompt, u32 history_limit);
~ChatPrompt();
// Input character or string
@@ -162,8 +160,7 @@ public:
std::wstring getLine() const { return m_line; }
// Get section of line that is currently selected
- std::wstring getSelection() const
- { return m_line.substr(m_cursor, m_cursor_len); }
+ std::wstring getSelection() const { return m_line.substr(m_cursor, m_cursor_len); }
// Clear the current line
void clear();
diff --git a/src/client.cpp b/src/client.cpp
index 5476aad0e..a5228132d 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -32,172 +32,33 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client.h"
#include "network/clientopcodes.h"
#include "filesys.h"
-#include "porting.h"
#include "mapblock_mesh.h"
#include "mapblock.h"
#include "minimap.h"
-#include "settings.h"
+#include "mods.h"
#include "profiler.h"
#include "gettext.h"
-#include "log.h"
-#include "nodemetadata.h"
-#include "itemdef.h"
-#include "shader.h"
#include "clientmap.h"
#include "clientmedia.h"
-#include "sound.h"
-#include "IMeshCache.h"
-#include "config.h"
#include "version.h"
#include "drawscene.h"
#include "database-sqlite3.h"
#include "serialization.h"
#include "guiscalingfilter.h"
+#include "script/scripting_client.h"
+#include "game.h"
extern gui::IGUIEnvironment* guienv;
/*
- QueuedMeshUpdate
-*/
-
-QueuedMeshUpdate::QueuedMeshUpdate():
- p(-1337,-1337,-1337),
- data(NULL),
- ack_block_to_server(false)
-{
-}
-
-QueuedMeshUpdate::~QueuedMeshUpdate()
-{
- if(data)
- delete data;
-}
-
-/*
- MeshUpdateQueue
-*/
-
-MeshUpdateQueue::MeshUpdateQueue()
-{
-}
-
-MeshUpdateQueue::~MeshUpdateQueue()
-{
- MutexAutoLock lock(m_mutex);
-
- for(std::vector<QueuedMeshUpdate*>::iterator
- i = m_queue.begin();
- i != m_queue.end(); ++i)
- {
- QueuedMeshUpdate *q = *i;
- delete q;
- }
-}
-
-/*
- peer_id=0 adds with nobody to send to
-*/
-void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server, bool urgent)
-{
- DSTACK(FUNCTION_NAME);
-
- assert(data); // pre-condition
-
- MutexAutoLock lock(m_mutex);
-
- if(urgent)
- m_urgents.insert(p);
-
- /*
- Find if block is already in queue.
- If it is, update the data and quit.
- */
- for(std::vector<QueuedMeshUpdate*>::iterator
- i = m_queue.begin();
- i != m_queue.end(); ++i)
- {
- QueuedMeshUpdate *q = *i;
- if(q->p == p)
- {
- if(q->data)
- delete q->data;
- q->data = data;
- if(ack_block_to_server)
- q->ack_block_to_server = true;
- return;
- }
- }
-
- /*
- Add the block
- */
- QueuedMeshUpdate *q = new QueuedMeshUpdate;
- q->p = p;
- q->data = data;
- q->ack_block_to_server = ack_block_to_server;
- m_queue.push_back(q);
-}
-
-// Returned pointer must be deleted
-// Returns NULL if queue is empty
-QueuedMeshUpdate *MeshUpdateQueue::pop()
-{
- MutexAutoLock lock(m_mutex);
-
- bool must_be_urgent = !m_urgents.empty();
- for(std::vector<QueuedMeshUpdate*>::iterator
- i = m_queue.begin();
- i != m_queue.end(); ++i)
- {
- QueuedMeshUpdate *q = *i;
- if(must_be_urgent && m_urgents.count(q->p) == 0)
- continue;
- m_queue.erase(i);
- m_urgents.erase(q->p);
- return q;
- }
- return NULL;
-}
-
-/*
- MeshUpdateThread
-*/
-
-void MeshUpdateThread::enqueueUpdate(v3s16 p, MeshMakeData *data,
- bool ack_block_to_server, bool urgent)
-{
- m_queue_in.addBlock(p, data, ack_block_to_server, urgent);
- deferUpdate();
-}
-
-void MeshUpdateThread::doUpdate()
-{
- QueuedMeshUpdate *q;
- while ((q = m_queue_in.pop())) {
-
- ScopeProfiler sp(g_profiler, "Client: Mesh making");
-
- MapBlockMesh *mesh_new = new MapBlockMesh(q->data, m_camera_offset);
-
- MeshUpdateResult r;
- r.p = q->p;
- r.mesh = mesh_new;
- r.ack_block_to_server = q->ack_block_to_server;
-
- m_queue_out.push_back(r);
-
- delete q;
- }
-}
-
-/*
Client
*/
Client::Client(
IrrlichtDevice *device,
const char *playername,
- std::string password,
+ const std::string &password,
+ const std::string &address_name,
MapDrawControl &control,
IWritableTextureSource *tsrc,
IWritableShaderSource *shsrc,
@@ -205,7 +66,8 @@ Client::Client(
IWritableNodeDefManager *nodedef,
ISoundManager *sound,
MtEventManager *event,
- bool ipv6
+ bool ipv6,
+ GameUIFlags *game_ui_flags
):
m_packetcounter_timer(0.0),
m_connection_reinit_timer(0.1),
@@ -218,9 +80,9 @@ Client::Client(
m_nodedef(nodedef),
m_sound(sound),
m_event(event),
- m_mesh_update_thread(),
+ m_mesh_update_thread(this),
m_env(
- new ClientMap(this, this, control,
+ new ClientMap(this, control,
device->getSceneManager()->getRootSceneNode(),
device->getSceneManager(), 666),
device->getSceneManager(),
@@ -228,8 +90,10 @@ Client::Client(
),
m_particle_manager(&m_env),
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, ipv6, this),
+ m_address_name(address_name),
m_device(device),
m_camera(NULL),
+ m_minimap(NULL),
m_minimap_disabled_by_server(false),
m_server_ser_ver(SER_FMT_VER_INVALID),
m_proto_ver(0),
@@ -240,6 +104,8 @@ Client::Client(
m_animation_time(0),
m_crack_level(-1),
m_crack_pos(0,0,0),
+ m_last_chat_message_sent(time(NULL)),
+ m_chat_message_allowance(5.0f),
m_map_seed(0),
m_password(password),
m_chosen_auth_mech(AUTH_MECHANISM_NONE),
@@ -255,23 +121,95 @@ Client::Client(
m_recommended_send_interval(0.1),
m_removed_sounds_check_timer(0),
m_state(LC_Created),
- m_localdb(NULL)
+ m_localdb(NULL),
+ m_script(NULL),
+ m_mod_storage_save_timer(10.0f),
+ m_game_ui_flags(game_ui_flags),
+ m_shutdown(false)
{
// Add local player
m_env.setLocalPlayer(new LocalPlayer(this, playername));
- m_mapper = new Mapper(device, this);
+ if (g_settings->getBool("enable_minimap")) {
+ m_minimap = new Minimap(device, this);
+ }
m_cache_save_interval = g_settings->getU16("server_map_save_interval");
- m_cache_smooth_lighting = g_settings->getBool("smooth_lighting");
- m_cache_enable_shaders = g_settings->getBool("enable_shaders");
- m_cache_use_tangent_vertices = m_cache_enable_shaders && (
- g_settings->getBool("enable_bumpmapping") ||
- g_settings->getBool("enable_parallax_occlusion"));
+ m_modding_enabled = g_settings->getBool("enable_client_modding");
+ m_script = new ClientScripting(this);
+ m_env.setScript(m_script);
+ m_script->setEnv(&m_env);
+}
+
+void Client::initMods()
+{
+ m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
+
+ // If modding is not enabled, don't load mods, just builtin
+ if (!m_modding_enabled) {
+ return;
+ }
+
+ ClientModConfiguration modconf(getClientModsLuaPath());
+ std::vector<ModSpec> mods = modconf.getMods();
+ std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
+ // complain about mods with unsatisfied dependencies
+ if (!modconf.isConsistent()) {
+ modconf.printUnsatisfiedModsError();
+ }
+
+ // Print mods
+ infostream << "Client Loading mods: ";
+ for (std::vector<ModSpec>::const_iterator i = mods.begin();
+ i != mods.end(); ++i) {
+ infostream << (*i).name << " ";
+ }
+
+ infostream << std::endl;
+ // Load and run "mod" scripts
+ for (std::vector<ModSpec>::const_iterator it = mods.begin();
+ it != mods.end(); ++it) {
+ const ModSpec &mod = *it;
+ if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
+ throw ModError("Error loading mod \"" + mod.name +
+ "\": Mod name does not follow naming conventions: "
+ "Only characters [a-z0-9_] are allowed.");
+ }
+ std::string script_path = mod.path + DIR_DELIM + "init.lua";
+ infostream << " [" << padStringRight(mod.name, 12) << "] [\""
+ << script_path << "\"]" << std::endl;
+ m_script->loadMod(script_path, mod.name);
+ }
+}
+
+const std::string &Client::getBuiltinLuaPath()
+{
+ static const std::string builtin_dir = porting::path_share + DIR_DELIM + "builtin";
+ return builtin_dir;
+}
+
+const std::string &Client::getClientModsLuaPath()
+{
+ static const std::string clientmods_dir = porting::path_share + DIR_DELIM + "clientmods";
+ return clientmods_dir;
+}
+
+const std::vector<ModSpec>& Client::getMods() const
+{
+ static std::vector<ModSpec> client_modspec_temp;
+ return client_modspec_temp;
+}
+
+const ModSpec* Client::getModSpec(const std::string &modname) const
+{
+ return NULL;
}
void Client::Stop()
{
+ m_shutdown = true;
+ // Don't disable this part when modding is disabled, it's used in builtin
+ m_script->on_shutdown();
//request all client managed threads to stop
m_mesh_update_thread.stop();
// Save local server map
@@ -279,18 +217,18 @@ void Client::Stop()
infostream << "Local map saving ended." << std::endl;
m_localdb->endSave();
}
+
+ delete m_script;
}
bool Client::isShutdown()
{
-
- if (!m_mesh_update_thread.isRunning()) return true;
-
- return false;
+ return m_shutdown || !m_mesh_update_thread.isRunning();
}
Client::~Client()
{
+ m_shutdown = true;
m_con.Disconnect();
m_mesh_update_thread.stop();
@@ -319,16 +257,14 @@ Client::~Client()
m_device->getSceneManager()->getMeshCache()->removeMesh(mesh);
}
- delete m_mapper;
+ delete m_minimap;
}
-void Client::connect(Address address,
- const std::string &address_name,
- bool is_local_server)
+void Client::connect(Address address, bool is_local_server)
{
DSTACK(FUNCTION_NAME);
- initLocalMapSaving(address, address_name, is_local_server);
+ initLocalMapSaving(address, m_address_name, is_local_server);
m_con.SetTimeoutMs(0);
m_con.Connect(address);
@@ -467,6 +403,14 @@ void Client::step(float dtime)
}
/*
+ Send pending messages on out chat queue
+ */
+ if (!m_out_chat_queue.empty() && canSendChatMessage()) {
+ sendChatMessage(m_out_chat_queue.front());
+ m_out_chat_queue.pop();
+ }
+
+ /*
Handle environment
*/
// Control local player (0ms)
@@ -476,20 +420,19 @@ void Client::step(float dtime)
// Step environment
m_env.step(dtime);
+ m_sound->step(dtime);
/*
Get events
*/
- for(;;) {
- ClientEnvEvent event = m_env.getClientEvent();
- if(event.type == CEE_NONE) {
- break;
- }
- else if(event.type == CEE_PLAYER_DAMAGE) {
- if(m_ignore_damage_timer <= 0) {
- u8 damage = event.player_damage.amount;
+ while (m_env.hasClientEnvEvents()) {
+ ClientEnvEvent envEvent = m_env.getClientEnvEvent();
+
+ if (envEvent.type == CEE_PLAYER_DAMAGE) {
+ if (m_ignore_damage_timer <= 0) {
+ u8 damage = envEvent.player_damage.amount;
- if(event.player_damage.send_to_server)
+ if (envEvent.player_damage.send_to_server)
sendDamage(damage);
// Add to ClientEvent queue
@@ -499,9 +442,10 @@ void Client::step(float dtime)
m_client_event_queue.push(event);
}
}
- else if(event.type == CEE_PLAYER_BREATH) {
- u16 breath = event.player_breath.amount;
- sendBreath(breath);
+ // Protocol v29 or greater obsoleted this event
+ else if (envEvent.type == CEE_PLAYER_BREATH && m_proto_ver < 29) {
+ u16 breath = envEvent.player_breath.amount;
+ sendBreath(breath);
}
}
@@ -555,20 +499,24 @@ void Client::step(float dtime)
minimap_mapblock = r.mesh->moveMinimapMapblock();
if (minimap_mapblock == NULL)
do_mapper_update = false;
- }
- if (r.mesh && r.mesh->getMesh()->getMeshBufferCount() == 0) {
- delete r.mesh;
- } else {
- // Replace with the new mesh
- block->mesh = r.mesh;
+ bool is_empty = true;
+ for (int l = 0; l < MAX_TILE_LAYERS; l++)
+ if (r.mesh->getMesh(l)->getMeshBufferCount() != 0)
+ is_empty = false;
+
+ if (is_empty)
+ delete r.mesh;
+ else
+ // Replace with the new mesh
+ block->mesh = r.mesh;
}
} else {
delete r.mesh;
}
- if (do_mapper_update)
- m_mapper->addBlock(r.p, minimap_mapblock);
+ if (m_minimap && do_mapper_update)
+ m_minimap->addBlock(r.p, minimap_mapblock);
if (r.ack_block_to_server) {
/*
@@ -590,7 +538,6 @@ void Client::step(float dtime)
if (m_media_downloader && m_media_downloader->isStarted()) {
m_media_downloader->step(this);
if (m_media_downloader->isDone()) {
- received_media();
delete m_media_downloader;
m_media_downloader = NULL;
}
@@ -663,6 +610,18 @@ void Client::step(float dtime)
}
}
+ m_mod_storage_save_timer -= dtime;
+ if (m_mod_storage_save_timer <= 0.0f) {
+ verbosestream << "Saving registered mod storages." << std::endl;
+ m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
+ for (UNORDERED_MAP<std::string, ModMetadata *>::const_iterator
+ it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
+ if (it->second->isModified()) {
+ it->second->save(getModStoragePath());
+ }
+ }
+ }
+
// Write server map
if (m_localdb && m_localdb_save_interval.step(dtime,
m_cache_save_interval)) {
@@ -799,14 +758,6 @@ void Client::request_media(const std::vector<std::string> &file_requests)
<< file_requests.size() << " files. packet size)" << std::endl;
}
-void Client::received_media()
-{
- NetworkPacket pkt(TOSERVER_RECEIVED_MEDIA, 0);
- Send(&pkt);
- infostream << "Client: Notifying server that we received all media"
- << std::endl;
-}
-
void Client::initLocalMapSaving(const Address &address,
const std::string &hostname,
bool is_local_server)
@@ -822,7 +773,7 @@ void Client::initLocalMapSaving(const Address &address,
fs::CreateAllDirs(world_path);
- m_localdb = new Database_SQLite3(world_path);
+ m_localdb = new MapDatabaseSQLite3(world_path);
m_localdb->beginSave();
actionstream << "Local map saving started, map will be saved at '" << world_path << "'" << std::endl;
}
@@ -830,7 +781,7 @@ void Client::initLocalMapSaving(const Address &address,
void Client::ReceiveAll()
{
DSTACK(FUNCTION_NAME);
- u32 start_ms = porting::getTimeMs();
+ u64 start_ms = porting::getTimeMs();
for(;;)
{
// Limit time even if there would be huge amounts of data to
@@ -1217,13 +1168,50 @@ void Client::sendInventoryAction(InventoryAction *a)
Send(&pkt);
}
+bool Client::canSendChatMessage() const
+{
+ u32 now = time(NULL);
+ float time_passed = now - m_last_chat_message_sent;
+
+ float virt_chat_message_allowance = m_chat_message_allowance + time_passed *
+ (CLIENT_CHAT_MESSAGE_LIMIT_PER_10S / 8.0f);
+
+ if (virt_chat_message_allowance < 1.0f)
+ return false;
+
+ return true;
+}
+
void Client::sendChatMessage(const std::wstring &message)
{
- NetworkPacket pkt(TOSERVER_CHAT_MESSAGE, 2 + message.size() * sizeof(u16));
+ const s16 max_queue_size = g_settings->getS16("max_out_chat_queue_size");
+ if (canSendChatMessage()) {
+ u32 now = time(NULL);
+ float time_passed = now - m_last_chat_message_sent;
+ m_last_chat_message_sent = time(NULL);
- pkt << message;
+ m_chat_message_allowance += time_passed * (CLIENT_CHAT_MESSAGE_LIMIT_PER_10S / 8.0f);
+ if (m_chat_message_allowance > CLIENT_CHAT_MESSAGE_LIMIT_PER_10S)
+ m_chat_message_allowance = CLIENT_CHAT_MESSAGE_LIMIT_PER_10S;
- Send(&pkt);
+ m_chat_message_allowance -= 1.0f;
+
+ NetworkPacket pkt(TOSERVER_CHAT_MESSAGE, 2 + message.size() * sizeof(u16));
+
+ pkt << message;
+
+ Send(&pkt);
+ } else if (m_out_chat_queue.size() < (u16) max_queue_size || max_queue_size == -1) {
+ m_out_chat_queue.push(message);
+ } else {
+ infostream << "Could not queue chat message because maximum out chat queue size ("
+ << max_queue_size << ") is reached." << std::endl;
+ }
+}
+
+void Client::clearOutChatQueue()
+{
+ m_out_chat_queue = std::queue<std::wstring>();
}
void Client::sendChangePassword(const std::string &oldpassword,
@@ -1270,6 +1258,10 @@ void Client::sendBreath(u16 breath)
{
DSTACK(FUNCTION_NAME);
+ // Protocol v29 make this obsolete
+ if (m_proto_ver >= 29)
+ return;
+
NetworkPacket pkt(TOSERVER_BREATH, sizeof(u16));
pkt << breath;
Send(&pkt);
@@ -1384,6 +1376,11 @@ void Client::removeNode(v3s16 p)
}
}
+MapNode Client::getNode(v3s16 p, bool *is_valid_position)
+{
+ return m_env.getMap().getNodeNoEx(p, is_valid_position);
+}
+
void Client::addNode(v3s16 p, MapNode n, bool remove_metadata)
{
//TimeTaker timer1("Client::addNode()");
@@ -1495,44 +1492,6 @@ void Client::inventoryAction(InventoryAction *a)
delete a;
}
-ClientActiveObject * Client::getSelectedActiveObject(
- f32 max_d,
- v3f from_pos_f_on_map,
- core::line3d<f32> shootline_on_map
- )
-{
- std::vector<DistanceSortedActiveObject> objects;
-
- m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
-
- // Sort them.
- // After this, the closest object is the first in the array.
- std::sort(objects.begin(), objects.end());
-
- for(unsigned int i=0; i<objects.size(); i++)
- {
- ClientActiveObject *obj = objects[i].obj;
-
- aabb3f *selection_box = obj->getSelectionBox();
- if(selection_box == NULL)
- continue;
-
- v3f pos = obj->getPosition();
-
- aabb3f offsetted_box(
- selection_box->MinEdge + pos,
- selection_box->MaxEdge + pos
- );
-
- if(offsetted_box.intersectsWithLine(shootline_on_map))
- {
- return obj;
- }
- }
-
- return NULL;
-}
-
float Client::getAnimationTime()
{
return m_animation_time;
@@ -1543,6 +1502,11 @@ int Client::getCrackLevel()
return m_crack_level;
}
+v3s16 Client::getCrackPos()
+{
+ return m_crack_pos;
+}
+
void Client::setCrack(int level, v3s16 pos)
{
int old_crack_level = m_crack_level;
@@ -1585,47 +1549,37 @@ void Client::typeChatMessage(const std::wstring &message)
if(message == L"")
return;
+ // If message was ate by script API, don't send it to server
+ if (m_script->on_sending_message(wide_to_utf8(message))) {
+ return;
+ }
+
// Send to others
sendChatMessage(message);
// Show locally
- if (message[0] == L'/')
- {
- m_chat_queue.push((std::wstring)L"issued command: " + message);
- }
- else
+ if (message[0] != L'/')
{
- LocalPlayer *player = m_env.getLocalPlayer();
- assert(player != NULL);
- std::wstring name = narrow_to_wide(player->getName());
- m_chat_queue.push((std::wstring)L"<" + name + L"> " + message);
+ // compatibility code
+ if (m_proto_ver < 29) {
+ LocalPlayer *player = m_env.getLocalPlayer();
+ assert(player != NULL);
+ std::wstring name = narrow_to_wide(player->getName());
+ pushToChatQueue((std::wstring)L"<" + name + L"> " + message);
+ }
}
}
void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
{
+ // Check if the block exists to begin with. In the case when a non-existing
+ // neighbor is automatically added, it may not. In that case we don't want
+ // to tell the mesh update thread about it.
MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
- if(b == NULL)
+ if (b == NULL)
return;
- /*
- Create a task to update the mesh of the block
- */
-
- MeshMakeData *data = new MeshMakeData(this, m_cache_enable_shaders,
- m_cache_use_tangent_vertices);
-
- {
- //TimeTaker timer("data fill");
- // Release: ~0ms
- // Debug: 1-6ms, avg=2ms
- data->fill(b);
- data->setCrack(m_crack_level, m_crack_pos);
- data->setSmoothLighting(m_cache_smooth_lighting);
- }
-
- // Add task to queue
- m_mesh_update_thread.enqueueUpdate(p, data, ack_to_server, urgent);
+ m_mesh_update_thread.updateBlock(&m_env.getMap(), p, ack_to_server, urgent);
}
void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
@@ -1691,14 +1645,11 @@ void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool ur
ClientEvent Client::getClientEvent()
{
- ClientEvent event;
- if (m_client_event_queue.empty()) {
- event.type = CE_NONE;
- }
- else {
- event = m_client_event_queue.front();
- m_client_event_queue.pop();
- }
+ FATAL_ERROR_IF(m_client_event_queue.empty(),
+ "Cannot getClientEvent, queue is empty.");
+
+ ClientEvent event = m_client_event_queue.front();
+ m_client_event_queue.pop();
return event;
}
@@ -1713,9 +1664,10 @@ float Client::mediaReceiveProgress()
typedef struct TextureUpdateArgs {
IrrlichtDevice *device;
gui::IGUIEnvironment *guienv;
- u32 last_time_ms;
+ u64 last_time_ms;
u16 last_percent;
const wchar_t* text_base;
+ ITextureSource *tsrc;
} TextureUpdateArgs;
void texture_update_progress(void *args, u32 progress, u32 max_progress)
@@ -1725,10 +1677,10 @@ void texture_update_progress(void *args, u32 progress, u32 max_progress)
// update the loading menu -- if neccessary
bool do_draw = false;
- u32 time_ms = targs->last_time_ms;
+ u64 time_ms = targs->last_time_ms;
if (cur_percent != targs->last_percent) {
targs->last_percent = cur_percent;
- time_ms = getTimeMs();
+ time_ms = porting::getTimeMs();
// only draw when the user will notice something:
do_draw = (time_ms - targs->last_time_ms > 100);
}
@@ -1737,8 +1689,8 @@ void texture_update_progress(void *args, u32 progress, u32 max_progress)
targs->last_time_ms = time_ms;
std::basic_stringstream<wchar_t> strm;
strm << targs->text_base << " " << targs->last_percent << "%...";
- draw_load_screen(strm.str(), targs->device, targs->guienv, 0,
- 72 + (u16) ((18. / 100.) * (double) targs->last_percent));
+ draw_load_screen(strm.str(), targs->device, targs->guienv, targs->tsrc, 0,
+ 72 + (u16) ((18. / 100.) * (double) targs->last_percent), true);
}
}
@@ -1758,21 +1710,21 @@ void Client::afterContentReceived(IrrlichtDevice *device)
// Rebuild inherited images and recreate textures
infostream<<"- Rebuilding images and textures"<<std::endl;
- draw_load_screen(text,device, guienv, 0, 70);
+ draw_load_screen(text,device, guienv, m_tsrc, 0, 70);
m_tsrc->rebuildImagesAndTextures();
delete[] text;
// Rebuild shaders
infostream<<"- Rebuilding shaders"<<std::endl;
text = wgettext("Rebuilding shaders...");
- draw_load_screen(text, device, guienv, 0, 71);
+ draw_load_screen(text, device, guienv, m_tsrc, 0, 71);
m_shsrc->rebuildShaders();
delete[] text;
// Update node aliases
infostream<<"- Updating node aliases"<<std::endl;
text = wgettext("Initializing nodes...");
- draw_load_screen(text, device, guienv, 0, 72);
+ draw_load_screen(text, device, guienv, m_tsrc, 0, 72);
m_nodedef->updateAliases(m_itemdef);
std::string texture_path = g_settings->get("texture_path");
if (texture_path != "" && fs::IsDir(texture_path))
@@ -1786,9 +1738,10 @@ void Client::afterContentReceived(IrrlichtDevice *device)
TextureUpdateArgs tu_args;
tu_args.device = device;
tu_args.guienv = guienv;
- tu_args.last_time_ms = getTimeMs();
+ tu_args.last_time_ms = porting::getTimeMs();
tu_args.last_percent = 0;
tu_args.text_base = wgettext("Initializing nodes");
+ tu_args.tsrc = m_tsrc;
m_nodedef->updateTextures(this, texture_update_progress, &tu_args);
delete[] tu_args.text_base;
@@ -1798,29 +1751,29 @@ void Client::afterContentReceived(IrrlichtDevice *device)
m_state = LC_Ready;
sendReady();
+
+ if (g_settings->getBool("enable_client_modding")) {
+ m_script->on_client_ready(m_env.getLocalPlayer());
+ m_script->on_connect();
+ }
+
text = wgettext("Done!");
- draw_load_screen(text, device, guienv, 0, 100);
+ draw_load_screen(text, device, guienv, m_tsrc, 0, 100);
infostream<<"Client::afterContentReceived() done"<<std::endl;
delete[] text;
}
-float Client::getRTT(void)
+float Client::getRTT()
{
return m_con.getPeerStat(PEER_ID_SERVER,con::AVG_RTT);
}
-float Client::getCurRate(void)
+float Client::getCurRate()
{
- return ( m_con.getLocalStat(con::CUR_INC_RATE) +
+ return (m_con.getLocalStat(con::CUR_INC_RATE) +
m_con.getLocalStat(con::CUR_DL_RATE));
}
-float Client::getAvgRate(void)
-{
- return ( m_con.getLocalStat(con::AVG_INC_RATE) +
- m_con.getLocalStat(con::AVG_DL_RATE));
-}
-
void Client::makeScreenshot(IrrlichtDevice *device)
{
irr::video::IVideoDriver *driver = device->getVideoDriver();
@@ -1871,7 +1824,7 @@ void Client::makeScreenshot(IrrlichtDevice *device)
} else {
sstr << "Failed to save screenshot '" << filename << "'";
}
- m_chat_queue.push(narrow_to_wide(sstr.str()));
+ pushToChatQueue(narrow_to_wide(sstr.str()));
infostream << sstr.str() << std::endl;
image->drop();
}
@@ -1880,6 +1833,41 @@ void Client::makeScreenshot(IrrlichtDevice *device)
raw_image->drop();
}
+bool Client::shouldShowMinimap() const
+{
+ return !m_minimap_disabled_by_server;
+}
+
+void Client::showGameChat(const bool show)
+{
+ m_game_ui_flags->show_chat = show;
+}
+
+void Client::showGameHud(const bool show)
+{
+ m_game_ui_flags->show_hud = show;
+}
+
+void Client::showMinimap(const bool show)
+{
+ m_game_ui_flags->show_minimap = show;
+}
+
+void Client::showProfiler(const bool show)
+{
+ m_game_ui_flags->show_profiler_graph = show;
+}
+
+void Client::showGameFog(const bool show)
+{
+ m_game_ui_flags->force_fog_off = !show;
+}
+
+void Client::showGameDebug(const bool show)
+{
+ m_game_ui_flags->show_debug = show;
+}
+
// IGameDef interface
// Under envlock
IItemDefManager* Client::getItemDefManager()
@@ -1956,3 +1944,30 @@ scene::IAnimatedMesh* Client::getMesh(const std::string &filename)
smgr->getMeshCache()->removeMesh(mesh);
return mesh;
}
+
+bool Client::registerModStorage(ModMetadata *storage)
+{
+ if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
+ errorstream << "Unable to register same mod storage twice. Storage name: "
+ << storage->getModName() << std::endl;
+ return false;
+ }
+
+ m_mod_storages[storage->getModName()] = storage;
+ return true;
+}
+
+void Client::unregisterModStorage(const std::string &name)
+{
+ UNORDERED_MAP<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
+ if (it != m_mod_storages.end()) {
+ // Save unconditionaly on unregistration
+ it->second->save(getModStoragePath());
+ m_mod_storages.erase(name);
+ }
+}
+
+std::string Client::getModStoragePath() const
+{
+ return porting::path_user + DIR_DELIM + "client" + DIR_DELIM + "mod_storage";
+}
diff --git a/src/client.h b/src/client.h
index 9f5bda059..b4145c76f 100644
--- a/src/client.h
+++ b/src/client.h
@@ -21,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define CLIENT_HEADER
#include "network/connection.h"
-#include "environment.h"
+#include "clientenvironment.h"
#include "irrlichttypes_extrabloated.h"
#include "threading/mutex.h"
#include <ostream>
@@ -34,7 +34,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "localplayer.h"
#include "hud.h"
#include "particles.h"
-#include "network/networkpacket.h"
+#include "mapnode.h"
+#include "tileanimation.h"
+#include "mesh_generator_thread.h"
+
+#define CLIENT_CHAT_MESSAGE_LIMIT_PER_10S 10.0f
struct MeshMakeData;
class MapBlockMesh;
@@ -47,20 +51,11 @@ class ClientMediaDownloader;
struct MapDrawControl;
class MtEventManager;
struct PointedThing;
-class Database;
-class Mapper;
+class MapDatabase;
+class Minimap;
struct MinimapMapblock;
class Camera;
-
-struct QueuedMeshUpdate
-{
- v3s16 p;
- MeshMakeData *data;
- bool ack_block_to_server;
-
- QueuedMeshUpdate();
- ~QueuedMeshUpdate();
-};
+class NetworkPacket;
enum LocalClientState {
LC_Created,
@@ -68,71 +63,6 @@ enum LocalClientState {
LC_Ready
};
-/*
- A thread-safe queue of mesh update tasks
-*/
-class MeshUpdateQueue
-{
-public:
- MeshUpdateQueue();
-
- ~MeshUpdateQueue();
-
- /*
- peer_id=0 adds with nobody to send to
- */
- void addBlock(v3s16 p, MeshMakeData *data,
- bool ack_block_to_server, bool urgent);
-
- // Returned pointer must be deleted
- // Returns NULL if queue is empty
- QueuedMeshUpdate * pop();
-
- u32 size()
- {
- MutexAutoLock lock(m_mutex);
- return m_queue.size();
- }
-
-private:
- std::vector<QueuedMeshUpdate*> m_queue;
- std::set<v3s16> m_urgents;
- Mutex m_mutex;
-};
-
-struct MeshUpdateResult
-{
- v3s16 p;
- MapBlockMesh *mesh;
- bool ack_block_to_server;
-
- MeshUpdateResult():
- p(-1338,-1338,-1338),
- mesh(NULL),
- ack_block_to_server(false)
- {
- }
-};
-
-class MeshUpdateThread : public UpdateThread
-{
-private:
- MeshUpdateQueue m_queue_in;
-
-protected:
- virtual void doUpdate();
-
-public:
-
- MeshUpdateThread() : UpdateThread("Mesh") {}
-
- void enqueueUpdate(v3s16 p, MeshMakeData *data,
- bool ack_block_to_server, bool urgent);
- MutexedQueue<MeshUpdateResult> m_queue_out;
-
- v3s16 m_camera_offset;
-};
-
enum ClientEventType
{
CE_NONE,
@@ -140,6 +70,7 @@ enum ClientEventType
CE_PLAYER_FORCE_MOVE,
CE_DEATHSCREEN,
CE_SHOW_FORMSPEC,
+ CE_SHOW_LOCAL_FORMSPEC,
CE_SPAWN_PARTICLE,
CE_ADD_PARTICLESPAWNER,
CE_DELETE_PARTICLESPAWNER,
@@ -148,6 +79,7 @@ enum ClientEventType
CE_HUDCHANGE,
CE_SET_SKY,
CE_OVERRIDE_DAY_NIGHT_RATIO,
+ CE_CLOUD_PARAMS,
};
struct ClientEvent
@@ -185,6 +117,8 @@ struct ClientEvent
bool collision_removal;
bool vertical;
std::string *texture;
+ struct TileAnimationParams animation;
+ u8 glow;
} spawn_particle;
struct{
u16 amount;
@@ -205,6 +139,8 @@ struct ClientEvent
bool vertical;
std::string *texture;
u32 id;
+ struct TileAnimationParams animation;
+ u8 glow;
} add_particlespawner;
struct{
u32 id;
@@ -240,11 +176,21 @@ struct ClientEvent
video::SColor *bgcolor;
std::string *type;
std::vector<std::string> *params;
+ bool clouds;
} set_sky;
struct{
bool do_override;
float ratio_f;
} override_day_night_ratio;
+ struct {
+ f32 density;
+ u32 color_bright;
+ u32 color_ambient;
+ f32 height;
+ f32 thickness;
+ f32 speed_x;
+ f32 speed_y;
+ } cloud_params;
};
};
@@ -299,6 +245,9 @@ private:
std::map<u16, u16> m_packets;
};
+class ClientScripting;
+struct GameUIFlags;
+
class Client : public con::PeerHandler, public InventoryManager, public IGameDef
{
public:
@@ -309,7 +258,8 @@ public:
Client(
IrrlichtDevice *device,
const char *playername,
- std::string password,
+ const std::string &password,
+ const std::string &address_name,
MapDrawControl &control,
IWritableTextureSource *tsrc,
IWritableShaderSource *shsrc,
@@ -317,11 +267,14 @@ public:
IWritableNodeDefManager *nodedef,
ISoundManager *sound,
MtEventManager *event,
- bool ipv6
+ bool ipv6,
+ GameUIFlags *game_ui_flags
);
~Client();
+ void initMods();
+
/*
request all threads managed by client to be stopped
*/
@@ -334,9 +287,7 @@ public:
The name of the local player should already be set when
calling this, as it is sent in the initialization.
*/
- void connect(Address address,
- const std::string &address_name,
- bool is_local_server);
+ void connect(Address address, bool is_local_server);
/*
Stuff that references the environment is valid only as
@@ -372,16 +323,14 @@ public:
void handleCommand_HP(NetworkPacket* pkt);
void handleCommand_Breath(NetworkPacket* pkt);
void handleCommand_MovePlayer(NetworkPacket* pkt);
- void handleCommand_PlayerItem(NetworkPacket* pkt);
void handleCommand_DeathScreen(NetworkPacket* pkt);
void handleCommand_AnnounceMedia(NetworkPacket* pkt);
void handleCommand_Media(NetworkPacket* pkt);
- void handleCommand_ToolDef(NetworkPacket* pkt);
void handleCommand_NodeDef(NetworkPacket* pkt);
- void handleCommand_CraftItemDef(NetworkPacket* pkt);
void handleCommand_ItemDef(NetworkPacket* pkt);
void handleCommand_PlaySound(NetworkPacket* pkt);
void handleCommand_StopSound(NetworkPacket* pkt);
+ void handleCommand_FadeSound(NetworkPacket *pkt);
void handleCommand_Privileges(NetworkPacket* pkt);
void handleCommand_InventoryFormSpec(NetworkPacket* pkt);
void handleCommand_DetachedInventory(NetworkPacket* pkt);
@@ -395,6 +344,7 @@ public:
void handleCommand_HudSetFlags(NetworkPacket* pkt);
void handleCommand_HudSetParam(NetworkPacket* pkt);
void handleCommand_HudSetSky(NetworkPacket* pkt);
+ void handleCommand_CloudParams(NetworkPacket* pkt);
void handleCommand_OverrideDayNightRatio(NetworkPacket* pkt);
void handleCommand_LocalPlayerAnimations(NetworkPacket* pkt);
void handleCommand_EyeOffset(NetworkPacket* pkt);
@@ -402,9 +352,6 @@ public:
void ProcessData(NetworkPacket *pkt);
- // Returns true if something was received
- bool AsyncProcessPacket();
- bool AsyncProcessData();
void Send(NetworkPacket* pkt);
void interact(u8 action, const PointedThing& pointed);
@@ -415,6 +362,7 @@ public:
const StringMap &fields);
void sendInventoryAction(InventoryAction *a);
void sendChatMessage(const std::wstring &message);
+ void clearOutChatQueue();
void sendChangePassword(const std::string &oldpassword,
const std::string &newpassword);
void sendDamage(u8 damage);
@@ -422,11 +370,18 @@ public:
void sendRespawn();
void sendReady();
- ClientEnvironment& getEnv()
- { return m_env; }
+ ClientEnvironment& getEnv() { return m_env; }
+ ITextureSource *tsrc() { return getTextureSource(); }
+ ISoundManager *sound() { return getSoundManager(); }
+ static const std::string &getBuiltinLuaPath();
+ static const std::string &getClientModsLuaPath();
+
+ virtual const std::vector<ModSpec> &getMods() const;
+ virtual const ModSpec* getModSpec(const std::string &modname) const;
// Causes urgent mesh updates (unlike Map::add/removeNodeWithEvent)
void removeNode(v3s16 p);
+ MapNode getNode(v3s16 p, bool *is_valid_position);
void addNode(v3s16 p, MapNode n, bool remove_metadata = true);
void setPlayerControl(PlayerControl &control);
@@ -445,14 +400,6 @@ public:
Inventory* getInventory(const InventoryLocation &loc);
void inventoryAction(InventoryAction *a);
- // Gets closest object pointed by the shootline
- // Returns NULL if not found
- ClientActiveObject * getSelectedActiveObject(
- f32 max_d,
- v3f from_pos_f_on_map,
- core::line3d<f32> shootline_on_map
- );
-
const std::list<std::string> &getConnectedPlayerNames()
{
return m_env.getPlayerNames();
@@ -461,6 +408,7 @@ public:
float getAnimationTime();
int getCrackLevel();
+ v3s16 getCrackPos();
void setCrack(int level, v3s16 pos);
u16 getHP();
@@ -481,16 +429,23 @@ public:
void updateCameraOffset(v3s16 camera_offset)
{ m_mesh_update_thread.m_camera_offset = camera_offset; }
- // Get event from queue. CE_NONE is returned if queue is empty.
+ bool hasClientEvents() const { return !m_client_event_queue.empty(); }
+ // Get event from queue. If queue is empty, it triggers an assertion failure.
ClientEvent getClientEvent();
- bool accessDenied()
- { return m_access_denied; }
+ bool accessDenied() const { return m_access_denied; }
+
+ bool reconnectRequested() const { return m_access_denied_reconnect; }
- bool reconnectRequested() { return m_access_denied_reconnect; }
+ void setFatalError(const std::string &reason)
+ {
+ m_access_denied = true;
+ m_access_denied_reason = reason;
+ }
- std::string accessDeniedReason()
- { return m_access_denied_reason; }
+ // Renaming accessDeniedReason to better name could be good as it's used to
+ // disconnect client when CSM failed.
+ const std::string &accessDeniedReason() const { return m_access_denied_reason; }
bool itemdefReceived()
{ return m_itemdef_received; }
@@ -509,49 +464,78 @@ public:
void afterContentReceived(IrrlichtDevice *device);
- float getRTT(void);
- float getCurRate(void);
- float getAvgRate(void);
+ float getRTT();
+ float getCurRate();
- Mapper* getMapper ()
- { return m_mapper; }
+ Minimap* getMinimap() { return m_minimap; }
+ void setCamera(Camera* camera) { m_camera = camera; }
- void setCamera(Camera* camera)
- { m_camera = camera; }
+ Camera* getCamera () { return m_camera; }
- Camera* getCamera ()
- { return m_camera; }
-
- bool isMinimapDisabledByServer()
- { return m_minimap_disabled_by_server; }
+ bool shouldShowMinimap() const;
// IGameDef interface
virtual IItemDefManager* getItemDefManager();
virtual INodeDefManager* getNodeDefManager();
virtual ICraftDefManager* getCraftDefManager();
- virtual ITextureSource* getTextureSource();
+ ITextureSource* getTextureSource();
virtual IShaderSource* getShaderSource();
- virtual scene::ISceneManager* getSceneManager();
+ IShaderSource *shsrc() { return getShaderSource(); }
+ scene::ISceneManager* getSceneManager();
virtual u16 allocateUnknownNodeId(const std::string &name);
virtual ISoundManager* getSoundManager();
virtual MtEventManager* getEventManager();
virtual ParticleManager* getParticleManager();
- virtual bool checkLocalPrivilege(const std::string &priv)
+ bool checkLocalPrivilege(const std::string &priv)
{ return checkPrivilege(priv); }
virtual scene::IAnimatedMesh* getMesh(const std::string &filename);
+ virtual std::string getModStoragePath() const;
+ virtual bool registerModStorage(ModMetadata *meta);
+ virtual void unregisterModStorage(const std::string &name);
+
// The following set of functions is used by ClientMediaDownloader
// Insert a media file appropriately into the appropriate manager
bool loadMedia(const std::string &data, const std::string &filename);
// Send a request for conventional media transfer
void request_media(const std::vector<std::string> &file_requests);
- // Send a notification that no conventional media transfer is needed
- void received_media();
LocalClientState getState() { return m_state; }
void makeScreenshot(IrrlichtDevice *device);
+ inline void pushToChatQueue(const std::wstring &input)
+ {
+ m_chat_queue.push(input);
+ }
+
+ ClientScripting *getScript() { return m_script; }
+ const bool moddingEnabled() const { return m_modding_enabled; }
+
+ inline void pushToEventQueue(const ClientEvent &event)
+ {
+ m_client_event_queue.push(event);
+ }
+
+ void showGameChat(const bool show = true);
+ void showGameHud(const bool show = true);
+ void showMinimap(const bool show = true);
+ void showProfiler(const bool show = true);
+ void showGameFog(const bool show = true);
+ void showGameDebug(const bool show = true);
+
+ IrrlichtDevice *getDevice() const { return m_device; }
+
+ const Address getServerAddress()
+ {
+ return m_con.GetPeerAddress(PEER_ID_SERVER);
+ }
+
+ const std::string &getAddressName() const
+ {
+ return m_address_name;
+ }
+
private:
// Virtual methods from con::PeerHandler
@@ -584,6 +568,8 @@ private:
inline std::string getPlayerName()
{ return m_env.getLocalPlayer()->getName(); }
+ bool canSendChatMessage() const;
+
float m_packetcounter_timer;
float m_connection_reinit_timer;
float m_avg_rtt_timer;
@@ -603,9 +589,10 @@ private:
ClientEnvironment m_env;
ParticleManager m_particle_manager;
con::Connection m_con;
+ std::string m_address_name;
IrrlichtDevice *m_device;
Camera *m_camera;
- Mapper *m_mapper;
+ Minimap *m_minimap;
bool m_minimap_disabled_by_server;
// Server serialization version
u8 m_server_ser_ver;
@@ -630,6 +617,9 @@ private:
//s32 m_daynight_i;
//u32 m_daynight_ratio;
std::queue<std::wstring> m_chat_queue;
+ std::queue<std::wstring> m_out_chat_queue;
+ u32 m_last_chat_message_sent;
+ float m_chat_message_allowance;
// The authentication methods we can use to enter sudo mode (=change password)
u32 m_sudo_auth_methods;
@@ -686,15 +676,17 @@ private:
LocalClientState m_state;
// Used for saving server map to disk client-side
- Database *m_localdb;
+ MapDatabase *m_localdb;
IntervalLimiter m_localdb_save_interval;
u16 m_cache_save_interval;
- // TODO: Add callback to update these when g_settings changes
- bool m_cache_smooth_lighting;
- bool m_cache_enable_shaders;
- bool m_cache_use_tangent_vertices;
+ ClientScripting *m_script;
+ bool m_modding_enabled;
+ UNORDERED_MAP<std::string, ModMetadata *> m_mod_storages;
+ float m_mod_storage_save_timer;
+ GameUIFlags *m_game_ui_flags;
+ bool m_shutdown;
DISABLE_CLASS_COPY(Client);
};
diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt
index 5faa186a7..2d274ae68 100644
--- a/src/client/CMakeLists.txt
+++ b/src/client/CMakeLists.txt
@@ -1,5 +1,6 @@
set(client_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/clientlauncher.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/inputhandler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/joystick_controller.cpp
PARENT_SCOPE
diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp
index 6145e3dde..289d1537b 100644
--- a/src/client/clientlauncher.cpp
+++ b/src/client/clientlauncher.cpp
@@ -42,31 +42,15 @@ gui::IGUIEnvironment *guienv = NULL;
gui::IGUIStaticText *guiroot = NULL;
MainMenuManager g_menumgr;
-bool noMenuActive()
+bool isMenuActive()
{
- return g_menumgr.menuCount() == 0;
+ return g_menumgr.menuCount() != 0;
}
// Passed to menus to allow disconnecting and exiting
MainGameCallback *g_gamecallback = NULL;
-// Instance of the time getter
-static TimeGetter *g_timegetter = NULL;
-
-u32 getTimeMs()
-{
- if (g_timegetter == NULL)
- return 0;
- return g_timegetter->getTime(PRECISION_MILLI);
-}
-
-u32 getTime(TimePrecision prec) {
- if (g_timegetter == NULL)
- return 0;
- return g_timegetter->getTime(prec);
-}
-
ClientLauncher::~ClientLauncher()
{
if (receiver)
@@ -96,9 +80,6 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
return false;
}
- // Create time getter
- g_timegetter = new IrrlichtTimeGetter(device);
-
// Speed tests (done after irrlicht is loaded to get timer)
if (cmd_args.getFlag("speedtests")) {
dstream << "Running speed tests" << std::endl;
@@ -114,7 +95,7 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
porting::setXorgClassHint(video_driver->getExposedVideoData(), PROJECT_NAME_C);
- porting::setXorgWindowIcon(device);
+ porting::setWindowIcon(device);
/*
This changes the minimum allowed number of vertices in a VBO.
@@ -127,10 +108,7 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
device->setResizable(true);
- if (random_input)
- input = new RandomInputHandler();
- else
- input = new RealInputHandler(device, receiver);
+ init_input();
smgr = device->getSceneManager();
smgr->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
@@ -337,6 +315,33 @@ bool ClientLauncher::init_engine()
return device != NULL;
}
+void ClientLauncher::init_input()
+{
+ if (random_input)
+ input = new RandomInputHandler();
+ else
+ input = new RealInputHandler(device, receiver);
+
+ if (g_settings->getBool("enable_joysticks")) {
+ irr::core::array<irr::SJoystickInfo> infos;
+ std::vector<irr::SJoystickInfo> joystick_infos;
+
+ // Make sure this is called maximum once per
+ // irrlicht device, otherwise it will give you
+ // multiple events for the same joystick.
+ if (device->activateJoysticks(infos)) {
+ infostream << "Joystick support enabled" << std::endl;
+ joystick_infos.reserve(infos.size());
+ for (u32 i = 0; i < infos.size(); i++) {
+ joystick_infos.push_back(infos[i]);
+ }
+ input->joystick.onJoystickConnect(joystick_infos);
+ } else {
+ errorstream << "Could not activate joystick support." << std::endl;
+ }
+ }
+}
+
bool ClientLauncher::launch_game(std::string &error_message,
bool reconnect_requested, GameParams &game_params,
const Settings &cmd_args)
@@ -403,15 +408,14 @@ bool ClientLauncher::launch_game(std::string &error_message,
return false;
}
- if (menudata.name == "")
- menudata.name = std::string("Guest") + itos(myrand_range(1000, 9999));
- else
- playername = menudata.name;
+ if (menudata.name == "" && !simple_singleplayer_mode) {
+ error_message = gettext("Please choose a name!");
+ return false;
+ }
+ playername = menudata.name;
password = menudata.password;
- g_settings->set("name", playername);
-
current_playername = playername;
current_password = password;
current_address = address;
@@ -424,13 +428,16 @@ bool ClientLauncher::launch_game(std::string &error_message,
current_password = "";
current_address = "";
current_port = myrand_range(49152, 65535);
- } else if (address != "") {
- ServerListSpec server;
- server["name"] = menudata.servername;
- server["address"] = menudata.address;
- server["port"] = menudata.port;
- server["description"] = menudata.serverdescription;
- ServerList::insert(server);
+ } else {
+ g_settings->set("name", playername);
+ if (address != "") {
+ ServerListSpec server;
+ server["name"] = menudata.servername;
+ server["address"] = menudata.address;
+ server["port"] = menudata.port;
+ server["description"] = menudata.serverdescription;
+ ServerList::insert(server);
+ }
}
infostream << "Selected world: " << worldspec.name
@@ -489,7 +496,7 @@ void ClientLauncher::main_menu(MainMenuData *menudata)
infostream << "Waiting for other menus" << std::endl;
while (device->run() && *kill == false) {
- if (noMenuActive())
+ if (!isMenuActive())
break;
driver->beginScene(true, true, video::SColor(255, 128, 128, 128));
guienv->drawAll();
@@ -528,7 +535,7 @@ bool ClientLauncher::create_engine_device()
// Determine driver
video::E_DRIVER_TYPE driverType = video::EDT_OPENGL;
- std::string driverstring = g_settings->get("video_driver");
+ const std::string &driverstring = g_settings->get("video_driver");
std::vector<video::E_DRIVER_TYPE> drivers
= porting::getSupportedVideoDrivers();
u32 i;
@@ -564,25 +571,8 @@ bool ClientLauncher::create_engine_device()
device = createDeviceEx(params);
- if (device) {
- if (g_settings->getBool("enable_joysticks")) {
- irr::core::array<irr::SJoystickInfo> infos;
- std::vector<irr::SJoystickInfo> joystick_infos;
- // Make sure this is called maximum once per
- // irrlicht device, otherwise it will give you
- // multiple events for the same joystick.
- if (device->activateJoysticks(infos)) {
- infostream << "Joystick support enabled" << std::endl;
- joystick_infos.reserve(infos.size());
- for (u32 i = 0; i < infos.size(); i++) {
- joystick_infos.push_back(infos[i]);
- }
- } else {
- errorstream << "Could not activate joystick support." << std::endl;
- }
- }
+ if (device)
porting::initIrrlicht(device);
- }
return device != NULL;
}
diff --git a/src/client/clientlauncher.h b/src/client/clientlauncher.h
index b10bbebc9..4ff77bc03 100644
--- a/src/client/clientlauncher.h
+++ b/src/client/clientlauncher.h
@@ -24,42 +24,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/inputhandler.h"
#include "gameparams.h"
-// A small helper class
-class TimeGetter
-{
-public:
- virtual u32 getTime(TimePrecision prec) = 0;
-};
-
-// A precise irrlicht one
-class IrrlichtTimeGetter: public TimeGetter
-{
-public:
- IrrlichtTimeGetter(IrrlichtDevice *device):
- m_device(device)
- {}
- u32 getTime(TimePrecision prec)
- {
- if (prec == PRECISION_MILLI) {
- if (m_device == NULL)
- return 0;
- return m_device->getTimer()->getRealTime();
- } else {
- return porting::getTime(prec);
- }
- }
-private:
- IrrlichtDevice *m_device;
-};
-// Not so precise one which works without irrlicht
-class SimpleTimeGetter: public TimeGetter
-{
-public:
- u32 getTime(TimePrecision prec)
- {
- return porting::getTime(prec);
- }
-};
class ClientLauncher
{
@@ -91,6 +55,7 @@ public:
protected:
void init_args(GameParams &game_params, const Settings &cmd_args);
bool init_engine();
+ void init_input();
bool launch_game(std::string &error_message, bool reconnect_requested,
GameParams &game_params, const Settings &cmd_args);
diff --git a/src/client/inputhandler.cpp b/src/client/inputhandler.cpp
new file mode 100644
index 000000000..9c7a94c4e
--- /dev/null
+++ b/src/client/inputhandler.cpp
@@ -0,0 +1,119 @@
+/*
+Minetest
+Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "util/numeric.h"
+#include "inputhandler.h"
+#include "mainmenumanager.h"
+
+bool MyEventReceiver::OnEvent(const SEvent &event)
+{
+ /*
+ React to nothing here if a menu is active
+ */
+ if (isMenuActive()) {
+#ifdef HAVE_TOUCHSCREENGUI
+ if (m_touchscreengui) {
+ m_touchscreengui->Toggle(false);
+ }
+#endif
+ return g_menumgr.preprocessEvent(event);
+ }
+
+ // Remember whether each key is down or up
+ if (event.EventType == irr::EET_KEY_INPUT_EVENT) {
+ const KeyPress &keyCode = event.KeyInput;
+ if (keysListenedFor[keyCode]) {
+ if (event.KeyInput.PressedDown) {
+ keyIsDown.set(keyCode);
+ keyWasDown.set(keyCode);
+ } else {
+ keyIsDown.unset(keyCode);
+ }
+ return true;
+ }
+ }
+
+#ifdef HAVE_TOUCHSCREENGUI
+ // case of touchscreengui we have to handle different events
+ if (m_touchscreengui && event.EventType == irr::EET_TOUCH_INPUT_EVENT) {
+ m_touchscreengui->translateEvent(event);
+ return true;
+ }
+#endif
+
+ if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) {
+ /* TODO add a check like:
+ if (event.JoystickEvent != joystick_we_listen_for)
+ return false;
+ */
+ return joystick->handleEvent(event.JoystickEvent);
+ }
+ // handle mouse events
+ if (event.EventType == irr::EET_MOUSE_INPUT_EVENT) {
+ if (isMenuActive()) {
+ left_active = false;
+ middle_active = false;
+ right_active = false;
+ } else {
+ left_active = event.MouseInput.isLeftPressed();
+ middle_active = event.MouseInput.isMiddlePressed();
+ right_active = event.MouseInput.isRightPressed();
+
+ if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) {
+ leftclicked = true;
+ }
+ if (event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN) {
+ rightclicked = true;
+ }
+ if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) {
+ leftreleased = true;
+ }
+ if (event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP) {
+ rightreleased = true;
+ }
+ if (event.MouseInput.Event == EMIE_MOUSE_WHEEL) {
+ mouse_wheel += event.MouseInput.Wheel;
+ }
+ }
+ } else if (event.EventType == irr::EET_LOG_TEXT_EVENT) {
+ static const LogLevel irr_loglev_conv[] = {
+ LL_VERBOSE, // ELL_DEBUG
+ LL_INFO, // ELL_INFORMATION
+ LL_WARNING, // ELL_WARNING
+ LL_ERROR, // ELL_ERROR
+ LL_NONE, // ELL_NONE
+ };
+ assert(event.LogEvent.Level < ARRLEN(irr_loglev_conv));
+ g_logger.log(irr_loglev_conv[event.LogEvent.Level],
+ std::string("Irrlicht: ") +
+ (const char *)event.LogEvent.Text);
+ return true;
+ }
+ /* always return false in order to continue processing events */
+ return false;
+}
+
+/*
+ * RandomInputHandler
+ */
+s32 RandomInputHandler::Rand(s32 min, s32 max)
+{
+ return (myrand() % (max - min + 1)) + min;
+}
diff --git a/src/client/inputhandler.h b/src/client/inputhandler.h
index 824b0da2e..7c422d189 100644
--- a/src/client/inputhandler.h
+++ b/src/client/inputhandler.h
@@ -22,104 +22,87 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h"
#include "joystick_controller.h"
+#include <list>
+#include "keycode.h"
-class MyEventReceiver : public IEventReceiver
-{
-public:
- // This is the one method that we have to implement
- virtual bool OnEvent(const SEvent& event)
- {
- /*
- React to nothing here if a menu is active
- */
- if (noMenuActive() == false) {
#ifdef HAVE_TOUCHSCREENGUI
- if (m_touchscreengui != 0) {
- m_touchscreengui->Toggle(false);
- }
+#include "touchscreengui.h"
#endif
- return g_menumgr.preprocessEvent(event);
- }
- // Remember whether each key is down or up
- if (event.EventType == irr::EET_KEY_INPUT_EVENT) {
- const KeyPress &keyCode = event.KeyInput;
- if (keysListenedFor[keyCode]) {
- if (event.KeyInput.PressedDown) {
- keyIsDown.set(keyCode);
- keyWasDown.set(keyCode);
- } else {
- keyIsDown.unset(keyCode);
- }
- return true;
- }
- }
+class KeyList : private std::list<KeyPress>
+{
+ typedef std::list<KeyPress> super;
+ typedef super::iterator iterator;
+ typedef super::const_iterator const_iterator;
-#ifdef HAVE_TOUCHSCREENGUI
- // case of touchscreengui we have to handle different events
- if ((m_touchscreengui != 0) &&
- (event.EventType == irr::EET_TOUCH_INPUT_EVENT)) {
- m_touchscreengui->translateEvent(event);
- return true;
- }
-#endif
+ virtual const_iterator find(const KeyPress &key) const
+ {
+ const_iterator f(begin());
+ const_iterator e(end());
+
+ while (f != e) {
+ if (*f == key)
+ return f;
- if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) {
- /* TODO add a check like:
- if (event.JoystickEvent != joystick_we_listen_for)
- return false;
- */
- return joystick->handleEvent(event.JoystickEvent);
+ ++f;
}
- // handle mouse events
- if (event.EventType == irr::EET_MOUSE_INPUT_EVENT) {
- if (noMenuActive() == false) {
- left_active = false;
- middle_active = false;
- right_active = false;
- } else {
- left_active = event.MouseInput.isLeftPressed();
- middle_active = event.MouseInput.isMiddlePressed();
- right_active = event.MouseInput.isRightPressed();
-
- if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) {
- leftclicked = true;
- }
- if (event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN) {
- rightclicked = true;
- }
- if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) {
- leftreleased = true;
- }
- if (event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP) {
- rightreleased = true;
- }
- if (event.MouseInput.Event == EMIE_MOUSE_WHEEL) {
- mouse_wheel += event.MouseInput.Wheel;
- }
- }
- } else if (event.EventType == irr::EET_LOG_TEXT_EVENT) {
- static const LogLevel irr_loglev_conv[] = {
- LL_VERBOSE, // ELL_DEBUG
- LL_INFO, // ELL_INFORMATION
- LL_WARNING, // ELL_WARNING
- LL_ERROR, // ELL_ERROR
- LL_NONE, // ELL_NONE
- };
- assert(event.LogEvent.Level < ARRLEN(irr_loglev_conv));
- g_logger.log(irr_loglev_conv[event.LogEvent.Level],
- std::string("Irrlicht: ") + (const char*) event.LogEvent.Text);
- return true;
+
+ return e;
+ }
+
+ virtual iterator find(const KeyPress &key)
+ {
+ iterator f(begin());
+ iterator e(end());
+
+ while (f != e) {
+ if (*f == key)
+ return f;
+
+ ++f;
}
- /* always return false in order to continue processing events */
- return false;
+
+ return e;
+ }
+
+public:
+ void clear() { super::clear(); }
+
+ void set(const KeyPress &key)
+ {
+ if (find(key) == end())
+ push_back(key);
}
- bool IsKeyDown(const KeyPress &keyCode) const
+ void unset(const KeyPress &key)
{
- return keyIsDown[keyCode];
+ iterator p(find(key));
+
+ if (p != end())
+ erase(p);
}
+ void toggle(const KeyPress &key)
+ {
+ iterator p(this->find(key));
+
+ if (p != end())
+ erase(p);
+ else
+ push_back(key);
+ }
+
+ bool operator[](const KeyPress &key) const { return find(key) != end(); }
+};
+
+class MyEventReceiver : public IEventReceiver
+{
+public:
+ // This is the one method that we have to implement
+ virtual bool OnEvent(const SEvent &event);
+
+ bool IsKeyDown(const KeyPress &keyCode) const { return keyIsDown[keyCode]; }
+
// Checks whether a key was down and resets the state
bool WasKeyDown(const KeyPress &keyCode)
{
@@ -129,14 +112,8 @@ public:
return b;
}
- void listenForKey(const KeyPress &keyCode)
- {
- keysListenedFor.set(keyCode);
- }
- void dontListenForKeys()
- {
- keysListenedFor.clear();
- }
+ void listenForKey(const KeyPress &keyCode) { keysListenedFor.set(keyCode); }
+ void dontListenForKeys() { keysListenedFor.clear(); }
s32 getMouseWheel()
{
@@ -184,7 +161,7 @@ public:
JoystickController *joystick;
#ifdef HAVE_TOUCHSCREENGUI
- TouchScreenGUI* m_touchscreengui;
+ TouchScreenGUI *m_touchscreengui;
#endif
private:
@@ -200,7 +177,42 @@ private:
KeyList keysListenedFor;
};
+class InputHandler
+{
+public:
+ InputHandler() {}
+ virtual ~InputHandler() {}
+
+ virtual bool isKeyDown(const KeyPress &keyCode) = 0;
+ virtual bool wasKeyDown(const KeyPress &keyCode) = 0;
+
+ virtual void listenForKey(const KeyPress &keyCode) {}
+ virtual void dontListenForKeys() {}
+
+ virtual v2s32 getMousePos() = 0;
+ virtual void setMousePos(s32 x, s32 y) = 0;
+
+ virtual bool getLeftState() = 0;
+ virtual bool getRightState() = 0;
+
+ virtual bool getLeftClicked() = 0;
+ virtual bool getRightClicked() = 0;
+ virtual void resetLeftClicked() = 0;
+ virtual void resetRightClicked() = 0;
+
+ virtual bool getLeftReleased() = 0;
+ virtual bool getRightReleased() = 0;
+ virtual void resetLeftReleased() = 0;
+ virtual void resetRightReleased() = 0;
+ virtual s32 getMouseWheel() = 0;
+
+ virtual void step(float dtime) {}
+
+ virtual void clear() {}
+
+ JoystickController joystick;
+};
/*
Separated input handler
*/
@@ -208,10 +220,8 @@ private:
class RealInputHandler : public InputHandler
{
public:
- RealInputHandler(IrrlichtDevice *device, MyEventReceiver *receiver):
- m_device(device),
- m_receiver(receiver),
- m_mousepos(0,0)
+ RealInputHandler(IrrlichtDevice *device, MyEventReceiver *receiver)
+ : m_device(device), m_receiver(receiver), m_mousepos(0, 0)
{
m_receiver->joystick = &joystick;
}
@@ -227,16 +237,12 @@ public:
{
m_receiver->listenForKey(keyCode);
}
- virtual void dontListenForKeys()
- {
- m_receiver->dontListenForKeys();
- }
+ virtual void dontListenForKeys() { m_receiver->dontListenForKeys(); }
virtual v2s32 getMousePos()
{
if (m_device->getCursorControl()) {
return m_device->getCursorControl()->getPosition();
- }
- else {
+ } else {
return m_mousepos;
}
}
@@ -244,69 +250,36 @@ public:
{
if (m_device->getCursorControl()) {
m_device->getCursorControl()->setPosition(x, y);
- }
- else {
- m_mousepos = v2s32(x,y);
+ } else {
+ m_mousepos = v2s32(x, y);
}
}
- virtual bool getLeftState()
- {
- return m_receiver->left_active;
- }
- virtual bool getRightState()
- {
- return m_receiver->right_active;
- }
+ virtual bool getLeftState() { return m_receiver->left_active; }
+ virtual bool getRightState() { return m_receiver->right_active; }
- virtual bool getLeftClicked()
- {
- return m_receiver->leftclicked;
- }
- virtual bool getRightClicked()
- {
- return m_receiver->rightclicked;
- }
- virtual void resetLeftClicked()
- {
- m_receiver->leftclicked = false;
- }
- virtual void resetRightClicked()
- {
- m_receiver->rightclicked = false;
- }
+ virtual bool getLeftClicked() { return m_receiver->leftclicked; }
+ virtual bool getRightClicked() { return m_receiver->rightclicked; }
+ virtual void resetLeftClicked() { m_receiver->leftclicked = false; }
+ virtual void resetRightClicked() { m_receiver->rightclicked = false; }
- virtual bool getLeftReleased()
- {
- return m_receiver->leftreleased;
- }
- virtual bool getRightReleased()
- {
- return m_receiver->rightreleased;
- }
- virtual void resetLeftReleased()
- {
- m_receiver->leftreleased = false;
- }
- virtual void resetRightReleased()
- {
- m_receiver->rightreleased = false;
- }
+ virtual bool getLeftReleased() { return m_receiver->leftreleased; }
+ virtual bool getRightReleased() { return m_receiver->rightreleased; }
+ virtual void resetLeftReleased() { m_receiver->leftreleased = false; }
+ virtual void resetRightReleased() { m_receiver->rightreleased = false; }
- virtual s32 getMouseWheel()
- {
- return m_receiver->getMouseWheel();
- }
+ virtual s32 getMouseWheel() { return m_receiver->getMouseWheel(); }
void clear()
{
joystick.clear();
m_receiver->clearInput();
}
+
private:
- IrrlichtDevice *m_device;
+ IrrlichtDevice *m_device;
MyEventReceiver *m_receiver;
- v2s32 m_mousepos;
+ v2s32 m_mousepos;
};
class RandomInputHandler : public InputHandler
@@ -322,70 +295,25 @@ public:
rightreleased = false;
keydown.clear();
}
- virtual bool isKeyDown(const KeyPress &keyCode)
- {
- return keydown[keyCode];
- }
- virtual bool wasKeyDown(const KeyPress &keyCode)
- {
- return false;
- }
- virtual v2s32 getMousePos()
- {
- return mousepos;
- }
- virtual void setMousePos(s32 x, s32 y)
- {
- mousepos = v2s32(x, y);
- }
+ virtual bool isKeyDown(const KeyPress &keyCode) { return keydown[keyCode]; }
+ virtual bool wasKeyDown(const KeyPress &keyCode) { return false; }
+ virtual v2s32 getMousePos() { return mousepos; }
+ virtual void setMousePos(s32 x, s32 y) { mousepos = v2s32(x, y); }
- virtual bool getLeftState()
- {
- return leftdown;
- }
- virtual bool getRightState()
- {
- return rightdown;
- }
+ virtual bool getLeftState() { return leftdown; }
+ virtual bool getRightState() { return rightdown; }
- virtual bool getLeftClicked()
- {
- return leftclicked;
- }
- virtual bool getRightClicked()
- {
- return rightclicked;
- }
- virtual void resetLeftClicked()
- {
- leftclicked = false;
- }
- virtual void resetRightClicked()
- {
- rightclicked = false;
- }
+ virtual bool getLeftClicked() { return leftclicked; }
+ virtual bool getRightClicked() { return rightclicked; }
+ virtual void resetLeftClicked() { leftclicked = false; }
+ virtual void resetRightClicked() { rightclicked = false; }
- virtual bool getLeftReleased()
- {
- return leftreleased;
- }
- virtual bool getRightReleased()
- {
- return rightreleased;
- }
- virtual void resetLeftReleased()
- {
- leftreleased = false;
- }
- virtual void resetRightReleased()
- {
- rightreleased = false;
- }
+ virtual bool getLeftReleased() { return leftreleased; }
+ virtual bool getRightReleased() { return rightreleased; }
+ virtual void resetLeftReleased() { leftreleased = false; }
+ virtual void resetRightReleased() { rightreleased = false; }
- virtual s32 getMouseWheel()
- {
- return 0;
- }
+ virtual s32 getMouseWheel() { return 0; }
virtual void step(float dtime)
{
@@ -456,10 +384,8 @@ public:
mousepos += mousespeed;
}
- s32 Rand(s32 min, s32 max)
- {
- return (myrand()%(max-min+1))+min;
- }
+ s32 Rand(s32 min, s32 max);
+
private:
KeyList keydown;
v2s32 mousepos;
diff --git a/src/client/joystick_controller.cpp b/src/client/joystick_controller.cpp
index ef8d18ab0..905ca6420 100644
--- a/src/client/joystick_controller.cpp
+++ b/src/client/joystick_controller.cpp
@@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "keys.h"
#include "settings.h"
#include "gettime.h"
+#include "porting.h"
+#include "../util/string.h"
bool JoystickButtonCmb::isTriggered(const irr::SEvent::SJoystickEvent &ev) const
{
@@ -42,7 +44,7 @@ bool JoystickAxisCmb::isTriggered(const irr::SEvent::SJoystickEvent &ev) const
#define JLO_B_PB(A, B, C) jlo.button_keys.push_back(JoystickButtonCmb(A, B, C))
#define JLO_A_PB(A, B, C, D) jlo.axis_keys.push_back(JoystickAxisCmb(A, B, C, D))
-static JoystickLayout create_default_layout()
+JoystickLayout create_default_layout()
{
JoystickLayout jlo;
@@ -103,11 +105,59 @@ static JoystickLayout create_default_layout()
return jlo;
}
-static const JoystickLayout default_layout = create_default_layout();
+JoystickLayout create_xbox_layout()
+{
+ JoystickLayout jlo;
+
+ jlo.axes_dead_border = 7000;
+
+ const JoystickAxisLayout axes[JA_COUNT] = {
+ {0, 1}, // JA_SIDEWARD_MOVE
+ {1, 1}, // JA_FORWARD_MOVE
+ {2, 1}, // JA_FRUSTUM_HORIZONTAL
+ {3, 1}, // JA_FRUSTUM_VERTICAL
+ };
+ memcpy(jlo.axes, axes, sizeof(jlo.axes));
+
+ // The back button means "ESC".
+ JLO_B_PB(KeyType::ESC, 1 << 8, 1 << 8); // back
+ JLO_B_PB(KeyType::ESC, 1 << 9, 1 << 9); // start
+
+ // 4 Buttons
+ JLO_B_PB(KeyType::JUMP, 1 << 0, 1 << 0); // A/green
+ JLO_B_PB(KeyType::ESC, 1 << 1, 1 << 1); // B/red
+ JLO_B_PB(KeyType::SPECIAL1, 1 << 2, 1 << 2); // X/blue
+ JLO_B_PB(KeyType::INVENTORY, 1 << 3, 1 << 3); // Y/yellow
+
+ // Analog Sticks
+ JLO_B_PB(KeyType::SPECIAL1, 1 << 11, 1 << 11); // left
+ JLO_B_PB(KeyType::SNEAK, 1 << 12, 1 << 12); // right
+
+ // Triggers
+ JLO_B_PB(KeyType::MOUSE_L, 1 << 6, 1 << 6); // lt
+ JLO_B_PB(KeyType::MOUSE_R, 1 << 7, 1 << 7); // rt
+ JLO_B_PB(KeyType::SCROLL_UP, 1 << 4, 1 << 4); // lb
+ JLO_B_PB(KeyType::SCROLL_DOWN, 1 << 5, 1 << 5); // rb
+
+ // D-PAD
+ JLO_B_PB(KeyType::ZOOM, 1 << 15, 1 << 15); // up
+ JLO_B_PB(KeyType::DROP, 1 << 13, 1 << 13); // left
+ JLO_B_PB(KeyType::SCREENSHOT, 1 << 14, 1 << 14); // right
+ JLO_B_PB(KeyType::FREEMOVE, 1 << 16, 1 << 16); // down
+
+ // Movement buttons, important for vessels
+ JLO_A_PB(KeyType::FORWARD, 1, 1, 1024);
+ JLO_A_PB(KeyType::BACKWARD, 1, -1, 1024);
+ JLO_A_PB(KeyType::LEFT, 0, 1, 1024);
+ JLO_A_PB(KeyType::RIGHT, 0, -1, 1024);
+
+ return jlo;
+}
JoystickController::JoystickController()
{
- m_layout = &default_layout;
+ m_joystick_id = 0;
+
doubling_dtime = g_settings->getFloat("repeat_joystick_button_time");
for (size_t i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) {
@@ -116,23 +166,55 @@ JoystickController::JoystickController()
clear();
}
+void JoystickController::onJoystickConnect(const std::vector<irr::SJoystickInfo> &joystick_infos)
+{
+ s32 id = g_settings->getS32("joystick_id");
+ std::string layout = g_settings->get("joystick_type");
+
+ if (id < 0 || (u16)id >= joystick_infos.size()) {
+ // TODO: auto detection
+ id = 0;
+ }
+
+ if (id >= 0 && (u16)id < joystick_infos.size()) {
+ if (layout.empty() || layout == "auto")
+ setLayoutFromControllerName(joystick_infos[id].Name.c_str());
+ else
+ setLayoutFromControllerName(layout);
+ }
+
+ m_joystick_id = id;
+}
+
+void JoystickController::setLayoutFromControllerName(const std::string &name)
+{
+ if (lowercase(name).find("xbox") != std::string::npos) {
+ m_layout = create_xbox_layout();
+ } else {
+ m_layout = create_default_layout();
+ }
+}
+
bool JoystickController::handleEvent(const irr::SEvent::SJoystickEvent &ev)
{
- m_internal_time = getTimeMs() / 1000.f;
+ if (ev.Joystick != m_joystick_id)
+ return false;
+
+ m_internal_time = porting::getTimeMs() / 1000.f;
std::bitset<KeyType::INTERNAL_ENUM_COUNT> keys_pressed;
// First generate a list of keys pressed
- for (size_t i = 0; i < m_layout->button_keys.size(); i++) {
- if (m_layout->button_keys[i].isTriggered(ev)) {
- keys_pressed.set(m_layout->button_keys[i].key);
+ for (size_t i = 0; i < m_layout.button_keys.size(); i++) {
+ if (m_layout.button_keys[i].isTriggered(ev)) {
+ keys_pressed.set(m_layout.button_keys[i].key);
}
}
- for (size_t i = 0; i < m_layout->axis_keys.size(); i++) {
- if (m_layout->axis_keys[i].isTriggered(ev)) {
- keys_pressed.set(m_layout->axis_keys[i].key);
+ for (size_t i = 0; i < m_layout.axis_keys.size(); i++) {
+ if (m_layout.axis_keys[i].isTriggered(ev)) {
+ keys_pressed.set(m_layout.axis_keys[i].key);
}
}
@@ -153,7 +235,7 @@ bool JoystickController::handleEvent(const irr::SEvent::SJoystickEvent &ev)
}
for (size_t i = 0; i < JA_COUNT; i++) {
- const JoystickAxisLayout &ax_la = m_layout->axes[i];
+ const JoystickAxisLayout &ax_la = m_layout.axes[i];
m_axes_vals[i] = ax_la.invert * ev.Axis[ax_la.axis_id];
}
@@ -172,8 +254,8 @@ void JoystickController::clear()
s16 JoystickController::getAxisWithoutDead(JoystickAxis axis)
{
s16 v = m_axes_vals[axis];
- if (((v > 0) && (v < m_layout->axes_dead_border)) ||
- ((v < 0) && (v > -m_layout->axes_dead_border)))
+ if (((v > 0) && (v < m_layout.axes_dead_border)) ||
+ ((v < 0) && (v > -m_layout.axes_dead_border)))
return 0;
return v;
}
diff --git a/src/client/joystick_controller.h b/src/client/joystick_controller.h
index ed0ee4068..2c0e7b90a 100644
--- a/src/client/joystick_controller.h
+++ b/src/client/joystick_controller.h
@@ -98,6 +98,9 @@ class JoystickController {
public:
JoystickController();
+
+ void onJoystickConnect(const std::vector<irr::SJoystickInfo> &joystick_infos);
+
bool handleEvent(const irr::SEvent::SJoystickEvent &ev);
void clear();
@@ -146,10 +149,14 @@ public:
f32 doubling_dtime;
private:
- const JoystickLayout *m_layout;
+ void setLayoutFromControllerName(const std::string &name);
+
+ JoystickLayout m_layout;
s16 m_axes_vals[JA_COUNT];
+ u8 m_joystick_id;
+
std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_pressed_keys;
f32 m_internal_time;
diff --git a/src/client/keys.h b/src/client/keys.h
index 6467c443e..9478737f6 100644
--- a/src/client/keys.h
+++ b/src/client/keys.h
@@ -20,11 +20,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef KEYS_HEADER
#define KEYS_HEADER
-#include<list>
+#include <list>
-class KeyType {
+class KeyType
+{
public:
- enum T {
+ enum T
+ {
// Player movement
FORWARD,
BACKWARD,
@@ -42,11 +44,17 @@ public:
INVENTORY,
CHAT,
CMD,
+ CMD_LOCAL,
CONSOLE,
MINIMAP,
FREEMOVE,
FASTMOVE,
NOCLIP,
+ HOTBAR_PREV,
+ HOTBAR_NEXT,
+ MUTE,
+ INC_VOLUME,
+ DEC_VOLUME,
CINEMATIC,
SCREENSHOT,
TOGGLE_HUD,
@@ -82,5 +90,4 @@ public:
typedef KeyType::T GameKeyType;
-
#endif
diff --git a/src/client/tile.cpp b/src/client/tile.cpp
index 8f0c39465..99495132b 100644
--- a/src/client/tile.cpp
+++ b/src/client/tile.cpp
@@ -134,9 +134,8 @@ std::string getTexturePath(const std::string &filename)
/*
Check from texture_path
*/
- std::string texture_path = g_settings->get("texture_path");
- if (texture_path != "")
- {
+ const std::string &texture_path = g_settings->get("texture_path");
+ if (texture_path != "") {
std::string testpath = texture_path + DIR_DELIM + filename;
// Check all filename extensions. Returns "" if not found.
fullpath = getImagePath(testpath);
@@ -342,6 +341,8 @@ public:
*/
video::ITexture* getTextureForMesh(const std::string &name, u32 *id);
+ virtual Palette* getPalette(const std::string &name);
+
// Returns a pointer to the irrlicht device
virtual IrrlichtDevice* getDevice()
{
@@ -378,11 +379,6 @@ public:
video::ITexture* generateTextureFromMesh(
const TextureFromMeshParams &params);
- // Generates an image from a full string like
- // "stone.png^mineral_coal.png^[crack:1:0".
- // Shall be called from the main thread.
- video::IImage* generateImage(const std::string &name);
-
video::ITexture* getNormalTexture(const std::string &name);
video::SColor getTextureAverageColor(const std::string &name);
video::ITexture *getShaderFlagsTexture(bool normamap_present);
@@ -405,6 +401,13 @@ private:
// if baseimg is NULL, it is created. Otherwise stuff is made on it.
bool generateImagePart(std::string part_of_name, video::IImage *& baseimg);
+ /*! Generates an image from a full string like
+ * "stone.png^mineral_coal.png^[crack:1:0".
+ * Shall be called from the main thread.
+ * The returned Image should be dropped.
+ */
+ video::IImage* generateImage(const std::string &name);
+
// Thread-safe cache of what source images are known (true = known)
MutexedMap<std::string, bool> m_source_image_existence;
@@ -423,6 +426,9 @@ private:
// but can't be deleted because the ITexture* might still be used
std::vector<video::ITexture*> m_texture_trash;
+ // Maps image file names to loaded palettes.
+ UNORDERED_MAP<std::string, Palette> m_palettes;
+
// Cached settings needed for making textures from meshes
bool m_setting_trilinear_filter;
bool m_setting_bilinear_filter;
@@ -558,7 +564,11 @@ static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst,
// color alpha with the destination alpha.
// Otherwise, any pixels that are not fully transparent get the color alpha.
static void apply_colorize(video::IImage *dst, v2u32 dst_pos, v2u32 size,
- video::SColor color, int ratio, bool keep_alpha);
+ const video::SColor &color, int ratio, bool keep_alpha);
+
+// paint a texture using the given color
+static void apply_multiplication(video::IImage *dst, v2u32 dst_pos, v2u32 size,
+ const video::SColor &color);
// Apply a mask to an image
static void apply_mask(video::IImage *mask, video::IImage *dst,
@@ -682,6 +692,61 @@ video::ITexture* TextureSource::getTextureForMesh(const std::string &name, u32 *
return getTexture(name + "^[applyfiltersformesh", id);
}
+Palette* TextureSource::getPalette(const std::string &name)
+{
+ // Only the main thread may load images
+ sanity_check(thr_is_current_thread(m_main_thread));
+
+ if (name == "")
+ return NULL;
+
+ UNORDERED_MAP<std::string, Palette>::iterator it = m_palettes.find(name);
+ if (it == m_palettes.end()) {
+ // Create palette
+ video::IImage *img = generateImage(name);
+ if (!img) {
+ warningstream << "TextureSource::getPalette(): palette \"" << name
+ << "\" could not be loaded." << std::endl;
+ return NULL;
+ }
+ Palette new_palette;
+ u32 w = img->getDimension().Width;
+ u32 h = img->getDimension().Height;
+ // Real area of the image
+ u32 area = h * w;
+ if (area == 0)
+ return NULL;
+ if (area > 256) {
+ warningstream << "TextureSource::getPalette(): the specified"
+ << " palette image \"" << name << "\" is larger than 256"
+ << " pixels, using the first 256." << std::endl;
+ area = 256;
+ } else if (256 % area != 0)
+ warningstream << "TextureSource::getPalette(): the "
+ << "specified palette image \"" << name << "\" does not "
+ << "contain power of two pixels." << std::endl;
+ // We stretch the palette so it will fit 256 values
+ // This many param2 values will have the same color
+ u32 step = 256 / area;
+ // For each pixel in the image
+ for (u32 i = 0; i < area; i++) {
+ video::SColor c = img->getPixel(i % w, i / w);
+ // Fill in palette with 'step' colors
+ for (u32 j = 0; j < step; j++)
+ new_palette.push_back(c);
+ }
+ img->drop();
+ // Fill in remaining elements
+ while (new_palette.size() < 256)
+ new_palette.push_back(video::SColor(0xFFFFFFFF));
+ m_palettes[name] = new_palette;
+ it = m_palettes.find(name);
+ }
+ if (it != m_palettes.end())
+ return &((*it).second);
+ return NULL;
+}
+
void TextureSource::processQueue()
{
/*
@@ -725,8 +790,6 @@ void TextureSource::rebuildImagesAndTextures()
video::IImage *img = generateImage(ti->name);
#ifdef __ANDROID__
img = Align2Npot2(img, driver);
- sanity_check(img->getDimension().Height == npot2(img->getDimension().Height));
- sanity_check(img->getDimension().Width == npot2(img->getDimension().Width));
#endif
// Create texture from resulting image
video::ITexture *t = NULL;
@@ -938,7 +1001,7 @@ video::ITexture* TextureSource::generateTextureFromMesh(
smgr->drop();
// Unset render target
- driver->setRenderTarget(0, false, true, 0);
+ driver->setRenderTarget(0, false, true, video::SColor(0,0,0,0));
if (params.delete_texture_on_shutdown)
m_texture_trash.push_back(rtt);
@@ -1059,6 +1122,13 @@ video::IImage* TextureSource::generateImage(const std::string &name)
* @param driver driver to use for image operations
* @return image or copy of image aligned to npot2
*/
+
+inline u16 get_GL_major_version()
+{
+ const GLubyte *gl_version = glGetString(GL_VERSION);
+ return (u16) (gl_version[0] - '0');
+}
+
video::IImage * Align2Npot2(video::IImage * image,
video::IVideoDriver* driver)
{
@@ -1069,7 +1139,10 @@ video::IImage * Align2Npot2(video::IImage * image,
core::dimension2d<u32> dim = image->getDimension();
std::string extensions = (char*) glGetString(GL_EXTENSIONS);
- if (extensions.find("GL_OES_texture_npot") != std::string::npos) {
+
+ // Only GLES2 is trusted to correctly report npot support
+ if (get_GL_major_version() > 1 &&
+ extensions.find("GL_OES_texture_npot") != std::string::npos) {
return image;
}
@@ -1135,17 +1208,17 @@ bool TextureSource::generateImagePart(std::string part_of_name,
#endif
if (image == NULL) {
if (part_of_name != "") {
- if (part_of_name.find("_normal.png") == std::string::npos){
- errorstream<<"generateImage(): Could not load image \""
- <<part_of_name<<"\""<<" while building texture"<<std::endl;
- errorstream<<"generateImage(): Creating a dummy"
- <<" image for \""<<part_of_name<<"\""<<std::endl;
- } else {
- infostream<<"generateImage(): Could not load normal map \""
- <<part_of_name<<"\""<<std::endl;
- infostream<<"generateImage(): Creating a dummy"
- <<" normal map for \""<<part_of_name<<"\""<<std::endl;
+
+ // Do not create normalmap dummies
+ if (part_of_name.find("_normal.png") != std::string::npos) {
+ warningstream << "generateImage(): Could not load normal map \""
+ << part_of_name << "\"" << std::endl;
+ return true;
}
+
+ errorstream << "generateImage(): Could not load image \""
+ << part_of_name << "\" while building texture; "
+ "Creating a dummy image" << std::endl;
}
// Just create a dummy image
@@ -1660,6 +1733,30 @@ bool TextureSource::generateImagePart(std::string part_of_name,
}
}
/*
+ [multiply:color
+ multiplys a given color to any pixel of an image
+ color = color as ColorString
+ */
+ else if (str_starts_with(part_of_name, "[multiply:")) {
+ Strfnd sf(part_of_name);
+ sf.next(":");
+ std::string color_str = sf.next(":");
+
+ if (baseimg == NULL) {
+ errorstream << "generateImagePart(): baseimg != NULL "
+ << "for part_of_name=\"" << part_of_name
+ << "\", cancelling." << std::endl;
+ return false;
+ }
+
+ video::SColor color;
+
+ if (!parseColorString(color_str, color, false))
+ return false;
+
+ apply_multiplication(baseimg, v2u32(0, 0), baseimg->getDimension(), color);
+ }
+ /*
[colorize:color
Overlays image with given color
color = color as ColorString
@@ -1716,6 +1813,12 @@ bool TextureSource::generateImagePart(std::string part_of_name,
* equal to the target minimum. If e.g. this is a vertical frames
* animation, the short dimension will be the real size.
*/
+ if ((dim.Width == 0) || (dim.Height == 0)) {
+ errorstream << "generateImagePart(): Illegal 0 dimension "
+ << "for part_of_name=\""<< part_of_name
+ << "\", cancelling." << std::endl;
+ return false;
+ }
u32 xscale = scaleto / dim.Width;
u32 yscale = scaleto / dim.Height;
u32 scale = (xscale > yscale) ? xscale : yscale;
@@ -1823,10 +1926,53 @@ bool TextureSource::generateImagePart(std::string part_of_name,
for (u32 x = 0; x < dim.Width; x++)
{
video::SColor c = baseimg->getPixel(x, y);
- c.color ^= mask;
+ c.color ^= mask;
baseimg->setPixel(x, y, c);
}
}
+ /*
+ [sheet:WxH:X,Y
+ Retrieves a tile at position X,Y (in tiles)
+ from the base image it assumes to be a
+ tilesheet with dimensions W,H (in tiles).
+ */
+ else if (part_of_name.substr(0,7) == "[sheet:") {
+ if (baseimg == NULL) {
+ errorstream << "generateImagePart(): baseimg != NULL "
+ << "for part_of_name=\"" << part_of_name
+ << "\", cancelling." << std::endl;
+ return false;
+ }
+
+ Strfnd sf(part_of_name);
+ sf.next(":");
+ u32 w0 = stoi(sf.next("x"));
+ u32 h0 = stoi(sf.next(":"));
+ u32 x0 = stoi(sf.next(","));
+ u32 y0 = stoi(sf.next(":"));
+
+ core::dimension2d<u32> img_dim = baseimg->getDimension();
+ core::dimension2d<u32> tile_dim(v2u32(img_dim) / v2u32(w0, h0));
+
+ video::IImage *img = driver->createImage(
+ video::ECF_A8R8G8B8, tile_dim);
+ if (!img) {
+ errorstream << "generateImagePart(): Could not create image "
+ << "for part_of_name=\"" << part_of_name
+ << "\", cancelling." << std::endl;
+ return false;
+ }
+
+ img->fill(video::SColor(0,0,0,0));
+ v2u32 vdim(tile_dim);
+ core::rect<s32> rect(v2s32(x0 * vdim.X, y0 * vdim.Y), tile_dim);
+ baseimg->copyToWithAlpha(img, v2s32(0), rect,
+ video::SColor(255,255,255,255), NULL);
+
+ // Replace baseimg
+ baseimg->drop();
+ baseimg = img;
+ }
else
{
errorstream << "generateImagePart(): Invalid "
@@ -1920,7 +2066,7 @@ static void blit_with_interpolate_overlay(video::IImage *src, video::IImage *dst
Apply color to destination
*/
static void apply_colorize(video::IImage *dst, v2u32 dst_pos, v2u32 size,
- video::SColor color, int ratio, bool keep_alpha)
+ const video::SColor &color, int ratio, bool keep_alpha)
{
u32 alpha = color.getAlpha();
video::SColor dst_c;
@@ -1955,6 +2101,27 @@ static void apply_colorize(video::IImage *dst, v2u32 dst_pos, v2u32 size,
}
/*
+ Apply color to destination
+*/
+static void apply_multiplication(video::IImage *dst, v2u32 dst_pos, v2u32 size,
+ const video::SColor &color)
+{
+ video::SColor dst_c;
+
+ for (u32 y = dst_pos.Y; y < dst_pos.Y + size.Y; y++)
+ for (u32 x = dst_pos.X; x < dst_pos.X + size.X; x++) {
+ dst_c = dst->getPixel(x, y);
+ dst_c.set(
+ dst_c.getAlpha(),
+ (dst_c.getRed() * color.getRed()) / 255,
+ (dst_c.getGreen() * color.getGreen()) / 255,
+ (dst_c.getBlue() * color.getBlue()) / 255
+ );
+ dst->setPixel(x, y, dst_c);
+ }
+}
+
+/*
Apply mask to destination
*/
static void apply_mask(video::IImage *mask, video::IImage *dst,
@@ -2171,7 +2338,8 @@ video::ITexture* TextureSource::getNormalTexture(const std::string &name)
if (isKnownSourceImage("override_normal.png"))
return getTexture("override_normal.png");
std::string fname_base = name;
- std::string normal_ext = "_normal.png";
+ static const char *normal_ext = "_normal.png";
+ static const u32 normal_ext_size = strlen(normal_ext);
size_t pos = fname_base.find(".");
std::string fname_normal = fname_base.substr(0, pos) + normal_ext;
if (isKnownSourceImage(fname_normal)) {
@@ -2179,10 +2347,10 @@ video::ITexture* TextureSource::getNormalTexture(const std::string &name)
size_t i = 0;
while ((i = fname_base.find(".", i)) != std::string::npos) {
fname_base.replace(i, 4, normal_ext);
- i += normal_ext.length();
+ i += normal_ext_size;
}
return getTexture(fname_base);
- }
+ }
return NULL;
}
diff --git a/src/client/tile.h b/src/client/tile.h
index b75916841..15854fb71 100644
--- a/src/client/tile.h
+++ b/src/client/tile.h
@@ -33,6 +33,8 @@ class IGameDef;
struct TileSpec;
struct TileDef;
+typedef std::vector<video::SColor> Palette;
+
/*
tile.{h,cpp}: Texture handling stuff.
*/
@@ -106,6 +108,13 @@ public:
const std::string &name, u32 *id = NULL)=0;
virtual video::ITexture* getTextureForMesh(
const std::string &name, u32 *id = NULL) = 0;
+ /*!
+ * Returns a palette from the given texture name.
+ * The pointer is valid until the texture source is
+ * destructed.
+ * Should be called from the main thread.
+ */
+ virtual Palette* getPalette(const std::string &name) = 0;
virtual IrrlichtDevice* getDevice()=0;
virtual bool isKnownSourceImage(const std::string &name)=0;
virtual video::ITexture* generateTextureFromMesh(
@@ -161,9 +170,7 @@ enum MaterialType{
// Should the crack be drawn on transparent pixels (unset) or not (set)?
// Ignored if MATERIAL_FLAG_CRACK is not set.
#define MATERIAL_FLAG_CRACK_OVERLAY 0x04
-// Animation made up by splitting the texture to vertical frames, as
-// defined by extra parameters
-#define MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES 0x08
+#define MATERIAL_FLAG_ANIMATION 0x08
#define MATERIAL_FLAG_HIGHLIGHTED 0x10
#define MATERIAL_FLAG_TILEABLE_HORIZONTAL 0x20
#define MATERIAL_FLAG_TILEABLE_VERTICAL 0x40
@@ -187,65 +194,67 @@ struct FrameSpec
video::ITexture *flags_texture;
};
-struct TileSpec
+#define MAX_TILE_LAYERS 2
+
+//! Defines a layer of a tile.
+struct TileLayer
{
- TileSpec():
- texture_id(0),
+ TileLayer():
texture(NULL),
normal_texture(NULL),
flags_texture(NULL),
- alpha(255),
+ shader_id(0),
+ texture_id(0),
+ animation_frame_length_ms(0),
+ animation_frame_count(1),
material_type(TILE_MATERIAL_BASIC),
material_flags(
//0 // <- DEBUG, Use the one below
- MATERIAL_FLAG_BACKFACE_CULLING
+ MATERIAL_FLAG_BACKFACE_CULLING |
+ MATERIAL_FLAG_TILEABLE_HORIZONTAL|
+ MATERIAL_FLAG_TILEABLE_VERTICAL
),
- shader_id(0),
- animation_frame_count(1),
- animation_frame_length_ms(0),
- rotation(0)
+ has_color(false),
+ color()
{
}
- bool operator==(const TileSpec &other) const
+ /*!
+ * Two layers are equal if they can be merged.
+ */
+ bool operator==(const TileLayer &other) const
{
- return (
+ return
texture_id == other.texture_id &&
- /* texture == other.texture && */
- alpha == other.alpha &&
material_type == other.material_type &&
material_flags == other.material_flags &&
- rotation == other.rotation
- );
+ color == other.color;
}
- bool operator!=(const TileSpec &other) const
+ /*!
+ * Two tiles are not equal if they must have different vertices.
+ */
+ bool operator!=(const TileLayer &other) const
{
return !(*this == other);
}
-
+
// Sets everything else except the texture in the material
void applyMaterialOptions(video::SMaterial &material) const
{
switch (material_type) {
case TILE_MATERIAL_BASIC:
+ case TILE_MATERIAL_WAVING_LEAVES:
+ case TILE_MATERIAL_WAVING_PLANTS:
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
break;
case TILE_MATERIAL_ALPHA:
- material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
- break;
case TILE_MATERIAL_LIQUID_TRANSPARENT:
- material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
+ material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
break;
case TILE_MATERIAL_LIQUID_OPAQUE:
material.MaterialType = video::EMT_SOLID;
break;
- case TILE_MATERIAL_WAVING_LEAVES:
- material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
- break;
- case TILE_MATERIAL_WAVING_PLANTS:
- material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
- break;
}
material.BackfaceCulling = (material_flags & MATERIAL_FLAG_BACKFACE_CULLING)
? true : false;
@@ -270,23 +279,73 @@ struct TileSpec
material.TextureLayer[1].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
}
}
-
- u32 texture_id;
+
+ bool isTileable() const
+ {
+ return (material_flags & MATERIAL_FLAG_TILEABLE_HORIZONTAL)
+ && (material_flags & MATERIAL_FLAG_TILEABLE_VERTICAL);
+ }
+
+ // Ordered for size, please do not reorder
+
video::ITexture *texture;
video::ITexture *normal_texture;
video::ITexture *flags_texture;
-
- // Vertex alpha (when MATERIAL_ALPHA_VERTEX is used)
- u8 alpha;
- // Material parameters
- u8 material_type;
- u8 material_flags;
+
u32 shader_id;
- // Animation parameters
- u8 animation_frame_count;
+
+ u32 texture_id;
+
u16 animation_frame_length_ms;
+ u8 animation_frame_count;
+
+ u8 material_type;
+ u8 material_flags;
+
+ //! If true, the tile has its own color.
+ bool has_color;
+
std::vector<FrameSpec> frames;
+ /*!
+ * The color of the tile, or if the tile does not own
+ * a color then the color of the node owning this tile.
+ */
+ video::SColor color;
+};
+
+/*!
+ * Defines a face of a node. May have up to two layers.
+ */
+struct TileSpec
+{
+ TileSpec():
+ rotation(0),
+ emissive_light(0)
+ {
+ for (int layer = 0; layer < MAX_TILE_LAYERS; layer++)
+ layers[layer] = TileLayer();
+ }
+
+ /*!
+ * Returns true if this tile can be merged with the other tile.
+ */
+ bool isTileable(const TileSpec &other) const {
+ for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
+ if (layers[layer] != other.layers[layer])
+ return false;
+ if (!layers[layer].isTileable())
+ return false;
+ }
+ return rotation == 0
+ && rotation == other.rotation
+ && emissive_light == other.emissive_light;
+ }
+
u8 rotation;
+ //! This much light does the tile emit.
+ u8 emissive_light;
+ //! The first is base texture, the second is overlay.
+ TileLayer layers[MAX_TILE_LAYERS];
};
#endif
diff --git a/src/clientenvironment.cpp b/src/clientenvironment.cpp
new file mode 100644
index 000000000..cc7cb54dd
--- /dev/null
+++ b/src/clientenvironment.cpp
@@ -0,0 +1,847 @@
+/*
+Minetest
+Copyright (C) 2010-2017 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 Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "util/serialize.h"
+#include "util/pointedthing.h"
+#include "clientenvironment.h"
+#include "clientsimpleobject.h"
+#include "clientmap.h"
+#include "scripting_client.h"
+#include "mapblock_mesh.h"
+#include "event.h"
+#include "collision.h"
+#include "profiler.h"
+#include "raycast.h"
+#include "voxelalgorithms.h"
+#include "settings.h"
+#include <algorithm>
+
+/*
+ ClientEnvironment
+*/
+
+ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
+ ITextureSource *texturesource, Client *client,
+ IrrlichtDevice *irr):
+ Environment(client),
+ m_map(map),
+ m_local_player(NULL),
+ m_smgr(smgr),
+ m_texturesource(texturesource),
+ m_client(client),
+ m_script(NULL),
+ m_irr(irr)
+{
+ char zero = 0;
+ memset(attachement_parent_ids, zero, sizeof(attachement_parent_ids));
+}
+
+ClientEnvironment::~ClientEnvironment()
+{
+ // delete active objects
+ for (UNORDERED_MAP<u16, ClientActiveObject*>::iterator i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i) {
+ delete i->second;
+ }
+
+ for(std::vector<ClientSimpleObject*>::iterator
+ i = m_simple_objects.begin(); i != m_simple_objects.end(); ++i) {
+ delete *i;
+ }
+
+ // Drop/delete map
+ m_map->drop();
+
+ delete m_local_player;
+}
+
+Map & ClientEnvironment::getMap()
+{
+ return *m_map;
+}
+
+ClientMap & ClientEnvironment::getClientMap()
+{
+ return *m_map;
+}
+
+void ClientEnvironment::setLocalPlayer(LocalPlayer *player)
+{
+ DSTACK(FUNCTION_NAME);
+ /*
+ It is a failure if already is a local player
+ */
+ FATAL_ERROR_IF(m_local_player != NULL,
+ "Local player already allocated");
+
+ m_local_player = player;
+}
+
+void ClientEnvironment::step(float dtime)
+{
+ DSTACK(FUNCTION_NAME);
+
+ /* Step time of day */
+ stepTimeOfDay(dtime);
+
+ // Get some settings
+ bool fly_allowed = m_client->checkLocalPrivilege("fly");
+ bool free_move = fly_allowed && g_settings->getBool("free_move");
+
+ // Get local player
+ LocalPlayer *lplayer = getLocalPlayer();
+ assert(lplayer);
+ // collision info queue
+ std::vector<CollisionInfo> player_collisions;
+
+ /*
+ Get the speed the player is going
+ */
+ bool is_climbing = lplayer->is_climbing;
+
+ f32 player_speed = lplayer->getSpeed().getLength();
+
+ /*
+ Maximum position increment
+ */
+ //f32 position_max_increment = 0.05*BS;
+ f32 position_max_increment = 0.1*BS;
+
+ // Maximum time increment (for collision detection etc)
+ // time = distance / speed
+ f32 dtime_max_increment = 1;
+ if(player_speed > 0.001)
+ dtime_max_increment = position_max_increment / player_speed;
+
+ // Maximum time increment is 10ms or lower
+ if(dtime_max_increment > 0.01)
+ dtime_max_increment = 0.01;
+
+ // Don't allow overly huge dtime
+ if(dtime > 0.5)
+ dtime = 0.5;
+
+ f32 dtime_downcount = dtime;
+
+ /*
+ Stuff that has a maximum time increment
+ */
+
+ u32 loopcount = 0;
+ do
+ {
+ loopcount++;
+
+ f32 dtime_part;
+ if(dtime_downcount > dtime_max_increment)
+ {
+ dtime_part = dtime_max_increment;
+ dtime_downcount -= dtime_part;
+ }
+ else
+ {
+ dtime_part = dtime_downcount;
+ /*
+ Setting this to 0 (no -=dtime_part) disables an infinite loop
+ when dtime_part is so small that dtime_downcount -= dtime_part
+ does nothing
+ */
+ dtime_downcount = 0;
+ }
+
+ /*
+ Handle local player
+ */
+
+ {
+ // Apply physics
+ if(!free_move && !is_climbing)
+ {
+ // Gravity
+ v3f speed = lplayer->getSpeed();
+ if(!lplayer->in_liquid)
+ speed.Y -= lplayer->movement_gravity * lplayer->physics_override_gravity * dtime_part * 2;
+
+ // Liquid floating / sinking
+ if(lplayer->in_liquid && !lplayer->swimming_vertical)
+ speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2;
+
+ // Liquid resistance
+ if(lplayer->in_liquid_stable || lplayer->in_liquid)
+ {
+ // How much the node's viscosity blocks movement, ranges between 0 and 1
+ // Should match the scale at which viscosity increase affects other liquid attributes
+ const f32 viscosity_factor = 0.3;
+
+ v3f d_wanted = -speed / lplayer->movement_liquid_fluidity;
+ f32 dl = d_wanted.getLength();
+ if(dl > lplayer->movement_liquid_fluidity_smooth)
+ dl = lplayer->movement_liquid_fluidity_smooth;
+ dl *= (lplayer->liquid_viscosity * viscosity_factor) + (1 - viscosity_factor);
+
+ v3f d = d_wanted.normalize() * dl;
+ speed += d;
+ }
+
+ lplayer->setSpeed(speed);
+ }
+
+ /*
+ Move the lplayer.
+ This also does collision detection.
+ */
+ lplayer->move(dtime_part, this, position_max_increment,
+ &player_collisions);
+ }
+ }
+ while(dtime_downcount > 0.001);
+
+ //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
+
+ for(std::vector<CollisionInfo>::iterator i = player_collisions.begin();
+ i != player_collisions.end(); ++i) {
+ CollisionInfo &info = *i;
+ v3f speed_diff = info.new_speed - info.old_speed;;
+ // Handle only fall damage
+ // (because otherwise walking against something in fast_move kills you)
+ if(speed_diff.Y < 0 || info.old_speed.Y >= 0)
+ continue;
+ // Get rid of other components
+ speed_diff.X = 0;
+ speed_diff.Z = 0;
+ f32 pre_factor = 1; // 1 hp per node/s
+ f32 tolerance = BS*14; // 5 without damage
+ f32 post_factor = 1; // 1 hp per node/s
+ if(info.type == COLLISION_NODE)
+ {
+ const ContentFeatures &f = m_client->ndef()->
+ get(m_map->getNodeNoEx(info.node_p));
+ // Determine fall damage multiplier
+ int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
+ pre_factor = 1.0 + (float)addp/100.0;
+ }
+ float speed = pre_factor * speed_diff.getLength();
+ if (speed > tolerance) {
+ f32 damage_f = (speed - tolerance) / BS * post_factor;
+ u8 damage = (u8)MYMIN(damage_f + 0.5, 255);
+ if (damage != 0) {
+ damageLocalPlayer(damage, true);
+ MtEvent *e = new SimpleTriggerEvent("PlayerFallingDamage");
+ m_client->event()->put(e);
+ }
+ }
+ }
+
+ if (m_client->moddingEnabled()) {
+ m_script->environment_step(dtime);
+ }
+
+ // Protocol v29 make this behaviour obsolete
+ if (getGameDef()->getProtoVersion() < 29) {
+ if (m_lava_hurt_interval.step(dtime, 1.0)) {
+ v3f pf = lplayer->getPosition();
+
+ // Feet, middle and head
+ v3s16 p1 = floatToInt(pf + v3f(0, BS * 0.1, 0), BS);
+ MapNode n1 = m_map->getNodeNoEx(p1);
+ v3s16 p2 = floatToInt(pf + v3f(0, BS * 0.8, 0), BS);
+ MapNode n2 = m_map->getNodeNoEx(p2);
+ v3s16 p3 = floatToInt(pf + v3f(0, BS * 1.6, 0), BS);
+ MapNode n3 = m_map->getNodeNoEx(p3);
+
+ u32 damage_per_second = 0;
+ damage_per_second = MYMAX(damage_per_second,
+ m_client->ndef()->get(n1).damage_per_second);
+ damage_per_second = MYMAX(damage_per_second,
+ m_client->ndef()->get(n2).damage_per_second);
+ damage_per_second = MYMAX(damage_per_second,
+ m_client->ndef()->get(n3).damage_per_second);
+
+ if (damage_per_second != 0)
+ damageLocalPlayer(damage_per_second, true);
+ }
+
+ /*
+ Drowning
+ */
+ if (m_drowning_interval.step(dtime, 2.0)) {
+ v3f pf = lplayer->getPosition();
+
+ // head
+ v3s16 p = floatToInt(pf + v3f(0, BS * 1.6, 0), BS);
+ MapNode n = m_map->getNodeNoEx(p);
+ ContentFeatures c = m_client->ndef()->get(n);
+ u8 drowning_damage = c.drowning;
+ if (drowning_damage > 0 && lplayer->hp > 0) {
+ u16 breath = lplayer->getBreath();
+ if (breath > 10) {
+ breath = 11;
+ }
+ if (breath > 0) {
+ breath -= 1;
+ }
+ lplayer->setBreath(breath);
+ updateLocalPlayerBreath(breath);
+ }
+
+ if (lplayer->getBreath() == 0 && drowning_damage > 0) {
+ damageLocalPlayer(drowning_damage, true);
+ }
+ }
+ if (m_breathing_interval.step(dtime, 0.5)) {
+ v3f pf = lplayer->getPosition();
+
+ // head
+ v3s16 p = floatToInt(pf + v3f(0, BS * 1.6, 0), BS);
+ MapNode n = m_map->getNodeNoEx(p);
+ ContentFeatures c = m_client->ndef()->get(n);
+ if (!lplayer->hp) {
+ lplayer->setBreath(11);
+ } else if (c.drowning == 0) {
+ u16 breath = lplayer->getBreath();
+ if (breath <= 10) {
+ breath += 1;
+ lplayer->setBreath(breath);
+ updateLocalPlayerBreath(breath);
+ }
+ }
+ }
+ }
+
+ // Update lighting on local player (used for wield item)
+ u32 day_night_ratio = getDayNightRatio();
+ {
+ // Get node at head
+
+ // On InvalidPositionException, use this as default
+ // (day: LIGHT_SUN, night: 0)
+ MapNode node_at_lplayer(CONTENT_AIR, 0x0f, 0);
+
+ v3s16 p = lplayer->getLightPosition();
+ node_at_lplayer = m_map->getNodeNoEx(p);
+
+ u16 light = getInteriorLight(node_at_lplayer, 0, m_client->ndef());
+ final_color_blend(&lplayer->light_color, light, day_night_ratio);
+ }
+
+ /*
+ Step active objects and update lighting of them
+ */
+
+ g_profiler->avg("CEnv: num of objects", m_active_objects.size());
+ bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21);
+ for (UNORDERED_MAP<u16, ClientActiveObject*>::iterator i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i) {
+ ClientActiveObject* obj = i->second;
+ // Step object
+ obj->step(dtime, this);
+
+ if(update_lighting)
+ {
+ // Update lighting
+ u8 light = 0;
+ bool pos_ok;
+
+ // Get node at head
+ v3s16 p = obj->getLightPosition();
+ MapNode n = m_map->getNodeNoEx(p, &pos_ok);
+ if (pos_ok)
+ light = n.getLightBlend(day_night_ratio, m_client->ndef());
+ else
+ light = blend_light(day_night_ratio, LIGHT_SUN, 0);
+
+ obj->updateLight(light);
+ }
+ }
+
+ /*
+ Step and handle simple objects
+ */
+ g_profiler->avg("CEnv: num of simple objects", m_simple_objects.size());
+ for(std::vector<ClientSimpleObject*>::iterator
+ i = m_simple_objects.begin(); i != m_simple_objects.end();) {
+ std::vector<ClientSimpleObject*>::iterator cur = i;
+ ClientSimpleObject *simple = *cur;
+
+ simple->step(dtime);
+ if(simple->m_to_be_removed) {
+ delete simple;
+ i = m_simple_objects.erase(cur);
+ }
+ else {
+ ++i;
+ }
+ }
+}
+
+void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)
+{
+ m_simple_objects.push_back(simple);
+}
+
+GenericCAO* ClientEnvironment::getGenericCAO(u16 id)
+{
+ ClientActiveObject *obj = getActiveObject(id);
+ if (obj && obj->getType() == ACTIVEOBJECT_TYPE_GENERIC)
+ return (GenericCAO*) obj;
+ else
+ return NULL;
+}
+
+ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
+{
+ UNORDERED_MAP<u16, ClientActiveObject*>::iterator n = m_active_objects.find(id);
+ if (n == m_active_objects.end())
+ return NULL;
+ return n->second;
+}
+
+bool isFreeClientActiveObjectId(const u16 id,
+ UNORDERED_MAP<u16, ClientActiveObject*> &objects)
+{
+ if(id == 0)
+ return false;
+
+ return objects.find(id) == objects.end();
+}
+
+u16 getFreeClientActiveObjectId(UNORDERED_MAP<u16, ClientActiveObject*> &objects)
+{
+ //try to reuse id's as late as possible
+ static u16 last_used_id = 0;
+ u16 startid = last_used_id;
+ for(;;) {
+ last_used_id ++;
+ if (isFreeClientActiveObjectId(last_used_id, objects))
+ return last_used_id;
+
+ if (last_used_id == startid)
+ return 0;
+ }
+}
+
+u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
+{
+ assert(object); // Pre-condition
+ if(object->getId() == 0)
+ {
+ u16 new_id = getFreeClientActiveObjectId(m_active_objects);
+ if(new_id == 0)
+ {
+ infostream<<"ClientEnvironment::addActiveObject(): "
+ <<"no free ids available"<<std::endl;
+ delete object;
+ return 0;
+ }
+ object->setId(new_id);
+ }
+ if (!isFreeClientActiveObjectId(object->getId(), m_active_objects)) {
+ infostream<<"ClientEnvironment::addActiveObject(): "
+ <<"id is not free ("<<object->getId()<<")"<<std::endl;
+ delete object;
+ return 0;
+ }
+ infostream<<"ClientEnvironment::addActiveObject(): "
+ <<"added (id="<<object->getId()<<")"<<std::endl;
+ m_active_objects[object->getId()] = object;
+ object->addToScene(m_smgr, m_texturesource, m_irr);
+ { // Update lighting immediately
+ u8 light = 0;
+ bool pos_ok;
+
+ // Get node at head
+ v3s16 p = object->getLightPosition();
+ MapNode n = m_map->getNodeNoEx(p, &pos_ok);
+ if (pos_ok)
+ light = n.getLightBlend(getDayNightRatio(), m_client->ndef());
+ else
+ light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
+
+ object->updateLight(light);
+ }
+ return object->getId();
+}
+
+void ClientEnvironment::addActiveObject(u16 id, u8 type,
+ const std::string &init_data)
+{
+ ClientActiveObject* obj =
+ ClientActiveObject::create((ActiveObjectType) type, m_client, this);
+ if(obj == NULL)
+ {
+ infostream<<"ClientEnvironment::addActiveObject(): "
+ <<"id="<<id<<" type="<<type<<": Couldn't create object"
+ <<std::endl;
+ return;
+ }
+
+ obj->setId(id);
+
+ try
+ {
+ obj->initialize(init_data);
+ }
+ catch(SerializationError &e)
+ {
+ errorstream<<"ClientEnvironment::addActiveObject():"
+ <<" id="<<id<<" type="<<type
+ <<": SerializationError in initialize(): "
+ <<e.what()
+ <<": init_data="<<serializeJsonString(init_data)
+ <<std::endl;
+ }
+
+ addActiveObject(obj);
+}
+
+void ClientEnvironment::removeActiveObject(u16 id)
+{
+ verbosestream<<"ClientEnvironment::removeActiveObject(): "
+ <<"id="<<id<<std::endl;
+ ClientActiveObject* obj = getActiveObject(id);
+ if (obj == NULL) {
+ infostream<<"ClientEnvironment::removeActiveObject(): "
+ <<"id="<<id<<" not found"<<std::endl;
+ return;
+ }
+ obj->removeFromScene(true);
+ delete obj;
+ m_active_objects.erase(id);
+}
+
+void ClientEnvironment::processActiveObjectMessage(u16 id, const std::string &data)
+{
+ ClientActiveObject *obj = getActiveObject(id);
+ if (obj == NULL) {
+ infostream << "ClientEnvironment::processActiveObjectMessage():"
+ << " got message for id=" << id << ", which doesn't exist."
+ << std::endl;
+ return;
+ }
+
+ try {
+ obj->processMessage(data);
+ } catch (SerializationError &e) {
+ errorstream<<"ClientEnvironment::processActiveObjectMessage():"
+ << " id=" << id << " type=" << obj->getType()
+ << " SerializationError in processMessage(): " << e.what()
+ << std::endl;
+ }
+}
+
+/*
+ Callbacks for activeobjects
+*/
+
+void ClientEnvironment::damageLocalPlayer(u8 damage, bool handle_hp)
+{
+ LocalPlayer *lplayer = getLocalPlayer();
+ assert(lplayer);
+
+ if (handle_hp) {
+ if (lplayer->hp > damage)
+ lplayer->hp -= damage;
+ else
+ lplayer->hp = 0;
+ }
+
+ ClientEnvEvent event;
+ event.type = CEE_PLAYER_DAMAGE;
+ event.player_damage.amount = damage;
+ event.player_damage.send_to_server = handle_hp;
+ m_client_event_queue.push(event);
+}
+
+void ClientEnvironment::updateLocalPlayerBreath(u16 breath)
+{
+ ClientEnvEvent event;
+ event.type = CEE_PLAYER_BREATH;
+ event.player_breath.amount = breath;
+ m_client_event_queue.push(event);
+}
+
+/*
+ Client likes to call these
+*/
+
+void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
+ std::vector<DistanceSortedActiveObject> &dest)
+{
+ for (UNORDERED_MAP<u16, ClientActiveObject*>::iterator i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i) {
+ ClientActiveObject* obj = i->second;
+
+ f32 d = (obj->getPosition() - origin).getLength();
+
+ if(d > max_d)
+ continue;
+
+ DistanceSortedActiveObject dso(obj, d);
+
+ dest.push_back(dso);
+ }
+}
+
+ClientEnvEvent ClientEnvironment::getClientEnvEvent()
+{
+ FATAL_ERROR_IF(m_client_event_queue.empty(),
+ "ClientEnvironment::getClientEnvEvent(): queue is empty");
+
+ ClientEnvEvent event = m_client_event_queue.front();
+ m_client_event_queue.pop();
+ return event;
+}
+
+ClientActiveObject * ClientEnvironment::getSelectedActiveObject(
+ const core::line3d<f32> &shootline_on_map, v3f *intersection_point,
+ v3s16 *intersection_normal)
+{
+ std::vector<DistanceSortedActiveObject> objects;
+ getActiveObjects(shootline_on_map.start,
+ shootline_on_map.getLength() + 3, objects);
+ const v3f line_vector = shootline_on_map.getVector();
+
+ // Sort them.
+ // After this, the closest object is the first in the array.
+ std::sort(objects.begin(), objects.end());
+
+ /* Because objects can have different nodebox sizes,
+ * the object whose center is the nearest isn't necessarily
+ * the closest one. If an object is found, don't stop
+ * immediately. */
+
+ f32 d_min = shootline_on_map.getLength();
+ ClientActiveObject *nearest_obj = NULL;
+ for (u32 i = 0; i < objects.size(); i++) {
+ ClientActiveObject *obj = objects[i].obj;
+
+ aabb3f *selection_box = obj->getSelectionBox();
+ if (selection_box == NULL)
+ continue;
+
+ v3f pos = obj->getPosition();
+
+ aabb3f offsetted_box(selection_box->MinEdge + pos,
+ selection_box->MaxEdge + pos);
+
+ if (offsetted_box.getCenter().getDistanceFrom(
+ shootline_on_map.start) > d_min + 9.6f*BS) {
+ // Probably there is no active object that has bigger nodebox than
+ // (-5.5,-5.5,-5.5,5.5,5.5,5.5)
+ // 9.6 > 5.5*sqrt(3)
+ break;
+ }
+
+ v3f current_intersection;
+ v3s16 current_normal;
+ if (boxLineCollision(offsetted_box, shootline_on_map.start, line_vector,
+ &current_intersection, &current_normal)) {
+ f32 d_current = current_intersection.getDistanceFrom(
+ shootline_on_map.start);
+ if (d_current <= d_min) {
+ d_min = d_current;
+ nearest_obj = obj;
+ *intersection_point = current_intersection;
+ *intersection_normal = current_normal;
+ }
+ }
+ }
+
+ return nearest_obj;
+}
+
+/*
+ Check if a node is pointable
+*/
+static inline bool isPointableNode(const MapNode &n,
+ INodeDefManager *ndef, bool liquids_pointable)
+{
+ const ContentFeatures &features = ndef->get(n);
+ return features.pointable ||
+ (liquids_pointable && features.isLiquid());
+}
+
+PointedThing ClientEnvironment::getPointedThing(
+ core::line3d<f32> shootline,
+ bool liquids_pointable,
+ bool look_for_object)
+{
+ PointedThing result;
+
+ INodeDefManager *nodedef = m_map->getNodeDefManager();
+
+ core::aabbox3d<s16> maximal_exceed = nodedef->getSelectionBoxIntUnion();
+ // The code needs to search these nodes
+ core::aabbox3d<s16> search_range(-maximal_exceed.MaxEdge,
+ -maximal_exceed.MinEdge);
+ // If a node is found, there might be a larger node behind.
+ // To find it, we have to go further.
+ s16 maximal_overcheck =
+ std::max(abs(search_range.MinEdge.X), abs(search_range.MaxEdge.X))
+ + std::max(abs(search_range.MinEdge.Y), abs(search_range.MaxEdge.Y))
+ + std::max(abs(search_range.MinEdge.Z), abs(search_range.MaxEdge.Z));
+
+ const v3f original_vector = shootline.getVector();
+ const f32 original_length = original_vector.getLength();
+
+ f32 min_distance = original_length;
+
+ // First try to find an active object
+ if (look_for_object) {
+ ClientActiveObject *selected_object = getSelectedActiveObject(
+ shootline, &result.intersection_point,
+ &result.intersection_normal);
+
+ if (selected_object != NULL) {
+ min_distance =
+ (result.intersection_point - shootline.start).getLength();
+
+ result.type = POINTEDTHING_OBJECT;
+ result.object_id = selected_object->getId();
+ }
+ }
+
+ // Reduce shootline
+ if (original_length > 0) {
+ shootline.end = shootline.start
+ + shootline.getVector() / original_length * min_distance;
+ }
+
+ // Try to find a node that is closer than the selected active
+ // object (if it exists).
+
+ voxalgo::VoxelLineIterator iterator(shootline.start / BS,
+ shootline.getVector() / BS);
+ v3s16 oldnode = iterator.m_current_node_pos;
+ // Indicates that a node was found.
+ bool is_node_found = false;
+ // If a node is found, it is possible that there's a node
+ // behind it with a large nodebox, so continue the search.
+ u16 node_foundcounter = 0;
+ // If a node is found, this is the center of the
+ // first nodebox the shootline meets.
+ v3f found_boxcenter(0, 0, 0);
+ // The untested nodes are in this range.
+ core::aabbox3d<s16> new_nodes;
+ while (true) {
+ // Test the nodes around the current node in search_range.
+ new_nodes = search_range;
+ new_nodes.MinEdge += iterator.m_current_node_pos;
+ new_nodes.MaxEdge += iterator.m_current_node_pos;
+
+ // Only check new nodes
+ v3s16 delta = iterator.m_current_node_pos - oldnode;
+ if (delta.X > 0)
+ new_nodes.MinEdge.X = new_nodes.MaxEdge.X;
+ else if (delta.X < 0)
+ new_nodes.MaxEdge.X = new_nodes.MinEdge.X;
+ else if (delta.Y > 0)
+ new_nodes.MinEdge.Y = new_nodes.MaxEdge.Y;
+ else if (delta.Y < 0)
+ new_nodes.MaxEdge.Y = new_nodes.MinEdge.Y;
+ else if (delta.Z > 0)
+ new_nodes.MinEdge.Z = new_nodes.MaxEdge.Z;
+ else if (delta.Z < 0)
+ new_nodes.MaxEdge.Z = new_nodes.MinEdge.Z;
+
+ // For each untested node
+ for (s16 x = new_nodes.MinEdge.X; x <= new_nodes.MaxEdge.X; x++) {
+ for (s16 y = new_nodes.MinEdge.Y; y <= new_nodes.MaxEdge.Y; y++) {
+ for (s16 z = new_nodes.MinEdge.Z; z <= new_nodes.MaxEdge.Z; z++) {
+ MapNode n;
+ v3s16 np(x, y, z);
+ bool is_valid_position;
+
+ n = m_map->getNodeNoEx(np, &is_valid_position);
+ if (!(is_valid_position &&
+ isPointableNode(n, nodedef, liquids_pointable))) {
+ continue;
+ }
+ std::vector<aabb3f> boxes;
+ n.getSelectionBoxes(nodedef, &boxes,
+ n.getNeighbors(np, m_map));
+
+ v3f npf = intToFloat(np, BS);
+ for (std::vector<aabb3f>::const_iterator i = boxes.begin();
+ i != boxes.end(); ++i) {
+ aabb3f box = *i;
+ box.MinEdge += npf;
+ box.MaxEdge += npf;
+ v3f intersection_point;
+ v3s16 intersection_normal;
+ if (!boxLineCollision(box, shootline.start, shootline.getVector(),
+ &intersection_point, &intersection_normal)) {
+ continue;
+ }
+ f32 distance = (intersection_point - shootline.start).getLength();
+ if (distance >= min_distance) {
+ continue;
+ }
+ result.type = POINTEDTHING_NODE;
+ result.node_undersurface = np;
+ result.intersection_point = intersection_point;
+ result.intersection_normal = intersection_normal;
+ found_boxcenter = box.getCenter();
+ min_distance = distance;
+ is_node_found = true;
+ }
+ }
+ }
+ }
+ if (is_node_found) {
+ node_foundcounter++;
+ if (node_foundcounter > maximal_overcheck) {
+ break;
+ }
+ }
+ // Next node
+ if (iterator.hasNext()) {
+ oldnode = iterator.m_current_node_pos;
+ iterator.next();
+ } else {
+ break;
+ }
+ }
+
+ if (is_node_found) {
+ // Set undersurface and abovesurface nodes
+ f32 d = 0.002 * BS;
+ v3f fake_intersection = result.intersection_point;
+ // Move intersection towards its source block.
+ if (fake_intersection.X < found_boxcenter.X)
+ fake_intersection.X += d;
+ else
+ fake_intersection.X -= d;
+
+ if (fake_intersection.Y < found_boxcenter.Y)
+ fake_intersection.Y += d;
+ else
+ fake_intersection.Y -= d;
+
+ if (fake_intersection.Z < found_boxcenter.Z)
+ fake_intersection.Z += d;
+ else
+ fake_intersection.Z -= d;
+
+ result.node_real_undersurface = floatToInt(fake_intersection, BS);
+ result.node_abovesurface = result.node_real_undersurface
+ + result.intersection_normal;
+ }
+ return result;
+}
diff --git a/src/clientenvironment.h b/src/clientenvironment.h
new file mode 100644
index 000000000..79b4797ad
--- /dev/null
+++ b/src/clientenvironment.h
@@ -0,0 +1,195 @@
+/*
+Minetest
+Copyright (C) 2010-2017 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 Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 CLIENT_ENVIRONMENT_HEADER
+#define CLIENT_ENVIRONMENT_HEADER
+
+#include <IrrlichtDevice.h>
+#include <ISceneManager.h>
+#include "environment.h"
+#include "clientobject.h"
+
+class ClientSimpleObject;
+class ClientMap;
+class ClientScripting;
+class ClientActiveObject;
+class GenericCAO;
+class LocalPlayer;
+struct PointedThing;
+
+/*
+ The client-side environment.
+
+ This is not thread-safe.
+ Must be called from main (irrlicht) thread (uses the SceneManager)
+ Client uses an environment mutex.
+*/
+
+enum ClientEnvEventType
+{
+ CEE_NONE,
+ CEE_PLAYER_DAMAGE,
+ CEE_PLAYER_BREATH
+};
+
+struct ClientEnvEvent
+{
+ ClientEnvEventType type;
+ union {
+ //struct{
+ //} none;
+ struct{
+ u8 amount;
+ bool send_to_server;
+ } player_damage;
+ struct{
+ u16 amount;
+ } player_breath;
+ };
+};
+
+class ClientEnvironment : public Environment
+{
+public:
+ ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
+ ITextureSource *texturesource, Client *client,
+ IrrlichtDevice *device);
+ ~ClientEnvironment();
+
+ Map & getMap();
+ ClientMap & getClientMap();
+
+ Client *getGameDef() { return m_client; }
+ void setScript(ClientScripting *script) { m_script = script; }
+
+ void step(f32 dtime);
+
+ virtual void setLocalPlayer(LocalPlayer *player);
+ LocalPlayer *getLocalPlayer() { return m_local_player; }
+
+ /*
+ ClientSimpleObjects
+ */
+
+ void addSimpleObject(ClientSimpleObject *simple);
+
+ /*
+ ActiveObjects
+ */
+
+ GenericCAO* getGenericCAO(u16 id);
+ ClientActiveObject* getActiveObject(u16 id);
+
+ /*
+ Adds an active object to the environment.
+ Environment handles deletion of object.
+ Object may be deleted by environment immediately.
+ If id of object is 0, assigns a free id to it.
+ Returns the id of the object.
+ Returns 0 if not added and thus deleted.
+ */
+ u16 addActiveObject(ClientActiveObject *object);
+
+ void addActiveObject(u16 id, u8 type, const std::string &init_data);
+ void removeActiveObject(u16 id);
+
+ void processActiveObjectMessage(u16 id, const std::string &data);
+
+ /*
+ Callbacks for activeobjects
+ */
+
+ void damageLocalPlayer(u8 damage, bool handle_hp=true);
+ void updateLocalPlayerBreath(u16 breath);
+
+ /*
+ Client likes to call these
+ */
+
+ // Get all nearby objects
+ void getActiveObjects(v3f origin, f32 max_d,
+ std::vector<DistanceSortedActiveObject> &dest);
+
+ bool hasClientEnvEvents() const { return !m_client_event_queue.empty(); }
+ // Get event from queue. If queue is empty, it triggers an assertion failure.
+ ClientEnvEvent getClientEnvEvent();
+
+ /*!
+ * Gets closest object pointed by the shootline.
+ * Returns NULL if not found.
+ *
+ * \param[in] shootline_on_map the shootline for
+ * the test in world coordinates
+ * \param[out] intersection_point the first point where
+ * the shootline meets the object. Valid only if
+ * not NULL is returned.
+ * \param[out] intersection_normal the normal vector of
+ * the intersection, pointing outwards. Zero vector if
+ * the shootline starts in an active object.
+ * Valid only if not NULL is returned.
+ */
+ ClientActiveObject * getSelectedActiveObject(
+ const core::line3d<f32> &shootline_on_map,
+ v3f *intersection_point,
+ v3s16 *intersection_normal
+ );
+
+ /*!
+ * Performs a raycast on the world.
+ * Returns the first thing the shootline meets.
+ *
+ * @param[in] shootline the shootline, starting from
+ * the camera position. This also gives the maximal distance
+ * of the search.
+ * @param[in] liquids_pointable if false, liquids are ignored
+ * @param[in] look_for_object if false, objects are ignored
+ */
+ PointedThing getPointedThing(
+ core::line3d<f32> shootline,
+ bool liquids_pointable,
+ bool look_for_object);
+
+ u16 attachement_parent_ids[USHRT_MAX + 1];
+
+ const std::list<std::string> &getPlayerNames() { return m_player_names; }
+ void addPlayerName(const std::string &name) { m_player_names.push_back(name); }
+ void removePlayerName(const std::string &name) { m_player_names.remove(name); }
+ void updateCameraOffset(v3s16 camera_offset)
+ { m_camera_offset = camera_offset; }
+ v3s16 getCameraOffset() const { return m_camera_offset; }
+private:
+ ClientMap *m_map;
+ LocalPlayer *m_local_player;
+ scene::ISceneManager *m_smgr;
+ ITextureSource *m_texturesource;
+ Client *m_client;
+ ClientScripting *m_script;
+ IrrlichtDevice *m_irr;
+ UNORDERED_MAP<u16, ClientActiveObject*> m_active_objects;
+ std::vector<ClientSimpleObject*> m_simple_objects;
+ std::queue<ClientEnvEvent> m_client_event_queue;
+ IntervalLimiter m_active_object_light_update_interval;
+ IntervalLimiter m_lava_hurt_interval;
+ IntervalLimiter m_drowning_interval;
+ IntervalLimiter m_breathing_interval;
+ std::list<std::string> m_player_names;
+ v3s16 m_camera_offset;
+};
+
+#endif
diff --git a/src/clientiface.cpp b/src/clientiface.cpp
index 0390cf0ff..68bd4afe7 100644
--- a/src/clientiface.cpp
+++ b/src/clientiface.cpp
@@ -20,18 +20,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <sstream>
#include "clientiface.h"
-#include "util/numeric.h"
-#include "util/mathconstants.h"
#include "remoteplayer.h"
#include "settings.h"
#include "mapblock.h"
#include "network/connection.h"
-#include "environment.h"
+#include "serverenvironment.h"
#include "map.h"
#include "emerge.h"
#include "content_sao.h" // TODO this is used for cleanup of only
#include "log.h"
+#include "network/serveropcodes.h"
#include "util/srp.h"
+#include "face_position_cache.h"
const char *ClientInterface::statenames[] = {
"Invalid",
@@ -198,6 +198,9 @@ void RemoteClient::GetNextBlocks (
s32 nearest_sent_d = -1;
//bool queue_is_full = false;
+ const v3s16 cam_pos_nodes = floatToInt(camera_pos, BS);
+ const bool occ_cull = g_settings->getBool("server_side_occlusion_culling");
+
s16 d;
for(d = d_start; d <= d_max; d++) {
/*
@@ -236,9 +239,9 @@ void RemoteClient::GetNextBlocks (
continue;
/*
- Do not go over-limit
+ Do not go over max mapgen limit
*/
- if (blockpos_over_limit(p))
+ if (blockpos_over_max_limit(p))
continue;
// If this is true, inexistent block will be made from scratch
@@ -250,8 +253,8 @@ void RemoteClient::GetNextBlocks (
FOV setting. The default of 72 degrees is fine.
*/
- if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, d_blocks_in_sight) == false)
- {
+ f32 dist;
+ if (!isBlockInSight(p, camera_pos, camera_dir, camera_fov, d_blocks_in_sight, &dist)) {
continue;
}
@@ -284,12 +287,6 @@ void RemoteClient::GetNextBlocks (
surely_not_found_on_disk = true;
}
- // Block is valid if lighting is up-to-date and data exists
- if(block->isValid() == false)
- {
- block_is_invalid = true;
- }
-
if(block->isGenerated() == false)
block_is_invalid = true;
@@ -305,6 +302,11 @@ void RemoteClient::GetNextBlocks (
if(block->getDayNightDiff() == false)
continue;
}
+
+ if (occ_cull && !block_is_invalid &&
+ env->getMap().isBlockOccluded(block, cam_pos_nodes)) {
+ continue;
+ }
}
/*
@@ -341,7 +343,7 @@ void RemoteClient::GetNextBlocks (
/*
Add block to send queue
*/
- PrioritySortedBlockTransfer q((float)d, p, peer_id);
+ PrioritySortedBlockTransfer q((float)dist, p, peer_id);
dest.push_back(q);
@@ -588,9 +590,9 @@ void RemoteClient::notifyEvent(ClientStateEvent event)
}
}
-u32 RemoteClient::uptime()
+u64 RemoteClient::uptime() const
{
- return getTime(PRECISION_SECONDS) - m_connection_time;
+ return porting::getTimeS() - m_connection_time;
}
ClientInterface::ClientInterface(con::Connection* con)
@@ -677,16 +679,17 @@ void ClientInterface::send(u16 peer_id, u8 channelnum,
m_con->Send(peer_id, channelnum, pkt, reliable);
}
-void ClientInterface::sendToAll(u16 channelnum,
- NetworkPacket* pkt, bool reliable)
+void ClientInterface::sendToAll(NetworkPacket *pkt)
{
MutexAutoLock clientslock(m_clients_mutex);
- for(UNORDERED_MAP<u16, RemoteClient*>::iterator i = m_clients.begin();
- i != m_clients.end(); ++i) {
+ for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = m_clients.begin();
+ i != m_clients.end(); ++i) {
RemoteClient *client = i->second;
if (client->net_proto_version != 0) {
- m_con->Send(client->peer_id, channelnum, pkt, reliable);
+ m_con->Send(client->peer_id,
+ clientCommandFactoryTable[pkt->getCommand()].channel, pkt,
+ clientCommandFactoryTable[pkt->getCommand()].reliable);
}
}
}
diff --git a/src/clientiface.h b/src/clientiface.h
index 551d71bbe..d2299c879 100644
--- a/src/clientiface.h
+++ b/src/clientiface.h
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "threading/mutex.h"
#include "network/networkpacket.h"
#include "util/cpp11_container.h"
+#include "porting.h"
#include <list>
#include <vector>
@@ -165,7 +166,6 @@ namespace con {
class Connection;
}
-#define CI_ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
// Also make sure to update the ClientInterface::statenames
// array when modifying these enums
@@ -266,7 +266,7 @@ public:
m_version_patch(0),
m_full_version("unknown"),
m_deployed_compression(0),
- m_connection_time(getTime(PRECISION_SECONDS))
+ m_connection_time(porting::getTimeS())
{
}
~RemoteClient()
@@ -325,14 +325,11 @@ public:
*/
std::set<u16> m_known_objects;
- ClientState getState()
- { return m_state; }
+ ClientState getState() const { return m_state; }
- std::string getName()
- { return m_name; }
+ std::string getName() const { return m_name; }
- void setName(std::string name)
- { m_name = name; }
+ void setName(const std::string &name) { m_name = name; }
/* update internal client state */
void notifyEvent(ClientStateEvent event);
@@ -348,10 +345,11 @@ public:
{ serialization_version = m_pending_serialization_version; }
/* get uptime */
- u32 uptime();
+ u64 uptime() const;
/* set version information */
- void setVersionInfo(u8 major, u8 minor, u8 patch, std::string full) {
+ void setVersionInfo(u8 major, u8 minor, u8 patch, const std::string &full)
+ {
m_version_major = major;
m_version_minor = minor;
m_version_patch = patch;
@@ -359,10 +357,9 @@ public:
}
/* read version information */
- u8 getMajor() { return m_version_major; }
- u8 getMinor() { return m_version_minor; }
- u8 getPatch() { return m_version_patch; }
- std::string getVersion() { return m_full_version; }
+ u8 getMajor() const { return m_version_major; }
+ u8 getMinor() const { return m_version_minor; }
+ u8 getPatch() const { return m_version_patch; }
private:
// Version is stored in here after INIT before INIT2
u8 m_pending_serialization_version;
@@ -435,7 +432,7 @@ private:
/*
time this client was created
*/
- const u32 m_connection_time;
+ const u64 m_connection_time;
};
class ClientInterface {
@@ -459,7 +456,7 @@ public:
void send(u16 peer_id, u8 channelnum, NetworkPacket* pkt, bool reliable);
/* send to all clients */
- void sendToAll(u16 channelnum, NetworkPacket* pkt, bool reliable);
+ void sendToAll(NetworkPacket *pkt);
/* delete a client */
void DeleteClient(u16 peer_id);
diff --git a/src/clientmap.cpp b/src/clientmap.cpp
index faa1461f6..6cd24ffc6 100644
--- a/src/clientmap.cpp
+++ b/src/clientmap.cpp
@@ -29,20 +29,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "profiler.h"
#include "settings.h"
#include "camera.h" // CameraModes
-#include "util/mathconstants.h"
+#include "util/basic_macros.h"
#include <algorithm>
-#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
-
ClientMap::ClientMap(
Client *client,
- IGameDef *gamedef,
MapDrawControl &control,
scene::ISceneNode* parent,
scene::ISceneManager* mgr,
s32 id
):
- Map(dout_client, gamedef),
+ Map(dout_client, client),
scene::ISceneNode(parent, mgr, id),
m_client(client),
m_control(control),
@@ -112,36 +109,7 @@ void ClientMap::OnRegisterSceneNode()
ISceneNode::OnRegisterSceneNode();
}
-static bool isOccluded(Map *map, v3s16 p0, v3s16 p1, float step, float stepfac,
- float start_off, float end_off, u32 needed_count, INodeDefManager *nodemgr)
-{
- float d0 = (float)BS * p0.getDistanceFrom(p1);
- v3s16 u0 = p1 - p0;
- v3f uf = v3f(u0.X, u0.Y, u0.Z) * BS;
- uf.normalize();
- v3f p0f = v3f(p0.X, p0.Y, p0.Z) * BS;
- u32 count = 0;
- for(float s=start_off; s<d0+end_off; s+=step){
- v3f pf = p0f + uf * s;
- v3s16 p = floatToInt(pf, BS);
- MapNode n = map->getNodeNoEx(p);
- bool is_transparent = false;
- const ContentFeatures &f = nodemgr->get(n);
- if(f.solidness == 0)
- is_transparent = (f.visual_solidness != 2);
- else
- is_transparent = (f.solidness != 2);
- if(!is_transparent){
- count++;
- if(count >= needed_count)
- return true;
- }
- step *= stepfac;
- }
- return false;
-}
-
-void ClientMap::getBlocksInViewRange(v3s16 cam_pos_nodes,
+void ClientMap::getBlocksInViewRange(v3s16 cam_pos_nodes,
v3s16 *p_blocks_min, v3s16 *p_blocks_max)
{
v3s16 box_nodes_d = m_control.wanted_range * v3s16(1, 1, 1);
@@ -173,8 +141,6 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG);
g_profiler->add("CM::updateDrawList() count", 1);
- INodeDefManager *nodemgr = m_gamedef->ndef();
-
for (std::map<v3s16, MapBlock*>::iterator i = m_drawlist.begin();
i != m_drawlist.end(); ++i) {
MapBlock *block = i->second;
@@ -214,6 +180,16 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
// Distance to farthest drawn block
float farthest_drawn = 0;
+ // No occlusion culling when free_move is on and camera is
+ // inside ground
+ bool occlusion_culling_enabled = true;
+ if (g_settings->getBool("free_move")) {
+ MapNode n = getNodeNoEx(cam_pos_nodes);
+ if (n.getContent() == CONTENT_IGNORE ||
+ m_nodedef->get(n).solidness == 2)
+ occlusion_culling_enabled = false;
+ }
+
for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
si != m_sectors.end(); ++si) {
MapSector *sector = si->second;
@@ -255,76 +231,20 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
camera_direction, camera_fov, range, &d))
continue;
- // This is ugly (spherical distance limit?)
- /*if(m_control.range_all == false &&
- d - 0.5*BS*MAP_BLOCKSIZE > range)
- continue;*/
-
blocks_in_range++;
/*
Ignore if mesh doesn't exist
*/
- {
- //MutexAutoLock lock(block->mesh_mutex);
-
- if (block->mesh == NULL) {
- blocks_in_range_without_mesh++;
- continue;
- }
+ if (block->mesh == NULL) {
+ blocks_in_range_without_mesh++;
+ continue;
}
/*
Occlusion culling
*/
-
- // No occlusion culling when free_move is on and camera is
- // inside ground
- bool occlusion_culling_enabled = true;
- if (g_settings->getBool("free_move")) {
- MapNode n = getNodeNoEx(cam_pos_nodes);
- if (n.getContent() == CONTENT_IGNORE ||
- nodemgr->get(n).solidness == 2)
- occlusion_culling_enabled = false;
- }
-
- v3s16 cpn = block->getPos() * MAP_BLOCKSIZE;
- cpn += v3s16(MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2);
- float step = BS * 1;
- float stepfac = 1.1;
- float startoff = BS * 1;
- // The occlusion search of 'isOccluded()' must stop short of the target
- // point by distance 'endoff' (end offset) to not enter the target mapblock.
- // For the 8 mapblock corners 'endoff' must therefore be the maximum diagonal
- // of a mapblock, because we must consider all view angles.
- // sqrt(1^2 + 1^2 + 1^2) = 1.732
- float endoff = -BS * MAP_BLOCKSIZE * 1.732050807569;
- v3s16 spn = cam_pos_nodes;
- s16 bs2 = MAP_BLOCKSIZE / 2 + 1;
- // to reduce the likelihood of falsely occluded blocks
- // require at least two solid blocks
- // this is a HACK, we should think of a more precise algorithm
- u32 needed_count = 2;
- if (occlusion_culling_enabled &&
- // For the central point of the mapblock 'endoff' can be halved
- isOccluded(this, spn, cpn,
- step, stepfac, startoff, endoff / 2.0f, needed_count, nodemgr) &&
- isOccluded(this, spn, cpn + v3s16(bs2,bs2,bs2),
- step, stepfac, startoff, endoff, needed_count, nodemgr) &&
- isOccluded(this, spn, cpn + v3s16(bs2,bs2,-bs2),
- step, stepfac, startoff, endoff, needed_count, nodemgr) &&
- isOccluded(this, spn, cpn + v3s16(bs2,-bs2,bs2),
- step, stepfac, startoff, endoff, needed_count, nodemgr) &&
- isOccluded(this, spn, cpn + v3s16(bs2,-bs2,-bs2),
- step, stepfac, startoff, endoff, needed_count, nodemgr) &&
- isOccluded(this, spn, cpn + v3s16(-bs2,bs2,bs2),
- step, stepfac, startoff, endoff, needed_count, nodemgr) &&
- isOccluded(this, spn, cpn + v3s16(-bs2,bs2,-bs2),
- step, stepfac, startoff, endoff, needed_count, nodemgr) &&
- isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,bs2),
- step, stepfac, startoff, endoff, needed_count, nodemgr) &&
- isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,-bs2),
- step, stepfac, startoff, endoff, needed_count, nodemgr)) {
+ if (occlusion_culling_enabled && isBlockOccluded(block, cam_pos_nodes)) {
blocks_occlusion_culled++;
continue;
}
@@ -370,6 +290,11 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
struct MeshBufList
{
+ /*!
+ * Specifies in which layer the list is.
+ * All lists which are in a lower layer are rendered before this list.
+ */
+ u8 layer;
video::SMaterial m;
std::vector<scene::IMeshBuffer*> bufs;
};
@@ -383,25 +308,29 @@ struct MeshBufListList
lists.clear();
}
- void add(scene::IMeshBuffer *buf)
+ void add(scene::IMeshBuffer *buf, u8 layer)
{
+ const video::SMaterial &m = buf->getMaterial();
for(std::vector<MeshBufList>::iterator i = lists.begin();
i != lists.end(); ++i){
MeshBufList &l = *i;
- video::SMaterial &m = buf->getMaterial();
// comparing a full material is quite expensive so we don't do it if
// not even first texture is equal
if (l.m.TextureLayer[0].Texture != m.TextureLayer[0].Texture)
continue;
+ if(l.layer != layer)
+ continue;
+
if (l.m == m) {
l.bufs.push_back(buf);
return;
}
}
MeshBufList l;
- l.m = buf->getMaterial();
+ l.layer = layer;
+ l.m = m;
l.bufs.push_back(buf);
lists.push_back(l);
}
@@ -448,11 +377,6 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
Get all blocks and draw all visible ones
*/
- v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
- v3s16 p_blocks_min;
- v3s16 p_blocks_max;
- getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max);
-
u32 vertex_count = 0;
u32 meshbuffer_count = 0;
@@ -490,7 +414,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
continue;
// Mesh animation
- {
+ if (pass == scene::ESNRP_SOLID) {
//MutexAutoLock lock(block->mesh_mutex);
MapBlockMesh *mapBlockMesh = block->mesh;
assert(mapBlockMesh);
@@ -519,28 +443,34 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
MapBlockMesh *mapBlockMesh = block->mesh;
assert(mapBlockMesh);
- scene::IMesh *mesh = mapBlockMesh->getMesh();
- assert(mesh);
-
- u32 c = mesh->getMeshBufferCount();
- for (u32 i = 0; i < c; i++)
- {
- scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
+ for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
+ scene::IMesh *mesh = mapBlockMesh->getMesh(layer);
+ assert(mesh);
- buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, m_cache_trilinear_filter);
- buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, m_cache_bilinear_filter);
- buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, m_cache_anistropic_filter);
- buf->getMaterial().setFlag(video::EMF_WIREFRAME, m_control.show_wireframe);
+ u32 c = mesh->getMeshBufferCount();
+ for (u32 i = 0; i < c; i++) {
+ scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
- const video::SMaterial& material = buf->getMaterial();
- video::IMaterialRenderer* rnd =
+ video::SMaterial& material = buf->getMaterial();
+ video::IMaterialRenderer* rnd =
driver->getMaterialRenderer(material.MaterialType);
- bool transparent = (rnd && rnd->isTransparent());
- if (transparent == is_transparent_pass) {
- if (buf->getVertexCount() == 0)
- errorstream << "Block [" << analyze_block(block)
- << "] contains an empty meshbuf" << std::endl;
- drawbufs.add(buf);
+ bool transparent = (rnd && rnd->isTransparent());
+ if (transparent == is_transparent_pass) {
+ if (buf->getVertexCount() == 0)
+ errorstream << "Block [" << analyze_block(block)
+ << "] contains an empty meshbuf" << std::endl;
+
+ material.setFlag(video::EMF_TRILINEAR_FILTER,
+ m_cache_trilinear_filter);
+ material.setFlag(video::EMF_BILINEAR_FILTER,
+ m_cache_bilinear_filter);
+ material.setFlag(video::EMF_ANISOTROPIC_FILTER,
+ m_cache_anistropic_filter);
+ material.setFlag(video::EMF_WIREFRAME,
+ m_control.show_wireframe);
+
+ drawbufs.add(buf, layer);
+ }
}
}
}
@@ -672,7 +602,6 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
int oldvalue, bool *sunlight_seen_result)
{
const bool debugprint = false;
- INodeDefManager *ndef = m_gamedef->ndef();
static v3f z_directions[50] = {
v3f(-100, 0, 0)
};
@@ -710,7 +639,7 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
float off = step * z_offsets[i];
bool sunlight_seen_now = false;
bool ok = getVisibleBrightness(this, m_camera_position, dir,
- step, 1.0, max_d*0.6+off, max_d, ndef, daylight_factor,
+ step, 1.0, max_d*0.6+off, max_d, m_nodedef, daylight_factor,
sunlight_min_d,
&br, &sunlight_seen_now);
if(sunlight_seen_now)
@@ -750,8 +679,8 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
int ret = 0;
if(brightness_count == 0){
MapNode n = getNodeNoEx(floatToInt(m_camera_position, BS));
- if(ndef->get(n).param_type == CPT_LIGHT){
- ret = decode_light(n.getLightBlend(daylight_factor, ndef));
+ if(m_nodedef->get(n).param_type == CPT_LIGHT){
+ ret = decode_light(n.getLightBlend(daylight_factor, m_nodedef));
} else {
ret = oldvalue;
}
@@ -774,8 +703,6 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
void ClientMap::renderPostFx(CameraMode cam_mode)
{
- INodeDefManager *nodemgr = m_gamedef->ndef();
-
// Sadly ISceneManager has no "post effects" render pass, in that case we
// could just register for that and handle it in renderMap().
@@ -784,10 +711,10 @@ void ClientMap::renderPostFx(CameraMode cam_mode)
// - If the player is in a solid node, make everything black.
// - If the player is in liquid, draw a semi-transparent overlay.
// - Do not if player is in third person mode
- const ContentFeatures& features = nodemgr->get(n);
+ const ContentFeatures& features = m_nodedef->get(n);
video::SColor post_effect_color = features.post_effect_color;
if(features.solidness == 2 && !(g_settings->getBool("noclip") &&
- m_gamedef->checkLocalPrivilege("noclip")) &&
+ m_client->checkLocalPrivilege("noclip")) &&
cam_mode == CAMERA_MODE_FIRST)
{
post_effect_color = video::SColor(255, 0, 0, 0);
diff --git a/src/clientmap.h b/src/clientmap.h
index cb686ff33..84228f4ca 100644
--- a/src/clientmap.h
+++ b/src/clientmap.h
@@ -59,7 +59,7 @@ class ITextureSource;
/*
ClientMap
-
+
This is the only map class that is able to render itself on screen.
*/
@@ -68,7 +68,6 @@ class ClientMap : public Map, public scene::ISceneNode
public:
ClientMap(
Client *client,
- IGameDef *gamedef,
MapDrawControl &control,
scene::ISceneNode* parent,
scene::ISceneManager* mgr,
@@ -114,13 +113,13 @@ public:
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
renderMap(driver, SceneManager->getSceneNodeRenderPass());
}
-
+
virtual const aabb3f &getBoundingBox() const
{
return m_box;
}
-
- void getBlocksInViewRange(v3s16 cam_pos_nodes,
+
+ void getBlocksInViewRange(v3s16 cam_pos_nodes,
v3s16 *p_blocks_min, v3s16 *p_blocks_max);
void updateDrawList(video::IVideoDriver* driver);
void renderMap(video::IVideoDriver* driver, s32 pass);
@@ -132,20 +131,14 @@ public:
// For debug printing
virtual void PrintInfo(std::ostream &out);
-
- // Check if sector was drawn on last render()
- bool sectorWasDrawn(v2s16 p)
- {
- return (m_last_drawn_sectors.find(p) != m_last_drawn_sectors.end());
- }
const MapDrawControl & getControl() const { return m_control; }
f32 getCameraFov() const { return m_camera_fov; }
private:
Client *m_client;
-
+
aabb3f m_box;
-
+
MapDrawControl &m_control;
v3f m_camera_position;
@@ -154,7 +147,7 @@ private:
v3s16 m_camera_offset;
std::map<v3s16, MapBlock*> m_drawlist;
-
+
std::set<v2s16> m_last_drawn_sectors;
bool m_cache_trilinear_filter;
diff --git a/src/clientmedia.cpp b/src/clientmedia.cpp
index bca3f67c2..9c1e430df 100644
--- a/src/clientmedia.cpp
+++ b/src/clientmedia.cpp
@@ -42,12 +42,12 @@ static std::string getMediaCacheDir()
*/
ClientMediaDownloader::ClientMediaDownloader():
- m_media_cache(getMediaCacheDir())
+ m_media_cache(getMediaCacheDir()),
+ m_initial_step_done(false),
+ m_uncached_count(0),
+ m_uncached_received_count(0),
+ m_name_bound("")
{
- m_initial_step_done = false;
- m_name_bound = ""; // works because "" is an invalid file name
- m_uncached_count = 0;
- m_uncached_received_count = 0;
m_httpfetch_caller = HTTPFETCH_DISCARD;
m_httpfetch_active = 0;
m_httpfetch_active_limit = 0;
@@ -69,7 +69,7 @@ ClientMediaDownloader::~ClientMediaDownloader()
delete m_remotes[i];
}
-void ClientMediaDownloader::addFile(std::string name, std::string sha1)
+void ClientMediaDownloader::addFile(const std::string &name, const std::string &sha1)
{
assert(!m_initial_step_done); // pre-condition
@@ -104,7 +104,7 @@ void ClientMediaDownloader::addFile(std::string name, std::string sha1)
m_files.insert(std::make_pair(name, filestatus));
}
-void ClientMediaDownloader::addRemoteServer(std::string baseurl)
+void ClientMediaDownloader::addRemoteServer(const std::string &baseurl)
{
assert(!m_initial_step_done); // pre-condition
@@ -348,7 +348,7 @@ void ClientMediaDownloader::remoteMediaReceived(
std::string name;
{
- std::map<unsigned long, std::string>::iterator it =
+ UNORDERED_MAP<unsigned long, std::string>::iterator it =
m_remote_file_transfers.find(fetch_result.request_id);
assert(it != m_remote_file_transfers.end());
name = it->second;
diff --git a/src/clientmedia.h b/src/clientmedia.h
index 1f0da70d9..3c96dfe8a 100644
--- a/src/clientmedia.h
+++ b/src/clientmedia.h
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <map>
#include <set>
#include <vector>
+#include "util/cpp11_container.h"
class Client;
struct HTTPFetchResult;
@@ -58,10 +59,10 @@ public:
}
// Add a file to the list of required file (but don't fetch it yet)
- void addFile(std::string name, std::string sha1);
+ void addFile(const std::string &name, const std::string &sha1);
// Add a remote server to the list; ignored if not built with cURL
- void addRemoteServer(std::string baseurl);
+ void addRemoteServer(const std::string &baseurl);
// Steps the media downloader:
// - May load media into client by calling client->loadMedia()
@@ -137,7 +138,7 @@ private:
s32 m_httpfetch_active;
s32 m_httpfetch_active_limit;
s32 m_outstanding_hash_sets;
- std::map<unsigned long, std::string> m_remote_file_transfers;
+ UNORDERED_MAP<unsigned long, std::string> m_remote_file_transfers;
// All files up to this name have either been received from a
// remote server or failed on all remote servers, so those files
diff --git a/src/clientobject.cpp b/src/clientobject.cpp
index ff3f47187..89a0474a4 100644
--- a/src/clientobject.cpp
+++ b/src/clientobject.cpp
@@ -20,16 +20,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "clientobject.h"
#include "debug.h"
#include "porting.h"
-#include "constants.h"
/*
ClientActiveObject
*/
-ClientActiveObject::ClientActiveObject(u16 id, IGameDef *gamedef,
+ClientActiveObject::ClientActiveObject(u16 id, Client *client,
ClientEnvironment *env):
ActiveObject(id),
- m_gamedef(gamedef),
+ m_client(client),
m_env(env)
{
}
@@ -40,7 +39,7 @@ ClientActiveObject::~ClientActiveObject()
}
ClientActiveObject* ClientActiveObject::create(ActiveObjectType type,
- IGameDef *gamedef, ClientEnvironment *env)
+ Client *client, ClientEnvironment *env)
{
// Find factory function
UNORDERED_MAP<u16, Factory>::iterator n = m_types.find(type);
@@ -52,7 +51,7 @@ ClientActiveObject* ClientActiveObject::create(ActiveObjectType type,
}
Factory f = n->second;
- ClientActiveObject *object = (*f)(gamedef, env);
+ ClientActiveObject *object = (*f)(client, env);
return object;
}
diff --git a/src/clientobject.h b/src/clientobject.h
index 83931e438..aa0ec9c56 100644
--- a/src/clientobject.h
+++ b/src/clientobject.h
@@ -25,20 +25,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <map>
#include "util/cpp11_container.h"
-/*
-
-Some planning
--------------
-
-* Client receives a network packet with information of added objects
- in it
-* Client supplies the information to its ClientEnvironment
-* The environment adds the specified objects to itself
-
-*/
-
class ClientEnvironment;
class ITextureSource;
+class Client;
class IGameDef;
class LocalPlayer;
struct ItemStack;
@@ -47,7 +36,7 @@ class WieldMeshSceneNode;
class ClientActiveObject : public ActiveObject
{
public:
- ClientActiveObject(u16 id, IGameDef *gamedef, ClientEnvironment *env);
+ ClientActiveObject(u16 id, Client *client, ClientEnvironment *env);
virtual ~ClientActiveObject();
virtual void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
@@ -58,20 +47,15 @@ public:
virtual void updateLightNoCheck(u8 light_at_pos){}
virtual v3s16 getLightPosition(){return v3s16(0,0,0);}
virtual aabb3f *getSelectionBox() { return NULL; }
- virtual bool getCollisionBox(aabb3f *toset){return false;}
- virtual bool collideWithObjects(){return false;}
- virtual v3f getPosition(){return v3f(0,0,0);}
- virtual float getYaw() const {return 0;}
- virtual scene::ISceneNode *getSceneNode(){return NULL;}
- virtual scene::IMeshSceneNode *getMeshSceneNode(){return NULL;}
- virtual scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode(){return NULL;}
- virtual WieldMeshSceneNode *getWieldMeshSceneNode(){return NULL;}
- virtual scene::IBillboardSceneNode *getSpriteSceneNode(){return NULL;}
- virtual bool isPlayer() const {return false;}
+ virtual bool getCollisionBox(aabb3f *toset) const { return false; }
+ virtual bool collideWithObjects() const { return false; }
+ virtual v3f getPosition(){ return v3f(0,0,0); }
+ virtual float getYaw() const { return 0; }
+ virtual scene::ISceneNode *getSceneNode() { return NULL; }
+ virtual scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode() { return NULL; }
virtual bool isLocalPlayer() const {return false;}
- virtual void setAttachments(){}
+ virtual void setAttachments() {}
virtual bool doShowSelectionBox(){return true;}
- virtual void updateCameraOffset(v3s16 camera_offset){};
// Step object in time
virtual void step(float dtime, ClientEnvironment *env){}
@@ -89,7 +73,7 @@ public:
virtual void initialize(const std::string &data){}
// Create a certain type of ClientActiveObject
- static ClientActiveObject* create(ActiveObjectType type, IGameDef *gamedef,
+ static ClientActiveObject* create(ActiveObjectType type, Client *client,
ClientEnvironment *env);
// If returns true, punch will not be sent to the server
@@ -99,9 +83,9 @@ public:
protected:
// Used for creating objects based on type
- typedef ClientActiveObject* (*Factory)(IGameDef *gamedef, ClientEnvironment *env);
+ typedef ClientActiveObject* (*Factory)(Client *client, ClientEnvironment *env);
static void registerType(u16 type, Factory f);
- IGameDef *m_gamedef;
+ Client *m_client;
ClientEnvironment *m_env;
private:
// Used for creating objects based on type
diff --git a/src/clientsimpleobject.h b/src/clientsimpleobject.h
index c94db22f1..f5b79b64f 100644
--- a/src/clientsimpleobject.h
+++ b/src/clientsimpleobject.h
@@ -29,10 +29,9 @@ protected:
public:
bool m_to_be_removed;
- ClientSimpleObject(): m_to_be_removed(false) {}
- virtual ~ClientSimpleObject(){}
- virtual void step(float dtime){}
+ ClientSimpleObject() : m_to_be_removed(false) {}
+ virtual ~ClientSimpleObject() {}
+ virtual void step(float dtime) {}
};
#endif
-
diff --git a/src/cloudparams.h b/src/cloudparams.h
new file mode 100644
index 000000000..dafec4b27
--- /dev/null
+++ b/src/cloudparams.h
@@ -0,0 +1,33 @@
+/*
+Minetest
+Copyright (C) 2017 bendeutsch, Ben Deutsch <ben@bendeutsch.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 CLOUDPARAMS_HEADER
+#define CLOUDPARAMS_HEADER
+
+struct CloudParams
+{
+ float density;
+ video::SColor color_bright;
+ video::SColor color_ambient;
+ float thickness;
+ float height;
+ v2f speed;
+};
+
+#endif
diff --git a/src/clouds.cpp b/src/clouds.cpp
index 82b63b6b3..10a533cae 100644
--- a/src/clouds.cpp
+++ b/src/clouds.cpp
@@ -32,6 +32,7 @@ irr::scene::ISceneManager *g_menucloudsmgr = NULL;
static void cloud_3d_setting_changed(const std::string &settingname, void *data)
{
+ // TODO: only re-read cloud settings, not height or radius
((Clouds *)data)->readSettings();
}
@@ -44,9 +45,10 @@ Clouds::Clouds(
):
scene::ISceneNode(parent, mgr, id),
m_seed(seed),
- m_camera_pos(0,0),
- m_time(0),
- m_camera_offset(0,0,0)
+ m_camera_pos(0.0f, 0.0f),
+ m_origin(0.0f, 0.0f),
+ m_camera_offset(0.0f, 0.0f, 0.0f),
+ m_color(1.0f, 1.0f, 1.0f, 1.0f)
{
m_material.setFlag(video::EMF_LIGHTING, false);
//m_material.setFlag(video::EMF_BACK_FACE_CULLING, false);
@@ -57,14 +59,18 @@ Clouds::Clouds(
//m_material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+ m_params.density = 0.4f;
+ m_params.thickness = 16.0f;
+ m_params.color_bright = video::SColor(229, 240, 240, 255);
+ m_params.color_ambient = video::SColor(255, 0, 0, 0);
+ m_params.speed = v2f(0.0f, -2.0f);
+
m_passed_cloud_y = cloudheight;
readSettings();
g_settings->registerChangedCallback("enable_3d_clouds",
&cloud_3d_setting_changed, this);
- m_box = aabb3f(-BS*1000000,m_cloud_y-BS,-BS*1000000,
- BS*1000000,m_cloud_y+BS,BS*1000000);
-
+ updateBox();
}
Clouds::~Clouds()
@@ -88,6 +94,10 @@ void Clouds::OnRegisterSceneNode()
void Clouds::render()
{
+
+ if (m_params.density <= 0.0f)
+ return; // no need to do anything
+
video::IVideoDriver* driver = SceneManager->getVideoDriver();
if(SceneManager->getSceneNodeRenderPass() != scene::ESNRP_TRANSPARENT)
@@ -107,15 +117,12 @@ void Clouds::render()
Clouds move from Z+ towards Z-
*/
- const float cloud_size = BS * 64;
- const v2f cloud_speed(0, -BS * 2);
+ static const float cloud_size = BS * 64.0f;
const float cloud_full_radius = cloud_size * m_cloud_radius_i;
- // Position of cloud noise origin in world coordinates
- v2f world_cloud_origin_pos_f = m_time * cloud_speed;
// Position of cloud noise origin from the camera
- v2f cloud_origin_from_camera_f = world_cloud_origin_pos_f - m_camera_pos;
+ v2f cloud_origin_from_camera_f = m_origin - m_camera_pos;
// The center point of drawing in the noise
v2f center_of_drawing_in_noise_f = -cloud_origin_from_camera_f;
// The integer center point of drawing in the noise
@@ -127,7 +134,7 @@ void Clouds::render()
v2f world_center_of_drawing_in_noise_f = v2f(
center_of_drawing_in_noise_i.X * cloud_size,
center_of_drawing_in_noise_i.Y * cloud_size
- ) + world_cloud_origin_pos_f;
+ ) + m_origin;
/*video::SColor c_top(128,b*240,b*240,b*255);
video::SColor c_side_1(128,b*230,b*230,b*255);
@@ -146,10 +153,6 @@ void Clouds::render()
c_bottom_f.r *= 0.80;
c_bottom_f.g *= 0.80;
c_bottom_f.b *= 0.80;
- c_top_f.a = 0.9;
- c_side_1_f.a = 0.9;
- c_side_2_f.a = 0.9;
- c_bottom_f.a = 0.9;
video::SColor c_top = c_top_f.toSColor();
video::SColor c_side_1 = c_side_1_f.toSColor();
video::SColor c_side_2 = c_side_2_f.toSColor();
@@ -187,11 +190,14 @@ void Clouds::render()
zi + center_of_drawing_in_noise_i.Y
);
- double noise = noise2d_perlin(
+ float noise = noise2d_perlin(
(float)p_in_noise_i.X * cloud_size_noise,
(float)p_in_noise_i.Y * cloud_size_noise,
m_seed, 3, 0.5);
- grid[i] = (noise >= 0.4);
+ // normalize to 0..1 (given 3 octaves)
+ static const float noise_bound = 1.0f + 0.5f + 0.25f;
+ float density = noise / noise_bound * 0.5f + 0.5f;
+ grid[i] = (density < m_params.density);
}
}
@@ -236,8 +242,9 @@ void Clouds::render()
v[3].Color.setBlue(255);
}*/
- f32 rx = cloud_size/2;
- f32 ry = 8 * BS;
+ f32 rx = cloud_size / 2.0f;
+ // if clouds are flat, the top layer should be at the given height
+ f32 ry = m_enable_3d ? m_params.thickness * BS : 0.0f;
f32 rz = cloud_size / 2;
for(int i=0; i<num_faces_to_draw; i++)
@@ -265,8 +272,8 @@ void Clouds::render()
}
v[0].Pos.set(-rx, ry,-rz);
v[1].Pos.set( rx, ry,-rz);
- v[2].Pos.set( rx,-ry,-rz);
- v[3].Pos.set(-rx,-ry,-rz);
+ v[2].Pos.set( rx, 0,-rz);
+ v[3].Pos.set(-rx, 0,-rz);
break;
case 2: //right
if (INAREA(xi + 1, zi, m_cloud_radius_i)) {
@@ -280,8 +287,8 @@ void Clouds::render()
}
v[0].Pos.set( rx, ry,-rz);
v[1].Pos.set( rx, ry, rz);
- v[2].Pos.set( rx,-ry, rz);
- v[3].Pos.set( rx,-ry,-rz);
+ v[2].Pos.set( rx, 0, rz);
+ v[3].Pos.set( rx, 0,-rz);
break;
case 3: // front
if (INAREA(xi, zi + 1, m_cloud_radius_i)) {
@@ -295,8 +302,8 @@ void Clouds::render()
}
v[0].Pos.set( rx, ry, rz);
v[1].Pos.set(-rx, ry, rz);
- v[2].Pos.set(-rx,-ry, rz);
- v[3].Pos.set( rx,-ry, rz);
+ v[2].Pos.set(-rx, 0, rz);
+ v[3].Pos.set( rx, 0, rz);
break;
case 4: // left
if (INAREA(xi-1, zi, m_cloud_radius_i)) {
@@ -310,22 +317,22 @@ void Clouds::render()
}
v[0].Pos.set(-rx, ry, rz);
v[1].Pos.set(-rx, ry,-rz);
- v[2].Pos.set(-rx,-ry,-rz);
- v[3].Pos.set(-rx,-ry, rz);
+ v[2].Pos.set(-rx, 0,-rz);
+ v[3].Pos.set(-rx, 0, rz);
break;
case 5: // bottom
for(int j=0;j<4;j++){
v[j].Color = c_bottom;
v[j].Normal.set(0,-1,0);
}
- v[0].Pos.set( rx,-ry, rz);
- v[1].Pos.set(-rx,-ry, rz);
- v[2].Pos.set(-rx,-ry,-rz);
- v[3].Pos.set( rx,-ry,-rz);
+ v[0].Pos.set( rx, 0, rz);
+ v[1].Pos.set(-rx, 0, rz);
+ v[2].Pos.set(-rx, 0,-rz);
+ v[3].Pos.set( rx, 0,-rz);
break;
}
- v3f pos(p0.X, m_cloud_y, p0.Y);
+ v3f pos(p0.X, m_params.height * BS, p0.Y);
pos -= intToFloat(m_camera_offset, BS);
for(u16 i=0; i<4; i++)
@@ -345,22 +352,25 @@ void Clouds::render()
void Clouds::step(float dtime)
{
- m_time += dtime;
+ m_origin = m_origin + dtime * BS * m_params.speed;
}
-void Clouds::update(v2f camera_p, video::SColorf color)
+void Clouds::update(v2f camera_p, video::SColorf color_diffuse)
{
m_camera_pos = camera_p;
- m_color = color;
- //m_brightness = brightness;
- //dstream<<"m_brightness="<<m_brightness<<std::endl;
+ m_color.r = MYMIN(MYMAX(color_diffuse.r * m_params.color_bright.getRed(),
+ m_params.color_ambient.getRed()), 255) / 255.0f;
+ m_color.g = MYMIN(MYMAX(color_diffuse.g * m_params.color_bright.getGreen(),
+ m_params.color_ambient.getGreen()), 255) / 255.0f;
+ m_color.b = MYMIN(MYMAX(color_diffuse.b * m_params.color_bright.getBlue(),
+ m_params.color_ambient.getBlue()), 255) / 255.0f;
+ m_color.a = m_params.color_bright.getAlpha() / 255.0f;
}
void Clouds::readSettings()
{
- m_cloud_y = BS * (m_passed_cloud_y ? m_passed_cloud_y :
+ m_params.height = (m_passed_cloud_y ? m_passed_cloud_y :
g_settings->getS16("cloud_height"));
m_cloud_radius_i = g_settings->getU16("cloud_radius");
m_enable_3d = g_settings->getBool("enable_3d_clouds");
}
-
diff --git a/src/clouds.h b/src/clouds.h
index 9c6b41786..a0bda28df 100644
--- a/src/clouds.h
+++ b/src/clouds.h
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h"
#include <iostream>
#include "constants.h"
+#include "cloudparams.h"
// Menu clouds
class Clouds;
@@ -79,27 +80,68 @@ public:
void updateCameraOffset(v3s16 camera_offset)
{
m_camera_offset = camera_offset;
- m_box = aabb3f(-BS * 1000000, m_cloud_y - BS - BS * camera_offset.Y, -BS * 1000000,
- BS * 1000000, m_cloud_y + BS - BS * camera_offset.Y, BS * 1000000);
+ updateBox();
}
void readSettings();
+ void setDensity(float density)
+ {
+ m_params.density = density;
+ // currently does not need bounding
+ }
+
+ void setColorBright(const video::SColor &color_bright)
+ {
+ m_params.color_bright = color_bright;
+ }
+
+ void setColorAmbient(const video::SColor &color_ambient)
+ {
+ m_params.color_ambient = color_ambient;
+ }
+
+ void setHeight(float height)
+ {
+ m_params.height = height; // add bounding when necessary
+ updateBox();
+ }
+
+ void setSpeed(v2f speed)
+ {
+ m_params.speed = speed;
+ }
+
+ void setThickness(float thickness)
+ {
+ m_params.thickness = thickness;
+ updateBox();
+ }
+
private:
+ void updateBox()
+ {
+ float height_bs = m_params.height * BS;
+ float thickness_bs = m_params.thickness * BS;
+ m_box = aabb3f(-BS * 1000000.0f, height_bs - BS * m_camera_offset.Y, -BS * 1000000.0f,
+ BS * 1000000.0f, height_bs + thickness_bs - BS * m_camera_offset.Y, BS * 1000000.0f);
+ }
+
video::SMaterial m_material;
aabb3f m_box;
s16 m_passed_cloud_y;
- float m_cloud_y;
u16 m_cloud_radius_i;
bool m_enable_3d;
- video::SColorf m_color;
u32 m_seed;
v2f m_camera_pos;
- float m_time;
+ v2f m_origin;
+ v2f m_speed;
v3s16 m_camera_offset;
+ video::SColorf m_color;
+ CloudParams m_params;
+
};
#endif
-
diff --git a/src/collision.cpp b/src/collision.cpp
index 8e5dbcc9b..c0891c152 100644
--- a/src/collision.cpp
+++ b/src/collision.cpp
@@ -22,11 +22,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h"
#include "nodedef.h"
#include "gamedef.h"
-#include "log.h"
-#include "environment.h"
+#ifndef SERVER
+#include "clientenvironment.h"
+#endif
+#include "serverenvironment.h"
#include "serverobject.h"
-#include <vector>
-#include <set>
#include "util/timetaker.h"
#include "profiler.h"
diff --git a/src/constants.h b/src/constants.h
index 55ae9daf3..fb9e97cb3 100644
--- a/src/constants.h
+++ b/src/constants.h
@@ -85,7 +85,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
// Size of player's main inventory
-#define PLAYER_INVENTORY_SIZE (8*4)
+#define PLAYER_INVENTORY_SIZE (8 * 4)
// Maximum hit points of a player
#define PLAYER_MAX_HP 20
@@ -110,10 +110,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// TODO: implement dpi-based scaling for windows and remove this hack
#if defined(_WIN32)
- #define TTF_DEFAULT_FONT_SIZE (18)
+#define TTF_DEFAULT_FONT_SIZE (18)
#else
- #define TTF_DEFAULT_FONT_SIZE (16)
+#define TTF_DEFAULT_FONT_SIZE (16)
#endif
-#define DEFAULT_FONT_SIZE (10)
+#define DEFAULT_FONT_SIZE (10)
#endif
diff --git a/src/content_abm.cpp b/src/content_abm.cpp
index 8694ef981..162f93364 100644
--- a/src/content_abm.cpp
+++ b/src/content_abm.cpp
@@ -26,11 +26,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "mapblock.h" // For getNodeBlockPos
#include "map.h"
-#include "scripting_game.h"
+#include "scripting_server.h"
#include "log.h"
-#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
-
-void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef) {
-
+void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef)
+{
}
diff --git a/src/content_abm.h b/src/content_abm.h
index 0a91a96a2..0fb3a0413 100644
--- a/src/content_abm.h
+++ b/src/content_abm.h
@@ -30,4 +30,3 @@ class INodeDefManager;
void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef);
#endif
-
diff --git a/src/content_cao.cpp b/src/content_cao.cpp
index 6b35d5881..d15c53e7a 100644
--- a/src/content_cao.cpp
+++ b/src/content_cao.cpp
@@ -26,13 +26,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_cao.h"
#include "util/numeric.h" // For IntervalLimiter
#include "util/serialize.h"
-#include "util/mathconstants.h"
+#include "util/basic_macros.h"
#include "client/tile.h"
#include "environment.h"
#include "collision.h"
#include "settings.h"
#include "serialization.h" // For decompressZlib
-#include "gamedef.h"
#include "clientobject.h"
#include "mesh.h"
#include "itemdef.h"
@@ -45,12 +44,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "camera.h" // CameraModes
#include "wieldmesh.h"
#include "log.h"
+#include <algorithm>
class Settings;
struct ToolCapabilities;
-#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
-
UNORDERED_MAP<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
SmoothTranslator::SmoothTranslator():
@@ -140,7 +138,7 @@ static void setBillboardTextureMatrix(scene::IBillboardSceneNode *bill,
class TestCAO : public ClientActiveObject
{
public:
- TestCAO(IGameDef *gamedef, ClientEnvironment *env);
+ TestCAO(Client *client, ClientEnvironment *env);
virtual ~TestCAO();
ActiveObjectType getType() const
@@ -148,7 +146,7 @@ public:
return ACTIVEOBJECT_TYPE_TEST;
}
- static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
+ static ClientActiveObject* create(Client *client, ClientEnvironment *env);
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr);
@@ -161,7 +159,7 @@ public:
void processMessage(const std::string &data);
- bool getCollisionBox(aabb3f *toset) { return false; }
+ bool getCollisionBox(aabb3f *toset) const { return false; }
private:
scene::IMeshSceneNode *m_node;
v3f m_position;
@@ -170,8 +168,8 @@ private:
// Prototype
TestCAO proto_TestCAO(NULL, NULL);
-TestCAO::TestCAO(IGameDef *gamedef, ClientEnvironment *env):
- ClientActiveObject(0, gamedef, env),
+TestCAO::TestCAO(Client *client, ClientEnvironment *env):
+ ClientActiveObject(0, client, env),
m_node(NULL),
m_position(v3f(0,10*BS,0))
{
@@ -182,9 +180,9 @@ TestCAO::~TestCAO()
{
}
-ClientActiveObject* TestCAO::create(IGameDef *gamedef, ClientEnvironment *env)
+ClientActiveObject* TestCAO::create(Client *client, ClientEnvironment *env)
{
- return new TestCAO(gamedef, env);
+ return new TestCAO(client, env);
}
void TestCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
@@ -284,7 +282,7 @@ void TestCAO::processMessage(const std::string &data)
class ItemCAO : public ClientActiveObject
{
public:
- ItemCAO(IGameDef *gamedef, ClientEnvironment *env);
+ ItemCAO(Client *client, ClientEnvironment *env);
virtual ~ItemCAO();
ActiveObjectType getType() const
@@ -292,7 +290,7 @@ public:
return ACTIVEOBJECT_TYPE_ITEM;
}
- static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
+ static ClientActiveObject* create(Client *client, ClientEnvironment *env);
void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
IrrlichtDevice *irr);
@@ -318,7 +316,7 @@ public:
std::string infoText()
{return m_infotext;}
- bool getCollisionBox(aabb3f *toset) { return false; }
+ bool getCollisionBox(aabb3f *toset) const { return false; }
private:
aabb3f m_selection_box;
scene::IMeshSceneNode *m_node;
@@ -332,13 +330,13 @@ private:
// Prototype
ItemCAO proto_ItemCAO(NULL, NULL);
-ItemCAO::ItemCAO(IGameDef *gamedef, ClientEnvironment *env):
- ClientActiveObject(0, gamedef, env),
+ItemCAO::ItemCAO(Client *client, ClientEnvironment *env):
+ ClientActiveObject(0, client, env),
m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.),
m_node(NULL),
m_position(v3f(0,10*BS,0))
{
- if(!gamedef && !env)
+ if(!client && !env)
{
ClientActiveObject::registerType(getType(), create);
}
@@ -348,9 +346,9 @@ ItemCAO::~ItemCAO()
{
}
-ClientActiveObject* ItemCAO::create(IGameDef *gamedef, ClientEnvironment *env)
+ClientActiveObject* ItemCAO::create(Client *client, ClientEnvironment *env)
{
- return new ItemCAO(gamedef, env);
+ return new ItemCAO(client, env);
}
void ItemCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
@@ -434,7 +432,7 @@ void ItemCAO::updateNodePos()
void ItemCAO::updateInfoText()
{
try{
- IItemDefManager *idef = m_gamedef->idef();
+ IItemDefManager *idef = m_client->idef();
ItemStack item;
item.deSerialize(m_itemstring, idef);
if(item.isKnown(idef))
@@ -459,10 +457,10 @@ void ItemCAO::updateTexture()
std::istringstream is(m_itemstring, std::ios_base::binary);
video::ITexture *texture = NULL;
try{
- IItemDefManager *idef = m_gamedef->idef();
+ IItemDefManager *idef = m_client->idef();
ItemStack item;
item.deSerialize(is, idef);
- texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_gamedef);
+ texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_client);
}
catch(SerializationError &e)
{
@@ -539,15 +537,15 @@ void ItemCAO::initialize(const std::string &data)
#include "genericobject.h"
-GenericCAO::GenericCAO(IGameDef *gamedef, ClientEnvironment *env):
- ClientActiveObject(0, gamedef, env),
+GenericCAO::GenericCAO(Client *client, ClientEnvironment *env):
+ ClientActiveObject(0, client, env),
//
m_is_player(false),
m_is_local_player(false),
//
m_smgr(NULL),
m_irr(NULL),
- m_gamedef(NULL),
+ m_client(NULL),
m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.),
m_meshnode(NULL),
m_animated_meshnode(NULL),
@@ -577,19 +575,21 @@ GenericCAO::GenericCAO(IGameDef *gamedef, ClientEnvironment *env):
m_anim_framelength(0.2),
m_anim_timer(0),
m_reset_textures_timer(-1),
+ m_previous_texture_modifier(""),
+ m_current_texture_modifier(""),
m_visuals_expired(false),
m_step_distance_counter(0),
m_last_light(255),
m_is_visible(false)
{
- if (gamedef == NULL) {
+ if (client == NULL) {
ClientActiveObject::registerType(getType(), create);
} else {
- m_gamedef = gamedef;
+ m_client = client;
}
}
-bool GenericCAO::getCollisionBox(aabb3f *toset)
+bool GenericCAO::getCollisionBox(aabb3f *toset) const
{
if (m_prop.physical)
{
@@ -606,7 +606,7 @@ bool GenericCAO::getCollisionBox(aabb3f *toset)
return false;
}
-bool GenericCAO::collideWithObjects()
+bool GenericCAO::collideWithObjects() const
{
return m_prop.collideWithObjects;
}
@@ -706,26 +706,11 @@ scene::ISceneNode* GenericCAO::getSceneNode()
return NULL;
}
-scene::IMeshSceneNode* GenericCAO::getMeshSceneNode()
-{
- return m_meshnode;
-}
-
scene::IAnimatedMeshSceneNode* GenericCAO::getAnimatedMeshSceneNode()
{
return m_animated_meshnode;
}
-WieldMeshSceneNode* GenericCAO::getWieldMeshSceneNode()
-{
- return m_wield_meshnode;
-}
-
-scene::IBillboardSceneNode* GenericCAO::getSpriteSceneNode()
-{
- return m_spritenode;
-}
-
void GenericCAO::setChildrenVisible(bool toset)
{
for (std::vector<u16>::size_type i = 0; i < m_children.size(); i++) {
@@ -794,7 +779,7 @@ void GenericCAO::removeFromScene(bool permanent)
}
if (m_nametag) {
- m_gamedef->getCamera()->removeNametag(m_nametag);
+ m_client->getCamera()->removeNametag(m_nametag);
m_nametag = NULL;
}
}
@@ -907,7 +892,7 @@ void GenericCAO::addToScene(scene::ISceneManager *smgr,
}
else if(m_prop.visual == "mesh") {
infostream<<"GenericCAO::addToScene(): mesh"<<std::endl;
- scene::IAnimatedMesh *mesh = m_gamedef->getMesh(m_prop.mesh);
+ scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh);
if(mesh)
{
m_animated_meshnode = smgr->addAnimatedMeshSceneNode(mesh, NULL);
@@ -934,33 +919,43 @@ void GenericCAO::addToScene(scene::ISceneManager *smgr,
errorstream<<"GenericCAO::addToScene(): Could not load mesh "<<m_prop.mesh<<std::endl;
}
else if(m_prop.visual == "wielditem") {
- infostream<<"GenericCAO::addToScene(): wielditem"<<std::endl;
- infostream<<"textures: "<<m_prop.textures.size()<<std::endl;
- if(m_prop.textures.size() >= 1){
- infostream<<"textures[0]: "<<m_prop.textures[0]<<std::endl;
- IItemDefManager *idef = m_gamedef->idef();
- ItemStack item(m_prop.textures[0], 1, 0, "", idef);
-
- m_wield_meshnode = new WieldMeshSceneNode(
- smgr->getRootSceneNode(), smgr, -1);
- m_wield_meshnode->setItem(item, m_gamedef);
-
- m_wield_meshnode->setScale(v3f(m_prop.visual_size.X/2,
- m_prop.visual_size.Y/2,
- m_prop.visual_size.X/2));
- u8 li = m_last_light;
- m_wield_meshnode->setColor(video::SColor(255,li,li,li));
+ ItemStack item;
+ infostream << "GenericCAO::addToScene(): wielditem" << std::endl;
+ if (m_prop.wield_item == "") {
+ // Old format, only textures are specified.
+ infostream << "textures: " << m_prop.textures.size() << std::endl;
+ if (m_prop.textures.size() >= 1) {
+ infostream << "textures[0]: " << m_prop.textures[0]
+ << std::endl;
+ IItemDefManager *idef = m_client->idef();
+ item = ItemStack(m_prop.textures[0], 1, 0, idef);
+ }
+ } else {
+ infostream << "serialized form: " << m_prop.wield_item << std::endl;
+ item.deSerialize(m_prop.wield_item, m_client->idef());
}
+ m_wield_meshnode = new WieldMeshSceneNode(smgr->getRootSceneNode(),
+ smgr, -1);
+ m_wield_meshnode->setItem(item, m_client);
+
+ m_wield_meshnode->setScale(
+ v3f(m_prop.visual_size.X / 2, m_prop.visual_size.Y / 2,
+ m_prop.visual_size.X / 2));
+ u8 li = m_last_light;
+ m_wield_meshnode->setColor(video::SColor(255, li, li, li));
} else {
infostream<<"GenericCAO::addToScene(): \""<<m_prop.visual
<<"\" not supported"<<std::endl;
}
- updateTextures("");
+
+ /* don't update while punch texture modifier is active */
+ if (m_reset_textures_timer < 0)
+ updateTextures(m_current_texture_modifier);
scene::ISceneNode *node = getSceneNode();
if (node && m_prop.nametag != "" && !m_is_local_player) {
// Add nametag
- m_nametag = m_gamedef->getCamera()->addNametag(node,
+ m_nametag = m_client->getCamera()->addNametag(node,
m_prop.nametag, m_prop.nametag_color);
}
@@ -1032,12 +1027,9 @@ void GenericCAO::updateNodePos()
void GenericCAO::step(float dtime, ClientEnvironment *env)
{
// Handel model of local player instantly to prevent lags
- if(m_is_local_player)
- {
+ if (m_is_local_player) {
LocalPlayer *player = m_env->getLocalPlayer();
-
- if (m_is_visible)
- {
+ if (m_is_visible) {
int old_anim = player->last_animation;
float old_anim_speed = player->last_animation_speed;
m_position = player->getPosition() + v3f(0,BS,0);
@@ -1045,7 +1037,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
m_acceleration = v3f(0,0,0);
pos_translator.vect_show = m_position;
m_yaw = player->getYaw();
- PlayerControl controls = player->getPlayerControl();
+ const PlayerControl &controls = player->getPlayerControl();
bool walking = false;
if (controls.up || controls.down || controls.left || controls.right ||
@@ -1059,18 +1051,17 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
// increase speed if using fast or flying fast
if((g_settings->getBool("fast_move") &&
- m_gamedef->checkLocalPrivilege("fast")) &&
+ m_client->checkLocalPrivilege("fast")) &&
(controls.aux1 ||
(!player->touching_ground &&
g_settings->getBool("free_move") &&
- m_gamedef->checkLocalPrivilege("fly"))))
+ m_client->checkLocalPrivilege("fly"))))
new_speed *= 1.5;
// slowdown speed if sneeking
- if(controls.sneak && walking)
+ if (controls.sneak && walking)
new_speed /= 2;
- if(walking && (controls.LMB || controls.RMB))
- {
+ if (walking && (controls.LMB || controls.RMB)) {
new_anim = player->local_animations[3];
player->last_animation = WD_ANIM;
} else if(walking) {
@@ -1083,8 +1074,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
// Apply animations if input detected and not attached
// or set idle animation
- if ((new_anim.X + new_anim.Y) > 0 && !player->isAttached)
- {
+ if ((new_anim.X + new_anim.Y) > 0 && !player->isAttached) {
allow_update = true;
m_animation_range = new_anim;
m_animation_speed = new_speed;
@@ -1092,8 +1082,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
} else {
player->last_animation = NO_ANIM;
- if (old_anim != NO_ANIM)
- {
+ if (old_anim != NO_ANIM) {
m_animation_range = player->local_animations[0];
updateAnimation();
}
@@ -1130,7 +1119,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
}
removeFromScene(false);
- addToScene(m_smgr, m_gamedef->tsrc(), m_irr);
+ addToScene(m_smgr, m_client->tsrc(), m_irr);
// Attachments, part 2: Now that the parent has been refreshed, put its attachments back
for (std::vector<u16>::size_type i = 0; i < m_children.size(); i++) {
@@ -1200,12 +1189,12 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
m_step_distance_counter = 0;
if(!m_is_local_player && m_prop.makes_footstep_sound)
{
- INodeDefManager *ndef = m_gamedef->ndef();
+ INodeDefManager *ndef = m_client->ndef();
v3s16 p = floatToInt(getPosition() + v3f(0,
(m_prop.collisionbox.MinEdge.Y-0.5)*BS, 0), BS);
MapNode n = m_env->getMap().getNodeNoEx(p);
SimpleSoundSpec spec = ndef->get(n).sound_footstep;
- m_gamedef->sound()->playSoundAt(spec, false, getPosition());
+ m_client->sound()->playSoundAt(spec, false, getPosition());
}
}
}
@@ -1224,9 +1213,9 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
if(m_reset_textures_timer >= 0)
{
m_reset_textures_timer -= dtime;
- if(m_reset_textures_timer <= 0){
+ if(m_reset_textures_timer <= 0) {
m_reset_textures_timer = -1;
- updateTextures("");
+ updateTextures(m_previous_texture_modifier);
}
}
if(getParent() == NULL && fabs(m_prop.automatic_rotate) > 0.001)
@@ -1304,14 +1293,17 @@ void GenericCAO::updateTexturePos()
}
}
-void GenericCAO::updateTextures(const std::string &mod)
+void GenericCAO::updateTextures(std::string mod)
{
- ITextureSource *tsrc = m_gamedef->tsrc();
+ ITextureSource *tsrc = m_client->tsrc();
bool use_trilinear_filter = g_settings->getBool("trilinear_filter");
bool use_bilinear_filter = g_settings->getBool("bilinear_filter");
bool use_anisotropic_filter = g_settings->getBool("anisotropic_filter");
+ m_previous_texture_modifier = m_current_texture_modifier;
+ m_current_texture_modifier = mod;
+
if(m_spritenode)
{
if(m_prop.visual == "sprite")
@@ -1577,6 +1569,10 @@ void GenericCAO::processMessage(const std::string &data)
m_initial_tx_basepos_set = true;
m_tx_basepos = m_prop.initial_sprite_basepos;
}
+ if (m_is_local_player) {
+ LocalPlayer *player = m_env->getLocalPlayer();
+ player->makes_footstep_sound = m_prop.makes_footstep_sound;
+ }
if ((m_is_player && !m_is_local_player) && m_prop.nametag == "")
m_prop.nametag = m_name;
@@ -1614,6 +1610,12 @@ void GenericCAO::processMessage(const std::string &data)
updateNodePos();
} else if (cmd == GENERIC_CMD_SET_TEXTURE_MOD) {
std::string mod = deSerializeString(is);
+
+ // immediatly reset a engine issued texture modifier if a mod sends a different one
+ if (m_reset_textures_timer > 0) {
+ m_reset_textures_timer = -1;
+ updateTextures(m_previous_texture_modifier);
+ }
updateTextures(mod);
} else if (cmd == GENERIC_CMD_SET_SPRITE) {
v2s16 p = readV2S16(is);
@@ -1634,6 +1636,7 @@ void GenericCAO::processMessage(const std::string &data)
// these are sent inverted so we get true when the server sends nothing
bool sneak = !readU8(is);
bool sneak_glitch = !readU8(is);
+ bool new_move = !readU8(is);
if(m_is_local_player)
@@ -1644,6 +1647,7 @@ void GenericCAO::processMessage(const std::string &data)
player->physics_override_gravity = override_gravity;
player->physics_override_sneak = sneak;
player->physics_override_sneak_glitch = sneak_glitch;
+ player->physics_override_new_move = new_move;
}
} else if (cmd == GENERIC_CMD_SET_ANIMATION) {
// TODO: change frames send as v2s32 value
@@ -1731,13 +1735,13 @@ void GenericCAO::processMessage(const std::string &data)
m_smgr, m_env, m_position,
m_prop.visual_size * BS);
m_env->addSimpleObject(simple);
- } else {
+ } else if (m_reset_textures_timer < 0) {
// TODO: Execute defined fast response
// Flashing shall suffice as there is no definition
m_reset_textures_timer = 0.05;
if(damage >= 2)
m_reset_textures_timer += 0.05 * damage;
- updateTextures("^[brighten");
+ updateTextures(m_current_texture_modifier + "^[brighten");
}
}
} else if (cmd == GENERIC_CMD_UPDATE_ARMOR_GROUPS) {
@@ -1768,7 +1772,7 @@ void GenericCAO::processMessage(const std::string &data)
} else {
warningstream << FUNCTION_NAME
<< ": unknown command or outdated client \""
- << cmd << std::endl;
+ << +cmd << "\"" << std::endl;
}
}
@@ -1779,7 +1783,7 @@ bool GenericCAO::directReportPunch(v3f dir, const ItemStack *punchitem,
{
assert(punchitem); // pre-condition
const ToolCapabilities *toolcap =
- &punchitem->getToolCapabilities(m_gamedef->idef());
+ &punchitem->getToolCapabilities(m_client->idef());
PunchDamageResult result = getPunchDamage(
m_armor_groups,
toolcap,
@@ -1802,10 +1806,12 @@ bool GenericCAO::directReportPunch(v3f dir, const ItemStack *punchitem,
}
// TODO: Execute defined fast response
// Flashing shall suffice as there is no definition
- m_reset_textures_timer = 0.05;
- if(result.damage >= 2)
- m_reset_textures_timer += 0.05 * result.damage;
- updateTextures("^[brighten");
+ if (m_reset_textures_timer < 0) {
+ m_reset_textures_timer = 0.05;
+ if (result.damage >= 2)
+ m_reset_textures_timer += 0.05 * result.damage;
+ updateTextures(m_current_texture_modifier + "^[brighten");
+ }
}
return false;
diff --git a/src/content_cao.h b/src/content_cao.h
index a158e8296..412cdff12 100644
--- a/src/content_cao.h
+++ b/src/content_cao.h
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "itemgroup.h"
class Camera;
+class Client;
struct Nametag;
/*
@@ -68,7 +69,7 @@ private:
//
scene::ISceneManager *m_smgr;
IrrlichtDevice *m_irr;
- IGameDef *m_gamedef;
+ Client *m_client;
aabb3f m_selection_box;
scene::IMeshSceneNode *m_meshnode;
scene::IAnimatedMeshSceneNode *m_animated_meshnode;
@@ -101,6 +102,8 @@ private:
float m_anim_timer;
ItemGroupList m_armor_groups;
float m_reset_textures_timer;
+ std::string m_previous_texture_modifier; // stores texture modifier before punch update
+ std::string m_current_texture_modifier; // last applied texture modifier
bool m_visuals_expired;
float m_step_distance_counter;
u8 m_last_light;
@@ -109,13 +112,13 @@ private:
std::vector<u16> m_children;
public:
- GenericCAO(IGameDef *gamedef, ClientEnvironment *env);
+ GenericCAO(Client *client, ClientEnvironment *env);
~GenericCAO();
- static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
+ static ClientActiveObject* create(Client *client, ClientEnvironment *env)
{
- return new GenericCAO(gamedef, env);
+ return new GenericCAO(client, env);
}
inline ActiveObjectType getType() const
@@ -129,9 +132,9 @@ public:
ClientActiveObject *getParent();
- bool getCollisionBox(aabb3f *toset);
+ bool getCollisionBox(aabb3f *toset) const;
- bool collideWithObjects();
+ bool collideWithObjects() const;
aabb3f *getSelectionBox();
@@ -143,19 +146,8 @@ public:
scene::ISceneNode *getSceneNode();
- scene::IMeshSceneNode *getMeshSceneNode();
-
scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode();
- WieldMeshSceneNode *getWieldMeshSceneNode();
-
- scene::IBillboardSceneNode *getSpriteSceneNode();
-
- inline bool isPlayer() const
- {
- return m_is_player;
- }
-
inline bool isLocalPlayer() const
{
return m_is_local_player;
@@ -197,7 +189,9 @@ public:
void updateTexturePos();
- void updateTextures(const std::string &mod);
+ // std::string copy is mandatory as mod can be a class member and there is a swap
+ // on those class members
+ void updateTextures(std::string mod);
void updateAnimation();
diff --git a/src/content_cso.cpp b/src/content_cso.cpp
index 0790024fc..aca71212b 100644
--- a/src/content_cso.cpp
+++ b/src/content_cso.cpp
@@ -20,22 +20,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_cso.h"
#include <IBillboardSceneNode.h>
#include "client/tile.h"
-#include "environment.h"
-#include "gamedef.h"
-#include "log.h"
+#include "clientenvironment.h"
+#include "client.h"
#include "map.h"
-/*
-static void setBillboardTextureMatrix(scene::IBillboardSceneNode *bill,
- float txs, float tys, int col, int row)
-{
- video::SMaterial& material = bill->getMaterial(0);
- core::matrix4& matrix = material.getTextureMatrix(0);
- matrix.setTextureTranslate(txs*col, tys*row);
- matrix.setTextureScale(txs, tys);
-}
-*/
-
class SmokePuffCSO: public ClientSimpleObject
{
float m_age;
diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp
index 8ce0f1e0a..e6dd8e83e 100644
--- a/src/content_mapblock.cpp
+++ b/src/content_mapblock.cpp
@@ -20,1778 +20,1289 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_mapblock.h"
#include "util/numeric.h"
#include "util/directiontables.h"
-#include "mapblock_mesh.h" // For MapBlock_LightColor() and MeshCollector
+#include "mapblock_mesh.h"
#include "settings.h"
#include "nodedef.h"
#include "client/tile.h"
#include "mesh.h"
#include <IMeshManipulator.h>
-#include "gamedef.h"
+#include "client.h"
#include "log.h"
#include "noise.h"
+#include "util/cpp11.h"
+// Distance of light extrapolation (for oversized nodes)
+// After this distance, it gives up and considers light level constant
+#define SMOOTH_LIGHTING_OVERSIZE 1.0
+
+// Node edge count (for glasslike-framed)
+#define FRAMED_EDGE_COUNT 12
+
+// Node neighbor count, including edge-connected, but not vertex-connected
+// (for glasslike-framed)
+// Corresponding offsets are listed in g_27dirs
+#define FRAMED_NEIGHBOR_COUNT 18
+
+static constexpr v3s16 light_dirs[8] = {
+ v3s16(-1, -1, -1),
+ v3s16(-1, -1, 1),
+ v3s16(-1, 1, -1),
+ v3s16(-1, 1, 1),
+ v3s16( 1, -1, -1),
+ v3s16( 1, -1, 1),
+ v3s16( 1, 1, -1),
+ v3s16( 1, 1, 1),
+};
+
+// Standard index set to make a quad on 4 vertices
+static constexpr u16 quad_indices[] = {0, 1, 2, 2, 3, 0};
+
+const std::string MapblockMeshGenerator::raillike_groupname = "connect_to_raillike";
+
+MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output)
+{
+ data = input;
+ collector = output;
+
+ nodedef = data->m_client->ndef();
+ smgr = data->m_client->getSceneManager();
+ meshmanip = smgr->getMeshManipulator();
+
+ enable_mesh_cache = g_settings->getBool("enable_mesh_cache") &&
+ !data->m_smooth_lighting; // Mesh cache is not supported with smooth lighting
+
+ blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
+}
+
+void MapblockMeshGenerator::useTile(int index, bool disable_backface_culling)
+{
+ getNodeTileN(n, p, index, data, tile);
+ if (!data->m_smooth_lighting)
+ color = encode_light(light, f->light_source);
+ for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
+ tile.layers[layer].material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
+ if (disable_backface_culling)
+ tile.layers[layer].material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
+ }
+}
+
+void MapblockMeshGenerator::useDefaultTile(bool set_color)
+{
+ getNodeTile(n, p, v3s16(0, 0, 0), data, tile);
+ if (set_color && !data->m_smooth_lighting)
+ color = encode_light(light, f->light_source);
+}
+
+void MapblockMeshGenerator::getTile(const v3s16& direction, TileSpec &tile)
+{
+ getNodeTile(n, p, direction, data, tile);
+}
+
+void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal)
+{
+ static const v2f tcoords[4] = {v2f(0, 0), v2f(1, 0), v2f(1, 1), v2f(0, 1)};
+ video::S3DVertex vertices[4];
+ bool shade_face = !f->light_source && (normal != v3s16(0, 0, 0));
+ v3f normal2(normal.X, normal.Y, normal.Z);
+ for (int j = 0; j < 4; j++) {
+ vertices[j].Pos = coords[j] + origin;
+ vertices[j].Normal = normal2;
+ if (data->m_smooth_lighting)
+ vertices[j].Color = blendLightColor(coords[j]);
+ else
+ vertices[j].Color = color;
+ if (shade_face)
+ applyFacesShading(vertices[j].Color, normal2);
+ vertices[j].TCoords = tcoords[j];
+ }
+ collector->append(tile, vertices, 4, quad_indices, 6);
+}
// Create a cuboid.
-// collector - the MeshCollector for the resulting polygons
-// box - the position and size of the box
// tiles - the tiles (materials) to use (for all 6 faces)
// tilecount - number of entries in tiles, 1<=tilecount<=6
-// c - vertex colour - used for all
+// lights - vertex light levels. The order is the same as in light_dirs.
+// NULL may be passed if smooth lighting is disabled.
// txc - texture coordinates - this is a list of texture coordinates
// for the opposite corners of each face - therefore, there
-// should be (2+2)*6=24 values in the list. Alternatively, pass
-// NULL to use the entire texture for each face. The order of
+// should be (2+2)*6=24 values in the list. The order of
// the faces in the list is up-down-right-left-back-front
-// (compatible with ContentFeatures). If you specified 0,0,1,1
-// for each face, that would be the same as passing NULL.
-void makeCuboid(MeshCollector *collector, const aabb3f &box,
- TileSpec *tiles, int tilecount, video::SColor &c, const f32* txc)
+// (compatible with ContentFeatures).
+void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
+ TileSpec *tiles, int tilecount, const u16 *lights, const f32 *txc)
{
assert(tilecount >= 1 && tilecount <= 6); // pre-condition
v3f min = box.MinEdge;
v3f max = box.MaxEdge;
-
-
- if(txc == NULL) {
- static const f32 txc_default[24] = {
- 0,0,1,1,
- 0,0,1,1,
- 0,0,1,1,
- 0,0,1,1,
- 0,0,1,1,
- 0,0,1,1
- };
- txc = txc_default;
+ video::SColor colors[6];
+ if (!data->m_smooth_lighting) {
+ for (int face = 0; face != 6; ++face) {
+ colors[face] = encode_light(light, f->light_source);
+ }
+ if (!f->light_source) {
+ applyFacesShading(colors[0], v3f(0, 1, 0));
+ applyFacesShading(colors[1], v3f(0, -1, 0));
+ applyFacesShading(colors[2], v3f(1, 0, 0));
+ applyFacesShading(colors[3], v3f(-1, 0, 0));
+ applyFacesShading(colors[4], v3f(0, 0, 1));
+ applyFacesShading(colors[5], v3f(0, 0, -1));
+ }
}
- video::S3DVertex vertices[24] =
- {
- // up
- video::S3DVertex(min.X,max.Y,max.Z, 0,1,0, c, txc[0],txc[1]),
- video::S3DVertex(max.X,max.Y,max.Z, 0,1,0, c, txc[2],txc[1]),
- video::S3DVertex(max.X,max.Y,min.Z, 0,1,0, c, txc[2],txc[3]),
- video::S3DVertex(min.X,max.Y,min.Z, 0,1,0, c, txc[0],txc[3]),
- // down
- video::S3DVertex(min.X,min.Y,min.Z, 0,-1,0, c, txc[4],txc[5]),
- video::S3DVertex(max.X,min.Y,min.Z, 0,-1,0, c, txc[6],txc[5]),
- video::S3DVertex(max.X,min.Y,max.Z, 0,-1,0, c, txc[6],txc[7]),
- video::S3DVertex(min.X,min.Y,max.Z, 0,-1,0, c, txc[4],txc[7]),
+ video::S3DVertex vertices[24] = {
+ // top
+ video::S3DVertex(min.X, max.Y, max.Z, 0, 1, 0, colors[0], txc[0], txc[1]),
+ video::S3DVertex(max.X, max.Y, max.Z, 0, 1, 0, colors[0], txc[2], txc[1]),
+ video::S3DVertex(max.X, max.Y, min.Z, 0, 1, 0, colors[0], txc[2], txc[3]),
+ video::S3DVertex(min.X, max.Y, min.Z, 0, 1, 0, colors[0], txc[0], txc[3]),
+ // bottom
+ video::S3DVertex(min.X, min.Y, min.Z, 0, -1, 0, colors[1], txc[4], txc[5]),
+ video::S3DVertex(max.X, min.Y, min.Z, 0, -1, 0, colors[1], txc[6], txc[5]),
+ video::S3DVertex(max.X, min.Y, max.Z, 0, -1, 0, colors[1], txc[6], txc[7]),
+ video::S3DVertex(min.X, min.Y, max.Z, 0, -1, 0, colors[1], txc[4], txc[7]),
// right
- video::S3DVertex(max.X,max.Y,min.Z, 1,0,0, c, txc[ 8],txc[9]),
- video::S3DVertex(max.X,max.Y,max.Z, 1,0,0, c, txc[10],txc[9]),
- video::S3DVertex(max.X,min.Y,max.Z, 1,0,0, c, txc[10],txc[11]),
- video::S3DVertex(max.X,min.Y,min.Z, 1,0,0, c, txc[ 8],txc[11]),
+ video::S3DVertex(max.X, max.Y, min.Z, 1, 0, 0, colors[2], txc[ 8], txc[9]),
+ video::S3DVertex(max.X, max.Y, max.Z, 1, 0, 0, colors[2], txc[10], txc[9]),
+ video::S3DVertex(max.X, min.Y, max.Z, 1, 0, 0, colors[2], txc[10], txc[11]),
+ video::S3DVertex(max.X, min.Y, min.Z, 1, 0, 0, colors[2], txc[ 8], txc[11]),
// left
- video::S3DVertex(min.X,max.Y,max.Z, -1,0,0, c, txc[12],txc[13]),
- video::S3DVertex(min.X,max.Y,min.Z, -1,0,0, c, txc[14],txc[13]),
- video::S3DVertex(min.X,min.Y,min.Z, -1,0,0, c, txc[14],txc[15]),
- video::S3DVertex(min.X,min.Y,max.Z, -1,0,0, c, txc[12],txc[15]),
+ video::S3DVertex(min.X, max.Y, max.Z, -1, 0, 0, colors[3], txc[12], txc[13]),
+ video::S3DVertex(min.X, max.Y, min.Z, -1, 0, 0, colors[3], txc[14], txc[13]),
+ video::S3DVertex(min.X, min.Y, min.Z, -1, 0, 0, colors[3], txc[14], txc[15]),
+ video::S3DVertex(min.X, min.Y, max.Z, -1, 0, 0, colors[3], txc[12], txc[15]),
// back
- video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c, txc[16],txc[17]),
- video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[18],txc[17]),
- video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[18],txc[19]),
- video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[16],txc[19]),
+ video::S3DVertex(max.X, max.Y, max.Z, 0, 0, 1, colors[4], txc[16], txc[17]),
+ video::S3DVertex(min.X, max.Y, max.Z, 0, 0, 1, colors[4], txc[18], txc[17]),
+ video::S3DVertex(min.X, min.Y, max.Z, 0, 0, 1, colors[4], txc[18], txc[19]),
+ video::S3DVertex(max.X, min.Y, max.Z, 0, 0, 1, colors[4], txc[16], txc[19]),
// front
- video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[20],txc[21]),
- video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[22],txc[21]),
- video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[22],txc[23]),
- video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[20],txc[23]),
+ video::S3DVertex(min.X, max.Y, min.Z, 0, 0, -1, colors[5], txc[20], txc[21]),
+ video::S3DVertex(max.X, max.Y, min.Z, 0, 0, -1, colors[5], txc[22], txc[21]),
+ video::S3DVertex(max.X, min.Y, min.Z, 0, 0, -1, colors[5], txc[22], txc[23]),
+ video::S3DVertex(min.X, min.Y, min.Z, 0, 0, -1, colors[5], txc[20], txc[23]),
+ };
+
+ static const u8 light_indices[24] = {
+ 3, 7, 6, 2,
+ 0, 4, 5, 1,
+ 6, 7, 5, 4,
+ 3, 2, 0, 1,
+ 7, 3, 1, 5,
+ 2, 6, 4, 0
};
- for(int i = 0; i < 6; i++)
- {
- switch (tiles[MYMIN(i, tilecount-1)].rotation)
- {
- case 0:
- break;
- case 1: //R90
- for (int x = 0; x < 4; x++)
- vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
- break;
- case 2: //R180
- for (int x = 0; x < 4; x++)
- vertices[i*4+x].TCoords.rotateBy(180,irr::core::vector2df(0, 0));
- break;
- case 3: //R270
- for (int x = 0; x < 4; x++)
- vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
- break;
- case 4: //FXR90
- for (int x = 0; x < 4; x++){
- vertices[i*4+x].TCoords.X = 1.0 - vertices[i*4+x].TCoords.X;
- vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
- }
- break;
- case 5: //FXR270
- for (int x = 0; x < 4; x++){
- vertices[i*4+x].TCoords.X = 1.0 - vertices[i*4+x].TCoords.X;
- vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
- }
- break;
- case 6: //FYR90
- for (int x = 0; x < 4; x++){
- vertices[i*4+x].TCoords.Y = 1.0 - vertices[i*4+x].TCoords.Y;
- vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
- }
- break;
- case 7: //FYR270
- for (int x = 0; x < 4; x++){
- vertices[i*4+x].TCoords.Y = 1.0 - vertices[i*4+x].TCoords.Y;
- vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
- }
- break;
- case 8: //FX
- for (int x = 0; x < 4; x++){
- vertices[i*4+x].TCoords.X = 1.0 - vertices[i*4+x].TCoords.X;
- }
- break;
- case 9: //FY
- for (int x = 0; x < 4; x++){
- vertices[i*4+x].TCoords.Y = 1.0 - vertices[i*4+x].TCoords.Y;
- }
- break;
- default:
- break;
- }
+ for (int face = 0; face < 6; face++) {
+ int tileindex = MYMIN(face, tilecount - 1);
+ const TileSpec &tile = tiles[tileindex];
+ for (int j = 0; j < 4; j++) {
+ video::S3DVertex &vertex = vertices[face * 4 + j];
+ v2f &tcoords = vertex.TCoords;
+ switch (tile.rotation) {
+ case 0:
+ break;
+ case 1: // R90
+ tcoords.rotateBy(90, irr::core::vector2df(0, 0));
+ break;
+ case 2: // R180
+ tcoords.rotateBy(180, irr::core::vector2df(0, 0));
+ break;
+ case 3: // R270
+ tcoords.rotateBy(270, irr::core::vector2df(0, 0));
+ break;
+ case 4: // FXR90
+ tcoords.X = 1.0 - tcoords.X;
+ tcoords.rotateBy(90, irr::core::vector2df(0, 0));
+ break;
+ case 5: // FXR270
+ tcoords.X = 1.0 - tcoords.X;
+ tcoords.rotateBy(270, irr::core::vector2df(0, 0));
+ break;
+ case 6: // FYR90
+ tcoords.Y = 1.0 - tcoords.Y;
+ tcoords.rotateBy(90, irr::core::vector2df(0, 0));
+ break;
+ case 7: // FYR270
+ tcoords.Y = 1.0 - tcoords.Y;
+ tcoords.rotateBy(270, irr::core::vector2df(0, 0));
+ break;
+ case 8: // FX
+ tcoords.X = 1.0 - tcoords.X;
+ break;
+ case 9: // FY
+ tcoords.Y = 1.0 - tcoords.Y;
+ break;
+ default:
+ break;
}
- u16 indices[] = {0,1,2,2,3,0};
+ }
+ }
+
+ if (data->m_smooth_lighting) {
+ for (int j = 0; j < 24; ++j) {
+ vertices[j].Color = encode_light(lights[light_indices[j]],
+ f->light_source);
+ if (!f->light_source)
+ applyFacesShading(vertices[j].Color, vertices[j].Normal);
+ }
+ }
+
// Add to mesh collector
- for (s32 j = 0; j < 24; j += 4) {
- int tileindex = MYMIN(j / 4, tilecount - 1);
- collector->append(tiles[tileindex], vertices + j, 4, indices, 6);
+ for (int k = 0; k < 6; ++k) {
+ int tileindex = MYMIN(k, tilecount - 1);
+ collector->append(tiles[tileindex], vertices + 4 * k, 4, quad_indices, 6);
}
}
-static inline void getNeighborConnectingFace(v3s16 p, INodeDefManager *nodedef,
- MeshMakeData *data, MapNode n, int v, int *neighbors)
+// Gets the base lighting values for a node
+void MapblockMeshGenerator::getSmoothLightFrame()
{
- MapNode n2 = data->m_vmanip.getNodeNoEx(p);
- if (nodedef->nodeboxConnects(n, n2, v))
- *neighbors |= v;
+ for (int k = 0; k < 8; ++k) {
+ u16 light = getSmoothLight(blockpos_nodes + p, light_dirs[k], data);
+ frame.lightsA[k] = light & 0xff;
+ frame.lightsB[k] = light >> 8;
+ }
}
-// For use in mapblock_mesh_generate_special
-// X,Y,Z of position must be -1,0,1
-// This expression is a simplification of
-// 3 * 3 * (pos.X + 1) + 3 * (pos.Y + 1) + (pos.Z + 1)
-static inline int NeighborToIndex(const v3s16 &pos)
+// Calculates vertex light level
+// vertex_pos - vertex position in the node (coordinates are clamped to [0.0, 1.0] or so)
+u16 MapblockMeshGenerator::blendLight(const v3f &vertex_pos)
{
- return 9 * pos.X + 3 * pos.Y + pos.Z + 13;
+ f32 x = core::clamp(vertex_pos.X / BS + 0.5, 0.0 - SMOOTH_LIGHTING_OVERSIZE, 1.0 + SMOOTH_LIGHTING_OVERSIZE);
+ f32 y = core::clamp(vertex_pos.Y / BS + 0.5, 0.0 - SMOOTH_LIGHTING_OVERSIZE, 1.0 + SMOOTH_LIGHTING_OVERSIZE);
+ f32 z = core::clamp(vertex_pos.Z / BS + 0.5, 0.0 - SMOOTH_LIGHTING_OVERSIZE, 1.0 + SMOOTH_LIGHTING_OVERSIZE);
+ f32 lightA = 0.0;
+ f32 lightB = 0.0;
+ for (int k = 0; k < 8; ++k) {
+ f32 dx = (k & 4) ? x : 1 - x;
+ f32 dy = (k & 2) ? y : 1 - y;
+ f32 dz = (k & 1) ? z : 1 - z;
+ lightA += dx * dy * dz * frame.lightsA[k];
+ lightB += dx * dy * dz * frame.lightsB[k];
+ }
+ return
+ core::clamp(core::round32(lightA), 0, 255) |
+ core::clamp(core::round32(lightB), 0, 255) << 8;
}
-/*
- TODO: Fix alpha blending for special nodes
- Currently only the last element rendered is blended correct
-*/
-void mapblock_mesh_generate_special(MeshMakeData *data,
- MeshCollector &collector)
+// Calculates vertex color to be used in mapblock mesh
+// vertex_pos - vertex position in the node (coordinates are clamped to [0.0, 1.0] or so)
+// tile_color - node's tile color
+video::SColor MapblockMeshGenerator::blendLightColor(const v3f &vertex_pos)
{
- INodeDefManager *nodedef = data->m_gamedef->ndef();
- scene::ISceneManager* smgr = data->m_gamedef->getSceneManager();
- scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
+ u16 light = blendLight(vertex_pos);
+ return encode_light(light, f->light_source);
+}
- // 0ms
- //TimeTaker timer("mapblock_mesh_generate_special()");
+video::SColor MapblockMeshGenerator::blendLightColor(const v3f &vertex_pos,
+ const v3f &vertex_normal)
+{
+ video::SColor color = blendLightColor(vertex_pos);
+ if (!f->light_source)
+ applyFacesShading(color, vertex_normal);
+ return color;
+}
- /*
- Some settings
- */
- bool enable_mesh_cache = g_settings->getBool("enable_mesh_cache");
+void MapblockMeshGenerator::generateCuboidTextureCoords(const aabb3f &box, f32 *coords)
+{
+ f32 tx1 = (box.MinEdge.X / BS) + 0.5;
+ f32 ty1 = (box.MinEdge.Y / BS) + 0.5;
+ f32 tz1 = (box.MinEdge.Z / BS) + 0.5;
+ f32 tx2 = (box.MaxEdge.X / BS) + 0.5;
+ f32 ty2 = (box.MaxEdge.Y / BS) + 0.5;
+ f32 tz2 = (box.MaxEdge.Z / BS) + 0.5;
+ f32 txc[24] = {
+ tx1, 1 - tz2, tx2, 1 - tz1, // up
+ tx1, tz1, tx2, tz2, // down
+ tz1, 1 - ty2, tz2, 1 - ty1, // right
+ 1 - tz2, 1 - ty2, 1 - tz1, 1 - ty1, // left
+ 1 - tx2, 1 - ty2, 1 - tx1, 1 - ty1, // back
+ tx1, 1 - ty2, tx2, 1 - ty1, // front
+ };
+ for (int i = 0; i != 24; ++i)
+ coords[i] = txc[i];
+}
- v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;
+void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
+ TileSpec *tiles, int tile_count)
+{
+ f32 texture_coord_buf[24];
+ f32 dx1 = box.MinEdge.X;
+ f32 dy1 = box.MinEdge.Y;
+ f32 dz1 = box.MinEdge.Z;
+ f32 dx2 = box.MaxEdge.X;
+ f32 dy2 = box.MaxEdge.Y;
+ f32 dz2 = box.MaxEdge.Z;
+ box.MinEdge += origin;
+ box.MaxEdge += origin;
+ if (!txc) {
+ generateCuboidTextureCoords(box, texture_coord_buf);
+ txc = texture_coord_buf;
+ }
+ if (!tiles) {
+ tiles = &tile;
+ tile_count = 1;
+ }
+ if (data->m_smooth_lighting) {
+ u16 lights[8];
+ for (int j = 0; j < 8; ++j) {
+ v3f d;
+ d.X = (j & 4) ? dx2 : dx1;
+ d.Y = (j & 2) ? dy2 : dy1;
+ d.Z = (j & 1) ? dz2 : dz1;
+ lights[j] = blendLight(d);
+ }
+ drawCuboid(box, tiles, tile_count, lights, txc);
+ } else {
+ drawCuboid(box, tiles, tile_count, NULL, txc);
+ }
+}
- for(s16 z = 0; z < MAP_BLOCKSIZE; z++)
- for(s16 y = 0; y < MAP_BLOCKSIZE; y++)
- for(s16 x = 0; x < MAP_BLOCKSIZE; x++)
- {
- v3s16 p(x,y,z);
+/*!
+ * Returns the i-th special tile for a map node.
+ */
+static TileSpec getSpecialTile(const ContentFeatures &f,
+ const MapNode &n, u8 i)
+{
+ TileSpec copy = f.special_tiles[i];
+ for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
+ TileLayer *layer = &copy.layers[layernum];
+ if (layer->texture_id == 0)
+ continue;
+ if (!layer->has_color)
+ n.getColor(f, &(layer->color));
+ }
+ return copy;
+}
- MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + p);
- const ContentFeatures &f = nodedef->get(n);
+void MapblockMeshGenerator::prepareLiquidNodeDrawing()
+{
+ tile_liquid_top = getSpecialTile(*f, n, 0);
+ tile_liquid = getSpecialTile(*f, n, 1);
+
+ MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(p.X, p.Y + 1, p.Z));
+ c_flowing = nodedef->getId(f->liquid_alternative_flowing);
+ c_source = nodedef->getId(f->liquid_alternative_source);
+ top_is_same_liquid = (ntop.getContent() == c_flowing) || (ntop.getContent() == c_source);
+
+ if (data->m_smooth_lighting)
+ return; // don't need to pre-compute anything in this case
+
+ if (f->light_source != 0) {
+ // If this liquid emits light and doesn't contain light, draw
+ // it at what it emits, for an increased effect
+ light = decode_light(f->light_source);
+ light = light | (light << 8);
+ } else if (nodedef->get(ntop).param_type == CPT_LIGHT) {
+ // Otherwise, use the light of the node on top if possible
+ light = getInteriorLight(ntop, 0, nodedef);
+ }
- // Only solidness=0 stuff is drawn here
- if(f.solidness != 0)
+ color_liquid_top = encode_light(light, f->light_source);
+ color = encode_light(light, f->light_source);
+}
+
+void MapblockMeshGenerator::getLiquidNeighborhood()
+{
+ u8 range = rangelim(nodedef->get(c_flowing).liquid_range, 1, 8);
+
+ for (int w = -1; w <= 1; w++)
+ for (int u = -1; u <= 1; u++) {
+ NeighborData &neighbor = liquid_neighbors[w + 1][u + 1];
+ v3s16 p2 = p + v3s16(u, 0, w);
+ MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
+ neighbor.content = n2.getContent();
+ neighbor.level = -0.5 * BS;
+ neighbor.is_same_liquid = false;
+ neighbor.top_is_same_liquid = false;
+
+ if (neighbor.content == CONTENT_IGNORE)
continue;
- switch(f.drawtype){
- default:
- infostream << "Got " << f.drawtype << std::endl;
- FATAL_ERROR("Unknown drawtype");
- break;
- case NDT_AIRLIKE:
- break;
- case NDT_LIQUID:
- {
- /*
- Add water sources to mesh if using new style
- */
- TileSpec tile_liquid = f.special_tiles[0];
- TileSpec tile_liquid_bfculled = getNodeTile(n, p, v3s16(0,0,0), data);
-
- bool top_is_same_liquid = false;
- MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
- content_t c_flowing = nodedef->getId(f.liquid_alternative_flowing);
- content_t c_source = nodedef->getId(f.liquid_alternative_source);
- if(ntop.getContent() == c_flowing || ntop.getContent() == c_source)
- top_is_same_liquid = true;
-
- u16 l = getInteriorLight(n, 0, nodedef);
- video::SColor c = MapBlock_LightColor(f.alpha, l, f.light_source);
-
- /*
- Generate sides
- */
- v3s16 side_dirs[4] = {
- v3s16(1,0,0),
- v3s16(-1,0,0),
- v3s16(0,0,1),
- v3s16(0,0,-1),
- };
- for(u32 i=0; i<4; i++)
- {
- v3s16 dir = side_dirs[i];
-
- MapNode neighbor = data->m_vmanip.getNodeNoEx(blockpos_nodes + p + dir);
- content_t neighbor_content = neighbor.getContent();
- const ContentFeatures &n_feat = nodedef->get(neighbor_content);
- MapNode n_top = data->m_vmanip.getNodeNoEx(blockpos_nodes + p + dir+ v3s16(0,1,0));
- content_t n_top_c = n_top.getContent();
-
- if(neighbor_content == CONTENT_IGNORE)
- continue;
-
- /*
- If our topside is liquid and neighbor's topside
- is liquid, don't draw side face
- */
- if(top_is_same_liquid && (n_top_c == c_flowing ||
- n_top_c == c_source || n_top_c == CONTENT_IGNORE))
- continue;
-
- // 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
- || neighbor_content == c_flowing);
-
- // Don't draw any faces if neighbor same is liquid and top is
- // same liquid
- if(neighbor_is_same_liquid && !top_is_same_liquid)
- continue;
-
- // Use backface culled material if neighbor doesn't have a
- // solidness of 0
- const TileSpec *current_tile = &tile_liquid;
- if(n_feat.solidness != 0 || n_feat.visual_solidness != 0)
- current_tile = &tile_liquid_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),
- };
-
- /*
- If our topside is liquid, set upper border of face
- at upper border of node
- */
- if (top_is_same_liquid) {
- vertices[2].Pos.Y = 0.5 * BS;
- vertices[3].Pos.Y = 0.5 * BS;
- } else {
- /*
- Otherwise upper position of face is liquid level
- */
- vertices[2].Pos.Y = 0.5 * BS;
- vertices[3].Pos.Y = 0.5 * BS;
- }
- /*
- If neighbor is liquid, lower border of face is liquid level
- */
- if (neighbor_is_same_liquid) {
- vertices[0].Pos.Y = 0.5 * BS;
- vertices[1].Pos.Y = 0.5 * BS;
- } else {
- /*
- If neighbor is not liquid, lower border of face is
- lower border of node
- */
- vertices[0].Pos.Y = -0.5 * BS;
- vertices[1].Pos.Y = -0.5 * BS;
- }
-
- for(s32 j=0; j<4; j++)
- {
- if(dir == v3s16(0,0,1))
- vertices[j].Pos.rotateXZBy(0);
- if(dir == v3s16(0,0,-1))
- vertices[j].Pos.rotateXZBy(180);
- if(dir == v3s16(-1,0,0))
- vertices[j].Pos.rotateXZBy(90);
- if(dir == v3s16(1,0,-0))
- vertices[j].Pos.rotateXZBy(-90);
-
- // Do this to not cause glitches when two liquids are
- // side-by-side
- /*if(neighbor_is_same_liquid == false){
- vertices[j].Pos.X *= 0.98;
- vertices[j].Pos.Z *= 0.98;
- }*/
-
- vertices[j].Pos += intToFloat(p, BS);
- }
-
- u16 indices[] = {0,1,2,2,3,0};
- // Add to mesh collector
- collector.append(*current_tile, vertices, 4, indices, 6);
- }
+ if (neighbor.content == c_source) {
+ neighbor.is_same_liquid = true;
+ neighbor.level = 0.5 * BS;
+ } else if (neighbor.content == c_flowing) {
+ neighbor.is_same_liquid = true;
+ u8 liquid_level = (n2.param2 & LIQUID_LEVEL_MASK);
+ if (liquid_level <= LIQUID_LEVEL_MAX + 1 - range)
+ liquid_level = 0;
+ else
+ liquid_level -= (LIQUID_LEVEL_MAX + 1 - range);
+ neighbor.level = (-0.5 + (liquid_level + 0.5) / range) * BS;
+ }
+
+ // Check node above neighbor.
+ // NOTE: This doesn't get executed if neighbor
+ // doesn't exist
+ p2.Y++;
+ n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
+ if (n2.getContent() == c_source || n2.getContent() == c_flowing)
+ neighbor.top_is_same_liquid = true;
+ }
+}
- /*
- Generate top
- */
- if(top_is_same_liquid)
+void MapblockMeshGenerator::calculateCornerLevels()
+{
+ for (int k = 0; k < 2; k++)
+ for (int i = 0; i < 2; i++)
+ corner_levels[k][i] = getCornerLevel(i, k);
+}
+
+f32 MapblockMeshGenerator::getCornerLevel(int i, int k)
+{
+ float sum = 0;
+ int count = 0;
+ int air_count = 0;
+ for (int dk = 0; dk < 2; dk++)
+ for (int di = 0; di < 2; di++) {
+ NeighborData &neighbor_data = liquid_neighbors[k + dk][i + di];
+ content_t content = neighbor_data.content;
+
+ // If top is liquid, draw starting from top of node
+ if (neighbor_data.top_is_same_liquid)
+ return 0.5 * BS;
+
+ // Source always has the full height
+ if (content == c_source)
+ return 0.5 * BS;
+
+ // Flowing liquid has level information
+ if (content == c_flowing) {
+ sum += neighbor_data.level;
+ count++;
+ } else if (content == CONTENT_AIR) {
+ air_count++;
+ if (air_count >= 2)
+ return -0.5 * BS + 0.2;
+ }
+ }
+ if (count > 0)
+ return sum / count;
+ return 0;
+}
+
+void MapblockMeshGenerator::drawLiquidSides()
+{
+ struct LiquidFaceDesc {
+ v3s16 dir; // XZ
+ v3s16 p[2]; // XZ only; 1 means +, 0 means -
+ };
+ struct UV {
+ int u, v;
+ };
+ static const LiquidFaceDesc base_faces[4] = {
+ {v3s16( 1, 0, 0), {v3s16(1, 0, 1), v3s16(1, 0, 0)}},
+ {v3s16(-1, 0, 0), {v3s16(0, 0, 0), v3s16(0, 0, 1)}},
+ {v3s16( 0, 0, 1), {v3s16(0, 0, 1), v3s16(1, 0, 1)}},
+ {v3s16( 0, 0, -1), {v3s16(1, 0, 0), v3s16(0, 0, 0)}},
+ };
+ static const UV base_vertices[4] = {
+ {0, 1},
+ {1, 1},
+ {1, 0},
+ {0, 0}
+ };
+ for (int i = 0; i < 4; i++) {
+ const LiquidFaceDesc &face = base_faces[i];
+ const NeighborData &neighbor = liquid_neighbors[face.dir.Z + 1][face.dir.X + 1];
+
+ // No face between nodes of the same liquid, unless there is node
+ // at the top to which it should be connected. Again, unless the face
+ // there would be inside the liquid
+ if (neighbor.is_same_liquid) {
+ if (!top_is_same_liquid)
+ continue;
+ if (neighbor.top_is_same_liquid)
continue;
+ }
- 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),
- };
-
- v3f offset(p.X * BS, (p.Y + 0.5) * BS, p.Z * BS);
- for(s32 i=0; i<4; i++)
- {
- vertices[i].Pos += offset;
- }
+ const ContentFeatures &neighbor_features = nodedef->get(neighbor.content);
+ // Don't draw face if neighbor is blocking the view
+ if (neighbor_features.solidness == 2)
+ continue;
- u16 indices[] = {0,1,2,2,3,0};
- // Add to mesh collector
- collector.append(tile_liquid, vertices, 4, indices, 6);
- break;}
- case NDT_FLOWINGLIQUID:
- {
- /*
- Add flowing liquid to mesh
- */
- TileSpec tile_liquid = f.special_tiles[0];
- TileSpec tile_liquid_bfculled = f.special_tiles[1];
-
- bool top_is_same_liquid = false;
- MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
- content_t c_flowing = nodedef->getId(f.liquid_alternative_flowing);
- content_t c_source = nodedef->getId(f.liquid_alternative_source);
- if(ntop.getContent() == c_flowing || ntop.getContent() == c_source)
- top_is_same_liquid = true;
-
- u16 l = 0;
- // If this liquid emits light and doesn't contain light, draw
- // it at what it emits, for an increased effect
- u8 light_source = nodedef->get(n).light_source;
- if(light_source != 0){
- l = decode_light(light_source);
- l = l | (l<<8);
- }
- // Use the light of the node on top if possible
- else if(nodedef->get(ntop).param_type == CPT_LIGHT)
- l = getInteriorLight(ntop, 0, nodedef);
- // Otherwise use the light of this node (the liquid)
+ video::S3DVertex vertices[4];
+ for (int j = 0; j < 4; j++) {
+ const UV &vertex = base_vertices[j];
+ const v3s16 &base = face.p[vertex.u];
+ v3f pos;
+ pos.X = (base.X - 0.5) * BS;
+ pos.Z = (base.Z - 0.5) * BS;
+ if (vertex.v)
+ pos.Y = neighbor.is_same_liquid ? corner_levels[base.Z][base.X] : -0.5 * BS;
else
- l = getInteriorLight(n, 0, nodedef);
- video::SColor c = MapBlock_LightColor(f.alpha, l, f.light_source);
-
- u8 range = rangelim(nodedef->get(c_flowing).liquid_range, 1, 8);
-
- // Neighbor liquid levels (key = relative position)
- // Includes current node
-
- struct NeighborData {
- f32 level;
- content_t content;
- u8 flags;
- };
- NeighborData neighbor_data_matrix[27];
-
- const u8 neighborflag_top_is_same_liquid = 0x01;
- v3s16 neighbor_dirs[9] = {
- v3s16(0,0,0),
- v3s16(0,0,1),
- v3s16(0,0,-1),
- v3s16(1,0,0),
- v3s16(-1,0,0),
- v3s16(1,0,1),
- v3s16(-1,0,-1),
- v3s16(1,0,-1),
- v3s16(-1,0,1),
- };
- for(u32 i=0; i<9; i++)
- {
- content_t content = CONTENT_AIR;
- float level = -0.5 * BS;
- u8 flags = 0;
- // Check neighbor
- v3s16 p2 = p + neighbor_dirs[i];
- MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
- if(n2.getContent() != CONTENT_IGNORE)
- {
- content = n2.getContent();
-
- if(n2.getContent() == c_source)
- level = 0.5 * BS;
- else if(n2.getContent() == c_flowing){
- u8 liquid_level = (n2.param2&LIQUID_LEVEL_MASK);
- if (liquid_level <= LIQUID_LEVEL_MAX+1-range)
- liquid_level = 0;
- else
- liquid_level -= (LIQUID_LEVEL_MAX+1-range);
- level = (-0.5 + ((float)liquid_level + 0.5) / (float)range) * BS;
- }
-
- // Check node above neighbor.
- // NOTE: This doesn't get executed if neighbor
- // doesn't exist
- p2.Y += 1;
- n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
- if(n2.getContent() == c_source ||
- n2.getContent() == c_flowing)
- flags |= neighborflag_top_is_same_liquid;
- }
-
- NeighborData &neighbor_data =
- neighbor_data_matrix[NeighborToIndex(neighbor_dirs[i])];
-
- neighbor_data.level = level;
- neighbor_data.content = content;
- neighbor_data.flags = flags;
- }
+ pos.Y = !top_is_same_liquid ? corner_levels[base.Z][base.X] : 0.5 * BS;
+ if (data->m_smooth_lighting)
+ color = blendLightColor(pos);
+ pos += origin;
+ vertices[j] = video::S3DVertex(pos.X, pos.Y, pos.Z, 0, 0, 0, color, vertex.u, vertex.v);
+ };
+ collector->append(tile_liquid, vertices, 4, quad_indices, 6);
+ }
+}
- // Corner heights (average between four liquids)
- f32 corner_levels[4];
-
- v3s16 halfdirs[4] = {
- v3s16(0,0,0),
- v3s16(1,0,0),
- v3s16(1,0,1),
- v3s16(0,0,1),
- };
- for(u32 i=0; i<4; i++)
- {
- v3s16 cornerdir = halfdirs[i];
- float cornerlevel = 0;
- u32 valid_count = 0;
- u32 air_count = 0;
- for(u32 j=0; j<4; j++)
- {
- v3s16 neighbordir = cornerdir - halfdirs[j];
-
- NeighborData &neighbor_data =
- neighbor_data_matrix[NeighborToIndex(neighbordir)];
- content_t content = neighbor_data.content;
- // If top is liquid, draw starting from top of node
- if (neighbor_data.flags & neighborflag_top_is_same_liquid)
- {
- cornerlevel = 0.5*BS;
- valid_count = 1;
- break;
- }
- // Source is always the same height
- else if(content == c_source)
- {
- cornerlevel = 0.5 * BS;
- valid_count = 1;
- break;
- }
- // Flowing liquid has level information
- else if(content == c_flowing)
- {
- cornerlevel += neighbor_data.level;
- valid_count++;
- }
- else if(content == CONTENT_AIR)
- {
- air_count++;
- }
- }
- if(air_count >= 2)
- cornerlevel = -0.5*BS+0.2;
- else if(valid_count > 0)
- cornerlevel /= valid_count;
- corner_levels[i] = cornerlevel;
- }
+void MapblockMeshGenerator::drawLiquidTop()
+{
+ // To get backface culling right, the vertices need to go
+ // clockwise around the front of the face. And we happened to
+ // calculate corner levels in exact reverse order.
+ static const int corner_resolve[4][2] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
+
+ video::S3DVertex vertices[4] = {
+ video::S3DVertex(-BS / 2, 0, BS / 2, 0, 0, 0, color_liquid_top, 0, 1),
+ video::S3DVertex( BS / 2, 0, BS / 2, 0, 0, 0, color_liquid_top, 1, 1),
+ video::S3DVertex( BS / 2, 0, -BS / 2, 0, 0, 0, color_liquid_top, 1, 0),
+ video::S3DVertex(-BS / 2, 0, -BS / 2, 0, 0, 0, color_liquid_top, 0, 0),
+ };
- /*
- Generate sides
- */
-
- v3s16 side_dirs[4] = {
- v3s16(1,0,0),
- v3s16(-1,0,0),
- v3s16(0,0,1),
- v3s16(0,0,-1),
- };
- s16 side_corners[4][2] = {
- {1, 2},
- {3, 0},
- {2, 3},
- {0, 1},
- };
- for(u32 i=0; i<4; i++)
- {
- v3s16 dir = side_dirs[i];
-
- NeighborData& neighbor_data =
- neighbor_data_matrix[NeighborToIndex(dir)];
- /*
- If our topside is liquid and neighbor's topside
- is liquid, don't draw side face
- */
- if (top_is_same_liquid &&
- neighbor_data.flags & neighborflag_top_is_same_liquid)
- continue;
-
- content_t neighbor_content = neighbor_data.content;
- const ContentFeatures &n_feat = nodedef->get(neighbor_content);
-
- // 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
- || neighbor_content == c_flowing);
-
- // Don't draw any faces if neighbor same is liquid and top is
- // same liquid
- 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
- const TileSpec *current_tile = &tile_liquid;
- if(n_feat.solidness != 0 || n_feat.visual_solidness != 0)
- current_tile = &tile_liquid_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),
- };
-
- /*
- If our topside is liquid, set upper border of face
- at upper border of node
- */
- if(top_is_same_liquid)
- {
- vertices[2].Pos.Y = 0.5*BS;
- vertices[3].Pos.Y = 0.5*BS;
- }
- /*
- Otherwise upper position of face is corner levels
- */
- else
- {
- vertices[2].Pos.Y = corner_levels[side_corners[i][0]];
- vertices[3].Pos.Y = corner_levels[side_corners[i][1]];
- }
-
- /*
- If neighbor is liquid, lower border of face is corner
- liquid levels
- */
- if(neighbor_is_same_liquid)
- {
- vertices[0].Pos.Y = corner_levels[side_corners[i][1]];
- vertices[1].Pos.Y = corner_levels[side_corners[i][0]];
- }
- /*
- If neighbor is not liquid, lower border of face is
- lower border of node
- */
- else
- {
- vertices[0].Pos.Y = -0.5*BS;
- vertices[1].Pos.Y = -0.5*BS;
- }
-
- for(s32 j=0; j<4; j++)
- {
- if(dir == v3s16(0,0,1))
- vertices[j].Pos.rotateXZBy(0);
- if(dir == v3s16(0,0,-1))
- vertices[j].Pos.rotateXZBy(180);
- if(dir == v3s16(-1,0,0))
- vertices[j].Pos.rotateXZBy(90);
- if(dir == v3s16(1,0,-0))
- vertices[j].Pos.rotateXZBy(-90);
-
- // Do this to not cause glitches when two liquids are
- // side-by-side
- /*if(neighbor_is_same_liquid == false){
- vertices[j].Pos.X *= 0.98;
- vertices[j].Pos.Z *= 0.98;
- }*/
-
- vertices[j].Pos += intToFloat(p, BS);
- }
-
- u16 indices[] = {0,1,2,2,3,0};
- // Add to mesh collector
- collector.append(*current_tile, vertices, 4, indices, 6);
- }
+ for (int i = 0; i < 4; i++) {
+ int u = corner_resolve[i][0];
+ int w = corner_resolve[i][1];
+ vertices[i].Pos.Y += corner_levels[w][u];
+ if (data->m_smooth_lighting)
+ vertices[i].Color = blendLightColor(vertices[i].Pos);
+ vertices[i].Pos += origin;
+ }
- /*
- Generate top side, if appropriate
- */
-
- if(top_is_same_liquid == false)
- {
- 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),
- };
-
- // To get backface culling right, the vertices need to go
- // clockwise around the front of the face. And we happened to
- // calculate corner levels in exact reverse order.
- s32 corner_resolve[4] = {3,2,1,0};
-
- for(s32 i=0; i<4; i++)
- {
- //vertices[i].Pos.Y += liquid_level;
- //vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
- s32 j = corner_resolve[i];
- vertices[i].Pos.Y += corner_levels[j];
- vertices[i].Pos += intToFloat(p, BS);
- }
-
- // Default downwards-flowing texture animation goes from
- // -Z towards +Z, thus the direction is +Z.
- // Rotate texture to make animation go in flow direction
- // Positive if liquid moves towards +Z
- f32 dz = (corner_levels[side_corners[3][0]] +
- corner_levels[side_corners[3][1]]) -
- (corner_levels[side_corners[2][0]] +
- corner_levels[side_corners[2][1]]);
- // Positive if liquid moves towards +X
- f32 dx = (corner_levels[side_corners[1][0]] +
- corner_levels[side_corners[1][1]]) -
- (corner_levels[side_corners[0][0]] +
- corner_levels[side_corners[0][1]]);
- f32 tcoord_angle = atan2(dz, dx) * core::RADTODEG ;
- v2f tcoord_center(0.5, 0.5);
- v2f tcoord_translate(
- blockpos_nodes.Z + z,
- blockpos_nodes.X + x);
- tcoord_translate.rotateBy(tcoord_angle);
- tcoord_translate.X -= floor(tcoord_translate.X);
- tcoord_translate.Y -= floor(tcoord_translate.Y);
-
- for(s32 i=0; i<4; i++)
- {
- vertices[i].TCoords.rotateBy(
- tcoord_angle,
- tcoord_center);
- vertices[i].TCoords += tcoord_translate;
- }
-
- v2f t = vertices[0].TCoords;
- vertices[0].TCoords = vertices[2].TCoords;
- vertices[2].TCoords = t;
-
- u16 indices[] = {0,1,2,2,3,0};
- // Add to mesh collector
- collector.append(tile_liquid, vertices, 4, indices, 6);
- }
- break;}
- case NDT_GLASSLIKE:
- {
- TileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data);
-
- u16 l = getInteriorLight(n, 1, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
-
- for(u32 j=0; j<6; j++)
- {
- // Check this neighbor
- v3s16 dir = g_6dirs[j];
- v3s16 n2p = blockpos_nodes + p + dir;
- MapNode n2 = data->m_vmanip.getNodeNoEx(n2p);
- // Don't make face if neighbor is of same type
- if(n2.getContent() == n.getContent())
- continue;
-
- // The face at Z+
- video::S3DVertex vertices[4] = {
- video::S3DVertex(-BS/2,-BS/2,BS/2, dir.X,dir.Y,dir.Z, c, 1,1),
- video::S3DVertex(BS/2,-BS/2,BS/2, dir.X,dir.Y,dir.Z, c, 0,1),
- video::S3DVertex(BS/2,BS/2,BS/2, dir.X,dir.Y,dir.Z, c, 0,0),
- video::S3DVertex(-BS/2,BS/2,BS/2, dir.X,dir.Y,dir.Z, c, 1,0),
- };
-
- // Rotations in the g_6dirs format
- if(j == 0) // Z+
- for(u16 i=0; i<4; i++)
- vertices[i].Pos.rotateXZBy(0);
- else if(j == 1) // Y+
- for(u16 i=0; i<4; i++)
- vertices[i].Pos.rotateYZBy(-90);
- else if(j == 2) // X+
- for(u16 i=0; i<4; i++)
- vertices[i].Pos.rotateXZBy(-90);
- else if(j == 3) // Z-
- for(u16 i=0; i<4; i++)
- vertices[i].Pos.rotateXZBy(180);
- else if(j == 4) // Y-
- for(u16 i=0; i<4; i++)
- vertices[i].Pos.rotateYZBy(90);
- else if(j == 5) // X-
- for(u16 i=0; i<4; i++)
- vertices[i].Pos.rotateXZBy(90);
-
- for(u16 i=0; i<4; i++){
- vertices[i].Pos += intToFloat(p, BS);
- }
-
- u16 indices[] = {0,1,2,2,3,0};
- // Add to mesh collector
- collector.append(tile, vertices, 4, indices, 6);
- }
- break;}
- case NDT_GLASSLIKE_FRAMED_OPTIONAL:
- // This is always pre-converted to something else
- FATAL_ERROR("NDT_GLASSLIKE_FRAMED_OPTIONAL not pre-converted as expected");
- break;
- case NDT_GLASSLIKE_FRAMED:
- {
- static const v3s16 dirs[6] = {
- v3s16( 0, 1, 0),
- v3s16( 0,-1, 0),
- v3s16( 1, 0, 0),
- v3s16(-1, 0, 0),
- v3s16( 0, 0, 1),
- v3s16( 0, 0,-1)
- };
-
- u8 i;
- TileSpec tiles[6];
- for (i = 0; i < 6; i++)
- tiles[i] = getNodeTile(n, p, dirs[i], data);
-
- TileSpec glass_tiles[6];
- if (tiles[1].texture && tiles[2].texture && tiles[3].texture) {
- glass_tiles[0] = tiles[2];
- glass_tiles[1] = tiles[3];
- glass_tiles[2] = tiles[1];
- glass_tiles[3] = tiles[1];
- glass_tiles[4] = tiles[1];
- glass_tiles[5] = tiles[1];
- } else {
- for (i = 0; i < 6; i++)
- glass_tiles[i] = tiles[1];
- }
+ // Default downwards-flowing texture animation goes from
+ // -Z towards +Z, thus the direction is +Z.
+ // Rotate texture to make animation go in flow direction
+ // Positive if liquid moves towards +Z
+ f32 dz = (corner_levels[0][0] + corner_levels[0][1]) -
+ (corner_levels[1][0] + corner_levels[1][1]);
+ // Positive if liquid moves towards +X
+ f32 dx = (corner_levels[0][0] + corner_levels[1][0]) -
+ (corner_levels[0][1] + corner_levels[1][1]);
+ f32 tcoord_angle = atan2(dz, dx) * core::RADTODEG;
+ v2f tcoord_center(0.5, 0.5);
+ v2f tcoord_translate(blockpos_nodes.Z + p.Z, blockpos_nodes.X + p.X);
+ tcoord_translate.rotateBy(tcoord_angle);
+ tcoord_translate.X -= floor(tcoord_translate.X);
+ tcoord_translate.Y -= floor(tcoord_translate.Y);
+
+ for (int i = 0; i < 4; i++) {
+ vertices[i].TCoords.rotateBy(tcoord_angle, tcoord_center);
+ vertices[i].TCoords += tcoord_translate;
+ }
- u8 param2 = n.getParam2();
- bool H_merge = ! bool(param2 & 128);
- bool V_merge = ! bool(param2 & 64);
- param2 = param2 & 63;
-
- u16 l = getInteriorLight(n, 1, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
- v3f pos = intToFloat(p, BS);
- static const float a = BS / 2;
- static const float g = a - 0.003;
- static const float b = .876 * ( BS / 2 );
-
- static const aabb3f frame_edges[12] = {
- aabb3f( b, b,-a, a, a, a), // y+
- aabb3f(-a, b,-a,-b, a, a), // y+
- aabb3f( b,-a,-a, a,-b, a), // y-
- aabb3f(-a,-a,-a,-b,-b, a), // y-
- aabb3f( b,-a, b, a, a, a), // x+
- aabb3f( b,-a,-a, a, a,-b), // x+
- aabb3f(-a,-a, b,-b, a, a), // x-
- aabb3f(-a,-a,-a,-b, a,-b), // x-
- aabb3f(-a, b, b, a, a, a), // z+
- aabb3f(-a,-a, b, a,-b, a), // z+
- aabb3f(-a,-a,-a, a,-b,-b), // z-
- aabb3f(-a, b,-a, a, a,-b) // z-
- };
- static const aabb3f glass_faces[6] = {
- aabb3f(-g, g,-g, g, g, g), // y+
- aabb3f(-g,-g,-g, g,-g, g), // y-
- aabb3f( g,-g,-g, g, g, g), // x+
- aabb3f(-g,-g,-g,-g, g, g), // x-
- aabb3f(-g,-g, g, g, g, g), // z+
- aabb3f(-g,-g,-g, g, g,-g) // z-
- };
-
- // table of node visible faces, 0 = invisible
- int visible_faces[6] = {0,0,0,0,0,0};
-
- // table of neighbours, 1 = same type, checked with g_26dirs
- int nb[18] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-
- // g_26dirs to check when only horizontal merge is allowed
- int nb_H_dirs[8] = {0,2,3,5,10,11,12,13};
-
- content_t current = n.getContent();
- content_t n2c;
- MapNode n2;
- v3s16 n2p;
-
- // neighbours checks for frames visibility
-
- if (!H_merge && V_merge) {
- n2p = blockpos_nodes + p + g_26dirs[1];
- n2 = data->m_vmanip.getNodeNoEx(n2p);
- n2c = n2.getContent();
- if (n2c == current || n2c == CONTENT_IGNORE)
- nb[1] = 1;
- n2p = blockpos_nodes + p + g_26dirs[4];
- n2 = data->m_vmanip.getNodeNoEx(n2p);
- n2c = n2.getContent();
- if (n2c == current || n2c == CONTENT_IGNORE)
- nb[4] = 1;
- } else if (H_merge && !V_merge) {
- for(i = 0; i < 8; i++) {
- n2p = blockpos_nodes + p + g_26dirs[nb_H_dirs[i]];
- n2 = data->m_vmanip.getNodeNoEx(n2p);
- n2c = n2.getContent();
- if (n2c == current || n2c == CONTENT_IGNORE)
- nb[nb_H_dirs[i]] = 1;
- }
- } else if (H_merge && V_merge) {
- for(i = 0; i < 18; i++) {
- n2p = blockpos_nodes + p + g_26dirs[i];
- n2 = data->m_vmanip.getNodeNoEx(n2p);
- n2c = n2.getContent();
- if (n2c == current || n2c == CONTENT_IGNORE)
- nb[i] = 1;
- }
- }
+ std::swap(vertices[0].TCoords, vertices[2].TCoords);
- // faces visibility checks
-
- if (!V_merge) {
- visible_faces[0] = 1;
- visible_faces[1] = 1;
- } else {
- for(i = 0; i < 2; i++) {
- n2p = blockpos_nodes + p + dirs[i];
- n2 = data->m_vmanip.getNodeNoEx(n2p);
- n2c = n2.getContent();
- if (n2c != current)
- visible_faces[i] = 1;
- }
- }
+ collector->append(tile_liquid_top, vertices, 4, quad_indices, 6);
+}
- if (!H_merge) {
- visible_faces[2] = 1;
- visible_faces[3] = 1;
- visible_faces[4] = 1;
- visible_faces[5] = 1;
- } else {
- for(i = 2; i < 6; i++) {
- n2p = blockpos_nodes + p + dirs[i];
- n2 = data->m_vmanip.getNodeNoEx(n2p);
- n2c = n2.getContent();
- if (n2c != current)
- visible_faces[i] = 1;
- }
- }
+void MapblockMeshGenerator::drawLiquidNode()
+{
+ prepareLiquidNodeDrawing();
+ getLiquidNeighborhood();
+ calculateCornerLevels();
+ drawLiquidSides();
+ if (!top_is_same_liquid)
+ drawLiquidTop();
+}
- static const u8 nb_triplet[12*3] = {
- 1,2, 7, 1,5, 6, 4,2,15, 4,5,14,
- 2,0,11, 2,3,13, 5,0,10, 5,3,12,
- 0,1, 8, 0,4,16, 3,4,17, 3,1, 9
- };
-
- f32 tx1, ty1, tz1, tx2, ty2, tz2;
- aabb3f box;
-
- for(i = 0; i < 12; i++)
- {
- int edge_invisible;
- if (nb[nb_triplet[i*3+2]])
- edge_invisible = nb[nb_triplet[i*3]] & nb[nb_triplet[i*3+1]];
- else
- edge_invisible = nb[nb_triplet[i*3]] ^ nb[nb_triplet[i*3+1]];
- if (edge_invisible)
- continue;
- box = frame_edges[i];
- box.MinEdge += pos;
- box.MaxEdge += pos;
- tx1 = (box.MinEdge.X / BS) + 0.5;
- ty1 = (box.MinEdge.Y / BS) + 0.5;
- tz1 = (box.MinEdge.Z / BS) + 0.5;
- tx2 = (box.MaxEdge.X / BS) + 0.5;
- ty2 = (box.MaxEdge.Y / BS) + 0.5;
- tz2 = (box.MaxEdge.Z / BS) + 0.5;
- f32 txc1[24] = {
- tx1, 1-tz2, tx2, 1-tz1,
- tx1, tz1, tx2, tz2,
- tz1, 1-ty2, tz2, 1-ty1,
- 1-tz2, 1-ty2, 1-tz1, 1-ty1,
- 1-tx2, 1-ty2, 1-tx1, 1-ty1,
- tx1, 1-ty2, tx2, 1-ty1,
- };
- makeCuboid(&collector, box, &tiles[0], 1, c, txc1);
+void MapblockMeshGenerator::drawGlasslikeNode()
+{
+ useDefaultTile();
+
+ for (int face = 0; face < 6; face++) {
+ // Check this neighbor
+ v3s16 dir = g_6dirs[face];
+ v3s16 neighbor_pos = blockpos_nodes + p + dir;
+ MapNode neighbor = data->m_vmanip.getNodeNoExNoEmerge(neighbor_pos);
+ // Don't make face if neighbor is of same type
+ if (neighbor.getContent() == n.getContent())
+ continue;
+ // Face at Z-
+ v3f vertices[4] = {
+ v3f(-BS / 2, BS / 2, -BS / 2),
+ v3f( BS / 2, BS / 2, -BS / 2),
+ v3f( BS / 2, -BS / 2, -BS / 2),
+ v3f(-BS / 2, -BS / 2, -BS / 2),
+ };
+ for (int i = 0; i < 4; i++) {
+ switch (face) {
+ case D6D_ZP: vertices[i].rotateXZBy(180); break;
+ case D6D_YP: vertices[i].rotateYZBy( 90); break;
+ case D6D_XP: vertices[i].rotateXZBy( 90); break;
+ case D6D_ZN: vertices[i].rotateXZBy( 0); break;
+ case D6D_YN: vertices[i].rotateYZBy(-90); break;
+ case D6D_XN: vertices[i].rotateXZBy(-90); break;
}
+ }
+ drawQuad(vertices, dir);
+ }
+}
- for(i = 0; i < 6; i++)
- {
- if (!visible_faces[i])
- continue;
- box = glass_faces[i];
- box.MinEdge += pos;
- box.MaxEdge += pos;
- tx1 = (box.MinEdge.X / BS) + 0.5;
- ty1 = (box.MinEdge.Y / BS) + 0.5;
- tz1 = (box.MinEdge.Z / BS) + 0.5;
- tx2 = (box.MaxEdge.X / BS) + 0.5;
- ty2 = (box.MaxEdge.Y / BS) + 0.5;
- tz2 = (box.MaxEdge.Z / BS) + 0.5;
- f32 txc2[24] = {
- tx1, 1-tz2, tx2, 1-tz1,
- tx1, tz1, tx2, tz2,
- tz1, 1-ty2, tz2, 1-ty1,
- 1-tz2, 1-ty2, 1-tz1, 1-ty1,
- 1-tx2, 1-ty2, 1-tx1, 1-ty1,
- tx1, 1-ty2, tx2, 1-ty1,
- };
- makeCuboid(&collector, box, &glass_tiles[i], 1, c, txc2);
- }
+void MapblockMeshGenerator::drawGlasslikeFramedNode()
+{
+ TileSpec tiles[6];
+ for (int face = 0; face < 6; face++)
+ getTile(g_6dirs[face], tiles[face]);
+
+ TileSpec glass_tiles[6];
+ if (tiles[1].layers[0].texture &&
+ tiles[2].layers[0].texture &&
+ tiles[3].layers[0].texture) {
+ glass_tiles[0] = tiles[4];
+ glass_tiles[1] = tiles[0];
+ glass_tiles[2] = tiles[4];
+ glass_tiles[3] = tiles[4];
+ glass_tiles[4] = tiles[3];
+ glass_tiles[5] = tiles[4];
+ } else {
+ for (int face = 0; face < 6; face++)
+ glass_tiles[face] = tiles[4];
+ }
- if (param2 > 0 && f.special_tiles[0].texture) {
- // Interior volume level is in range 0 .. 63,
- // convert it to -0.5 .. 0.5
- float vlev = (((float)param2 / 63.0 ) * 2.0 - 1.0);
- TileSpec interior_tiles[6];
- for (i = 0; i < 6; i++)
- interior_tiles[i] = f.special_tiles[0];
- float offset = 0.003;
- box = aabb3f(visible_faces[3] ? -b : -a + offset,
- visible_faces[1] ? -b : -a + offset,
- visible_faces[5] ? -b : -a + offset,
- visible_faces[2] ? b : a - offset,
- visible_faces[0] ? b * vlev : a * vlev - offset,
- visible_faces[4] ? b : a - offset);
- box.MinEdge += pos;
- box.MaxEdge += pos;
- tx1 = (box.MinEdge.X / BS) + 0.5;
- ty1 = (box.MinEdge.Y / BS) + 0.5;
- tz1 = (box.MinEdge.Z / BS) + 0.5;
- tx2 = (box.MaxEdge.X / BS) + 0.5;
- ty2 = (box.MaxEdge.Y / BS) + 0.5;
- tz2 = (box.MaxEdge.Z / BS) + 0.5;
- f32 txc3[24] = {
- tx1, 1-tz2, tx2, 1-tz1,
- tx1, tz1, tx2, tz2,
- tz1, 1-ty2, tz2, 1-ty1,
- 1-tz2, 1-ty2, 1-tz1, 1-ty1,
- 1-tx2, 1-ty2, 1-tx1, 1-ty1,
- tx1, 1-ty2, tx2, 1-ty1,
- };
- makeCuboid(&collector, box, interior_tiles, 6, c, txc3);
- }
- break;}
- case NDT_ALLFACES:
- {
- TileSpec tile_leaves = getNodeTile(n, p,
- v3s16(0,0,0), data);
-
- u16 l = getInteriorLight(n, 1, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
-
- v3f pos = intToFloat(p, BS);
- aabb3f box(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2);
- box.MinEdge += pos;
- box.MaxEdge += pos;
- makeCuboid(&collector, box, &tile_leaves, 1, c, NULL);
- break;}
- case NDT_ALLFACES_OPTIONAL:
- // This is always pre-converted to something else
- FATAL_ERROR("NDT_ALLFACES_OPTIONAL not pre-converted");
- break;
- case NDT_TORCHLIKE:
- {
- v3s16 dir = n.getWallMountedDir(nodedef);
-
- u8 tileindex = 0;
- if(dir == v3s16(0,-1,0)){
- tileindex = 0; // floor
- } else if(dir == v3s16(0,1,0)){
- tileindex = 1; // ceiling
- // For backwards compatibility
- } else if(dir == v3s16(0,0,0)){
- tileindex = 0; // floor
- } else {
- tileindex = 2; // side
- }
+ u8 param2 = n.getParam2();
+ bool H_merge = !(param2 & 128);
+ bool V_merge = !(param2 & 64);
+ param2 &= 63;
+
+ static const float a = BS / 2;
+ static const float g = a - 0.003;
+ static const float b = .876 * ( BS / 2 );
+
+ static const aabb3f frame_edges[FRAMED_EDGE_COUNT] = {
+ aabb3f( b, b, -a, a, a, a), // y+
+ aabb3f(-a, b, -a, -b, a, a), // y+
+ aabb3f( b, -a, -a, a, -b, a), // y-
+ aabb3f(-a, -a, -a, -b, -b, a), // y-
+ aabb3f( b, -a, b, a, a, a), // x+
+ aabb3f( b, -a, -a, a, a, -b), // x+
+ aabb3f(-a, -a, b, -b, a, a), // x-
+ aabb3f(-a, -a, -a, -b, a, -b), // x-
+ aabb3f(-a, b, b, a, a, a), // z+
+ aabb3f(-a, -a, b, a, -b, a), // z+
+ aabb3f(-a, -a, -a, a, -b, -b), // z-
+ aabb3f(-a, b, -a, a, a, -b), // z-
+ };
+ static const aabb3f glass_faces[6] = {
+ aabb3f(-g, -g, g, g, g, g), // z+
+ aabb3f(-g, g, -g, g, g, g), // y+
+ aabb3f( g, -g, -g, g, g, g), // x+
+ aabb3f(-g, -g, -g, g, g, -g), // z-
+ aabb3f(-g, -g, -g, g, -g, g), // y-
+ aabb3f(-g, -g, -g, -g, g, g), // x-
+ };
- TileSpec tile = getNodeTileN(n, p, tileindex, data);
- tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
- tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
-
- u16 l = getInteriorLight(n, 1, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
-
- float s = BS/2*f.visual_scale;
- // Wall at X+ of node
- video::S3DVertex vertices[4] =
- {
- video::S3DVertex(-s,-s,0, 0,0,0, c, 0,1),
- video::S3DVertex( s,-s,0, 0,0,0, c, 1,1),
- video::S3DVertex( s, s,0, 0,0,0, c, 1,0),
- video::S3DVertex(-s, s,0, 0,0,0, c, 0,0),
- };
-
- for(s32 i=0; i<4; i++)
- {
- if(dir == v3s16(1,0,0))
- vertices[i].Pos.rotateXZBy(0);
- if(dir == v3s16(-1,0,0))
- vertices[i].Pos.rotateXZBy(180);
- if(dir == v3s16(0,0,1))
- vertices[i].Pos.rotateXZBy(90);
- if(dir == v3s16(0,0,-1))
- vertices[i].Pos.rotateXZBy(-90);
- if(dir == v3s16(0,-1,0))
- vertices[i].Pos.rotateXZBy(45);
- if(dir == v3s16(0,1,0))
- vertices[i].Pos.rotateXZBy(-45);
-
- vertices[i].Pos += intToFloat(p, BS);
- }
+ // tables of neighbour (connect if same type and merge allowed),
+ // checked with g_26dirs
+
+ // 1 = connect, 0 = face visible
+ bool nb[FRAMED_NEIGHBOR_COUNT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+ // 1 = check
+ static const bool check_nb_vertical [FRAMED_NEIGHBOR_COUNT] = {0,1,0,0,1,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
+ static const bool check_nb_horizontal [FRAMED_NEIGHBOR_COUNT] = {1,0,1,1,0,1, 0,0,0,0, 1,1,1,1, 0,0,0,0};
+ static const bool check_nb_all [FRAMED_NEIGHBOR_COUNT] = {1,1,1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1};
+ const bool *check_nb = check_nb_all;
+
+ // neighbours checks for frames visibility
+ if (H_merge || V_merge) {
+ if (!H_merge)
+ check_nb = check_nb_vertical; // vertical-only merge
+ if (!V_merge)
+ check_nb = check_nb_horizontal; // horizontal-only merge
+ content_t current = n.getContent();
+ for (int i = 0; i < FRAMED_NEIGHBOR_COUNT; i++) {
+ if (!check_nb[i])
+ continue;
+ v3s16 n2p = blockpos_nodes + p + g_26dirs[i];
+ MapNode n2 = data->m_vmanip.getNodeNoEx(n2p);
+ content_t n2c = n2.getContent();
+ if (n2c == current || n2c == CONTENT_IGNORE)
+ nb[i] = 1;
+ }
+ }
- u16 indices[] = {0,1,2,2,3,0};
- // Add to mesh collector
- collector.append(tile, vertices, 4, indices, 6);
- break;}
- case NDT_SIGNLIKE:
- {
- TileSpec tile = getNodeTileN(n, p, 0, data);
- tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
- tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
-
- u16 l = getInteriorLight(n, 0, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
-
- float d = (float)BS/16;
- float s = BS/2*f.visual_scale;
- // Wall at X+ of node
- video::S3DVertex vertices[4] =
- {
- video::S3DVertex(BS/2-d, s, s, 0,0,0, c, 0,0),
- video::S3DVertex(BS/2-d, s, -s, 0,0,0, c, 1,0),
- video::S3DVertex(BS/2-d, -s, -s, 0,0,0, c, 1,1),
- video::S3DVertex(BS/2-d, -s, s, 0,0,0, c, 0,1),
- };
-
- v3s16 dir = n.getWallMountedDir(nodedef);
-
- for(s32 i=0; i<4; i++)
- {
- if(dir == v3s16(1,0,0))
- vertices[i].Pos.rotateXZBy(0);
- if(dir == v3s16(-1,0,0))
- vertices[i].Pos.rotateXZBy(180);
- if(dir == v3s16(0,0,1))
- vertices[i].Pos.rotateXZBy(90);
- if(dir == v3s16(0,0,-1))
- vertices[i].Pos.rotateXZBy(-90);
- if(dir == v3s16(0,-1,0))
- vertices[i].Pos.rotateXYBy(-90);
- if(dir == v3s16(0,1,0))
- vertices[i].Pos.rotateXYBy(90);
-
- vertices[i].Pos += intToFloat(p, BS);
- }
+ // edge visibility
- u16 indices[] = {0,1,2,2,3,0};
- // Add to mesh collector
- collector.append(tile, vertices, 4, indices, 6);
- break;}
- case NDT_PLANTLIKE:
- {
- PseudoRandom rng(x<<8 | z | y<<16);
-
- TileSpec tile = getNodeTileN(n, p, 0, data);
- tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
-
- u16 l = getInteriorLight(n, 1, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
-
- float s = BS / 2 * f.visual_scale;
- // add sqrt(2) visual scale
- if ((f.param_type_2 == CPT2_MESHOPTIONS) && ((n.param2 & 0x10) != 0))
- s *= 1.41421;
-
- float random_offset_X = .0;
- float random_offset_Z = .0;
- if ((f.param_type_2 == CPT2_MESHOPTIONS) && ((n.param2 & 0x8) != 0)) {
- random_offset_X = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145);
- random_offset_Z = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145);
- }
+ static const u8 nb_triplet[FRAMED_EDGE_COUNT][3] = {
+ {1, 2, 7}, {1, 5, 6}, {4, 2, 15}, {4, 5, 14},
+ {2, 0, 11}, {2, 3, 13}, {5, 0, 10}, {5, 3, 12},
+ {0, 1, 8}, {0, 4, 16}, {3, 4, 17}, {3, 1, 9},
+ };
- for (int j = 0; j < 4; j++) {
- video::S3DVertex vertices[4] =
- {
- video::S3DVertex(-s,-BS/2, 0, 0,0,0, c, 0,1),
- video::S3DVertex( s,-BS/2, 0, 0,0,0, c, 1,1),
- video::S3DVertex( s,-BS/2 + s*2,0, 0,0,0, c, 1,0),
- video::S3DVertex(-s,-BS/2 + s*2,0, 0,0,0, c, 0,0),
- };
-
- float rotate_degree = 0;
- u8 p2mesh = 0;
- if (f.param_type_2 == CPT2_DEGROTATE)
- rotate_degree = n.param2 * 2;
- if (f.param_type_2 != CPT2_MESHOPTIONS) {
- if (j == 0) {
- for (u16 i = 0; i < 4; i++)
- vertices[i].Pos.rotateXZBy(46 + rotate_degree);
- } else if (j == 1) {
- for (u16 i = 0; i < 4; i++)
- vertices[i].Pos.rotateXZBy(-44 + rotate_degree);
- }
- } else {
- p2mesh = n.param2 & 0x7;
- switch (p2mesh) {
- case 0:
- // x
- if (j == 0) {
- for (u16 i = 0; i < 4; i++)
- vertices[i].Pos.rotateXZBy(46);
- } else if (j == 1) {
- for (u16 i = 0; i < 4; i++)
- vertices[i].Pos.rotateXZBy(-44);
- }
- break;
- case 1:
- // +
- if (j == 0) {
- for (u16 i = 0; i < 4; i++)
- vertices[i].Pos.rotateXZBy(91);
- } else if (j == 1) {
- for (u16 i = 0; i < 4; i++)
- vertices[i].Pos.rotateXZBy(1);
- }
- break;
- case 2:
- // *
- if (j == 0) {
- for (u16 i = 0; i < 4; i++)
- vertices[i].Pos.rotateXZBy(121);
- } else if (j == 1) {
- for (u16 i = 0; i < 4; i++)
- vertices[i].Pos.rotateXZBy(241);
- } else { // (j == 2)
- for (u16 i = 0; i < 4; i++)
- vertices[i].Pos.rotateXZBy(1);
- }
- break;
- case 3:
- // #
- switch (j) {
- case 0:
- for (u16 i = 0; i < 4; i++) {
- vertices[i].Pos.rotateXZBy(1);
- vertices[i].Pos.Z += BS / 4;
- }
- break;
- case 1:
- for (u16 i = 0; i < 4; i++) {
- vertices[i].Pos.rotateXZBy(91);
- vertices[i].Pos.X += BS / 4;
- }
- break;
- case 2:
- for (u16 i = 0; i < 4; i++) {
- vertices[i].Pos.rotateXZBy(181);
- vertices[i].Pos.Z -= BS / 4;
- }
- break;
- case 3:
- for (u16 i = 0; i < 4; i++) {
- vertices[i].Pos.rotateXZBy(271);
- vertices[i].Pos.X -= BS / 4;
- }
- break;
- }
- break;
- case 4:
- // outward leaning #-like
- switch (j) {
- case 0:
- for (u16 i = 2; i < 4; i++)
- vertices[i].Pos.Z -= BS / 2;
- for (u16 i = 0; i < 4; i++)
- vertices[i].Pos.rotateXZBy(1);
- break;
- case 1:
- for (u16 i = 2; i < 4; i++)
- vertices[i].Pos.Z -= BS / 2;
- for (u16 i = 0; i < 4; i++)
- vertices[i].Pos.rotateXZBy(91);
- break;
- case 2:
- for (u16 i = 2; i < 4; i++)
- vertices[i].Pos.Z -= BS / 2;
- for (u16 i = 0; i < 4; i++)
- vertices[i].Pos.rotateXZBy(181);
- break;
- case 3:
- for (u16 i = 2; i < 4; i++)
- vertices[i].Pos.Z -= BS / 2;
- for (u16 i = 0; i < 4; i++)
- vertices[i].Pos.rotateXZBy(271);
- break;
- }
- break;
- }
- }
-
- for (int i = 0; i < 4; i++) {
- vertices[i].Pos *= f.visual_scale;
- vertices[i].Pos.Y += BS/2 * (f.visual_scale - 1);
- vertices[i].Pos += intToFloat(p, BS);
- // move to a random spot to avoid moire
- if ((f.param_type_2 == CPT2_MESHOPTIONS) && ((n.param2 & 0x8) != 0)) {
- vertices[i].Pos.X += random_offset_X;
- vertices[i].Pos.Z += random_offset_Z;
- }
- // randomly move each face up/down
- if ((f.param_type_2 == CPT2_MESHOPTIONS) && ((n.param2 & 0x20) != 0)) {
- PseudoRandom yrng(j | x<<16 | z<<8 | y<<24 );
- vertices[i].Pos.Y -= BS * ((yrng.next() % 16 / 16.0) * 0.125);
- }
- }
-
- u16 indices[] = {0, 1, 2, 2, 3, 0};
- // Add to mesh collector
- collector.append(tile, vertices, 4, indices, 6);
-
- // stop adding faces for meshes with less than 4 faces
- if (f.param_type_2 == CPT2_MESHOPTIONS) {
- if (((p2mesh == 0) || (p2mesh == 1)) && (j == 1))
- break;
- else if ((p2mesh == 2) && (j == 2))
- break;
- } else if (j == 1) {
- break;
- }
+ tile = tiles[1];
+ for (int edge = 0; edge < FRAMED_EDGE_COUNT; edge++) {
+ bool edge_invisible;
+ if (nb[nb_triplet[edge][2]])
+ edge_invisible = nb[nb_triplet[edge][0]] & nb[nb_triplet[edge][1]];
+ else
+ edge_invisible = nb[nb_triplet[edge][0]] ^ nb[nb_triplet[edge][1]];
+ if (edge_invisible)
+ continue;
+ drawAutoLightedCuboid(frame_edges[edge]);
+ }
- }
- break;}
- case NDT_FIRELIKE:
- {
- TileSpec tile = getNodeTileN(n, p, 0, data);
- tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
-
- u16 l = getInteriorLight(n, 1, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
-
- float s = BS / 2 * f.visual_scale;
-
- content_t current = n.getContent();
- content_t n2c;
- MapNode n2;
- v3s16 n2p;
-
- static const v3s16 dirs[6] = {
- v3s16( 0, 1, 0),
- v3s16( 0, -1, 0),
- v3s16( 1, 0, 0),
- v3s16(-1, 0, 0),
- v3s16( 0, 0, 1),
- v3s16( 0, 0, -1)
- };
-
- int doDraw[6] = {0, 0, 0, 0, 0, 0};
-
- bool drawAllFaces = true;
-
- // Check for adjacent nodes
- for (int i = 0; i < 6; i++) {
- n2p = blockpos_nodes + p + dirs[i];
- n2 = data->m_vmanip.getNodeNoEx(n2p);
- n2c = n2.getContent();
- if (n2c != CONTENT_IGNORE && n2c != CONTENT_AIR && n2c != current) {
- doDraw[i] = 1;
- if (drawAllFaces)
- drawAllFaces = false;
-
- }
- }
+ for (int face = 0; face < 6; face++) {
+ if (nb[face])
+ continue;
+ tile = glass_tiles[face];
+ drawAutoLightedCuboid(glass_faces[face]);
+ }
- for (int j = 0; j < 6; j++) {
-
- video::S3DVertex vertices[4] = {
- video::S3DVertex(-s, -BS / 2, 0, 0, 0, 0, c, 0, 1),
- video::S3DVertex( s, -BS / 2, 0, 0, 0, 0, c, 1, 1),
- video::S3DVertex( s, -BS / 2 + s * 2, 0, 0, 0, 0, c, 1, 0),
- video::S3DVertex(-s, -BS / 2 + s * 2, 0, 0, 0, 0, c, 0, 0),
- };
-
- // Calculate which faces should be drawn, (top or sides)
- if (j == 0 && (drawAllFaces ||
- (doDraw[3] == 1 || doDraw[1] == 1))) {
- for (int i = 0; i < 4; i++) {
- vertices[i].Pos.rotateXZBy(90);
- vertices[i].Pos.rotateXYBy(-10);
- vertices[i].Pos.X -= 4.0;
- }
- } else if (j == 1 && (drawAllFaces ||
- (doDraw[5] == 1 || doDraw[1] == 1))) {
- for (int i = 0; i < 4; i++) {
- vertices[i].Pos.rotateXZBy(180);
- vertices[i].Pos.rotateYZBy(10);
- vertices[i].Pos.Z -= 4.0;
- }
- } else if (j == 2 && (drawAllFaces ||
- (doDraw[2] == 1 || doDraw[1] == 1))) {
- for (int i = 0; i < 4; i++) {
- vertices[i].Pos.rotateXZBy(270);
- vertices[i].Pos.rotateXYBy(10);
- vertices[i].Pos.X += 4.0;
- }
- } else if (j == 3 && (drawAllFaces ||
- (doDraw[4] == 1 || doDraw[1] == 1))) {
- for (int i = 0; i < 4; i++) {
- vertices[i].Pos.rotateYZBy(-10);
- vertices[i].Pos.Z += 4.0;
- }
- // Center cross-flames
- } else if (j == 4 && (drawAllFaces || doDraw[1] == 1)) {
- for (int i = 0; i < 4; i++) {
- vertices[i].Pos.rotateXZBy(45);
- }
- } else if (j == 5 && (drawAllFaces || doDraw[1] == 1)) {
- for (int i = 0; i < 4; i++) {
- vertices[i].Pos.rotateXZBy(-45);
- }
- // Render flames on bottom of node above
- } else if (j == 0 && doDraw[0] == 1 && doDraw[1] == 0) {
- for (int i = 0; i < 4; i++) {
- vertices[i].Pos.rotateYZBy(70);
- vertices[i].Pos.rotateXZBy(90);
- vertices[i].Pos.Y += 4.84;
- vertices[i].Pos.X -= 4.7;
- }
- } else if (j == 1 && doDraw[0] == 1 && doDraw[1] == 0) {
- for (int i = 0; i < 4; i++) {
- vertices[i].Pos.rotateYZBy(70);
- vertices[i].Pos.rotateXZBy(180);
- vertices[i].Pos.Y += 4.84;
- vertices[i].Pos.Z -= 4.7;
- }
- } else if (j == 2 && doDraw[0] == 1 && doDraw[1] == 0) {
- for (int i = 0; i < 4; i++) {
- vertices[i].Pos.rotateYZBy(70);
- vertices[i].Pos.rotateXZBy(270);
- vertices[i].Pos.Y += 4.84;
- vertices[i].Pos.X += 4.7;
- }
- } else if (j == 3 && doDraw[0] == 1 && doDraw[1] == 0) {
- for (int i = 0; i < 4; i++) {
- vertices[i].Pos.rotateYZBy(70);
- vertices[i].Pos.Y += 4.84;
- vertices[i].Pos.Z += 4.7;
- }
- } else {
- // Skip faces that aren't adjacent to a node
- continue;
- }
-
- for (int i = 0; i < 4; i++) {
- vertices[i].Pos *= f.visual_scale;
- vertices[i].Pos += intToFloat(p, BS);
- }
-
- u16 indices[] = {0, 1, 2, 2, 3, 0};
- // Add to mesh collector
- collector.append(tile, vertices, 4, indices, 6);
- }
- break;}
- case NDT_FENCELIKE:
- {
- TileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data);
- TileSpec tile_nocrack = tile;
- tile_nocrack.material_flags &= ~MATERIAL_FLAG_CRACK;
-
- // Put wood the right way around in the posts
- TileSpec tile_rot = tile;
- tile_rot.rotation = 1;
-
- u16 l = getInteriorLight(n, 1, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
-
- const f32 post_rad=(f32)BS/8;
- const f32 bar_rad=(f32)BS/16;
- const f32 bar_len=(f32)(BS/2)-post_rad;
-
- v3f pos = intToFloat(p, BS);
-
- // The post - always present
- aabb3f post(-post_rad,-BS/2,-post_rad,post_rad,BS/2,post_rad);
- post.MinEdge += pos;
- post.MaxEdge += pos;
- f32 postuv[24]={
- 6/16.,6/16.,10/16.,10/16.,
- 6/16.,6/16.,10/16.,10/16.,
- 0/16.,0,4/16.,1,
- 4/16.,0,8/16.,1,
- 8/16.,0,12/16.,1,
- 12/16.,0,16/16.,1};
- makeCuboid(&collector, post, &tile_rot, 1, c, postuv);
-
- // Now a section of fence, +X, if there's a post there
- v3s16 p2 = p;
- p2.X++;
- MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
- const ContentFeatures *f2 = &nodedef->get(n2);
- if(f2->drawtype == NDT_FENCELIKE)
- {
- aabb3f bar(-bar_len+BS/2,-bar_rad+BS/4,-bar_rad,
- bar_len+BS/2,bar_rad+BS/4,bar_rad);
- bar.MinEdge += pos;
- bar.MaxEdge += pos;
- f32 xrailuv[24]={
- 0/16.,2/16.,16/16.,4/16.,
- 0/16.,4/16.,16/16.,6/16.,
- 6/16.,6/16.,8/16.,8/16.,
- 10/16.,10/16.,12/16.,12/16.,
- 0/16.,8/16.,16/16.,10/16.,
- 0/16.,14/16.,16/16.,16/16.};
- makeCuboid(&collector, bar, &tile_nocrack, 1,
- c, xrailuv);
- bar.MinEdge.Y -= BS/2;
- bar.MaxEdge.Y -= BS/2;
- makeCuboid(&collector, bar, &tile_nocrack, 1,
- c, xrailuv);
- }
+ // Optionally render internal liquid level defined by param2
+ // Liquid is textured with 1 tile defined in nodedef 'special_tiles'
+ if (param2 > 0 && f->param_type_2 == CPT2_GLASSLIKE_LIQUID_LEVEL &&
+ f->special_tiles[0].layers[0].texture) {
+ // Internal liquid level has param2 range 0 .. 63,
+ // convert it to -0.5 .. 0.5
+ float vlev = (param2 / 63.0) * 2.0 - 1.0;
+ tile = getSpecialTile(*f, n, 0);
+ drawAutoLightedCuboid(aabb3f(-(nb[5] ? g : b),
+ -(nb[4] ? g : b),
+ -(nb[3] ? g : b),
+ (nb[2] ? g : b),
+ (nb[1] ? g : b) * vlev,
+ (nb[0] ? g : b)));
+ }
+}
- // Now a section of fence, +Z, if there's a post there
- p2 = p;
- p2.Z++;
- n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
- f2 = &nodedef->get(n2);
- if(f2->drawtype == NDT_FENCELIKE)
- {
- aabb3f bar(-bar_rad,-bar_rad+BS/4,-bar_len+BS/2,
- bar_rad,bar_rad+BS/4,bar_len+BS/2);
- bar.MinEdge += pos;
- bar.MaxEdge += pos;
- f32 zrailuv[24]={
- 3/16.,1/16.,5/16.,5/16., // cannot rotate; stretch
- 4/16.,1/16.,6/16.,5/16., // for wood texture instead
- 0/16.,9/16.,16/16.,11/16.,
- 0/16.,6/16.,16/16.,8/16.,
- 6/16.,6/16.,8/16.,8/16.,
- 10/16.,10/16.,12/16.,12/16.};
- makeCuboid(&collector, bar, &tile_nocrack, 1,
- c, zrailuv);
- bar.MinEdge.Y -= BS/2;
- bar.MaxEdge.Y -= BS/2;
- makeCuboid(&collector, bar, &tile_nocrack, 1,
- c, zrailuv);
- }
- break;}
- case NDT_RAILLIKE:
- {
- bool is_rail_x[6]; /* (-1,-1,0) X (1,-1,0) (-1,0,0) X (1,0,0) (-1,1,0) X (1,1,0) */
- bool is_rail_z[6];
-
- content_t thiscontent = n.getContent();
- std::string groupname = "connect_to_raillike"; // name of the group that enables connecting to raillike nodes of different kind
- int self_group = ((ItemGroupList) nodedef->get(n).groups)[groupname];
-
- u8 index = 0;
- for (s8 y0 = -1; y0 <= 1; y0++) {
- // Prevent from indexing never used coordinates
- for (s8 xz = -1; xz <= 1; xz++) {
- if (xz == 0)
- continue;
- MapNode n_xy = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x + xz, y + y0, z));
- MapNode n_zy = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y + y0, z + xz));
- const ContentFeatures &def_xy = nodedef->get(n_xy);
- const ContentFeatures &def_zy = nodedef->get(n_zy);
-
- // Check if current node would connect with the rail
- is_rail_x[index] = ((def_xy.drawtype == NDT_RAILLIKE
- && ((ItemGroupList) def_xy.groups)[groupname] == self_group)
- || n_xy.getContent() == thiscontent);
-
- is_rail_z[index] = ((def_zy.drawtype == NDT_RAILLIKE
- && ((ItemGroupList) def_zy.groups)[groupname] == self_group)
- || n_zy.getContent() == thiscontent);
- index++;
- }
- }
+void MapblockMeshGenerator::drawAllfacesNode()
+{
+ static const aabb3f box(-BS / 2, -BS / 2, -BS / 2, BS / 2, BS / 2, BS / 2);
+ useDefaultTile(false);
+ drawAutoLightedCuboid(box);
+}
- bool is_rail_x_all[2]; // [0] = negative x, [1] = positive x coordinate from the current node position
- bool is_rail_z_all[2];
- is_rail_x_all[0] = is_rail_x[0] || is_rail_x[2] || is_rail_x[4];
- is_rail_x_all[1] = is_rail_x[1] || is_rail_x[3] || is_rail_x[5];
- is_rail_z_all[0] = is_rail_z[0] || is_rail_z[2] || is_rail_z[4];
- is_rail_z_all[1] = is_rail_z[1] || is_rail_z[3] || is_rail_z[5];
-
- // reasonable default, flat straight unrotated rail
- bool is_straight = true;
- int adjacencies = 0;
- int angle = 0;
- u8 tileindex = 0;
-
- // check for sloped rail
- if (is_rail_x[4] || is_rail_x[5] || is_rail_z[4] || is_rail_z[5]) {
- adjacencies = 5; // 5 means sloped
- is_straight = true; // sloped is always straight
- } else {
- // is really straight, rails on both sides
- is_straight = (is_rail_x_all[0] && is_rail_x_all[1]) || (is_rail_z_all[0] && is_rail_z_all[1]);
- adjacencies = is_rail_x_all[0] + is_rail_x_all[1] + is_rail_z_all[0] + is_rail_z_all[1];
- }
+void MapblockMeshGenerator::drawTorchlikeNode()
+{
+ u8 wall = n.getWallMounted(nodedef);
+ u8 tileindex = 0;
+ switch (wall) {
+ case DWM_YP: tileindex = 1; break; // ceiling
+ case DWM_YN: tileindex = 0; break; // floor
+ default: tileindex = 2; // side (or invalid—should we care?)
+ }
+ useTile(tileindex, true);
+
+ float size = BS / 2 * f->visual_scale;
+ v3f vertices[4] = {
+ v3f(-size, size, 0),
+ v3f( size, size, 0),
+ v3f( size, -size, 0),
+ v3f(-size, -size, 0),
+ };
+ for (int i = 0; i < 4; i++) {
+ switch (wall) {
+ case DWM_YP: vertices[i].rotateXZBy(-45); break;
+ case DWM_YN: vertices[i].rotateXZBy( 45); break;
+ case DWM_XP: vertices[i].rotateXZBy( 0); break;
+ case DWM_XN: vertices[i].rotateXZBy(180); break;
+ case DWM_ZP: vertices[i].rotateXZBy( 90); break;
+ case DWM_ZN: vertices[i].rotateXZBy(-90); break;
+ }
+ }
+ drawQuad(vertices);
+}
- switch (adjacencies) {
- case 1:
- if (is_rail_x_all[0] || is_rail_x_all[1])
- angle = 90;
- break;
- case 2:
- if (!is_straight)
- tileindex = 1; // curved
- if (is_rail_x_all[0] && is_rail_x_all[1])
- angle = 90;
- if (is_rail_z_all[0] && is_rail_z_all[1]) {
- if (is_rail_z[4])
- angle = 180;
- }
- else if (is_rail_x_all[0] && is_rail_z_all[0])
- angle = 270;
- else if (is_rail_x_all[0] && is_rail_z_all[1])
- angle = 180;
- else if (is_rail_x_all[1] && is_rail_z_all[1])
- angle = 90;
- break;
- case 3:
- // here is where the potential to 'switch' a junction is, but not implemented at present
- tileindex = 2; // t-junction
- if(!is_rail_x_all[1])
- angle = 180;
- if(!is_rail_z_all[0])
- angle = 90;
- if(!is_rail_z_all[1])
- angle = 270;
- break;
- case 4:
- tileindex = 3; // crossing
- break;
- case 5: //sloped
- if (is_rail_z[4])
- angle = 180;
- if (is_rail_x[4])
- angle = 90;
- if (is_rail_x[5])
- angle = -90;
- break;
- default:
- break;
- }
+void MapblockMeshGenerator::drawSignlikeNode()
+{
+ u8 wall = n.getWallMounted(nodedef);
+ useTile(0, true);
+ static const float offset = BS / 16;
+ float size = BS / 2 * f->visual_scale;
+ // Wall at X+ of node
+ v3f vertices[4] = {
+ v3f(BS / 2 - offset, size, size),
+ v3f(BS / 2 - offset, size, -size),
+ v3f(BS / 2 - offset, -size, -size),
+ v3f(BS / 2 - offset, -size, size),
+ };
+ for (int i = 0; i < 4; i++) {
+ switch (wall) {
+ case DWM_YP: vertices[i].rotateXYBy( 90); break;
+ case DWM_YN: vertices[i].rotateXYBy(-90); break;
+ case DWM_XP: vertices[i].rotateXZBy( 0); break;
+ case DWM_XN: vertices[i].rotateXZBy(180); break;
+ case DWM_ZP: vertices[i].rotateXZBy( 90); break;
+ case DWM_ZN: vertices[i].rotateXZBy(-90); break;
+ }
+ }
+ drawQuad(vertices);
+}
- TileSpec tile = getNodeTileN(n, p, tileindex, data);
- tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
- tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
-
- u16 l = getInteriorLight(n, 0, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
-
- float d = (float)BS/64;
- float s = BS/2;
-
- short g = -1;
- if (is_rail_x[4] || is_rail_x[5] || is_rail_z[4] || is_rail_z[5])
- g = 1; //Object is at a slope
-
- video::S3DVertex vertices[4] =
- {
- video::S3DVertex(-s, -s+d,-s, 0,0,0, c,0,1),
- video::S3DVertex( s, -s+d,-s, 0,0,0, c,1,1),
- video::S3DVertex( s, g*s+d, s, 0,0,0, c,1,0),
- video::S3DVertex(-s, g*s+d, s, 0,0,0, c,0,0),
- };
-
- for(s32 i=0; i<4; i++)
- {
- if(angle != 0)
- vertices[i].Pos.rotateXZBy(angle);
- vertices[i].Pos += intToFloat(p, BS);
- }
+void MapblockMeshGenerator::drawPlantlikeQuad(float rotation, float quad_offset,
+ bool offset_top_only)
+{
+ v3f vertices[4] = {
+ v3f(-scale, -BS / 2 + scale * 2, 0),
+ v3f( scale, -BS / 2 + scale * 2, 0),
+ v3f( scale, -BS / 2, 0),
+ v3f(-scale, -BS / 2, 0),
+ };
+ if (random_offset_Y) {
+ PseudoRandom yrng(face_num++ | p.X << 16 | p.Z << 8 | p.Y << 24);
+ offset.Y = BS * ((yrng.next() % 16 / 16.0) * 0.125);
+ }
+ int offset_count = offset_top_only ? 2 : 4;
+ for (int i = 0; i < offset_count; i++)
+ vertices[i].Z += quad_offset;
+ for (int i = 0; i < 4; i++) {
+ vertices[i].rotateXZBy(rotation + rotate_degree);
+ vertices[i] += offset;
+ }
+ drawQuad(vertices);
+}
- u16 indices[] = {0,1,2,2,3,0};
- collector.append(tile, vertices, 4, indices, 6);
- break;}
- case NDT_NODEBOX:
- {
- static const v3s16 tile_dirs[6] = {
- v3s16(0, 1, 0),
- v3s16(0, -1, 0),
- v3s16(1, 0, 0),
- v3s16(-1, 0, 0),
- v3s16(0, 0, 1),
- v3s16(0, 0, -1)
- };
- TileSpec tiles[6];
-
- u16 l = getInteriorLight(n, 1, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
-
- v3f pos = intToFloat(p, BS);
-
- int neighbors = 0;
-
- // locate possible neighboring nodes to connect to
- if (f.node_box.type == NODEBOX_CONNECTED) {
- v3s16 p2 = p;
-
- p2.Y++;
- getNeighborConnectingFace(blockpos_nodes + p2, nodedef, data, n, 1, &neighbors);
-
- p2 = p;
- p2.Y--;
- getNeighborConnectingFace(blockpos_nodes + p2, nodedef, data, n, 2, &neighbors);
-
- p2 = p;
- p2.Z--;
- getNeighborConnectingFace(blockpos_nodes + p2, nodedef, data, n, 4, &neighbors);
-
- p2 = p;
- p2.X--;
- getNeighborConnectingFace(blockpos_nodes + p2, nodedef, data, n, 8, &neighbors);
-
- p2 = p;
- p2.Z++;
- getNeighborConnectingFace(blockpos_nodes + p2, nodedef, data, n, 16, &neighbors);
-
- p2 = p;
- p2.X++;
- getNeighborConnectingFace(blockpos_nodes + p2, nodedef, data, n, 32, &neighbors);
- }
+void MapblockMeshGenerator::drawPlantlikeNode()
+{
+ useTile(0, false);
+ draw_style = PLANT_STYLE_CROSS;
+ scale = BS / 2 * f->visual_scale;
+ offset = v3f(0, 0, 0);
+ rotate_degree = 0;
+ random_offset_Y = false;
+ face_num = 0;
+
+ switch (f->param_type_2) {
+ case CPT2_MESHOPTIONS:
+ draw_style = PlantlikeStyle(n.param2 & MO_MASK_STYLE);
+ if (n.param2 & MO_BIT_SCALE_SQRT2)
+ scale *= 1.41421;
+ if (n.param2 & MO_BIT_RANDOM_OFFSET) {
+ PseudoRandom rng(p.X << 8 | p.Z | p.Y << 16);
+ offset.X = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145);
+ offset.Z = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145);
+ }
+ if (n.param2 & MO_BIT_RANDOM_OFFSET_Y)
+ random_offset_Y = true;
+ break;
- std::vector<aabb3f> boxes;
- n.getNodeBoxes(nodedef, &boxes, neighbors);
- for(std::vector<aabb3f>::iterator
- i = boxes.begin();
- i != boxes.end(); ++i)
- {
- for(int j = 0; j < 6; j++)
- {
- // Handles facedir rotation for textures
- tiles[j] = getNodeTile(n, p, tile_dirs[j], data);
- }
- aabb3f box = *i;
- box.MinEdge += pos;
- box.MaxEdge += pos;
-
- f32 temp;
- if (box.MinEdge.X > box.MaxEdge.X)
- {
- temp=box.MinEdge.X;
- box.MinEdge.X=box.MaxEdge.X;
- box.MaxEdge.X=temp;
- }
- if (box.MinEdge.Y > box.MaxEdge.Y)
- {
- temp=box.MinEdge.Y;
- box.MinEdge.Y=box.MaxEdge.Y;
- box.MaxEdge.Y=temp;
- }
- if (box.MinEdge.Z > box.MaxEdge.Z)
- {
- temp=box.MinEdge.Z;
- box.MinEdge.Z=box.MaxEdge.Z;
- box.MaxEdge.Z=temp;
- }
-
- //
- // Compute texture coords
- f32 tx1 = (box.MinEdge.X/BS)+0.5;
- f32 ty1 = (box.MinEdge.Y/BS)+0.5;
- f32 tz1 = (box.MinEdge.Z/BS)+0.5;
- f32 tx2 = (box.MaxEdge.X/BS)+0.5;
- f32 ty2 = (box.MaxEdge.Y/BS)+0.5;
- f32 tz2 = (box.MaxEdge.Z/BS)+0.5;
- f32 txc[24] = {
- // up
- tx1, 1-tz2, tx2, 1-tz1,
- // down
- tx1, tz1, tx2, tz2,
- // right
- tz1, 1-ty2, tz2, 1-ty1,
- // left
- 1-tz2, 1-ty2, 1-tz1, 1-ty1,
- // back
- 1-tx2, 1-ty2, 1-tx1, 1-ty1,
- // front
- tx1, 1-ty2, tx2, 1-ty1,
- };
- makeCuboid(&collector, box, tiles, 6, c, txc);
- }
- break;}
- case NDT_MESH:
- {
- v3f pos = intToFloat(p, BS);
- video::SColor c = MapBlock_LightColor(255, getInteriorLight(n, 1, nodedef), f.light_source);
-
- u8 facedir = 0;
- if (f.param_type_2 == CPT2_FACEDIR) {
- facedir = n.getFaceDir(nodedef);
- } else if (f.param_type_2 == CPT2_WALLMOUNTED) {
- //convert wallmounted to 6dfacedir.
- //when cache enabled, it is already converted
- facedir = n.getWallMounted(nodedef);
- if (!enable_mesh_cache) {
- static const u8 wm_to_6d[6] = {20, 0, 16+1, 12+3, 8, 4+2};
- facedir = wm_to_6d[facedir];
- }
- }
+ case CPT2_DEGROTATE:
+ rotate_degree = n.param2 * 2;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (draw_style) {
+ case PLANT_STYLE_CROSS:
+ drawPlantlikeQuad(46);
+ drawPlantlikeQuad(-44);
+ break;
+
+ case PLANT_STYLE_CROSS2:
+ drawPlantlikeQuad(91);
+ drawPlantlikeQuad(1);
+ break;
+
+ case PLANT_STYLE_STAR:
+ drawPlantlikeQuad(121);
+ drawPlantlikeQuad(241);
+ drawPlantlikeQuad(1);
+ break;
+
+ case PLANT_STYLE_HASH:
+ drawPlantlikeQuad( 1, BS / 4);
+ drawPlantlikeQuad( 91, BS / 4);
+ drawPlantlikeQuad(181, BS / 4);
+ drawPlantlikeQuad(271, BS / 4);
+ break;
+
+ case PLANT_STYLE_HASH2:
+ drawPlantlikeQuad( 1, -BS / 2, true);
+ drawPlantlikeQuad( 91, -BS / 2, true);
+ drawPlantlikeQuad(181, -BS / 2, true);
+ drawPlantlikeQuad(271, -BS / 2, true);
+ break;
+ }
+}
+
+void MapblockMeshGenerator::drawFirelikeQuad(float rotation, float opening_angle,
+ float offset_h, float offset_v)
+{
+ v3f vertices[4] = {
+ v3f(-scale, -BS / 2 + scale * 2, 0),
+ v3f( scale, -BS / 2 + scale * 2, 0),
+ v3f( scale, -BS / 2, 0),
+ v3f(-scale, -BS / 2, 0),
+ };
+ for (int i = 0; i < 4; i++) {
+ vertices[i].rotateYZBy(opening_angle);
+ vertices[i].Z += offset_h;
+ vertices[i].rotateXZBy(rotation);
+ vertices[i].Y += offset_v;
+ }
+ drawQuad(vertices);
+}
+
+void MapblockMeshGenerator::drawFirelikeNode()
+{
+ useTile(0, false);
+ scale = BS / 2 * f->visual_scale;
+
+ // Check for adjacent nodes
+ bool neighbors = false;
+ bool neighbor[6] = {0, 0, 0, 0, 0, 0};
+ content_t current = n.getContent();
+ for (int i = 0; i < 6; i++) {
+ v3s16 n2p = blockpos_nodes + p + g_6dirs[i];
+ MapNode n2 = data->m_vmanip.getNodeNoEx(n2p);
+ content_t n2c = n2.getContent();
+ if (n2c != CONTENT_IGNORE && n2c != CONTENT_AIR && n2c != current) {
+ neighbor[i] = true;
+ neighbors = true;
+ }
+ }
+ bool drawBasicFire = neighbor[D6D_YN] || !neighbors;
+ bool drawBottomFire = neighbor[D6D_YP];
+
+ if (drawBasicFire || neighbor[D6D_ZP])
+ drawFirelikeQuad(0, -10, 0.4 * BS);
+ else if (drawBottomFire)
+ drawFirelikeQuad(0, 70, 0.47 * BS, 0.484 * BS);
+
+ if (drawBasicFire || neighbor[D6D_XN])
+ drawFirelikeQuad(90, -10, 0.4 * BS);
+ else if (drawBottomFire)
+ drawFirelikeQuad(90, 70, 0.47 * BS, 0.484 * BS);
+
+ if (drawBasicFire || neighbor[D6D_ZN])
+ drawFirelikeQuad(180, -10, 0.4 * BS);
+ else if (drawBottomFire)
+ drawFirelikeQuad(180, 70, 0.47 * BS, 0.484 * BS);
+
+ if (drawBasicFire || neighbor[D6D_XP])
+ drawFirelikeQuad(270, -10, 0.4 * BS);
+ else if (drawBottomFire)
+ drawFirelikeQuad(270, 70, 0.47 * BS, 0.484 * BS);
+
+ if (drawBasicFire) {
+ drawFirelikeQuad(45, 0, 0.0);
+ drawFirelikeQuad(-45, 0, 0.0);
+ }
+}
+
+void MapblockMeshGenerator::drawFencelikeNode()
+{
+ useDefaultTile(false);
+ TileSpec tile_nocrack = tile;
+ for (int layer = 0; layer < MAX_TILE_LAYERS; layer++)
+ tile_nocrack.layers[layer].material_flags &= ~MATERIAL_FLAG_CRACK;
+
+ // Put wood the right way around in the posts
+ TileSpec tile_rot = tile;
+ tile_rot.rotation = 1;
+
+ static const f32 post_rad = BS / 8;
+ static const f32 bar_rad = BS / 16;
+ static const f32 bar_len = BS / 2 - post_rad;
+
+ // The post - always present
+ static const aabb3f post(-post_rad, -BS / 2, -post_rad,
+ post_rad, BS / 2, post_rad);
+ static const f32 postuv[24] = {
+ 0.375, 0.375, 0.625, 0.625,
+ 0.375, 0.375, 0.625, 0.625,
+ 0.000, 0.000, 0.250, 1.000,
+ 0.250, 0.000, 0.500, 1.000,
+ 0.500, 0.000, 0.750, 1.000,
+ 0.750, 0.000, 1.000, 1.000,
+ };
+ tile = tile_rot;
+ drawAutoLightedCuboid(post, postuv);
+
+ tile = tile_nocrack;
+
+ // Now a section of fence, +X, if there's a post there
+ v3s16 p2 = p;
+ p2.X++;
+ MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
+ const ContentFeatures *f2 = &nodedef->get(n2);
+ if (f2->drawtype == NDT_FENCELIKE) {
+ static const aabb3f bar_x1(BS / 2 - bar_len, BS / 4 - bar_rad, -bar_rad,
+ BS / 2 + bar_len, BS / 4 + bar_rad, bar_rad);
+ static const aabb3f bar_x2(BS / 2 - bar_len, -BS / 4 - bar_rad, -bar_rad,
+ BS / 2 + bar_len, -BS / 4 + bar_rad, bar_rad);
+ static const f32 xrailuv[24] = {
+ 0.000, 0.125, 1.000, 0.250,
+ 0.000, 0.250, 1.000, 0.375,
+ 0.375, 0.375, 0.500, 0.500,
+ 0.625, 0.625, 0.750, 0.750,
+ 0.000, 0.500, 1.000, 0.625,
+ 0.000, 0.875, 1.000, 1.000,
+ };
+ drawAutoLightedCuboid(bar_x1, xrailuv);
+ drawAutoLightedCuboid(bar_x2, xrailuv);
+ }
+
+ // Now a section of fence, +Z, if there's a post there
+ p2 = p;
+ p2.Z++;
+ n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
+ f2 = &nodedef->get(n2);
+ if (f2->drawtype == NDT_FENCELIKE) {
+ static const aabb3f bar_z1(-bar_rad, BS / 4 - bar_rad, BS / 2 - bar_len,
+ bar_rad, BS / 4 + bar_rad, BS / 2 + bar_len);
+ static const aabb3f bar_z2(-bar_rad, -BS / 4 - bar_rad, BS / 2 - bar_len,
+ bar_rad, -BS / 4 + bar_rad, BS / 2 + bar_len);
+ static const f32 zrailuv[24] = {
+ 0.1875, 0.0625, 0.3125, 0.3125, // cannot rotate; stretch
+ 0.2500, 0.0625, 0.3750, 0.3125, // for wood texture instead
+ 0.0000, 0.5625, 1.0000, 0.6875,
+ 0.0000, 0.3750, 1.0000, 0.5000,
+ 0.3750, 0.3750, 0.5000, 0.5000,
+ 0.6250, 0.6250, 0.7500, 0.7500,
+ };
+ drawAutoLightedCuboid(bar_z1, zrailuv);
+ drawAutoLightedCuboid(bar_z2, zrailuv);
+ }
+}
+
+bool MapblockMeshGenerator::isSameRail(v3s16 dir)
+{
+ MapNode node2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p + dir);
+ if (node2.getContent() == n.getContent())
+ return true;
+ const ContentFeatures &def2 = nodedef->get(node2);
+ return ((def2.drawtype == NDT_RAILLIKE) &&
+ (def2.getGroup(raillike_groupname) == raillike_group));
+}
+
+void MapblockMeshGenerator::drawRaillikeNode()
+{
+ static const v3s16 direction[4] = {
+ v3s16( 0, 0, 1),
+ v3s16( 0, 0, -1),
+ v3s16(-1, 0, 0),
+ v3s16( 1, 0, 0),
+ };
+ static const int slope_angle[4] = {0, 180, 90, -90};
+
+ enum RailTile {
+ straight,
+ curved,
+ junction,
+ cross,
+ };
+ struct RailDesc {
+ int tile_index;
+ int angle;
+ };
+ static const RailDesc rail_kinds[16] = {
+ // +x -x -z +z
+ //-------------
+ {straight, 0}, // . . . .
+ {straight, 0}, // . . . +Z
+ {straight, 0}, // . . -Z .
+ {straight, 0}, // . . -Z +Z
+ {straight, 90}, // . -X . .
+ { curved, 180}, // . -X . +Z
+ { curved, 270}, // . -X -Z .
+ {junction, 180}, // . -X -Z +Z
+ {straight, 90}, // +X . . .
+ { curved, 90}, // +X . . +Z
+ { curved, 0}, // +X . -Z .
+ {junction, 0}, // +X . -Z +Z
+ {straight, 90}, // +X -X . .
+ {junction, 90}, // +X -X . +Z
+ {junction, 270}, // +X -X -Z .
+ { cross, 0}, // +X -X -Z +Z
+ };
+
+ raillike_group = nodedef->get(n).getGroup(raillike_groupname);
+
+ int code = 0;
+ int angle;
+ int tile_index;
+ bool sloped = false;
+ for (int dir = 0; dir < 4; dir++) {
+ bool rail_above = isSameRail(direction[dir] + v3s16(0, 1, 0));
+ if (rail_above) {
+ sloped = true;
+ angle = slope_angle[dir];
+ }
+ if (rail_above ||
+ isSameRail(direction[dir]) ||
+ isSameRail(direction[dir] + v3s16(0, -1, 0)))
+ code |= 1 << dir;
+ }
+
+ if (sloped) {
+ tile_index = straight;
+ } else {
+ tile_index = rail_kinds[code].tile_index;
+ angle = rail_kinds[code].angle;
+ }
+
+ useTile(tile_index, true);
+
+ static const float offset = BS / 64;
+ static const float size = BS / 2;
+ float y2 = sloped ? size : -size;
+ v3f vertices[4] = {
+ v3f(-size, y2 + offset, size),
+ v3f( size, y2 + offset, size),
+ v3f( size, -size + offset, -size),
+ v3f(-size, -size + offset, -size),
+ };
+ if (angle)
+ for (int i = 0; i < 4; i++)
+ vertices[i].rotateXZBy(angle);
+ drawQuad(vertices);
+}
- if (f.mesh_ptr[facedir]) {
- // use cached meshes
- for(u16 j = 0; j < f.mesh_ptr[0]->getMeshBufferCount(); j++) {
- scene::IMeshBuffer *buf = f.mesh_ptr[facedir]->getMeshBuffer(j);
- collector.append(getNodeTileN(n, p, j, data),
- (video::S3DVertex *)buf->getVertices(), buf->getVertexCount(),
- buf->getIndices(), buf->getIndexCount(), pos, c);
- }
- } else if (f.mesh_ptr[0]) {
- // no cache, clone and rotate mesh
- scene::IMesh* mesh = cloneMesh(f.mesh_ptr[0]);
- rotateMeshBy6dFacedir(mesh, facedir);
- recalculateBoundingBox(mesh);
- meshmanip->recalculateNormals(mesh, true, false);
- for(u16 j = 0; j < mesh->getMeshBufferCount(); j++) {
- scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
- collector.append(getNodeTileN(n, p, j, data),
- (video::S3DVertex *)buf->getVertices(), buf->getVertexCount(),
- buf->getIndices(), buf->getIndexCount(), pos, c);
- }
- mesh->drop();
+void MapblockMeshGenerator::drawNodeboxNode()
+{
+ static const v3s16 tile_dirs[6] = {
+ v3s16(0, 1, 0),
+ v3s16(0, -1, 0),
+ v3s16(1, 0, 0),
+ v3s16(-1, 0, 0),
+ v3s16(0, 0, 1),
+ v3s16(0, 0, -1)
+ };
+
+ // we have this order for some reason...
+ static const v3s16 connection_dirs[6] = {
+ v3s16( 0, 1, 0), // top
+ v3s16( 0, -1, 0), // bottom
+ v3s16( 0, 0, -1), // front
+ v3s16(-1, 0, 0), // left
+ v3s16( 0, 0, 1), // back
+ v3s16( 1, 0, 0), // right
+ };
+
+ TileSpec tiles[6];
+ for (int face = 0; face < 6; face++) {
+ // Handles facedir rotation for textures
+ getTile(tile_dirs[face], tiles[face]);
+ }
+
+ // locate possible neighboring nodes to connect to
+ int neighbors_set = 0;
+ if (f->node_box.type == NODEBOX_CONNECTED) {
+ for (int dir = 0; dir != 6; dir++) {
+ int flag = 1 << dir;
+ v3s16 p2 = blockpos_nodes + p + connection_dirs[dir];
+ MapNode n2 = data->m_vmanip.getNodeNoEx(p2);
+ if (nodedef->nodeboxConnects(n, n2, flag))
+ neighbors_set |= flag;
+ }
+ }
+
+ std::vector<aabb3f> boxes;
+ n.getNodeBoxes(nodedef, &boxes, neighbors_set);
+ for (std::vector<aabb3f>::iterator i = boxes.begin(); i != boxes.end(); ++i)
+ drawAutoLightedCuboid(*i, NULL, tiles, 6);
+}
+
+void MapblockMeshGenerator::drawMeshNode()
+{
+ u8 facedir = 0;
+ scene::IMesh* mesh;
+ bool private_mesh; // as a grab/drop pair is not thread-safe
+
+ if (f->param_type_2 == CPT2_FACEDIR ||
+ f->param_type_2 == CPT2_COLORED_FACEDIR) {
+ facedir = n.getFaceDir(nodedef);
+ } else if (f->param_type_2 == CPT2_WALLMOUNTED ||
+ f->param_type_2 == CPT2_COLORED_WALLMOUNTED) {
+ // Convert wallmounted to 6dfacedir.
+ // When cache enabled, it is already converted.
+ facedir = n.getWallMounted(nodedef);
+ if (!enable_mesh_cache) {
+ static const u8 wm_to_6d[6] = {20, 0, 16 + 1, 12 + 3, 8, 4 + 2};
+ facedir = wm_to_6d[facedir];
+ }
+ }
+
+ if (!data->m_smooth_lighting && f->mesh_ptr[facedir]) {
+ // use cached meshes
+ private_mesh = false;
+ mesh = f->mesh_ptr[facedir];
+ } else if (f->mesh_ptr[0]) {
+ // no cache, clone and rotate mesh
+ private_mesh = true;
+ mesh = cloneMesh(f->mesh_ptr[0]);
+ rotateMeshBy6dFacedir(mesh, facedir);
+ recalculateBoundingBox(mesh);
+ meshmanip->recalculateNormals(mesh, true, false);
+ } else
+ return;
+
+ int mesh_buffer_count = mesh->getMeshBufferCount();
+ for (int j = 0; j < mesh_buffer_count; j++) {
+ useTile(j, false);
+ scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+ video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
+ int vertex_count = buf->getVertexCount();
+
+ if (data->m_smooth_lighting) {
+ // Mesh is always private here. So the lighting is applied to each
+ // vertex right here.
+ for (int k = 0; k < vertex_count; k++) {
+ video::S3DVertex &vertex = vertices[k];
+ vertex.Color = blendLightColor(vertex.Pos, vertex.Normal);
+ vertex.Pos += origin;
}
- break;}
+ collector->append(tile, vertices, vertex_count,
+ buf->getIndices(), buf->getIndexCount());
+ } else {
+ // Don't modify the mesh, it may not be private here.
+ // Instead, let the collector process colors, etc.
+ collector->append(tile, vertices, vertex_count,
+ buf->getIndices(), buf->getIndexCount(), origin,
+ color, f->light_source);
}
}
+ if (private_mesh)
+ mesh->drop();
}
+// also called when the drawtype is known but should have been pre-converted
+void MapblockMeshGenerator::errorUnknownDrawtype()
+{
+ infostream << "Got drawtype " << f->drawtype << std::endl;
+ FATAL_ERROR("Unknown drawtype");
+}
+
+void MapblockMeshGenerator::drawNode()
+{
+ if (data->m_smooth_lighting)
+ getSmoothLightFrame();
+ else
+ light = getInteriorLight(n, 1, nodedef);
+ switch (f->drawtype) {
+ case NDT_FLOWINGLIQUID: drawLiquidNode(); break;
+ case NDT_GLASSLIKE: drawGlasslikeNode(); break;
+ case NDT_GLASSLIKE_FRAMED: drawGlasslikeFramedNode(); break;
+ case NDT_ALLFACES: drawAllfacesNode(); break;
+ case NDT_TORCHLIKE: drawTorchlikeNode(); break;
+ case NDT_SIGNLIKE: drawSignlikeNode(); break;
+ case NDT_PLANTLIKE: drawPlantlikeNode(); break;
+ case NDT_FIRELIKE: drawFirelikeNode(); break;
+ case NDT_FENCELIKE: drawFencelikeNode(); break;
+ case NDT_RAILLIKE: drawRaillikeNode(); break;
+ case NDT_NODEBOX: drawNodeboxNode(); break;
+ case NDT_MESH: drawMeshNode(); break;
+ default: errorUnknownDrawtype(); break;
+ }
+}
+
+/*
+ TODO: Fix alpha blending for special nodes
+ Currently only the last element rendered is blended correct
+*/
+void MapblockMeshGenerator::generate()
+{
+ for (p.Z = 0; p.Z < MAP_BLOCKSIZE; p.Z++)
+ for (p.Y = 0; p.Y < MAP_BLOCKSIZE; p.Y++)
+ for (p.X = 0; p.X < MAP_BLOCKSIZE; p.X++) {
+ n = data->m_vmanip.getNodeNoEx(blockpos_nodes + p);
+ f = &nodedef->get(n);
+ // Solid nodes are drawn by MapBlockMesh
+ if (f->solidness != 0)
+ continue;
+ if (f->drawtype == NDT_AIRLIKE)
+ continue;
+ origin = intToFloat(p, BS);
+ drawNode();
+ }
+}
diff --git a/src/content_mapblock.h b/src/content_mapblock.h
index bb1e129da..2c6a4969e 100644
--- a/src/content_mapblock.h
+++ b/src/content_mapblock.h
@@ -19,11 +19,128 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef CONTENT_MAPBLOCK_HEADER
#define CONTENT_MAPBLOCK_HEADER
+#include "util/numeric.h"
+#include "nodedef.h"
+#include <IMeshManipulator.h>
struct MeshMakeData;
struct MeshCollector;
-void mapblock_mesh_generate_special(MeshMakeData *data,
- MeshCollector &collector);
-#endif
+struct LightFrame
+{
+ f32 lightsA[8];
+ f32 lightsB[8];
+};
+
+class MapblockMeshGenerator
+{
+public:
+ MeshMakeData *data;
+ MeshCollector *collector;
+
+ INodeDefManager *nodedef;
+ scene::ISceneManager *smgr;
+ scene::IMeshManipulator *meshmanip;
+
+// options
+ bool enable_mesh_cache;
+
+// current node
+ v3s16 blockpos_nodes;
+ v3s16 p;
+ v3f origin;
+ MapNode n;
+ const ContentFeatures *f;
+ u16 light;
+ LightFrame frame;
+ video::SColor color;
+ TileSpec tile;
+ float scale;
+
+// lighting
+ void getSmoothLightFrame();
+ u16 blendLight(const v3f &vertex_pos);
+ video::SColor blendLightColor(const v3f &vertex_pos);
+ video::SColor blendLightColor(const v3f &vertex_pos, const v3f &vertex_normal);
+
+ void useTile(int index, bool disable_backface_culling);
+ void useDefaultTile(bool set_color = true);
+ void getTile(const v3s16 &direction, TileSpec &tile);
+
+// face drawing
+ void drawQuad(v3f *vertices, const v3s16 &normal = v3s16(0, 0, 0));
+
+// cuboid drawing!
+ void drawCuboid(const aabb3f &box, TileSpec *tiles, int tilecount,
+ const u16 *lights , const f32 *txc);
+ void generateCuboidTextureCoords(aabb3f const &box, f32 *coords);
+ void drawAutoLightedCuboid(aabb3f box, const f32 *txc = NULL,
+ TileSpec *tiles = NULL, int tile_count = 0);
+
+// liquid-specific
+ bool top_is_same_liquid;
+ TileSpec tile_liquid;
+ TileSpec tile_liquid_top;
+ content_t c_flowing;
+ content_t c_source;
+ video::SColor color_liquid_top;
+ struct NeighborData {
+ f32 level;
+ content_t content;
+ bool is_same_liquid;
+ bool top_is_same_liquid;
+ };
+ NeighborData liquid_neighbors[3][3];
+ f32 corner_levels[2][2];
+ void prepareLiquidNodeDrawing();
+ void getLiquidNeighborhood();
+ void calculateCornerLevels();
+ f32 getCornerLevel(int i, int k);
+ void drawLiquidSides();
+ void drawLiquidTop();
+
+// raillike-specific
+ // name of the group that enables connecting to raillike nodes of different kind
+ static const std::string raillike_groupname;
+ int raillike_group;
+ bool isSameRail(v3s16 dir);
+
+// plantlike-specific
+ PlantlikeStyle draw_style;
+ v3f offset;
+ int rotate_degree;
+ bool random_offset_Y;
+ int face_num;
+
+ void drawPlantlikeQuad(float rotation, float quad_offset = 0,
+ bool offset_top_only = false);
+
+// firelike-specific
+ void drawFirelikeQuad(float rotation, float opening_angle,
+ float offset_h, float offset_v = 0.0);
+
+// drawtypes
+ void drawLiquidNode();
+ void drawGlasslikeNode();
+ void drawGlasslikeFramedNode();
+ void drawAllfacesNode();
+ void drawTorchlikeNode();
+ void drawSignlikeNode();
+ void drawPlantlikeNode();
+ void drawFirelikeNode();
+ void drawFencelikeNode();
+ void drawRaillikeNode();
+ void drawNodeboxNode();
+ void drawMeshNode();
+
+// common
+ void errorUnknownDrawtype();
+ void drawNode();
+
+public:
+ MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output);
+ void generate();
+};
+
+#endif
diff --git a/src/content_sao.cpp b/src/content_sao.cpp
index 77ab51a02..be1c52fe6 100644
--- a/src/content_sao.cpp
+++ b/src/content_sao.cpp
@@ -19,18 +19,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_sao.h"
#include "util/serialize.h"
-#include "util/mathconstants.h"
#include "collision.h"
#include "environment.h"
-#include "settings.h"
-#include "serialization.h" // For compressZlib
#include "tool.h" // For ToolCapabilities
#include "gamedef.h"
+#include "nodedef.h"
#include "remoteplayer.h"
#include "server.h"
-#include "scripting_game.h"
+#include "scripting_server.h"
#include "genericobject.h"
-#include "log.h"
std::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
@@ -93,13 +90,8 @@ public:
}
}
- bool getCollisionBox(aabb3f *toset) {
- return false;
- }
-
- bool collideWithObjects() {
- return false;
- }
+ bool getCollisionBox(aabb3f *toset) const { return false; }
+ bool collideWithObjects() const { return false; }
private:
float m_timer1;
@@ -110,6 +102,133 @@ private:
TestSAO proto_TestSAO(NULL, v3f(0,0,0));
/*
+ UnitSAO
+ */
+
+UnitSAO::UnitSAO(ServerEnvironment *env, v3f pos):
+ ServerActiveObject(env, pos),
+ m_hp(-1),
+ m_yaw(0),
+ m_properties_sent(true),
+ m_armor_groups_sent(false),
+ m_animation_range(0,0),
+ m_animation_speed(0),
+ m_animation_blend(0),
+ m_animation_loop(true),
+ m_animation_sent(false),
+ m_bone_position_sent(false),
+ m_attachment_parent_id(0),
+ m_attachment_sent(false)
+{
+ // Initialize something to armor groups
+ m_armor_groups["fleshy"] = 100;
+}
+
+bool UnitSAO::isAttached() const
+{
+ if (!m_attachment_parent_id)
+ return false;
+ // Check if the parent still exists
+ ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
+ if (obj)
+ return true;
+ return false;
+}
+
+void UnitSAO::setArmorGroups(const ItemGroupList &armor_groups)
+{
+ m_armor_groups = armor_groups;
+ m_armor_groups_sent = false;
+}
+
+const ItemGroupList &UnitSAO::getArmorGroups()
+{
+ return m_armor_groups;
+}
+
+void UnitSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop)
+{
+ // store these so they can be updated to clients
+ m_animation_range = frame_range;
+ m_animation_speed = frame_speed;
+ m_animation_blend = frame_blend;
+ m_animation_loop = frame_loop;
+ m_animation_sent = false;
+}
+
+void UnitSAO::getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop)
+{
+ *frame_range = m_animation_range;
+ *frame_speed = m_animation_speed;
+ *frame_blend = m_animation_blend;
+ *frame_loop = m_animation_loop;
+}
+
+void UnitSAO::setBonePosition(const std::string &bone, v3f position, v3f rotation)
+{
+ // store these so they can be updated to clients
+ m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
+ m_bone_position_sent = false;
+}
+
+void UnitSAO::getBonePosition(const std::string &bone, v3f *position, v3f *rotation)
+{
+ *position = m_bone_position[bone].X;
+ *rotation = m_bone_position[bone].Y;
+}
+
+void UnitSAO::setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation)
+{
+ // Attachments need to be handled on both the server and client.
+ // If we just attach on the server, we can only copy the position of the parent. Attachments
+ // are still sent to clients at an interval so players might see them lagging, plus we can't
+ // read and attach to skeletal bones.
+ // If we just attach on the client, the server still sees the child at its original location.
+ // This breaks some things so we also give the server the most accurate representation
+ // even if players only see the client changes.
+
+ m_attachment_parent_id = parent_id;
+ m_attachment_bone = bone;
+ m_attachment_position = position;
+ m_attachment_rotation = rotation;
+ m_attachment_sent = false;
+}
+
+void UnitSAO::getAttachment(int *parent_id, std::string *bone, v3f *position,
+ v3f *rotation)
+{
+ *parent_id = m_attachment_parent_id;
+ *bone = m_attachment_bone;
+ *position = m_attachment_position;
+ *rotation = m_attachment_rotation;
+}
+
+void UnitSAO::addAttachmentChild(int child_id)
+{
+ m_attachment_child_ids.insert(child_id);
+}
+
+void UnitSAO::removeAttachmentChild(int child_id)
+{
+ m_attachment_child_ids.erase(child_id);
+}
+
+const UNORDERED_SET<int> &UnitSAO::getAttachmentChildIds()
+{
+ return m_attachment_child_ids;
+}
+
+ObjectProperties* UnitSAO::accessObjectProperties()
+{
+ return &m_prop;
+}
+
+void UnitSAO::notifyObjectPropertiesModified()
+{
+ m_properties_sent = false;
+}
+
+/*
LuaEntitySAO
*/
@@ -124,29 +243,18 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
m_registered(false),
m_velocity(0,0,0),
m_acceleration(0,0,0),
- m_properties_sent(true),
m_last_sent_yaw(0),
m_last_sent_position(0,0,0),
m_last_sent_velocity(0,0,0),
m_last_sent_position_timer(0),
m_last_sent_move_precision(0),
- m_armor_groups_sent(false),
- m_animation_speed(0),
- m_animation_blend(0),
- m_animation_loop(true),
- m_animation_sent(false),
- m_bone_position_sent(false),
- m_attachment_parent_id(0),
- m_attachment_sent(false)
+ m_current_texture_modifier("")
{
// Only register type if no environment supplied
if(env == NULL){
ServerActiveObject::registerType(getType(), create);
return;
}
-
- // Initialize something to armor groups
- m_armor_groups["fleshy"] = 100;
}
LuaEntitySAO::~LuaEntitySAO()
@@ -218,17 +326,6 @@ ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
return sao;
}
-bool LuaEntitySAO::isAttached()
-{
- if(!m_attachment_parent_id)
- return false;
- // Check if the parent still exists
- ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
- if(obj)
- return true;
- return false;
-}
-
void LuaEntitySAO::step(float dtime, bool send_recommended)
{
if(!m_properties_sent)
@@ -272,7 +369,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
v3f p_pos = m_base_position;
v3f p_velocity = m_velocity;
v3f p_acceleration = m_acceleration;
- moveresult = collisionMoveSimple(m_env,m_env->getGameDef(),
+ moveresult = collisionMoveSimple(m_env, m_env->getGameDef(),
pos_max_d, box, m_prop.stepheight, dtime,
&p_pos, &p_velocity, p_acceleration,
this, m_prop.collideWithObjects);
@@ -309,6 +406,20 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
m_env->getScriptIface()->luaentity_Step(m_id, dtime);
}
+ // Remove LuaEntity beyond terrain edges
+ {
+ ServerMap *map = dynamic_cast<ServerMap *>(&m_env->getMap());
+ assert(map);
+ if (!m_pending_deactivation &&
+ map->saoPositionOverLimit(m_base_position)) {
+ infostream << "Remove SAO " << m_id << "(" << m_init_name
+ << "), outside of limits" << std::endl;
+ m_pending_deactivation = true;
+ m_removed = true;
+ return;
+ }
+ }
+
if(send_recommended == false)
return;
@@ -373,59 +484,48 @@ std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version)
{
std::ostringstream os(std::ios::binary);
- if(protocol_version >= 14)
- {
- writeU8(os, 1); // version
- os<<serializeString(""); // name
- writeU8(os, 0); // is_player
- writeS16(os, getId()); //id
- writeV3F1000(os, m_base_position);
- writeF1000(os, m_yaw);
- writeS16(os, m_hp);
-
- std::ostringstream msg_os(std::ios::binary);
- msg_os << serializeLongString(getPropertyPacket()); // message 1
- msg_os << serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
- msg_os << serializeLongString(gob_cmd_update_animation(
- m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop)); // 3
- for (UNORDERED_MAP<std::string, core::vector2d<v3f> >::const_iterator
- ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) {
- msg_os << serializeLongString(gob_cmd_update_bone_position((*ii).first,
- (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
- }
- msg_os << serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id,
- m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
- int message_count = 4 + m_bone_position.size();
- for (UNORDERED_SET<int>::const_iterator ii = m_attachment_child_ids.begin();
- (ii != m_attachment_child_ids.end()); ++ii) {
- if (ServerActiveObject *obj = m_env->getActiveObject(*ii)) {
- message_count++;
- msg_os << serializeLongString(gob_cmd_update_infant(*ii, obj->getSendType(),
- obj->getClientInitializationData(protocol_version)));
- }
- }
+ // protocol >= 14
+ writeU8(os, 1); // version
+ os << serializeString(""); // name
+ writeU8(os, 0); // is_player
+ writeS16(os, getId()); //id
+ writeV3F1000(os, m_base_position);
+ writeF1000(os, m_yaw);
+ writeS16(os, m_hp);
- writeU8(os, message_count);
- os.write(msg_os.str().c_str(), msg_os.str().size());
+ std::ostringstream msg_os(std::ios::binary);
+ msg_os << serializeLongString(getPropertyPacket()); // message 1
+ msg_os << serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
+ msg_os << serializeLongString(gob_cmd_update_animation(
+ m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop)); // 3
+ for (UNORDERED_MAP<std::string, core::vector2d<v3f> >::const_iterator
+ ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) {
+ msg_os << serializeLongString(gob_cmd_update_bone_position((*ii).first,
+ (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
}
- else
- {
- writeU8(os, 0); // version
- os<<serializeString(""); // name
- writeU8(os, 0); // is_player
- writeV3F1000(os, m_base_position);
- writeF1000(os, m_yaw);
- writeS16(os, m_hp);
- writeU8(os, 2); // number of messages stuffed in here
- os<<serializeLongString(getPropertyPacket()); // message 1
- os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
+ msg_os << serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id,
+ m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
+ int message_count = 4 + m_bone_position.size();
+ for (UNORDERED_SET<int>::const_iterator ii = m_attachment_child_ids.begin();
+ (ii != m_attachment_child_ids.end()); ++ii) {
+ if (ServerActiveObject *obj = m_env->getActiveObject(*ii)) {
+ message_count++;
+ msg_os << serializeLongString(gob_cmd_update_infant(*ii, obj->getSendType(),
+ obj->getClientInitializationData(protocol_version)));
+ }
}
+ msg_os << serializeLongString(gob_cmd_set_texture_mod(m_current_texture_modifier));
+ message_count++;
+
+ writeU8(os, message_count);
+ os.write(msg_os.str().c_str(), msg_os.str().size());
+
// return result
return os.str();
}
-std::string LuaEntitySAO::getStaticData()
+void LuaEntitySAO::getStaticData(std::string *result) const
{
verbosestream<<FUNCTION_NAME<<std::endl;
std::ostringstream os(std::ios::binary);
@@ -447,7 +547,7 @@ std::string LuaEntitySAO::getStaticData()
writeV3F1000(os, m_velocity);
// yaw
writeF1000(os, m_yaw);
- return os.str();
+ *result = os.str();
}
int LuaEntitySAO::punch(v3f dir,
@@ -478,28 +578,32 @@ int LuaEntitySAO::punch(v3f dir,
punchitem,
time_from_last_punch);
- if (result.did_punch) {
- setHP(getHP() - result.damage);
+ bool damage_handled = m_env->getScriptIface()->luaentity_Punch(m_id, puncher,
+ time_from_last_punch, toolcap, dir, result.did_punch ? result.damage : 0);
- if (result.damage > 0) {
- std::string punchername = puncher ? puncher->getDescription() : "nil";
+ if (!damage_handled) {
+ if (result.did_punch) {
+ setHP(getHP() - result.damage);
- actionstream << getDescription() << " punched by "
- << punchername << ", damage " << result.damage
- << " hp, health now " << getHP() << " hp" << std::endl;
- }
+ if (result.damage > 0) {
+ std::string punchername = puncher ? puncher->getDescription() : "nil";
- std::string str = gob_cmd_punched(result.damage, getHP());
- // create message and add to list
- ActiveObjectMessage aom(getId(), true, str);
- m_messages_out.push(aom);
+ actionstream << getDescription() << " punched by "
+ << punchername << ", damage " << result.damage
+ << " hp, health now " << getHP() << " hp" << std::endl;
+ }
+
+ std::string str = gob_cmd_punched(result.damage, getHP());
+ // create message and add to list
+ ActiveObjectMessage aom(getId(), true, str);
+ m_messages_out.push(aom);
+ }
}
if (getHP() == 0)
m_removed = true;
- m_env->getScriptIface()->luaentity_Punch(m_id, puncher,
- time_from_last_punch, toolcap, dir);
+
return result.wear;
}
@@ -558,97 +662,6 @@ s16 LuaEntitySAO::getHP() const
return m_hp;
}
-void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
-{
- m_armor_groups = armor_groups;
- m_armor_groups_sent = false;
-}
-
-ItemGroupList LuaEntitySAO::getArmorGroups()
-{
- return m_armor_groups;
-}
-
-void LuaEntitySAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop)
-{
- m_animation_range = frame_range;
- m_animation_speed = frame_speed;
- m_animation_blend = frame_blend;
- m_animation_loop = frame_loop;
- m_animation_sent = false;
-}
-
-void LuaEntitySAO::getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop)
-{
- *frame_range = m_animation_range;
- *frame_speed = m_animation_speed;
- *frame_blend = m_animation_blend;
- *frame_loop = m_animation_loop;
-}
-
-void LuaEntitySAO::setBonePosition(const std::string &bone, v3f position, v3f rotation)
-{
- m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
- m_bone_position_sent = false;
-}
-
-void LuaEntitySAO::getBonePosition(const std::string &bone, v3f *position, v3f *rotation)
-{
- *position = m_bone_position[bone].X;
- *rotation = m_bone_position[bone].Y;
-}
-
-void LuaEntitySAO::setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation)
-{
- // Attachments need to be handled on both the server and client.
- // If we just attach on the server, we can only copy the position of the parent. Attachments
- // are still sent to clients at an interval so players might see them lagging, plus we can't
- // read and attach to skeletal bones.
- // If we just attach on the client, the server still sees the child at its original location.
- // This breaks some things so we also give the server the most accurate representation
- // even if players only see the client changes.
-
- m_attachment_parent_id = parent_id;
- m_attachment_bone = bone;
- m_attachment_position = position;
- m_attachment_rotation = rotation;
- m_attachment_sent = false;
-}
-
-void LuaEntitySAO::getAttachment(int *parent_id, std::string *bone, v3f *position,
- v3f *rotation)
-{
- *parent_id = m_attachment_parent_id;
- *bone = m_attachment_bone;
- *position = m_attachment_position;
- *rotation = m_attachment_rotation;
-}
-
-void LuaEntitySAO::addAttachmentChild(int child_id)
-{
- m_attachment_child_ids.insert(child_id);
-}
-
-void LuaEntitySAO::removeAttachmentChild(int child_id)
-{
- m_attachment_child_ids.erase(child_id);
-}
-
-UNORDERED_SET<int> LuaEntitySAO::getAttachmentChildIds()
-{
- return m_attachment_child_ids;
-}
-
-ObjectProperties* LuaEntitySAO::accessObjectProperties()
-{
- return &m_prop;
-}
-
-void LuaEntitySAO::notifyObjectPropertiesModified()
-{
- m_properties_sent = false;
-}
-
void LuaEntitySAO::setVelocity(v3f velocity)
{
m_velocity = velocity;
@@ -672,11 +685,17 @@ v3f LuaEntitySAO::getAcceleration()
void LuaEntitySAO::setTextureMod(const std::string &mod)
{
std::string str = gob_cmd_set_texture_mod(mod);
+ m_current_texture_modifier = mod;
// create message and add to list
ActiveObjectMessage aom(getId(), true, str);
m_messages_out.push(aom);
}
+std::string LuaEntitySAO::getTextureMod() const
+{
+ return m_current_texture_modifier;
+}
+
void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
bool select_horiz_by_yawpitch)
{
@@ -731,7 +750,8 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
m_messages_out.push(aom);
}
-bool LuaEntitySAO::getCollisionBox(aabb3f *toset) {
+bool LuaEntitySAO::getCollisionBox(aabb3f *toset) const
+{
if (m_prop.physical)
{
//update collision box
@@ -747,7 +767,8 @@ bool LuaEntitySAO::getCollisionBox(aabb3f *toset) {
return false;
}
-bool LuaEntitySAO::collideWithObjects(){
+bool LuaEntitySAO::collideWithObjects() const
+{
return m_prop.collideWithObjects;
}
@@ -757,47 +778,41 @@ bool LuaEntitySAO::collideWithObjects(){
// No prototype, PlayerSAO does not need to be deserialized
-PlayerSAO::PlayerSAO(ServerEnvironment *env_, u16 peer_id_, bool is_singleplayer):
+PlayerSAO::PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, u16 peer_id_,
+ bool is_singleplayer):
UnitSAO(env_, v3f(0,0,0)),
- m_player(NULL),
+ m_player(player_),
m_peer_id(peer_id_),
m_inventory(NULL),
m_damage(0),
m_last_good_position(0,0,0),
+ m_time_from_last_teleport(0),
m_time_from_last_punch(0),
m_nocheat_dig_pos(32767, 32767, 32767),
m_nocheat_dig_time(0),
m_wield_index(0),
m_position_not_sent(false),
- m_armor_groups_sent(false),
- m_properties_sent(true),
m_is_singleplayer(is_singleplayer),
- m_animation_speed(0),
- m_animation_blend(0),
- m_animation_loop(true),
- m_animation_sent(false),
- m_bone_position_sent(false),
- m_attachment_parent_id(0),
- m_attachment_sent(false),
m_breath(PLAYER_MAX_BREATH),
m_pitch(0),
m_fov(0),
m_wanted_range(0),
+ m_extended_attributes_modified(false),
// public
m_physics_override_speed(1),
m_physics_override_jump(1),
m_physics_override_gravity(1),
m_physics_override_sneak(true),
- m_physics_override_sneak_glitch(true),
+ m_physics_override_sneak_glitch(false),
+ m_physics_override_new_move(true),
m_physics_override_sent(false)
{
assert(m_peer_id != 0); // pre-condition
- m_armor_groups["fleshy"] = 100;
m_prop.hp_max = PLAYER_MAX_HP;
m_prop.physical = false;
m_prop.weight = 75;
- m_prop.collisionbox = aabb3f(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.);
+ m_prop.collisionbox = aabb3f(-0.3f, -1.0f, -0.3f, 0.3f, 0.75f, 0.3f);
// start of default appearance, this should be overwritten by LUA
m_prop.visual = "upright_sprite";
m_prop.visual_size = v2f(1, 2);
@@ -819,7 +834,7 @@ PlayerSAO::~PlayerSAO()
delete m_inventory;
}
-void PlayerSAO::initialize(RemotePlayer *player, const std::set<std::string> &privs)
+void PlayerSAO::finalize(RemotePlayer *player, const std::set<std::string> &privs)
{
assert(player);
m_player = player;
@@ -827,6 +842,11 @@ void PlayerSAO::initialize(RemotePlayer *player, const std::set<std::string> &pr
m_inventory = &m_player->inventory;
}
+v3f PlayerSAO::getEyeOffset() const
+{
+ return v3f(0, BS * 1.625f, 0);
+}
+
std::string PlayerSAO::getDescription()
{
return std::string("player ") + m_player->getName();
@@ -855,93 +875,113 @@ void PlayerSAO::removingFromEnvironment()
}
}
-bool PlayerSAO::isStaticAllowed() const
-{
- return false;
-}
-
std::string PlayerSAO::getClientInitializationData(u16 protocol_version)
{
std::ostringstream os(std::ios::binary);
- if(protocol_version >= 15)
- {
- writeU8(os, 1); // version
- os<<serializeString(m_player->getName()); // name
- writeU8(os, 1); // is_player
- writeS16(os, getId()); //id
- writeV3F1000(os, m_base_position + v3f(0,BS*1,0));
- writeF1000(os, m_yaw);
- writeS16(os, getHP());
-
- std::ostringstream msg_os(std::ios::binary);
- msg_os << serializeLongString(getPropertyPacket()); // message 1
- msg_os << serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
- msg_os << serializeLongString(gob_cmd_update_animation(
- m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop)); // 3
- for (UNORDERED_MAP<std::string, core::vector2d<v3f> >::const_iterator
- ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) {
- msg_os << serializeLongString(gob_cmd_update_bone_position((*ii).first,
- (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
- }
- msg_os << serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id,
- m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
- msg_os << serializeLongString(gob_cmd_update_physics_override(m_physics_override_speed,
- m_physics_override_jump, m_physics_override_gravity, m_physics_override_sneak,
- m_physics_override_sneak_glitch)); // 5
- // (GENERIC_CMD_UPDATE_NAMETAG_ATTRIBUTES) : Deprecated, for backwards compatibility only.
- msg_os << serializeLongString(gob_cmd_update_nametag_attributes(m_prop.nametag_color)); // 6
- int message_count = 6 + m_bone_position.size();
- for (UNORDERED_SET<int>::const_iterator ii = m_attachment_child_ids.begin();
- ii != m_attachment_child_ids.end(); ++ii) {
- if (ServerActiveObject *obj = m_env->getActiveObject(*ii)) {
- message_count++;
- msg_os << serializeLongString(gob_cmd_update_infant(*ii, obj->getSendType(),
- obj->getClientInitializationData(protocol_version)));
- }
- }
-
- writeU8(os, message_count);
- os.write(msg_os.str().c_str(), msg_os.str().size());
+ // Protocol >= 15
+ writeU8(os, 1); // version
+ os << serializeString(m_player->getName()); // name
+ writeU8(os, 1); // is_player
+ writeS16(os, getId()); //id
+ writeV3F1000(os, m_base_position + v3f(0,BS*1,0));
+ writeF1000(os, m_yaw);
+ writeS16(os, getHP());
+
+ std::ostringstream msg_os(std::ios::binary);
+ msg_os << serializeLongString(getPropertyPacket()); // message 1
+ msg_os << serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
+ msg_os << serializeLongString(gob_cmd_update_animation(
+ m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop)); // 3
+ for (UNORDERED_MAP<std::string, core::vector2d<v3f> >::const_iterator
+ ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) {
+ msg_os << serializeLongString(gob_cmd_update_bone_position((*ii).first,
+ (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
}
- else
- {
- writeU8(os, 0); // version
- os<<serializeString(m_player->getName()); // name
- writeU8(os, 1); // is_player
- writeV3F1000(os, m_base_position + v3f(0,BS*1,0));
- writeF1000(os, m_yaw);
- writeS16(os, getHP());
- writeU8(os, 2); // number of messages stuffed in here
- os<<serializeLongString(getPropertyPacket()); // message 1
- os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
+ msg_os << serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id,
+ m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
+ msg_os << serializeLongString(gob_cmd_update_physics_override(m_physics_override_speed,
+ m_physics_override_jump, m_physics_override_gravity, m_physics_override_sneak,
+ m_physics_override_sneak_glitch, m_physics_override_new_move)); // 5
+ // (GENERIC_CMD_UPDATE_NAMETAG_ATTRIBUTES) : Deprecated, for backwards compatibility only.
+ msg_os << serializeLongString(gob_cmd_update_nametag_attributes(m_prop.nametag_color)); // 6
+ int message_count = 6 + m_bone_position.size();
+ for (UNORDERED_SET<int>::const_iterator ii = m_attachment_child_ids.begin();
+ ii != m_attachment_child_ids.end(); ++ii) {
+ if (ServerActiveObject *obj = m_env->getActiveObject(*ii)) {
+ message_count++;
+ msg_os << serializeLongString(gob_cmd_update_infant(*ii, obj->getSendType(),
+ obj->getClientInitializationData(protocol_version)));
+ }
}
+ writeU8(os, message_count);
+ os.write(msg_os.str().c_str(), msg_os.str().size());
+
// return result
return os.str();
}
-std::string PlayerSAO::getStaticData()
-{
- FATAL_ERROR("Deprecated function (?)");
- return "";
-}
-
-bool PlayerSAO::isAttached()
+void PlayerSAO::getStaticData(std::string *result) const
{
- if(!m_attachment_parent_id)
- return false;
- // Check if the parent still exists
- ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
- if(obj)
- return true;
- return false;
+ FATAL_ERROR("Deprecated function");
}
void PlayerSAO::step(float dtime, bool send_recommended)
{
- if(!m_properties_sent)
- {
+ if (m_drowning_interval.step(dtime, 2.0)) {
+ // get head position
+ v3s16 p = floatToInt(m_base_position + v3f(0, BS * 1.6, 0), BS);
+ MapNode n = m_env->getMap().getNodeNoEx(p);
+ const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n);
+ // If node generates drown
+ if (c.drowning > 0 && m_hp > 0) {
+ if (m_breath > 0)
+ setBreath(m_breath - 1);
+
+ // No more breath, damage player
+ if (m_breath == 0) {
+ setHP(m_hp - c.drowning);
+ m_env->getGameDef()->SendPlayerHPOrDie(this);
+ }
+ }
+ }
+
+ if (m_breathing_interval.step(dtime, 0.5)) {
+ // get head position
+ v3s16 p = floatToInt(m_base_position + v3f(0, BS * 1.6, 0), BS);
+ MapNode n = m_env->getMap().getNodeNoEx(p);
+ const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n);
+ // If player is alive & no drowning, breath
+ if (m_hp > 0 && m_breath < PLAYER_MAX_BREATH && c.drowning == 0)
+ setBreath(m_breath + 1);
+ }
+
+ if (m_node_hurt_interval.step(dtime, 1.0)) {
+ // Feet, middle and head
+ v3s16 p1 = floatToInt(m_base_position + v3f(0, BS*0.1, 0), BS);
+ MapNode n1 = m_env->getMap().getNodeNoEx(p1);
+ v3s16 p2 = floatToInt(m_base_position + v3f(0, BS*0.8, 0), BS);
+ MapNode n2 = m_env->getMap().getNodeNoEx(p2);
+ v3s16 p3 = floatToInt(m_base_position + v3f(0, BS*1.6, 0), BS);
+ MapNode n3 = m_env->getMap().getNodeNoEx(p3);
+
+ u32 damage_per_second = 0;
+ damage_per_second = MYMAX(damage_per_second,
+ m_env->getGameDef()->ndef()->get(n1).damage_per_second);
+ damage_per_second = MYMAX(damage_per_second,
+ m_env->getGameDef()->ndef()->get(n2).damage_per_second);
+ damage_per_second = MYMAX(damage_per_second,
+ m_env->getGameDef()->ndef()->get(n3).damage_per_second);
+
+ if (damage_per_second != 0 && m_hp > 0) {
+ s16 newhp = ((s32) damage_per_second > m_hp ? 0 : m_hp - damage_per_second);
+ setHP(newhp);
+ m_env->getGameDef()->SendPlayerHPOrDie(this);
+ }
+ }
+
+ if (!m_properties_sent) {
m_properties_sent = true;
std::string str = getPropertyPacket();
// create message and add to list
@@ -957,7 +997,7 @@ void PlayerSAO::step(float dtime, bool send_recommended)
m_attachment_position = v3f(0,0,0);
m_attachment_rotation = v3f(0,0,0);
setBasePosition(m_last_good_position);
- ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id);
+ m_env->getGameDef()->SendMovePlayer(m_peer_id);
}
//dstream<<"PlayerSAO::step: dtime: "<<dtime<<std::endl;
@@ -973,6 +1013,7 @@ void PlayerSAO::step(float dtime, bool send_recommended)
// Increment cheat prevention timers
m_dig_pool.add(dtime);
m_move_pool.add(dtime);
+ m_time_from_last_teleport += dtime;
m_time_from_last_punch += dtime;
m_nocheat_dig_time += dtime;
@@ -1024,7 +1065,8 @@ void PlayerSAO::step(float dtime, bool send_recommended)
m_physics_override_sent = true;
std::string str = gob_cmd_update_physics_override(m_physics_override_speed,
m_physics_override_jump, m_physics_override_gravity,
- m_physics_override_sneak, m_physics_override_sneak_glitch);
+ m_physics_override_sneak, m_physics_override_sneak_glitch,
+ m_physics_override_new_move);
// create message and add to list
ActiveObjectMessage aom(getId(), true, str);
m_messages_out.push(aom);
@@ -1079,7 +1121,9 @@ void PlayerSAO::setPos(const v3f &pos)
setBasePosition(pos);
// Movement caused by this command is always valid
m_last_good_position = pos;
- ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id);
+ m_move_pool.empty();
+ m_time_from_last_teleport = 0.0;
+ m_env->getGameDef()->SendMovePlayer(m_peer_id);
}
void PlayerSAO::moveTo(v3f pos, bool continuous)
@@ -1090,7 +1134,9 @@ void PlayerSAO::moveTo(v3f pos, bool continuous)
setBasePosition(pos);
// Movement caused by this command is always valid
m_last_good_position = pos;
- ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id);
+ m_move_pool.empty();
+ m_time_from_last_teleport = 0.0;
+ m_env->getGameDef()->SendMovePlayer(m_peer_id);
}
void PlayerSAO::setYaw(const float yaw)
@@ -1120,7 +1166,7 @@ void PlayerSAO::setWantedRange(const s16 range)
void PlayerSAO::setYawAndSend(const float yaw)
{
setYaw(yaw);
- ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id);
+ m_env->getGameDef()->SendMovePlayer(m_peer_id);
}
void PlayerSAO::setPitch(const float pitch)
@@ -1134,7 +1180,7 @@ void PlayerSAO::setPitch(const float pitch)
void PlayerSAO::setPitchAndSend(const float pitch)
{
setPitch(pitch);
- ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id);
+ m_env->getGameDef()->SendMovePlayer(m_peer_id);
}
int PlayerSAO::punch(v3f dir,
@@ -1198,10 +1244,6 @@ int PlayerSAO::punch(v3f dir,
return hitparams.wear;
}
-void PlayerSAO::rightClick(ServerActiveObject *)
-{
-}
-
s16 PlayerSAO::readDamage()
{
s16 damage = m_damage;
@@ -1237,105 +1279,15 @@ void PlayerSAO::setHP(s16 hp)
m_properties_sent = false;
}
-void PlayerSAO::setBreath(const u16 breath)
+void PlayerSAO::setBreath(const u16 breath, bool send)
{
if (m_player && breath != m_breath)
m_player->setDirty(true);
- m_breath = breath;
-}
+ m_breath = MYMIN(breath, PLAYER_MAX_BREATH);
-void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
-{
- m_armor_groups = armor_groups;
- m_armor_groups_sent = false;
-}
-
-ItemGroupList PlayerSAO::getArmorGroups()
-{
- return m_armor_groups;
-}
-
-void PlayerSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop)
-{
- // store these so they can be updated to clients
- m_animation_range = frame_range;
- m_animation_speed = frame_speed;
- m_animation_blend = frame_blend;
- m_animation_loop = frame_loop;
- m_animation_sent = false;
-}
-
-void PlayerSAO::getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop)
-{
- *frame_range = m_animation_range;
- *frame_speed = m_animation_speed;
- *frame_blend = m_animation_blend;
- *frame_loop = m_animation_loop;
-}
-
-void PlayerSAO::setBonePosition(const std::string &bone, v3f position, v3f rotation)
-{
- // store these so they can be updated to clients
- m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
- m_bone_position_sent = false;
-}
-
-void PlayerSAO::getBonePosition(const std::string &bone, v3f *position, v3f *rotation)
-{
- *position = m_bone_position[bone].X;
- *rotation = m_bone_position[bone].Y;
-}
-
-void PlayerSAO::setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation)
-{
- // Attachments need to be handled on both the server and client.
- // If we just attach on the server, we can only copy the position of the parent. Attachments
- // are still sent to clients at an interval so players might see them lagging, plus we can't
- // read and attach to skeletal bones.
- // If we just attach on the client, the server still sees the child at its original location.
- // This breaks some things so we also give the server the most accurate representation
- // even if players only see the client changes.
-
- m_attachment_parent_id = parent_id;
- m_attachment_bone = bone;
- m_attachment_position = position;
- m_attachment_rotation = rotation;
- m_attachment_sent = false;
-}
-
-void PlayerSAO::getAttachment(int *parent_id, std::string *bone, v3f *position,
- v3f *rotation)
-{
- *parent_id = m_attachment_parent_id;
- *bone = m_attachment_bone;
- *position = m_attachment_position;
- *rotation = m_attachment_rotation;
-}
-
-void PlayerSAO::addAttachmentChild(int child_id)
-{
- m_attachment_child_ids.insert(child_id);
-}
-
-void PlayerSAO::removeAttachmentChild(int child_id)
-{
- m_attachment_child_ids.erase(child_id);
-}
-
-UNORDERED_SET<int> PlayerSAO::getAttachmentChildIds()
-{
- return m_attachment_child_ids;
-}
-
-ObjectProperties* PlayerSAO::accessObjectProperties()
-{
- return &m_prop;
-}
-
-void PlayerSAO::notifyObjectPropertiesModified()
-{
- m_properties_sent = false;
+ if (send)
+ m_env->getGameDef()->SendPlayerBreath(this);
}
Inventory* PlayerSAO::getInventory()
@@ -1366,6 +1318,16 @@ ItemStack PlayerSAO::getWieldedItem() const
const InventoryList *mlist = inv->getList(getWieldList());
if (mlist && getWieldIndex() < (s32)mlist->getSize())
ret = mlist->getItem(getWieldIndex());
+ return ret;
+}
+
+ItemStack PlayerSAO::getWieldedItemOrHand() const
+{
+ const Inventory *inv = getInventory();
+ ItemStack ret;
+ const InventoryList *mlist = inv->getList(getWieldList());
+ if (mlist && getWieldIndex() < (s32)mlist->getSize())
+ ret = mlist->getItem(getWieldIndex());
if (ret.name.empty()) {
const InventoryList *hlist = inv->getList("hand");
if (hlist)
@@ -1380,14 +1342,6 @@ bool PlayerSAO::setWieldedItem(const ItemStack &item)
if (inv) {
InventoryList *mlist = inv->getList(getWieldList());
if (mlist) {
- ItemStack olditem = mlist->getItem(getWieldIndex());
- if (olditem.name.empty()) {
- InventoryList *hlist = inv->getList("hand");
- if (hlist) {
- hlist->changeItem(0, item);
- return true;
- }
- }
mlist->changeItem(getWieldIndex(), item);
return true;
}
@@ -1472,24 +1426,25 @@ bool PlayerSAO::checkMovementCheat()
if (m_move_pool.grab(required_time)) {
m_last_good_position = m_base_position;
} else {
- actionstream << "Player " << m_player->getName()
- << " moved too fast; resetting position"
- << std::endl;
+ const float LAG_POOL_MIN = 5.0;
+ float lag_pool_max = m_env->getMaxLagEstimate() * 2.0;
+ lag_pool_max = MYMAX(lag_pool_max, LAG_POOL_MIN);
+ if (m_time_from_last_teleport > lag_pool_max) {
+ actionstream << "Player " << m_player->getName()
+ << " moved too fast; resetting position"
+ << std::endl;
+ cheated = true;
+ }
setBasePosition(m_last_good_position);
- cheated = true;
}
return cheated;
}
-bool PlayerSAO::getCollisionBox(aabb3f *toset)
+bool PlayerSAO::getCollisionBox(aabb3f *toset) const
{
- *toset = aabb3f(-BS * 0.30, 0.0, -BS * 0.30, BS * 0.30, BS * 1.75, BS * 0.30);
+ *toset = aabb3f(-0.3f * BS, 0.0f, -0.3f * BS, 0.3f * BS, 1.75f * BS, 0.3f * BS);
+
toset->MinEdge += m_base_position;
toset->MaxEdge += m_base_position;
return true;
}
-
-bool PlayerSAO::collideWithObjects()
-{
- return true;
-}
diff --git a/src/content_sao.h b/src/content_sao.h
index 86255183d..0dad54805 100644
--- a/src/content_sao.h
+++ b/src/content_sao.h
@@ -20,17 +20,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef CONTENT_SAO_HEADER
#define CONTENT_SAO_HEADER
+#include <util/numeric.h>
#include "serverobject.h"
#include "itemgroup.h"
#include "object_properties.h"
-#include "constants.h"
class UnitSAO: public ServerActiveObject
{
public:
- UnitSAO(ServerEnvironment *env, v3f pos):
- ServerActiveObject(env, pos),
- m_hp(-1), m_yaw(0) {}
+ UnitSAO(ServerEnvironment *env, v3f pos);
virtual ~UnitSAO() {}
virtual void setYaw(const float yaw) { m_yaw = yaw; }
@@ -42,9 +40,47 @@ public:
s16 getHP() const { return m_hp; }
// Use a function, if isDead can be defined by other conditions
bool isDead() const { return m_hp == 0; }
+
+ bool isAttached() const;
+ void setArmorGroups(const ItemGroupList &armor_groups);
+ const ItemGroupList &getArmorGroups();
+ void setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop);
+ void getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop);
+ void setBonePosition(const std::string &bone, v3f position, v3f rotation);
+ void getBonePosition(const std::string &bone, v3f *position, v3f *rotation);
+ void setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation);
+ void getAttachment(int *parent_id, std::string *bone, v3f *position, v3f *rotation);
+ void addAttachmentChild(int child_id);
+ void removeAttachmentChild(int child_id);
+ const UNORDERED_SET<int> &getAttachmentChildIds();
+ ObjectProperties* accessObjectProperties();
+ void notifyObjectPropertiesModified();
protected:
s16 m_hp;
float m_yaw;
+
+ bool m_properties_sent;
+ struct ObjectProperties m_prop;
+
+ ItemGroupList m_armor_groups;
+ bool m_armor_groups_sent;
+
+ v2f m_animation_range;
+ float m_animation_speed;
+ float m_animation_blend;
+ bool m_animation_loop;
+ bool m_animation_sent;
+
+ // Stores position and rotation for each bone name
+ UNORDERED_MAP<std::string, core::vector2d<v3f> > m_bone_position;
+ bool m_bone_position_sent;
+
+ int m_attachment_parent_id;
+ UNORDERED_SET<int> m_attachment_child_ids;
+ std::string m_attachment_bone;
+ v3f m_attachment_position;
+ v3f m_attachment_rotation;
+ bool m_attachment_sent;
};
/*
@@ -64,10 +100,9 @@ public:
virtual void addedToEnvironment(u32 dtime_s);
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
- bool isAttached();
void step(float dtime, bool send_recommended);
std::string getClientInitializationData(u16 protocol_version);
- std::string getStaticData();
+ void getStaticData(std::string *result) const;
int punch(v3f dir,
const ToolCapabilities *toolcap=NULL,
ServerActiveObject *puncher=NULL,
@@ -79,19 +114,6 @@ public:
std::string getDescription();
void setHP(s16 hp);
s16 getHP() const;
- void setArmorGroups(const ItemGroupList &armor_groups);
- ItemGroupList getArmorGroups();
- void setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop);
- void getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop);
- void setBonePosition(const std::string &bone, v3f position, v3f rotation);
- void getBonePosition(const std::string &bone, v3f *position, v3f *rotation);
- void setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation);
- void getAttachment(int *parent_id, std::string *bone, v3f *position, v3f *rotation);
- void addAttachmentChild(int child_id);
- void removeAttachmentChild(int child_id);
- UNORDERED_SET<int> getAttachmentChildIds();
- ObjectProperties* accessObjectProperties();
- void notifyObjectPropertiesModified();
/* LuaEntitySAO-specific */
void setVelocity(v3f velocity);
v3f getVelocity();
@@ -99,11 +121,12 @@ public:
v3f getAcceleration();
void setTextureMod(const std::string &mod);
+ std::string getTextureMod() const;
void setSprite(v2s16 p, int num_frames, float framelength,
bool select_horiz_by_yawpitch);
std::string getName();
- bool getCollisionBox(aabb3f *toset);
- bool collideWithObjects();
+ bool getCollisionBox(aabb3f *toset) const;
+ bool collideWithObjects() const;
private:
std::string getPropertyPacket();
void sendPosition(bool do_interpolate, bool is_movement_end);
@@ -111,36 +134,16 @@ private:
std::string m_init_name;
std::string m_init_state;
bool m_registered;
- struct ObjectProperties m_prop;
v3f m_velocity;
v3f m_acceleration;
- ItemGroupList m_armor_groups;
-
- bool m_properties_sent;
float m_last_sent_yaw;
v3f m_last_sent_position;
v3f m_last_sent_velocity;
float m_last_sent_position_timer;
float m_last_sent_move_precision;
- bool m_armor_groups_sent;
-
- v2f m_animation_range;
- float m_animation_speed;
- float m_animation_blend;
- bool m_animation_loop;
- bool m_animation_sent;
-
- UNORDERED_MAP<std::string, core::vector2d<v3f> > m_bone_position;
- bool m_bone_position_sent;
-
- int m_attachment_parent_id;
- UNORDERED_SET<int> m_attachment_child_ids;
- std::string m_attachment_bone;
- v3f m_attachment_position;
- v3f m_attachment_rotation;
- bool m_attachment_sent;
+ std::string m_current_texture_modifier;
};
/*
@@ -154,18 +157,26 @@ class LagPool
public:
LagPool(): m_pool(15), m_max(15)
{}
+
void setMax(float new_max)
{
m_max = new_max;
if(m_pool > new_max)
m_pool = new_max;
}
+
void add(float dtime)
{
m_pool -= dtime;
if(m_pool < 0)
m_pool = 0;
}
+
+ void empty()
+ {
+ m_pool = m_max;
+ }
+
bool grab(float dtime)
{
if(dtime <= 0)
@@ -177,12 +188,13 @@ public:
}
};
+typedef UNORDERED_MAP<std::string, std::string> PlayerAttributes;
class RemotePlayer;
class PlayerSAO : public UnitSAO
{
public:
- PlayerSAO(ServerEnvironment *env_, u16 peer_id_, bool is_singleplayer);
+ PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, u16 peer_id_, bool is_singleplayer);
~PlayerSAO();
ActiveObjectType getType() const
{ return ACTIVEOBJECT_TYPE_PLAYER; }
@@ -196,10 +208,9 @@ public:
void addedToEnvironment(u32 dtime_s);
void removingFromEnvironment();
- bool isStaticAllowed() const;
+ bool isStaticAllowed() const { return false; }
std::string getClientInitializationData(u16 protocol_version);
- std::string getStaticData();
- bool isAttached();
+ void getStaticData(std::string *result) const;
void step(float dtime, bool send_recommended);
void setBasePosition(const v3f &position);
void setPos(const v3f &pos);
@@ -227,25 +238,12 @@ public:
const ToolCapabilities *toolcap,
ServerActiveObject *puncher,
float time_from_last_punch);
- void rightClick(ServerActiveObject *clicker);
+ void rightClick(ServerActiveObject *clicker) {}
void setHP(s16 hp);
void setHPRaw(s16 hp) { m_hp = hp; }
s16 readDamage();
u16 getBreath() const { return m_breath; }
- void setBreath(const u16 breath);
- void setArmorGroups(const ItemGroupList &armor_groups);
- ItemGroupList getArmorGroups();
- void setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop);
- void getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop);
- void setBonePosition(const std::string &bone, v3f position, v3f rotation);
- void getBonePosition(const std::string &bone, v3f *position, v3f *rotation);
- void setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation);
- void getAttachment(int *parent_id, std::string *bone, v3f *position, v3f *rotation);
- void addAttachmentChild(int child_id);
- void removeAttachmentChild(int child_id);
- UNORDERED_SET<int> getAttachmentChildIds();
- ObjectProperties* accessObjectProperties();
- void notifyObjectPropertiesModified();
+ void setBreath(const u16 breath, bool send = true);
/*
Inventory interface
@@ -256,11 +254,55 @@ public:
InventoryLocation getInventoryLocation() const;
std::string getWieldList() const;
ItemStack getWieldedItem() const;
+ ItemStack getWieldedItemOrHand() const;
bool setWieldedItem(const ItemStack &item);
int getWieldIndex() const;
void setWieldIndex(int i);
/*
+ Modding interface
+ */
+ inline void setExtendedAttribute(const std::string &attr, const std::string &value)
+ {
+ m_extra_attributes[attr] = value;
+ m_extended_attributes_modified = true;
+ }
+
+ inline bool getExtendedAttribute(const std::string &attr, std::string *value)
+ {
+ if (m_extra_attributes.find(attr) == m_extra_attributes.end())
+ return false;
+
+ *value = m_extra_attributes[attr];
+ return true;
+ }
+
+ inline void removeExtendedAttribute(const std::string &attr)
+ {
+ PlayerAttributes::iterator it = m_extra_attributes.find(attr);
+ if (it == m_extra_attributes.end())
+ return;
+
+ m_extra_attributes.erase(it);
+ m_extended_attributes_modified = true;
+ }
+
+ inline const PlayerAttributes &getExtendedAttributes()
+ {
+ return m_extra_attributes;
+ }
+
+ inline bool extendedAttributesModified() const
+ {
+ return m_extended_attributes_modified;
+ }
+
+ inline void setExtendedAttributeModified(bool v)
+ {
+ m_extended_attributes_modified = v;
+ }
+
+ /*
PlayerSAO-specific
*/
@@ -314,13 +356,13 @@ public:
m_is_singleplayer = is_singleplayer;
}
- bool getCollisionBox(aabb3f *toset);
- bool collideWithObjects();
+ bool getCollisionBox(aabb3f *toset) const;
+ bool collideWithObjects() const { return true; }
- void initialize(RemotePlayer *player, const std::set<std::string> &privs);
+ void finalize(RemotePlayer *player, const std::set<std::string> &privs);
v3f getEyePosition() const { return m_base_position + getEyeOffset(); }
- v3f getEyeOffset() const { return v3f(0, BS * 1.625f, 0); }
+ v3f getEyeOffset() const;
private:
std::string getPropertyPacket();
@@ -335,47 +377,37 @@ private:
LagPool m_dig_pool;
LagPool m_move_pool;
v3f m_last_good_position;
+ float m_time_from_last_teleport;
float m_time_from_last_punch;
v3s16 m_nocheat_dig_pos;
float m_nocheat_dig_time;
+ // Timers
+ IntervalLimiter m_breathing_interval;
+ IntervalLimiter m_drowning_interval;
+ IntervalLimiter m_node_hurt_interval;
+
int m_wield_index;
bool m_position_not_sent;
- ItemGroupList m_armor_groups;
- bool m_armor_groups_sent;
- bool m_properties_sent;
- struct ObjectProperties m_prop;
// Cached privileges for enforcement
std::set<std::string> m_privs;
bool m_is_singleplayer;
- v2f m_animation_range;
- float m_animation_speed;
- float m_animation_blend;
- bool m_animation_loop;
- bool m_animation_sent;
-
- // Stores position and rotation for each bone name
- UNORDERED_MAP<std::string, core::vector2d<v3f> > m_bone_position;
- bool m_bone_position_sent;
-
- int m_attachment_parent_id;
- UNORDERED_SET<int> m_attachment_child_ids;
- std::string m_attachment_bone;
- v3f m_attachment_position;
- v3f m_attachment_rotation;
- bool m_attachment_sent;
u16 m_breath;
f32 m_pitch;
f32 m_fov;
s16 m_wanted_range;
+
+ PlayerAttributes m_extra_attributes;
+ bool m_extended_attributes_modified;
public:
float m_physics_override_speed;
float m_physics_override_jump;
float m_physics_override_gravity;
bool m_physics_override_sneak;
bool m_physics_override_sneak_glitch;
+ bool m_physics_override_new_move;
bool m_physics_override_sent;
};
diff --git a/src/craftdef.cpp b/src/craftdef.cpp
index 45d3018a7..286d1eada 100644
--- a/src/craftdef.cpp
+++ b/src/craftdef.cpp
@@ -139,7 +139,7 @@ static std::vector<ItemStack> craftGetItems(
for (std::vector<std::string>::size_type i = 0;
i < items.size(); i++) {
result.push_back(ItemStack(std::string(items[i]), (u16)1,
- (u16)0, "", gamedef->getItemDefManager()));
+ (u16)0, gamedef->getItemDefManager()));
}
return result;
}
@@ -1126,4 +1126,3 @@ IWritableCraftDefManager* createCraftDefManager()
{
return new CCraftDefManager();
}
-
diff --git a/src/craftdef.h b/src/craftdef.h
index 695ee0c2c..bdd741f7c 100644
--- a/src/craftdef.h
+++ b/src/craftdef.h
@@ -97,7 +97,7 @@ struct CraftOutput
CraftOutput():
item(""), time(0)
{}
- CraftOutput(std::string item_, float time_):
+ CraftOutput(const std::string &item_, float time_):
item(item_), time(time_)
{}
std::string dump() const;
@@ -124,7 +124,7 @@ struct CraftReplacements
CraftReplacements():
pairs()
{}
- CraftReplacements(std::vector<std::pair<std::string, std::string> > pairs_):
+ CraftReplacements(const std::vector<std::pair<std::string, std::string> > &pairs_):
pairs(pairs_)
{}
std::string dump() const;
@@ -359,10 +359,13 @@ public:
CraftDefinitionFuel():
recipe(""), hash_inited(false), burntime()
{}
- CraftDefinitionFuel(std::string recipe_,
+ CraftDefinitionFuel(const std::string &recipe_,
float burntime_,
const CraftReplacements &replacements_):
- recipe(recipe_), hash_inited(false), burntime(burntime_), replacements(replacements_)
+ recipe(recipe_),
+ hash_inited(false),
+ burntime(burntime_),
+ replacements(replacements_)
{}
virtual ~CraftDefinitionFuel(){}
diff --git a/src/database-dummy.h b/src/database-dummy.h
index 72100edd0..7d1cb2279 100644
--- a/src/database-dummy.h
+++ b/src/database-dummy.h
@@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "database.h"
#include "irrlichttypes.h"
-class Database_Dummy : public Database
+class Database_Dummy : public MapDatabase, public PlayerDatabase
{
public:
bool saveBlock(const v3s16 &pos, const std::string &data);
@@ -33,9 +33,15 @@ public:
bool deleteBlock(const v3s16 &pos);
void listAllLoadableBlocks(std::vector<v3s16> &dst);
+ void savePlayer(RemotePlayer *player) {}
+ bool loadPlayer(RemotePlayer *player, PlayerSAO *sao) { return true; }
+ bool removePlayer(const std::string &name) { return true; }
+ void listPlayers(std::vector<std::string> &) {}
+
+ void beginSave() {}
+ void endSave() {}
private:
std::map<s64, std::string> m_database;
};
#endif
-
diff --git a/src/database-files.cpp b/src/database-files.cpp
new file mode 100644
index 000000000..3b130f91b
--- /dev/null
+++ b/src/database-files.cpp
@@ -0,0 +1,179 @@
+/*
+Minetest
+Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 <cassert>
+#include <json/json.h>
+#include "database-files.h"
+#include "content_sao.h"
+#include "remoteplayer.h"
+#include "settings.h"
+#include "porting.h"
+#include "filesys.h"
+
+// !!! WARNING !!!
+// This backend is intended to be used on Minetest 0.4.16 only for the transition backend
+// for player files
+
+void PlayerDatabaseFiles::serialize(std::ostringstream &os, RemotePlayer *player)
+{
+ // Utilize a Settings object for storing values
+ Settings args;
+ args.setS32("version", 1);
+ args.set("name", player->getName());
+
+ sanity_check(player->getPlayerSAO());
+ args.setS32("hp", player->getPlayerSAO()->getHP());
+ args.setV3F("position", player->getPlayerSAO()->getBasePosition());
+ args.setFloat("pitch", player->getPlayerSAO()->getPitch());
+ args.setFloat("yaw", player->getPlayerSAO()->getYaw());
+ args.setS32("breath", player->getPlayerSAO()->getBreath());
+
+ std::string extended_attrs = "";
+ player->serializeExtraAttributes(extended_attrs);
+ args.set("extended_attributes", extended_attrs);
+
+ args.writeLines(os);
+
+ os << "PlayerArgsEnd\n";
+
+ player->inventory.serialize(os);
+}
+
+void PlayerDatabaseFiles::savePlayer(RemotePlayer *player)
+{
+ std::string savedir = m_savedir + DIR_DELIM;
+ std::string path = savedir + player->getName();
+ bool path_found = false;
+ RemotePlayer testplayer("", NULL);
+
+ for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES && !path_found; i++) {
+ if (!fs::PathExists(path)) {
+ path_found = true;
+ continue;
+ }
+
+ // Open and deserialize file to check player name
+ std::ifstream is(path.c_str(), std::ios_base::binary);
+ if (!is.good()) {
+ errorstream << "Failed to open " << path << std::endl;
+ return;
+ }
+
+ testplayer.deSerialize(is, path, NULL);
+ is.close();
+ if (strcmp(testplayer.getName(), player->getName()) == 0) {
+ path_found = true;
+ continue;
+ }
+
+ path = savedir + player->getName() + itos(i);
+ }
+
+ if (!path_found) {
+ errorstream << "Didn't find free file for player " << player->getName()
+ << std::endl;
+ return;
+ }
+
+ // Open and serialize file
+ std::ostringstream ss(std::ios_base::binary);
+ serialize(ss, player);
+ if (!fs::safeWriteToFile(path, ss.str())) {
+ infostream << "Failed to write " << path << std::endl;
+ }
+ player->setModified(false);
+}
+
+bool PlayerDatabaseFiles::removePlayer(const std::string &name)
+{
+ std::string players_path = m_savedir + DIR_DELIM;
+ std::string path = players_path + name;
+
+ RemotePlayer temp_player("", NULL);
+ for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) {
+ // Open file and deserialize
+ std::ifstream is(path.c_str(), std::ios_base::binary);
+ if (!is.good())
+ continue;
+
+ temp_player.deSerialize(is, path, NULL);
+ is.close();
+
+ if (temp_player.getName() == name) {
+ fs::DeleteSingleFileOrEmptyDirectory(path);
+ return true;
+ }
+
+ path = players_path + name + itos(i);
+ }
+
+ return false;
+}
+
+bool PlayerDatabaseFiles::loadPlayer(RemotePlayer *player, PlayerSAO *sao)
+{
+ std::string players_path = m_savedir + DIR_DELIM;
+ std::string path = players_path + player->getName();
+
+ const std::string player_to_load = player->getName();
+ for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) {
+ // Open file and deserialize
+ std::ifstream is(path.c_str(), std::ios_base::binary);
+ if (!is.good())
+ continue;
+
+ player->deSerialize(is, path, sao);
+ is.close();
+
+ if (player->getName() == player_to_load)
+ return true;
+
+ path = players_path + player_to_load + itos(i);
+ }
+
+ infostream << "Player file for player " << player_to_load << " not found" << std::endl;
+ return false;
+}
+
+void PlayerDatabaseFiles::listPlayers(std::vector<std::string> &res)
+{
+ std::vector<fs::DirListNode> files = fs::GetDirListing(m_savedir);
+ // list files into players directory
+ for (std::vector<fs::DirListNode>::const_iterator it = files.begin(); it !=
+ files.end(); ++it) {
+ // Ignore directories
+ if (it->dir)
+ continue;
+
+ const std::string &filename = it->name;
+ std::string full_path = m_savedir + DIR_DELIM + filename;
+ std::ifstream is(full_path.c_str(), std::ios_base::binary);
+ if (!is.good())
+ continue;
+
+ RemotePlayer player(filename.c_str(), NULL);
+ // Null env & dummy peer_id
+ PlayerSAO playerSAO(NULL, &player, 15789, false);
+
+ player.deSerialize(is, "", &playerSAO);
+ is.close();
+
+ res.push_back(player.getName());
+ }
+}
diff --git a/src/database-files.h b/src/database-files.h
new file mode 100644
index 000000000..888362249
--- /dev/null
+++ b/src/database-files.h
@@ -0,0 +1,46 @@
+/*
+Minetest
+Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 DATABASE_FILES_HEADER
+#define DATABASE_FILES_HEADER
+
+// !!! WARNING !!!
+// This backend is intended to be used on Minetest 0.4.16 only for the transition backend
+// for player files
+
+#include "database.h"
+
+class PlayerDatabaseFiles : public PlayerDatabase
+{
+public:
+ PlayerDatabaseFiles(const std::string &savedir) : m_savedir(savedir) {}
+ virtual ~PlayerDatabaseFiles() {}
+
+ void savePlayer(RemotePlayer *player);
+ bool loadPlayer(RemotePlayer *player, PlayerSAO *sao);
+ bool removePlayer(const std::string &name);
+ void listPlayers(std::vector<std::string> &res);
+
+private:
+ void serialize(std::ostringstream &os, RemotePlayer *player);
+
+ std::string m_savedir;
+};
+
+#endif
diff --git a/src/database-leveldb.h b/src/database-leveldb.h
index 3993db0c3..52ccebe70 100644
--- a/src/database-leveldb.h
+++ b/src/database-leveldb.h
@@ -24,11 +24,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#if USE_LEVELDB
+#include <string>
#include "database.h"
#include "leveldb/db.h"
-#include <string>
-class Database_LevelDB : public Database
+class Database_LevelDB : public MapDatabase
{
public:
Database_LevelDB(const std::string &savedir);
@@ -39,6 +39,8 @@ public:
bool deleteBlock(const v3s16 &pos);
void listAllLoadableBlocks(std::vector<v3s16> &dst);
+ void beginSave() {}
+ void endSave() {}
private:
leveldb::DB *m_database;
};
@@ -46,4 +48,3 @@ private:
#endif // USE_LEVELDB
#endif
-
diff --git a/src/database-postgresql.cpp b/src/database-postgresql.cpp
index 3b6b42aea..a6b62bad5 100644
--- a/src/database-postgresql.cpp
+++ b/src/database-postgresql.cpp
@@ -39,13 +39,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
#include "exceptions.h"
#include "settings.h"
+#include "content_sao.h"
+#include "remoteplayer.h"
-Database_PostgreSQL::Database_PostgreSQL(const Settings &conf) :
- m_connect_string(""),
+Database_PostgreSQL::Database_PostgreSQL(const std::string &connect_string) :
+ m_connect_string(connect_string),
m_conn(NULL),
m_pgversion(0)
{
- if (!conf.getNoEx("pgsql_connection", m_connect_string)) {
+ if (m_connect_string.empty()) {
throw SettingNotFoundException(
"Set pgsql_connection string in world.mt to "
"use the postgresql backend\n"
@@ -57,8 +59,6 @@ Database_PostgreSQL::Database_PostgreSQL(const Settings &conf) :
"DELETE rights on the database.\n"
"Don't create mt_user as a SUPERUSER!");
}
-
- connectToDatabase();
}
Database_PostgreSQL::~Database_PostgreSQL()
@@ -80,12 +80,12 @@ void Database_PostgreSQL::connectToDatabase()
/*
* We are using UPSERT feature from PostgreSQL 9.5
- * to have the better performance,
- * set the minimum version to 90500
+ * to have the better performance where possible.
*/
if (m_pgversion < 90500) {
- throw DatabaseException("PostgreSQL database error: "
- "Server version 9.5 or greater required.");
+ warningstream << "Your PostgreSQL server lacks UPSERT "
+ << "support. Use version 9.5 or better if possible."
+ << std::endl;
}
infostream << "PostgreSQL Database: Version " << m_pgversion
@@ -118,26 +118,6 @@ bool Database_PostgreSQL::initialized() const
return (PQstatus(m_conn) == CONNECTION_OK);
}
-void Database_PostgreSQL::initStatements()
-{
- prepareStatement("read_block",
- "SELECT data FROM blocks "
- "WHERE posX = $1::int4 AND posY = $2::int4 AND "
- "posZ = $3::int4");
-
- prepareStatement("write_block",
- "INSERT INTO blocks (posX, posY, posZ, data) VALUES "
- "($1::int4, $2::int4, $3::int4, $4::bytea) "
- "ON CONFLICT ON CONSTRAINT blocks_pkey DO "
- "UPDATE SET data = $4::bytea");
-
- prepareStatement("delete_block", "DELETE FROM blocks WHERE "
- "posX = $1::int4 AND posY = $2::int4 AND posZ = $3::int4");
-
- prepareStatement("list_all_loadable_blocks",
- "SELECT posX, posY, posZ FROM blocks");
-}
-
PGresult *Database_PostgreSQL::checkResults(PGresult *result, bool clear)
{
ExecStatusType statusType = PQresultStatus(result);
@@ -159,30 +139,21 @@ PGresult *Database_PostgreSQL::checkResults(PGresult *result, bool clear)
return result;
}
-void Database_PostgreSQL::createDatabase()
+void Database_PostgreSQL::createTableIfNotExists(const std::string &table_name,
+ const std::string &definition)
{
- PGresult *result = checkResults(PQexec(m_conn,
- "SELECT relname FROM pg_class WHERE relname='blocks';"),
- false);
+ std::string sql_check_table = "SELECT relname FROM pg_class WHERE relname='" +
+ table_name + "';";
+ PGresult *result = checkResults(PQexec(m_conn, sql_check_table.c_str()), false);
// If table doesn't exist, create it
if (!PQntuples(result)) {
- static const char* dbcreate_sql = "CREATE TABLE blocks ("
- "posX INT NOT NULL,"
- "posY INT NOT NULL,"
- "posZ INT NOT NULL,"
- "data BYTEA,"
- "PRIMARY KEY (posX,posY,posZ)"
- ");";
- checkResults(PQexec(m_conn, dbcreate_sql));
+ checkResults(PQexec(m_conn, definition.c_str()));
}
PQclear(result);
-
- infostream << "PostgreSQL: Game Database was inited." << std::endl;
}
-
void Database_PostgreSQL::beginSave()
{
verifyDatabase();
@@ -194,14 +165,70 @@ void Database_PostgreSQL::endSave()
checkResults(PQexec(m_conn, "COMMIT;"));
}
-bool Database_PostgreSQL::saveBlock(const v3s16 &pos,
- const std::string &data)
+MapDatabasePostgreSQL::MapDatabasePostgreSQL(const std::string &connect_string):
+ Database_PostgreSQL(connect_string),
+ MapDatabase()
+{
+ connectToDatabase();
+}
+
+
+void MapDatabasePostgreSQL::createDatabase()
+{
+ createTableIfNotExists("blocks",
+ "CREATE TABLE blocks ("
+ "posX INT NOT NULL,"
+ "posY INT NOT NULL,"
+ "posZ INT NOT NULL,"
+ "data BYTEA,"
+ "PRIMARY KEY (posX,posY,posZ)"
+ ");"
+ );
+
+ infostream << "PostgreSQL: Map Database was initialized." << std::endl;
+}
+
+void MapDatabasePostgreSQL::initStatements()
+{
+ prepareStatement("read_block",
+ "SELECT data FROM blocks "
+ "WHERE posX = $1::int4 AND posY = $2::int4 AND "
+ "posZ = $3::int4");
+
+ if (getPGVersion() < 90500) {
+ prepareStatement("write_block_insert",
+ "INSERT INTO blocks (posX, posY, posZ, data) SELECT "
+ "$1::int4, $2::int4, $3::int4, $4::bytea "
+ "WHERE NOT EXISTS (SELECT true FROM blocks "
+ "WHERE posX = $1::int4 AND posY = $2::int4 AND "
+ "posZ = $3::int4)");
+
+ prepareStatement("write_block_update",
+ "UPDATE blocks SET data = $4::bytea "
+ "WHERE posX = $1::int4 AND posY = $2::int4 AND "
+ "posZ = $3::int4");
+ } else {
+ prepareStatement("write_block",
+ "INSERT INTO blocks (posX, posY, posZ, data) VALUES "
+ "($1::int4, $2::int4, $3::int4, $4::bytea) "
+ "ON CONFLICT ON CONSTRAINT blocks_pkey DO "
+ "UPDATE SET data = $4::bytea");
+ }
+
+ prepareStatement("delete_block", "DELETE FROM blocks WHERE "
+ "posX = $1::int4 AND posY = $2::int4 AND posZ = $3::int4");
+
+ prepareStatement("list_all_loadable_blocks",
+ "SELECT posX, posY, posZ FROM blocks");
+}
+
+bool MapDatabasePostgreSQL::saveBlock(const v3s16 &pos, const std::string &data)
{
// Verify if we don't overflow the platform integer with the mapblock size
if (data.size() > INT_MAX) {
errorstream << "Database_PostgreSQL::saveBlock: Data truncation! "
- << "data.size() over 0xFFFF (== " << data.size()
- << ")" << std::endl;
+ << "data.size() over 0xFFFFFFFF (== " << data.size()
+ << ")" << std::endl;
return false;
}
@@ -218,12 +245,16 @@ bool Database_PostgreSQL::saveBlock(const v3s16 &pos,
};
const int argFmt[] = { 1, 1, 1, 1 };
- execPrepared("write_block", ARRLEN(args), args, argLen, argFmt);
+ if (getPGVersion() < 90500) {
+ execPrepared("write_block_update", ARRLEN(args), args, argLen, argFmt);
+ execPrepared("write_block_insert", ARRLEN(args), args, argLen, argFmt);
+ } else {
+ execPrepared("write_block", ARRLEN(args), args, argLen, argFmt);
+ }
return true;
}
-void Database_PostgreSQL::loadBlock(const v3s16 &pos,
- std::string *block)
+void MapDatabasePostgreSQL::loadBlock(const v3s16 &pos, std::string *block)
{
verifyDatabase();
@@ -237,19 +268,17 @@ void Database_PostgreSQL::loadBlock(const v3s16 &pos,
const int argFmt[] = { 1, 1, 1 };
PGresult *results = execPrepared("read_block", ARRLEN(args), args,
- argLen, argFmt, false);
+ argLen, argFmt, false);
*block = "";
- if (PQntuples(results)) {
- *block = std::string(PQgetvalue(results, 0, 0),
- PQgetlength(results, 0, 0));
- }
+ if (PQntuples(results))
+ *block = std::string(PQgetvalue(results, 0, 0), PQgetlength(results, 0, 0));
PQclear(results);
}
-bool Database_PostgreSQL::deleteBlock(const v3s16 &pos)
+bool MapDatabasePostgreSQL::deleteBlock(const v3s16 &pos)
{
verifyDatabase();
@@ -262,24 +291,344 @@ bool Database_PostgreSQL::deleteBlock(const v3s16 &pos)
const int argLen[] = { sizeof(x), sizeof(y), sizeof(z) };
const int argFmt[] = { 1, 1, 1 };
- execPrepared("read_block", ARRLEN(args), args, argLen, argFmt);
+ execPrepared("delete_block", ARRLEN(args), args, argLen, argFmt);
return true;
}
-void Database_PostgreSQL::listAllLoadableBlocks(std::vector<v3s16> &dst)
+void MapDatabasePostgreSQL::listAllLoadableBlocks(std::vector<v3s16> &dst)
{
verifyDatabase();
PGresult *results = execPrepared("list_all_loadable_blocks", 0,
- NULL, NULL, NULL, false, false);
+ NULL, NULL, NULL, false, false);
int numrows = PQntuples(results);
- for (int row = 0; row < numrows; ++row) {
+ for (int row = 0; row < numrows; ++row)
dst.push_back(pg_to_v3s16(results, 0, 0));
+
+ PQclear(results);
+}
+
+/*
+ * Player Database
+ */
+PlayerDatabasePostgreSQL::PlayerDatabasePostgreSQL(const std::string &connect_string):
+ Database_PostgreSQL(connect_string),
+ PlayerDatabase()
+{
+ connectToDatabase();
+}
+
+
+void PlayerDatabasePostgreSQL::createDatabase()
+{
+ createTableIfNotExists("player",
+ "CREATE TABLE player ("
+ "name VARCHAR(60) NOT NULL,"
+ "pitch NUMERIC(15, 7) NOT NULL,"
+ "yaw NUMERIC(15, 7) NOT NULL,"
+ "posX NUMERIC(15, 7) NOT NULL,"
+ "posY NUMERIC(15, 7) NOT NULL,"
+ "posZ NUMERIC(15, 7) NOT NULL,"
+ "hp INT NOT NULL,"
+ "breath INT NOT NULL,"
+ "creation_date TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT NOW(),"
+ "modification_date TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT NOW(),"
+ "PRIMARY KEY (name)"
+ ");"
+ );
+
+ createTableIfNotExists("player_inventories",
+ "CREATE TABLE player_inventories ("
+ "player VARCHAR(60) NOT NULL,"
+ "inv_id INT NOT NULL,"
+ "inv_width INT NOT NULL,"
+ "inv_name TEXT NOT NULL DEFAULT '',"
+ "inv_size INT NOT NULL,"
+ "PRIMARY KEY(player, inv_id),"
+ "CONSTRAINT player_inventories_fkey FOREIGN KEY (player) REFERENCES "
+ "player (name) ON DELETE CASCADE"
+ ");"
+ );
+
+ createTableIfNotExists("player_inventory_items",
+ "CREATE TABLE player_inventory_items ("
+ "player VARCHAR(60) NOT NULL,"
+ "inv_id INT NOT NULL,"
+ "slot_id INT NOT NULL,"
+ "item TEXT NOT NULL DEFAULT '',"
+ "PRIMARY KEY(player, inv_id, slot_id),"
+ "CONSTRAINT player_inventory_items_fkey FOREIGN KEY (player) REFERENCES "
+ "player (name) ON DELETE CASCADE"
+ ");"
+ );
+
+ createTableIfNotExists("player_metadata",
+ "CREATE TABLE player_metadata ("
+ "player VARCHAR(60) NOT NULL,"
+ "attr VARCHAR(256) NOT NULL,"
+ "value TEXT,"
+ "PRIMARY KEY(player, attr),"
+ "CONSTRAINT player_metadata_fkey FOREIGN KEY (player) REFERENCES "
+ "player (name) ON DELETE CASCADE"
+ ");"
+ );
+
+ infostream << "PostgreSQL: Player Database was inited." << std::endl;
+}
+
+void PlayerDatabasePostgreSQL::initStatements()
+{
+ if (getPGVersion() < 90500) {
+ prepareStatement("create_player",
+ "INSERT INTO player(name, pitch, yaw, posX, posY, posZ, hp, breath) VALUES "
+ "($1, $2, $3, $4, $5, $6, $7::int, $8::int)");
+
+ prepareStatement("update_player",
+ "UPDATE SET pitch = $2, yaw = $3, posX = $4, posY = $5, posZ = $6, hp = $7::int, "
+ "breath = $8::int, modification_date = NOW() WHERE name = $1");
+ } else {
+ prepareStatement("save_player",
+ "INSERT INTO player(name, pitch, yaw, posX, posY, posZ, hp, breath) VALUES "
+ "($1, $2, $3, $4, $5, $6, $7::int, $8::int)"
+ "ON CONFLICT ON CONSTRAINT player_pkey DO UPDATE SET pitch = $2, yaw = $3, "
+ "posX = $4, posY = $5, posZ = $6, hp = $7::int, breath = $8::int, "
+ "modification_date = NOW()");
}
+ prepareStatement("remove_player", "DELETE FROM player WHERE name = $1");
+
+ prepareStatement("load_player_list", "SELECT name FROM player");
+
+ prepareStatement("remove_player_inventories",
+ "DELETE FROM player_inventories WHERE player = $1");
+
+ prepareStatement("remove_player_inventory_items",
+ "DELETE FROM player_inventory_items WHERE player = $1");
+
+ prepareStatement("add_player_inventory",
+ "INSERT INTO player_inventories (player, inv_id, inv_width, inv_name, inv_size) VALUES "
+ "($1, $2::int, $3::int, $4, $5::int)");
+
+ prepareStatement("add_player_inventory_item",
+ "INSERT INTO player_inventory_items (player, inv_id, slot_id, item) VALUES "
+ "($1, $2::int, $3::int, $4)");
+
+ prepareStatement("load_player_inventories",
+ "SELECT inv_id, inv_width, inv_name, inv_size FROM player_inventories "
+ "WHERE player = $1 ORDER BY inv_id");
+
+ prepareStatement("load_player_inventory_items",
+ "SELECT slot_id, item FROM player_inventory_items WHERE "
+ "player = $1 AND inv_id = $2::int");
+
+ prepareStatement("load_player",
+ "SELECT pitch, yaw, posX, posY, posZ, hp, breath FROM player WHERE name = $1");
+
+ prepareStatement("remove_player_metadata",
+ "DELETE FROM player_metadata WHERE player = $1");
+
+ prepareStatement("save_player_metadata",
+ "INSERT INTO player_metadata (player, attr, value) VALUES ($1, $2, $3)");
+
+ prepareStatement("load_player_metadata",
+ "SELECT attr, value FROM player_metadata WHERE player = $1");
+
+}
+
+bool PlayerDatabasePostgreSQL::playerDataExists(const std::string &playername)
+{
+ verifyDatabase();
+
+ const char *values[] = { playername.c_str() };
+ PGresult *results = execPrepared("load_player", 1, values, false);
+
+ bool res = (PQntuples(results) > 0);
+ PQclear(results);
+ return res;
+}
+
+void PlayerDatabasePostgreSQL::savePlayer(RemotePlayer *player)
+{
+ PlayerSAO* sao = player->getPlayerSAO();
+ if (!sao)
+ return;
+
+ verifyDatabase();
+
+ v3f pos = sao->getBasePosition();
+ std::string pitch = ftos(sao->getPitch());
+ std::string yaw = ftos(sao->getYaw());
+ std::string posx = ftos(pos.X);
+ std::string posy = ftos(pos.Y);
+ std::string posz = ftos(pos.Z);
+ std::string hp = itos(sao->getHP());
+ std::string breath = itos(sao->getBreath());
+ const char *values[] = {
+ player->getName(),
+ pitch.c_str(),
+ yaw.c_str(),
+ posx.c_str(), posy.c_str(), posz.c_str(),
+ hp.c_str(),
+ breath.c_str()
+ };
+
+ const char* rmvalues[] = { player->getName() };
+ beginSave();
+
+ if (getPGVersion() < 90500) {
+ if (!playerDataExists(player->getName()))
+ execPrepared("create_player", 8, values, true, false);
+ else
+ execPrepared("update_player", 8, values, true, false);
+ }
+ else
+ execPrepared("save_player", 8, values, true, false);
+
+ // Write player inventories
+ execPrepared("remove_player_inventories", 1, rmvalues);
+ execPrepared("remove_player_inventory_items", 1, rmvalues);
+
+ std::vector<const InventoryList*> inventory_lists = sao->getInventory()->getLists();
+ for (u16 i = 0; i < inventory_lists.size(); i++) {
+ const InventoryList* list = inventory_lists[i];
+ std::string name = list->getName(), width = itos(list->getWidth()),
+ inv_id = itos(i), lsize = itos(list->getSize());
+
+ const char* inv_values[] = {
+ player->getName(),
+ inv_id.c_str(),
+ width.c_str(),
+ name.c_str(),
+ lsize.c_str()
+ };
+ execPrepared("add_player_inventory", 5, inv_values);
+
+ for (u32 j = 0; j < list->getSize(); j++) {
+ std::ostringstream os;
+ list->getItem(j).serialize(os);
+ std::string itemStr = os.str(), slotId = itos(j);
+
+ const char* invitem_values[] = {
+ player->getName(),
+ inv_id.c_str(),
+ slotId.c_str(),
+ itemStr.c_str()
+ };
+ execPrepared("add_player_inventory_item", 4, invitem_values);
+ }
+ }
+
+ execPrepared("remove_player_metadata", 1, rmvalues);
+ const PlayerAttributes &attrs = sao->getExtendedAttributes();
+ for (PlayerAttributes::const_iterator it = attrs.begin(); it != attrs.end(); ++it) {
+ const char *meta_values[] = {
+ player->getName(),
+ it->first.c_str(),
+ it->second.c_str()
+ };
+ execPrepared("save_player_metadata", 3, meta_values);
+ }
+ endSave();
+}
+
+bool PlayerDatabasePostgreSQL::loadPlayer(RemotePlayer *player, PlayerSAO *sao)
+{
+ sanity_check(sao);
+ verifyDatabase();
+
+ const char *values[] = { player->getName() };
+ PGresult *results = execPrepared("load_player", 1, values, false, false);
+
+ // Player not found, return not found
+ if (!PQntuples(results)) {
+ PQclear(results);
+ return false;
+ }
+
+ sao->setPitch(pg_to_float(results, 0, 0));
+ sao->setYaw(pg_to_float(results, 0, 1));
+ sao->setBasePosition(v3f(
+ pg_to_float(results, 0, 2),
+ pg_to_float(results, 0, 3),
+ pg_to_float(results, 0, 4))
+ );
+ sao->setHPRaw((s16) pg_to_int(results, 0, 5));
+ sao->setBreath((u16) pg_to_int(results, 0, 6), false);
+
+ PQclear(results);
+
+ // Load inventory
+ results = execPrepared("load_player_inventories", 1, values, false, false);
+
+ int resultCount = PQntuples(results);
+
+ for (int row = 0; row < resultCount; ++row) {
+ InventoryList* invList = player->inventory.
+ addList(PQgetvalue(results, row, 2), pg_to_uint(results, row, 3));
+ invList->setWidth(pg_to_uint(results, row, 1));
+
+ u32 invId = pg_to_uint(results, row, 0);
+ std::string invIdStr = itos(invId);
+
+ const char* values2[] = {
+ player->getName(),
+ invIdStr.c_str()
+ };
+ PGresult *results2 = execPrepared("load_player_inventory_items", 2,
+ values2, false, false);
+
+ int resultCount2 = PQntuples(results2);
+ for (int row2 = 0; row2 < resultCount2; row2++) {
+ const std::string itemStr = PQgetvalue(results2, row2, 1);
+ if (itemStr.length() > 0) {
+ ItemStack stack;
+ stack.deSerialize(itemStr);
+ invList->addItem(pg_to_uint(results2, row2, 0), stack);
+ }
+ }
+ PQclear(results2);
+ }
+
+ PQclear(results);
+
+ results = execPrepared("load_player_metadata", 1, values, false);
+
+ int numrows = PQntuples(results);
+ for (int row = 0; row < numrows; row++) {
+ sao->setExtendedAttribute(PQgetvalue(results, row, 0),PQgetvalue(results, row, 1));
+ }
+
+ PQclear(results);
+
+ return true;
+}
+
+bool PlayerDatabasePostgreSQL::removePlayer(const std::string &name)
+{
+ if (!playerDataExists(name))
+ return false;
+
+ verifyDatabase();
+
+ const char *values[] = { name.c_str() };
+ execPrepared("remove_player", 1, values);
+
+ return true;
+}
+
+void PlayerDatabasePostgreSQL::listPlayers(std::vector<std::string> &res)
+{
+ verifyDatabase();
+
+ PGresult *results = execPrepared("load_player_list", 0, NULL, false);
+
+ int numrows = PQntuples(results);
+ for (int row = 0; row < numrows; row++)
+ res.push_back(PQgetvalue(results, row, 0));
+
PQclear(results);
}
diff --git a/src/database-postgresql.h b/src/database-postgresql.h
index 1cfa544e3..d6f208fd9 100644
--- a/src/database-postgresql.h
+++ b/src/database-postgresql.h
@@ -27,53 +27,33 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Settings;
-class Database_PostgreSQL : public Database
+class Database_PostgreSQL: public Database
{
public:
- Database_PostgreSQL(const Settings &conf);
+ Database_PostgreSQL(const std::string &connect_string);
~Database_PostgreSQL();
void beginSave();
void endSave();
- bool saveBlock(const v3s16 &pos, const std::string &data);
- void loadBlock(const v3s16 &pos, std::string *block);
- bool deleteBlock(const v3s16 &pos);
- void listAllLoadableBlocks(std::vector<v3s16> &dst);
bool initialized() const;
-private:
- // Database initialization
- void connectToDatabase();
- void initStatements();
- void createDatabase();
- inline void prepareStatement(const std::string &name, const std::string &sql)
+protected:
+ // Conversion helpers
+ inline int pg_to_int(PGresult *res, int row, int col)
{
- checkResults(PQprepare(m_conn, name.c_str(), sql.c_str(), 0, NULL));
+ return atoi(PQgetvalue(res, row, col));
}
- // Database connectivity checks
- void ping();
- void verifyDatabase();
-
- // Database usage
- PGresult *checkResults(PGresult *res, bool clear = true);
-
- inline PGresult *execPrepared(const char *stmtName, const int paramsNumber,
- const void **params,
- const int *paramsLengths = NULL, const int *paramsFormats = NULL,
- bool clear = true, bool nobinary = true)
+ inline u32 pg_to_uint(PGresult *res, int row, int col)
{
- return checkResults(PQexecPrepared(m_conn, stmtName, paramsNumber,
- (const char* const*) params, paramsLengths, paramsFormats,
- nobinary ? 1 : 0), clear);
+ return (u32) atoi(PQgetvalue(res, row, col));
}
- // Conversion helpers
- inline int pg_to_int(PGresult *res, int row, int col)
+ inline float pg_to_float(PGresult *res, int row, int col)
{
- return atoi(PQgetvalue(res, row, col));
+ return (float) atof(PQgetvalue(res, row, col));
}
inline v3s16 pg_to_v3s16(PGresult *res, int row, int col)
@@ -85,11 +65,86 @@ private:
);
}
+ inline PGresult *execPrepared(const char *stmtName, const int paramsNumber,
+ const void **params,
+ const int *paramsLengths = NULL, const int *paramsFormats = NULL,
+ bool clear = true, bool nobinary = true)
+ {
+ return checkResults(PQexecPrepared(m_conn, stmtName, paramsNumber,
+ (const char* const*) params, paramsLengths, paramsFormats,
+ nobinary ? 1 : 0), clear);
+ }
+
+ inline PGresult *execPrepared(const char *stmtName, const int paramsNumber,
+ const char **params, bool clear = true, bool nobinary = true)
+ {
+ return execPrepared(stmtName, paramsNumber,
+ (const void **)params, NULL, NULL, clear, nobinary);
+ }
+
+ void createTableIfNotExists(const std::string &table_name, const std::string &definition);
+ void verifyDatabase();
+
+ // Database initialization
+ void connectToDatabase();
+ virtual void createDatabase() = 0;
+ virtual void initStatements() = 0;
+ inline void prepareStatement(const std::string &name, const std::string &sql)
+ {
+ checkResults(PQprepare(m_conn, name.c_str(), sql.c_str(), 0, NULL));
+ }
+
+ const int getPGVersion() const { return m_pgversion; }
+private:
+ // Database connectivity checks
+ void ping();
+
+ // Database usage
+ PGresult *checkResults(PGresult *res, bool clear = true);
+
// Attributes
std::string m_connect_string;
PGconn *m_conn;
int m_pgversion;
};
+class MapDatabasePostgreSQL : private Database_PostgreSQL, public MapDatabase
+{
+public:
+ MapDatabasePostgreSQL(const std::string &connect_string);
+ virtual ~MapDatabasePostgreSQL() {}
+
+ bool saveBlock(const v3s16 &pos, const std::string &data);
+ void loadBlock(const v3s16 &pos, std::string *block);
+ bool deleteBlock(const v3s16 &pos);
+ void listAllLoadableBlocks(std::vector<v3s16> &dst);
+
+ void beginSave() { Database_PostgreSQL::beginSave(); }
+ void endSave() { Database_PostgreSQL::endSave(); }
+
+protected:
+ virtual void createDatabase();
+ virtual void initStatements();
+};
+
+class PlayerDatabasePostgreSQL : private Database_PostgreSQL, public PlayerDatabase
+{
+public:
+ PlayerDatabasePostgreSQL(const std::string &connect_string);
+ virtual ~PlayerDatabasePostgreSQL() {}
+
+ void savePlayer(RemotePlayer *player);
+ bool loadPlayer(RemotePlayer *player, PlayerSAO *sao);
+ bool removePlayer(const std::string &name);
+ void listPlayers(std::vector<std::string> &res);
+
+protected:
+ virtual void createDatabase();
+ virtual void initStatements();
+
+private:
+ bool playerDataExists(const std::string &playername);
+};
+
#endif
diff --git a/src/database-redis.cpp b/src/database-redis.cpp
index 3bcedad9b..93e6717fa 100644
--- a/src/database-redis.cpp
+++ b/src/database-redis.cpp
@@ -44,7 +44,8 @@ Database_Redis::Database_Redis(Settings &conf)
}
const char *addr = tmp.c_str();
int port = conf.exists("redis_port") ? conf.getU16("redis_port") : 6379;
- ctx = redisConnect(addr, port);
+ // if redis_address contains '/' assume unix socket, else hostname/ip
+ ctx = tmp.find('/') != std::string::npos ? redisConnectUnix(addr) : redisConnect(addr, port);
if (!ctx) {
throw DatabaseException("Cannot allocate redis context");
} else if (ctx->err) {
@@ -52,6 +53,18 @@ Database_Redis::Database_Redis(Settings &conf)
redisFree(ctx);
throw DatabaseException(err);
}
+ if (conf.exists("redis_password")) {
+ tmp = conf.get("redis_password");
+ redisReply *reply = static_cast<redisReply *>(redisCommand(ctx, "AUTH %s", tmp.c_str()));
+ if (!reply)
+ throw DatabaseException("Redis authentication failed");
+ if (reply->type == REDIS_REPLY_ERROR) {
+ std::string err = "Redis authentication failed: " + std::string(reply->str, reply->len);
+ freeReplyObject(reply);
+ throw DatabaseException(err);
+ }
+ freeReplyObject(reply);
+ }
}
Database_Redis::~Database_Redis()
diff --git a/src/database-redis.h b/src/database-redis.h
index 3addaa20a..fa15dd8a7 100644
--- a/src/database-redis.h
+++ b/src/database-redis.h
@@ -24,13 +24,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#if USE_REDIS
-#include "database.h"
#include <hiredis.h>
#include <string>
+#include "database.h"
class Settings;
-class Database_Redis : public Database
+class Database_Redis : public MapDatabase
{
public:
Database_Redis(Settings &conf);
@@ -52,4 +52,3 @@ private:
#endif // USE_REDIS
#endif
-
diff --git a/src/database-sqlite3.cpp b/src/database-sqlite3.cpp
index 095d485c0..7bc87a7d0 100644
--- a/src/database-sqlite3.cpp
+++ b/src/database-sqlite3.cpp
@@ -33,6 +33,8 @@ SQLite format specification:
#include "settings.h"
#include "porting.h"
#include "util/string.h"
+#include "content_sao.h"
+#include "remoteplayer.h"
#include <cassert>
@@ -69,7 +71,7 @@ int Database_SQLite3::busyHandler(void *data, int count)
{
s64 &first_time = reinterpret_cast<s64 *>(data)[0];
s64 &prev_time = reinterpret_cast<s64 *>(data)[1];
- s64 cur_time = getTimeMs();
+ s64 cur_time = porting::getTimeMs();
if (count == 0) {
first_time = cur_time;
@@ -111,27 +113,26 @@ int Database_SQLite3::busyHandler(void *data, int count)
}
-Database_SQLite3::Database_SQLite3(const std::string &savedir) :
+Database_SQLite3::Database_SQLite3(const std::string &savedir, const std::string &dbname) :
+ m_database(NULL),
m_initialized(false),
m_savedir(savedir),
- m_database(NULL),
- m_stmt_read(NULL),
- m_stmt_write(NULL),
- m_stmt_list(NULL),
- m_stmt_delete(NULL),
+ m_dbname(dbname),
m_stmt_begin(NULL),
m_stmt_end(NULL)
{
}
-void Database_SQLite3::beginSave() {
+void Database_SQLite3::beginSave()
+{
verifyDatabase();
SQLRES(sqlite3_step(m_stmt_begin), SQLITE_DONE,
"Failed to start SQLite3 transaction");
sqlite3_reset(m_stmt_begin);
}
-void Database_SQLite3::endSave() {
+void Database_SQLite3::endSave()
+{
verifyDatabase();
SQLRES(sqlite3_step(m_stmt_end), SQLITE_DONE,
"Failed to commit SQLite3 transaction");
@@ -142,7 +143,7 @@ void Database_SQLite3::openDatabase()
{
if (m_database) return;
- std::string dbp = m_savedir + DIR_DELIM + "map.sqlite";
+ std::string dbp = m_savedir + DIR_DELIM + m_dbname + ".sqlite";
// Open the database connection
@@ -170,6 +171,8 @@ void Database_SQLite3::openDatabase()
+ itos(g_settings->getU16("sqlite_synchronous"));
SQLOK(sqlite3_exec(m_database, query_str.c_str(), NULL, NULL, NULL),
"Failed to modify sqlite3 synchronous mode");
+ SQLOK(sqlite3_exec(m_database, "PRAGMA foreign_keys = ON", NULL, NULL, NULL),
+ "Failed to enable sqlite3 foreign key support");
}
void Database_SQLite3::verifyDatabase()
@@ -178,8 +181,61 @@ void Database_SQLite3::verifyDatabase()
openDatabase();
- PREPARE_STATEMENT(begin, "BEGIN");
- PREPARE_STATEMENT(end, "COMMIT");
+ PREPARE_STATEMENT(begin, "BEGIN;");
+ PREPARE_STATEMENT(end, "COMMIT;");
+
+ initStatements();
+
+ m_initialized = true;
+}
+
+Database_SQLite3::~Database_SQLite3()
+{
+ FINALIZE_STATEMENT(m_stmt_begin)
+ FINALIZE_STATEMENT(m_stmt_end)
+
+ SQLOK_ERRSTREAM(sqlite3_close(m_database), "Failed to close database");
+}
+
+/*
+ * Map database
+ */
+
+MapDatabaseSQLite3::MapDatabaseSQLite3(const std::string &savedir):
+ Database_SQLite3(savedir, "map"),
+ MapDatabase(),
+ m_stmt_read(NULL),
+ m_stmt_write(NULL),
+ m_stmt_list(NULL),
+ m_stmt_delete(NULL)
+{
+
+}
+
+MapDatabaseSQLite3::~MapDatabaseSQLite3()
+{
+ FINALIZE_STATEMENT(m_stmt_read)
+ FINALIZE_STATEMENT(m_stmt_write)
+ FINALIZE_STATEMENT(m_stmt_list)
+ FINALIZE_STATEMENT(m_stmt_delete)
+}
+
+
+void MapDatabaseSQLite3::createDatabase()
+{
+ assert(m_database); // Pre-condition
+
+ SQLOK(sqlite3_exec(m_database,
+ "CREATE TABLE IF NOT EXISTS `blocks` (\n"
+ " `pos` INT PRIMARY KEY,\n"
+ " `data` BLOB\n"
+ ");\n",
+ NULL, NULL, NULL),
+ "Failed to create database table");
+}
+
+void MapDatabaseSQLite3::initStatements()
+{
PREPARE_STATEMENT(read, "SELECT `data` FROM `blocks` WHERE `pos` = ? LIMIT 1");
#ifdef __ANDROID__
PREPARE_STATEMENT(write, "INSERT INTO `blocks` (`pos`, `data`) VALUES (?, ?)");
@@ -189,18 +245,16 @@ void Database_SQLite3::verifyDatabase()
PREPARE_STATEMENT(delete, "DELETE FROM `blocks` WHERE `pos` = ?");
PREPARE_STATEMENT(list, "SELECT `pos` FROM `blocks`");
- m_initialized = true;
-
verbosestream << "ServerMap: SQLite3 database opened." << std::endl;
}
-inline void Database_SQLite3::bindPos(sqlite3_stmt *stmt, const v3s16 &pos, int index)
+inline void MapDatabaseSQLite3::bindPos(sqlite3_stmt *stmt, const v3s16 &pos, int index)
{
SQLOK(sqlite3_bind_int64(stmt, index, getBlockAsInteger(pos)),
"Internal error: failed to bind query at " __FILE__ ":" TOSTRING(__LINE__));
}
-bool Database_SQLite3::deleteBlock(const v3s16 &pos)
+bool MapDatabaseSQLite3::deleteBlock(const v3s16 &pos)
{
verifyDatabase();
@@ -216,7 +270,7 @@ bool Database_SQLite3::deleteBlock(const v3s16 &pos)
return good;
}
-bool Database_SQLite3::saveBlock(const v3s16 &pos, const std::string &data)
+bool MapDatabaseSQLite3::saveBlock(const v3s16 &pos, const std::string &data)
{
verifyDatabase();
@@ -243,7 +297,7 @@ bool Database_SQLite3::saveBlock(const v3s16 &pos, const std::string &data)
return true;
}
-void Database_SQLite3::loadBlock(const v3s16 &pos, std::string *block)
+void MapDatabaseSQLite3::loadBlock(const v3s16 &pos, std::string *block)
{
verifyDatabase();
@@ -264,37 +318,312 @@ void Database_SQLite3::loadBlock(const v3s16 &pos, std::string *block)
sqlite3_reset(m_stmt_read);
}
-void Database_SQLite3::createDatabase()
+void MapDatabaseSQLite3::listAllLoadableBlocks(std::vector<v3s16> &dst)
+{
+ verifyDatabase();
+
+ while (sqlite3_step(m_stmt_list) == SQLITE_ROW)
+ dst.push_back(getIntegerAsBlock(sqlite3_column_int64(m_stmt_list, 0)));
+
+ sqlite3_reset(m_stmt_list);
+}
+
+/*
+ * Player Database
+ */
+
+PlayerDatabaseSQLite3::PlayerDatabaseSQLite3(const std::string &savedir):
+ Database_SQLite3(savedir, "players"),
+ PlayerDatabase(),
+ m_stmt_player_load(NULL),
+ m_stmt_player_add(NULL),
+ m_stmt_player_update(NULL),
+ m_stmt_player_remove(NULL),
+ m_stmt_player_list(NULL),
+ m_stmt_player_load_inventory(NULL),
+ m_stmt_player_load_inventory_items(NULL),
+ m_stmt_player_add_inventory(NULL),
+ m_stmt_player_add_inventory_items(NULL),
+ m_stmt_player_remove_inventory(NULL),
+ m_stmt_player_remove_inventory_items(NULL),
+ m_stmt_player_metadata_load(NULL),
+ m_stmt_player_metadata_remove(NULL),
+ m_stmt_player_metadata_add(NULL)
+{
+
+}
+PlayerDatabaseSQLite3::~PlayerDatabaseSQLite3()
+{
+ FINALIZE_STATEMENT(m_stmt_player_load)
+ FINALIZE_STATEMENT(m_stmt_player_add)
+ FINALIZE_STATEMENT(m_stmt_player_update)
+ FINALIZE_STATEMENT(m_stmt_player_remove)
+ FINALIZE_STATEMENT(m_stmt_player_list)
+ FINALIZE_STATEMENT(m_stmt_player_add_inventory)
+ FINALIZE_STATEMENT(m_stmt_player_add_inventory_items)
+ FINALIZE_STATEMENT(m_stmt_player_remove_inventory)
+ FINALIZE_STATEMENT(m_stmt_player_remove_inventory_items)
+ FINALIZE_STATEMENT(m_stmt_player_load_inventory)
+ FINALIZE_STATEMENT(m_stmt_player_load_inventory_items)
+ FINALIZE_STATEMENT(m_stmt_player_metadata_load)
+ FINALIZE_STATEMENT(m_stmt_player_metadata_add)
+ FINALIZE_STATEMENT(m_stmt_player_metadata_remove)
+};
+
+
+void PlayerDatabaseSQLite3::createDatabase()
{
assert(m_database); // Pre-condition
+
SQLOK(sqlite3_exec(m_database,
- "CREATE TABLE IF NOT EXISTS `blocks` (\n"
- " `pos` INT PRIMARY KEY,\n"
- " `data` BLOB\n"
- ");\n",
+ "CREATE TABLE IF NOT EXISTS `player` ("
+ "`name` VARCHAR(50) NOT NULL,"
+ "`pitch` NUMERIC(11, 4) NOT NULL,"
+ "`yaw` NUMERIC(11, 4) NOT NULL,"
+ "`posX` NUMERIC(11, 4) NOT NULL,"
+ "`posY` NUMERIC(11, 4) NOT NULL,"
+ "`posZ` NUMERIC(11, 4) NOT NULL,"
+ "`hp` INT NOT NULL,"
+ "`breath` INT NOT NULL,"
+ "`creation_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,"
+ "`modification_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,"
+ "PRIMARY KEY (`name`));",
NULL, NULL, NULL),
- "Failed to create database table");
+ "Failed to create player table");
+
+ SQLOK(sqlite3_exec(m_database,
+ "CREATE TABLE IF NOT EXISTS `player_metadata` ("
+ " `player` VARCHAR(50) NOT NULL,"
+ " `metadata` VARCHAR(256) NOT NULL,"
+ " `value` TEXT,"
+ " PRIMARY KEY(`player`, `metadata`),"
+ " FOREIGN KEY (`player`) REFERENCES player (`name`) ON DELETE CASCADE );",
+ NULL, NULL, NULL),
+ "Failed to create player metadata table");
+
+ SQLOK(sqlite3_exec(m_database,
+ "CREATE TABLE IF NOT EXISTS `player_inventories` ("
+ " `player` VARCHAR(50) NOT NULL,"
+ " `inv_id` INT NOT NULL,"
+ " `inv_width` INT NOT NULL,"
+ " `inv_name` TEXT NOT NULL DEFAULT '',"
+ " `inv_size` INT NOT NULL,"
+ " PRIMARY KEY(player, inv_id),"
+ " FOREIGN KEY (`player`) REFERENCES player (`name`) ON DELETE CASCADE );",
+ NULL, NULL, NULL),
+ "Failed to create player inventory table");
+
+ SQLOK(sqlite3_exec(m_database,
+ "CREATE TABLE `player_inventory_items` ("
+ " `player` VARCHAR(50) NOT NULL,"
+ " `inv_id` INT NOT NULL,"
+ " `slot_id` INT NOT NULL,"
+ " `item` TEXT NOT NULL DEFAULT '',"
+ " PRIMARY KEY(player, inv_id, slot_id),"
+ " FOREIGN KEY (`player`) REFERENCES player (`name`) ON DELETE CASCADE );",
+ NULL, NULL, NULL),
+ "Failed to create player inventory items table");
}
-void Database_SQLite3::listAllLoadableBlocks(std::vector<v3s16> &dst)
+void PlayerDatabaseSQLite3::initStatements()
+{
+ PREPARE_STATEMENT(player_load, "SELECT `pitch`, `yaw`, `posX`, `posY`, `posZ`, `hp`, "
+ "`breath`"
+ "FROM `player` WHERE `name` = ?")
+ PREPARE_STATEMENT(player_add, "INSERT INTO `player` (`name`, `pitch`, `yaw`, `posX`, "
+ "`posY`, `posZ`, `hp`, `breath`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
+ PREPARE_STATEMENT(player_update, "UPDATE `player` SET `pitch` = ?, `yaw` = ?, "
+ "`posX` = ?, `posY` = ?, `posZ` = ?, `hp` = ?, `breath` = ?, "
+ "`modification_date` = CURRENT_TIMESTAMP WHERE `name` = ?")
+ PREPARE_STATEMENT(player_remove, "DELETE FROM `player` WHERE `name` = ?")
+ PREPARE_STATEMENT(player_list, "SELECT `name` FROM `player`")
+
+ PREPARE_STATEMENT(player_add_inventory, "INSERT INTO `player_inventories` "
+ "(`player`, `inv_id`, `inv_width`, `inv_name`, `inv_size`) VALUES (?, ?, ?, ?, ?)")
+ PREPARE_STATEMENT(player_add_inventory_items, "INSERT INTO `player_inventory_items` "
+ "(`player`, `inv_id`, `slot_id`, `item`) VALUES (?, ?, ?, ?)")
+ PREPARE_STATEMENT(player_remove_inventory, "DELETE FROM `player_inventories` "
+ "WHERE `player` = ?")
+ PREPARE_STATEMENT(player_remove_inventory_items, "DELETE FROM `player_inventory_items` "
+ "WHERE `player` = ?")
+ PREPARE_STATEMENT(player_load_inventory, "SELECT `inv_id`, `inv_width`, `inv_name`, "
+ "`inv_size` FROM `player_inventories` WHERE `player` = ? ORDER BY inv_id")
+ PREPARE_STATEMENT(player_load_inventory_items, "SELECT `slot_id`, `item` "
+ "FROM `player_inventory_items` WHERE `player` = ? AND `inv_id` = ?")
+
+ PREPARE_STATEMENT(player_metadata_load, "SELECT `metadata`, `value` FROM "
+ "`player_metadata` WHERE `player` = ?")
+ PREPARE_STATEMENT(player_metadata_add, "INSERT INTO `player_metadata` "
+ "(`player`, `metadata`, `value`) VALUES (?, ?, ?)")
+ PREPARE_STATEMENT(player_metadata_remove, "DELETE FROM `player_metadata` "
+ "WHERE `player` = ?")
+ verbosestream << "ServerEnvironment: SQLite3 database opened (players)." << std::endl;
+}
+
+bool PlayerDatabaseSQLite3::playerDataExists(const std::string &name)
{
verifyDatabase();
+ str_to_sqlite(m_stmt_player_load, 1, name);
+ bool res = (sqlite3_step(m_stmt_player_load) == SQLITE_ROW);
+ sqlite3_reset(m_stmt_player_load);
+ return res;
+}
- while (sqlite3_step(m_stmt_list) == SQLITE_ROW) {
- dst.push_back(getIntegerAsBlock(sqlite3_column_int64(m_stmt_list, 0)));
+void PlayerDatabaseSQLite3::savePlayer(RemotePlayer *player)
+{
+ PlayerSAO* sao = player->getPlayerSAO();
+ sanity_check(sao);
+
+ const v3f &pos = sao->getBasePosition();
+ // Begin save in brace is mandatory
+ if (!playerDataExists(player->getName())) {
+ beginSave();
+ str_to_sqlite(m_stmt_player_add, 1, player->getName());
+ double_to_sqlite(m_stmt_player_add, 2, sao->getPitch());
+ double_to_sqlite(m_stmt_player_add, 3, sao->getYaw());
+ double_to_sqlite(m_stmt_player_add, 4, pos.X);
+ double_to_sqlite(m_stmt_player_add, 5, pos.Y);
+ double_to_sqlite(m_stmt_player_add, 6, pos.Z);
+ int64_to_sqlite(m_stmt_player_add, 7, sao->getHP());
+ int64_to_sqlite(m_stmt_player_add, 8, sao->getBreath());
+
+ sqlite3_vrfy(sqlite3_step(m_stmt_player_add), SQLITE_DONE);
+ sqlite3_reset(m_stmt_player_add);
+ } else {
+ beginSave();
+ double_to_sqlite(m_stmt_player_update, 1, sao->getPitch());
+ double_to_sqlite(m_stmt_player_update, 2, sao->getYaw());
+ double_to_sqlite(m_stmt_player_update, 3, pos.X);
+ double_to_sqlite(m_stmt_player_update, 4, pos.Y);
+ double_to_sqlite(m_stmt_player_update, 5, pos.Z);
+ int64_to_sqlite(m_stmt_player_update, 6, sao->getHP());
+ int64_to_sqlite(m_stmt_player_update, 7, sao->getBreath());
+ str_to_sqlite(m_stmt_player_update, 8, player->getName());
+
+ sqlite3_vrfy(sqlite3_step(m_stmt_player_update), SQLITE_DONE);
+ sqlite3_reset(m_stmt_player_update);
}
- sqlite3_reset(m_stmt_list);
+
+ // Write player inventories
+ str_to_sqlite(m_stmt_player_remove_inventory, 1, player->getName());
+ sqlite3_vrfy(sqlite3_step(m_stmt_player_remove_inventory), SQLITE_DONE);
+ sqlite3_reset(m_stmt_player_remove_inventory);
+
+ str_to_sqlite(m_stmt_player_remove_inventory_items, 1, player->getName());
+ sqlite3_vrfy(sqlite3_step(m_stmt_player_remove_inventory_items), SQLITE_DONE);
+ sqlite3_reset(m_stmt_player_remove_inventory_items);
+
+ std::vector<const InventoryList*> inventory_lists = sao->getInventory()->getLists();
+ for (u16 i = 0; i < inventory_lists.size(); i++) {
+ const InventoryList* list = inventory_lists[i];
+
+ str_to_sqlite(m_stmt_player_add_inventory, 1, player->getName());
+ int_to_sqlite(m_stmt_player_add_inventory, 2, i);
+ int_to_sqlite(m_stmt_player_add_inventory, 3, list->getWidth());
+ str_to_sqlite(m_stmt_player_add_inventory, 4, list->getName());
+ int_to_sqlite(m_stmt_player_add_inventory, 5, list->getSize());
+ sqlite3_vrfy(sqlite3_step(m_stmt_player_add_inventory), SQLITE_DONE);
+ sqlite3_reset(m_stmt_player_add_inventory);
+
+ for (u32 j = 0; j < list->getSize(); j++) {
+ std::ostringstream os;
+ list->getItem(j).serialize(os);
+ std::string itemStr = os.str();
+
+ str_to_sqlite(m_stmt_player_add_inventory_items, 1, player->getName());
+ int_to_sqlite(m_stmt_player_add_inventory_items, 2, i);
+ int_to_sqlite(m_stmt_player_add_inventory_items, 3, j);
+ str_to_sqlite(m_stmt_player_add_inventory_items, 4, itemStr);
+ sqlite3_vrfy(sqlite3_step(m_stmt_player_add_inventory_items), SQLITE_DONE);
+ sqlite3_reset(m_stmt_player_add_inventory_items);
+ }
+ }
+
+ str_to_sqlite(m_stmt_player_metadata_remove, 1, player->getName());
+ sqlite3_vrfy(sqlite3_step(m_stmt_player_metadata_remove), SQLITE_DONE);
+ sqlite3_reset(m_stmt_player_metadata_remove);
+
+ const PlayerAttributes &attrs = sao->getExtendedAttributes();
+ for (PlayerAttributes::const_iterator it = attrs.begin(); it != attrs.end(); ++it) {
+ str_to_sqlite(m_stmt_player_metadata_add, 1, player->getName());
+ str_to_sqlite(m_stmt_player_metadata_add, 2, it->first);
+ str_to_sqlite(m_stmt_player_metadata_add, 3, it->second);
+ sqlite3_vrfy(sqlite3_step(m_stmt_player_metadata_add), SQLITE_DONE);
+ sqlite3_reset(m_stmt_player_metadata_add);
+ }
+
+ endSave();
}
-Database_SQLite3::~Database_SQLite3()
+bool PlayerDatabaseSQLite3::loadPlayer(RemotePlayer *player, PlayerSAO *sao)
{
- FINALIZE_STATEMENT(m_stmt_read)
- FINALIZE_STATEMENT(m_stmt_write)
- FINALIZE_STATEMENT(m_stmt_list)
- FINALIZE_STATEMENT(m_stmt_begin)
- FINALIZE_STATEMENT(m_stmt_end)
- FINALIZE_STATEMENT(m_stmt_delete)
+ verifyDatabase();
- SQLOK_ERRSTREAM(sqlite3_close(m_database), "Failed to close database");
+ str_to_sqlite(m_stmt_player_load, 1, player->getName());
+ if (sqlite3_step(m_stmt_player_load) != SQLITE_ROW) {
+ sqlite3_reset(m_stmt_player_load);
+ return false;
+ }
+ sao->setPitch(sqlite_to_float(m_stmt_player_load, 0));
+ sao->setYaw(sqlite_to_float(m_stmt_player_load, 1));
+ sao->setBasePosition(sqlite_to_v3f(m_stmt_player_load, 2));
+ sao->setHPRaw((s16) MYMIN(sqlite_to_int(m_stmt_player_load, 5), S16_MAX));
+ sao->setBreath((u16) MYMIN(sqlite_to_int(m_stmt_player_load, 6), U16_MAX), false);
+ sqlite3_reset(m_stmt_player_load);
+
+ // Load inventory
+ str_to_sqlite(m_stmt_player_load_inventory, 1, player->getName());
+ while (sqlite3_step(m_stmt_player_load_inventory) == SQLITE_ROW) {
+ InventoryList *invList = player->inventory.addList(
+ sqlite_to_string(m_stmt_player_load_inventory, 2),
+ sqlite_to_uint(m_stmt_player_load_inventory, 3));
+ invList->setWidth(sqlite_to_uint(m_stmt_player_load_inventory, 1));
+
+ u32 invId = sqlite_to_uint(m_stmt_player_load_inventory, 0);
+
+ str_to_sqlite(m_stmt_player_load_inventory_items, 1, player->getName());
+ int_to_sqlite(m_stmt_player_load_inventory_items, 2, invId);
+ while (sqlite3_step(m_stmt_player_load_inventory_items) == SQLITE_ROW) {
+ const std::string itemStr = sqlite_to_string(m_stmt_player_load_inventory_items, 1);
+ if (itemStr.length() > 0) {
+ ItemStack stack;
+ stack.deSerialize(itemStr);
+ invList->addItem(sqlite_to_uint(m_stmt_player_load_inventory_items, 0), stack);
+ }
+ }
+ sqlite3_reset(m_stmt_player_load_inventory_items);
+ }
+
+ sqlite3_reset(m_stmt_player_load_inventory);
+
+ str_to_sqlite(m_stmt_player_metadata_load, 1, sao->getPlayer()->getName());
+ while (sqlite3_step(m_stmt_player_metadata_load) == SQLITE_ROW) {
+ std::string attr = sqlite_to_string(m_stmt_player_metadata_load, 0);
+ std::string value = sqlite_to_string(m_stmt_player_metadata_load, 1);
+
+ sao->setExtendedAttribute(attr, value);
+ }
+ sqlite3_reset(m_stmt_player_metadata_load);
+ return true;
+}
+
+bool PlayerDatabaseSQLite3::removePlayer(const std::string &name)
+{
+ if (!playerDataExists(name))
+ return false;
+
+ str_to_sqlite(m_stmt_player_remove, 1, name);
+ sqlite3_vrfy(sqlite3_step(m_stmt_player_remove), SQLITE_DONE);
+ sqlite3_reset(m_stmt_player_remove);
+ return true;
}
+void PlayerDatabaseSQLite3::listPlayers(std::vector<std::string> &res)
+{
+ verifyDatabase();
+
+ while (sqlite3_step(m_stmt_player_list) == SQLITE_ROW)
+ res.push_back(sqlite_to_string(m_stmt_player_list, 0));
+
+ sqlite3_reset(m_stmt_player_list);
+}
diff --git a/src/database-sqlite3.h b/src/database-sqlite3.h
index debbc9d8b..3244facc9 100644
--- a/src/database-sqlite3.h
+++ b/src/database-sqlite3.h
@@ -20,47 +20,109 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef DATABASE_SQLITE3_HEADER
#define DATABASE_SQLITE3_HEADER
-#include "database.h"
+#include <cstring>
#include <string>
+#include "database.h"
+#include "exceptions.h"
extern "C" {
- #include "sqlite3.h"
+#include "sqlite3.h"
}
class Database_SQLite3 : public Database
{
public:
- Database_SQLite3(const std::string &savedir);
- ~Database_SQLite3();
+ virtual ~Database_SQLite3();
void beginSave();
void endSave();
- bool saveBlock(const v3s16 &pos, const std::string &data);
- void loadBlock(const v3s16 &pos, std::string *block);
- bool deleteBlock(const v3s16 &pos);
- void listAllLoadableBlocks(std::vector<v3s16> &dst);
bool initialized() const { return m_initialized; }
+protected:
+ Database_SQLite3(const std::string &savedir, const std::string &dbname);
-private:
- // Open the database
- void openDatabase();
- // Create the database structure
- void createDatabase();
// Open and initialize the database if needed
void verifyDatabase();
- void bindPos(sqlite3_stmt *stmt, const v3s16 &pos, int index=1);
+ // Convertors
+ inline void str_to_sqlite(sqlite3_stmt *s, int iCol, const std::string &str) const
+ {
+ sqlite3_vrfy(sqlite3_bind_text(s, iCol, str.c_str(), str.size(), NULL));
+ }
+
+ inline void str_to_sqlite(sqlite3_stmt *s, int iCol, const char *str) const
+ {
+ sqlite3_vrfy(sqlite3_bind_text(s, iCol, str, strlen(str), NULL));
+ }
+
+ inline void int_to_sqlite(sqlite3_stmt *s, int iCol, int val) const
+ {
+ sqlite3_vrfy(sqlite3_bind_int(s, iCol, val));
+ }
+
+ inline void int64_to_sqlite(sqlite3_stmt *s, int iCol, s64 val) const
+ {
+ sqlite3_vrfy(sqlite3_bind_int64(s, iCol, (sqlite3_int64) val));
+ }
+
+ inline void double_to_sqlite(sqlite3_stmt *s, int iCol, double val) const
+ {
+ sqlite3_vrfy(sqlite3_bind_double(s, iCol, val));
+ }
+
+ inline std::string sqlite_to_string(sqlite3_stmt *s, int iCol)
+ {
+ const char* text = reinterpret_cast<const char*>(sqlite3_column_text(s, iCol));
+ return std::string(text ? text : "");
+ }
+
+ inline s32 sqlite_to_int(sqlite3_stmt *s, int iCol)
+ {
+ return sqlite3_column_int(s, iCol);
+ }
+
+ inline u32 sqlite_to_uint(sqlite3_stmt *s, int iCol)
+ {
+ return (u32) sqlite3_column_int(s, iCol);
+ }
+
+ inline float sqlite_to_float(sqlite3_stmt *s, int iCol)
+ {
+ return (float) sqlite3_column_double(s, iCol);
+ }
+
+ inline const v3f sqlite_to_v3f(sqlite3_stmt *s, int iCol)
+ {
+ return v3f(sqlite_to_float(s, iCol), sqlite_to_float(s, iCol + 1),
+ sqlite_to_float(s, iCol + 2));
+ }
+
+ // Query verifiers helpers
+ inline void sqlite3_vrfy(int s, const std::string &m = "", int r = SQLITE_OK) const
+ {
+ if (s != r)
+ throw DatabaseException(m + ": " + sqlite3_errmsg(m_database));
+ }
+
+ inline void sqlite3_vrfy(const int s, const int r, const std::string &m = "") const
+ {
+ sqlite3_vrfy(s, m, r);
+ }
+
+ // Create the database structure
+ virtual void createDatabase() = 0;
+ virtual void initStatements() = 0;
+
+ sqlite3 *m_database;
+private:
+ // Open the database
+ void openDatabase();
bool m_initialized;
std::string m_savedir;
+ std::string m_dbname;
- sqlite3 *m_database;
- sqlite3_stmt *m_stmt_read;
- sqlite3_stmt *m_stmt_write;
- sqlite3_stmt *m_stmt_list;
- sqlite3_stmt *m_stmt_delete;
sqlite3_stmt *m_stmt_begin;
sqlite3_stmt *m_stmt_end;
@@ -69,5 +131,66 @@ private:
static int busyHandler(void *data, int count);
};
-#endif
+class MapDatabaseSQLite3 : private Database_SQLite3, public MapDatabase
+{
+public:
+ MapDatabaseSQLite3(const std::string &savedir);
+ virtual ~MapDatabaseSQLite3();
+
+ bool saveBlock(const v3s16 &pos, const std::string &data);
+ void loadBlock(const v3s16 &pos, std::string *block);
+ bool deleteBlock(const v3s16 &pos);
+ void listAllLoadableBlocks(std::vector<v3s16> &dst);
+
+ void beginSave() { Database_SQLite3::beginSave(); }
+ void endSave() { Database_SQLite3::endSave(); }
+protected:
+ virtual void createDatabase();
+ virtual void initStatements();
+
+private:
+ void bindPos(sqlite3_stmt *stmt, const v3s16 &pos, int index = 1);
+
+ // Map
+ sqlite3_stmt *m_stmt_read;
+ sqlite3_stmt *m_stmt_write;
+ sqlite3_stmt *m_stmt_list;
+ sqlite3_stmt *m_stmt_delete;
+};
+
+class PlayerDatabaseSQLite3 : private Database_SQLite3, public PlayerDatabase
+{
+public:
+ PlayerDatabaseSQLite3(const std::string &savedir);
+ virtual ~PlayerDatabaseSQLite3();
+ void savePlayer(RemotePlayer *player);
+ bool loadPlayer(RemotePlayer *player, PlayerSAO *sao);
+ bool removePlayer(const std::string &name);
+ void listPlayers(std::vector<std::string> &res);
+
+protected:
+ virtual void createDatabase();
+ virtual void initStatements();
+
+private:
+ bool playerDataExists(const std::string &name);
+
+ // Players
+ sqlite3_stmt *m_stmt_player_load;
+ sqlite3_stmt *m_stmt_player_add;
+ sqlite3_stmt *m_stmt_player_update;
+ sqlite3_stmt *m_stmt_player_remove;
+ sqlite3_stmt *m_stmt_player_list;
+ sqlite3_stmt *m_stmt_player_load_inventory;
+ sqlite3_stmt *m_stmt_player_load_inventory_items;
+ sqlite3_stmt *m_stmt_player_add_inventory;
+ sqlite3_stmt *m_stmt_player_add_inventory_items;
+ sqlite3_stmt *m_stmt_player_remove_inventory;
+ sqlite3_stmt *m_stmt_player_remove_inventory_items;
+ sqlite3_stmt *m_stmt_player_metadata_load;
+ sqlite3_stmt *m_stmt_player_metadata_remove;
+ sqlite3_stmt *m_stmt_player_metadata_add;
+};
+
+#endif
diff --git a/src/database.cpp b/src/database.cpp
index 262d475ec..8e1483893 100644
--- a/src/database.cpp
+++ b/src/database.cpp
@@ -48,7 +48,7 @@ static inline s64 pythonmodulo(s64 i, s16 mod)
}
-s64 Database::getBlockAsInteger(const v3s16 &pos)
+s64 MapDatabase::getBlockAsInteger(const v3s16 &pos)
{
return (u64) pos.Z * 0x1000000 +
(u64) pos.Y * 0x1000 +
@@ -56,7 +56,7 @@ s64 Database::getBlockAsInteger(const v3s16 &pos)
}
-v3s16 Database::getIntegerAsBlock(s64 i)
+v3s16 MapDatabase::getIntegerAsBlock(s64 i)
{
v3s16 pos;
pos.X = unsigned_to_signed(pythonmodulo(i, 4096), 2048);
diff --git a/src/database.h b/src/database.h
index 0cf75232f..5a2b844fd 100644
--- a/src/database.h
+++ b/src/database.h
@@ -20,22 +20,24 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef DATABASE_HEADER
#define DATABASE_HEADER
-#include <vector>
#include <string>
+#include <vector>
#include "irr_v3d.h"
#include "irrlichttypes.h"
-
-#ifndef PP
- #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
-#endif
+#include "util/basic_macros.h"
class Database
{
public:
- virtual ~Database() {}
+ virtual void beginSave() = 0;
+ virtual void endSave() = 0;
+ virtual bool initialized() const { return true; }
+};
- virtual void beginSave() {}
- virtual void endSave() {}
+class MapDatabase : public Database
+{
+public:
+ virtual ~MapDatabase() {}
virtual bool saveBlock(const v3s16 &pos, const std::string &data) = 0;
virtual void loadBlock(const v3s16 &pos, std::string *block) = 0;
@@ -45,9 +47,19 @@ public:
static v3s16 getIntegerAsBlock(s64 i);
virtual void listAllLoadableBlocks(std::vector<v3s16> &dst) = 0;
+};
- virtual bool initialized() const { return true; }
+class PlayerSAO;
+class RemotePlayer;
+
+class PlayerDatabase
+{
+public:
+ virtual ~PlayerDatabase() {}
+ virtual void savePlayer(RemotePlayer *player) = 0;
+ virtual bool loadPlayer(RemotePlayer *player, PlayerSAO *sao) = 0;
+ virtual bool removePlayer(const std::string &name) = 0;
+ virtual void listPlayers(std::vector<std::string> &res) = 0;
};
#endif
-
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index 0b4be6322..0a44069fd 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -23,14 +23,43 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "config.h"
#include "constants.h"
#include "porting.h"
+#include "util/string.h"
void set_default_settings(Settings *settings)
{
// Client and server
-
+ settings->setDefault("language", "");
settings->setDefault("name", "");
+ settings->setDefault("bind_address", "");
+ settings->setDefault("serverlist_url", "servers.minetest.net");
+
+ // Client
+ settings->setDefault("address", "");
+ settings->setDefault("enable_sound", "true");
+ settings->setDefault("sound_volume", "0.8");
+ settings->setDefault("enable_mesh_cache", "false");
+ settings->setDefault("mesh_generation_interval", "0");
+ settings->setDefault("meshgen_block_cache_size", "20");
+ settings->setDefault("enable_vbo", "true");
+ settings->setDefault("free_move", "false");
+ settings->setDefault("fast_move", "false");
+ settings->setDefault("noclip", "false");
+ settings->setDefault("screenshot_path", ".");
+ settings->setDefault("screenshot_format", "png");
+ settings->setDefault("screenshot_quality", "0");
+ settings->setDefault("client_unload_unused_data_timeout", "600");
+ settings->setDefault("client_mapblock_limit", "5000");
+ settings->setDefault("enable_build_where_you_stand", "false" );
+ settings->setDefault("send_pre_v25_init", "false");
+ settings->setDefault("curl_timeout", "5000");
+ settings->setDefault("curl_parallel_limit", "8");
+ settings->setDefault("curl_file_download_timeout", "300000");
+ settings->setDefault("curl_verify_cert", "true");
+ settings->setDefault("enable_remote_media_server", "true");
+ settings->setDefault("enable_client_modding", "false");
+ settings->setDefault("max_out_chat_queue_size", "20");
- // Client stuff
+ // Keymap
settings->setDefault("remote_port", "30000");
settings->setDefault("keymap_forward", "KEY_KEY_W");
settings->setDefault("keymap_autorun", "");
@@ -45,38 +74,33 @@ void set_default_settings(Settings *settings)
settings->setDefault("keymap_special1", "KEY_KEY_E");
settings->setDefault("keymap_chat", "KEY_KEY_T");
settings->setDefault("keymap_cmd", "/");
+ settings->setDefault("keymap_cmd_local", ".");
settings->setDefault("keymap_minimap", "KEY_F9");
settings->setDefault("keymap_console", "KEY_F10");
settings->setDefault("keymap_rangeselect", "KEY_KEY_R");
settings->setDefault("keymap_freemove", "KEY_KEY_K");
settings->setDefault("keymap_fastmove", "KEY_KEY_J");
settings->setDefault("keymap_noclip", "KEY_KEY_H");
+ settings->setDefault("keymap_hotbar_next", "KEY_KEY_N");
+ settings->setDefault("keymap_hotbar_previous", "KEY_KEY_B");
+ settings->setDefault("keymap_mute", "KEY_KEY_M");
+ settings->setDefault("keymap_increase_volume", "");
+ settings->setDefault("keymap_decrease_volume", "");
settings->setDefault("keymap_cinematic", "");
- settings->setDefault("keymap_screenshot", "KEY_F12");
settings->setDefault("keymap_toggle_hud", "KEY_F1");
settings->setDefault("keymap_toggle_chat", "KEY_F2");
settings->setDefault("keymap_toggle_force_fog_off", "KEY_F3");
- settings->setDefault("keymap_toggle_update_camera",
#if DEBUG
- "KEY_F4");
+ settings->setDefault("keymap_toggle_update_camera", "KEY_F4");
#else
- "");
+ settings->setDefault("keymap_toggle_update_camera", "");
#endif
settings->setDefault("keymap_toggle_debug", "KEY_F5");
settings->setDefault("keymap_toggle_profiler", "KEY_F6");
settings->setDefault("keymap_camera_mode", "KEY_F7");
+ settings->setDefault("keymap_screenshot", "KEY_F12");
settings->setDefault("keymap_increase_viewing_range_min", "+");
settings->setDefault("keymap_decrease_viewing_range_min", "-");
- settings->setDefault("enable_build_where_you_stand", "false" );
- settings->setDefault("3d_mode", "none");
- settings->setDefault("3d_paralax_strength", "0.025");
- settings->setDefault("aux1_descends", "false");
- settings->setDefault("doubletap_jump", "false");
- settings->setDefault("always_fly_fast", "true");
- settings->setDefault("directional_colored_fog", "true");
- settings->setDefault("tooltip_show_delay", "400");
- settings->setDefault("zoom_fov", "15");
-
// Some (temporary) keys for debugging
settings->setDefault("keymap_print_debug_stacks", "KEY_KEY_P");
settings->setDefault("keymap_quicktune_prev", "KEY_HOME");
@@ -84,53 +108,41 @@ void set_default_settings(Settings *settings)
settings->setDefault("keymap_quicktune_dec", "KEY_NEXT");
settings->setDefault("keymap_quicktune_inc", "KEY_PRIOR");
- // Show debug info by default?
- #ifdef NDEBUG
+ // Visuals
+#ifdef NDEBUG
settings->setDefault("show_debug", "false");
- #else
+#else
settings->setDefault("show_debug", "true");
- #endif
-
+#endif
+ settings->setDefault("fsaa", "0");
+ settings->setDefault("undersampling", "0");
+ settings->setDefault("enable_fog", "true");
+ settings->setDefault("fog_start", "0.4");
+ settings->setDefault("3d_mode", "none");
+ settings->setDefault("3d_paralax_strength", "0.025");
+ settings->setDefault("tooltip_show_delay", "400");
+ settings->setDefault("zoom_fov", "15");
settings->setDefault("fps_max", "60");
settings->setDefault("pause_fps_max", "20");
settings->setDefault("viewing_range", "100");
- settings->setDefault("map_generation_limit", "31000");
settings->setDefault("screenW", "800");
settings->setDefault("screenH", "600");
+ settings->setDefault("autosave_screensize", "true");
settings->setDefault("fullscreen", "false");
settings->setDefault("fullscreen_bpp", "24");
- settings->setDefault("fsaa", "0");
settings->setDefault("vsync", "false");
- settings->setDefault("address", "");
- settings->setDefault("random_input", "false");
- settings->setDefault("client_unload_unused_data_timeout", "600");
- settings->setDefault("client_mapblock_limit", "5000");
- settings->setDefault("enable_fog", "true");
- settings->setDefault("fog_start", "0.4");
settings->setDefault("fov", "72");
- settings->setDefault("view_bobbing", "true");
settings->setDefault("leaves_style", "fancy");
settings->setDefault("connected_glass", "false");
settings->setDefault("smooth_lighting", "true");
- settings->setDefault("display_gamma", "1.8");
+ settings->setDefault("display_gamma", "2.2");
settings->setDefault("texture_path", "");
settings->setDefault("shader_path", "");
settings->setDefault("video_driver", "opengl");
- settings->setDefault("free_move", "false");
- settings->setDefault("noclip", "false");
- settings->setDefault("continuous_forward", "false");
- settings->setDefault("enable_joysticks", "false");
- settings->setDefault("repeat_joystick_button_time", "0.17");
- settings->setDefault("joystick_frustum_sensitivity", "170");
settings->setDefault("cinematic", "false");
settings->setDefault("camera_smoothing", "0");
settings->setDefault("cinematic_camera_smoothing", "0.7");
- settings->setDefault("fast_move", "false");
- settings->setDefault("invert_mouse", "false");
settings->setDefault("enable_clouds", "true");
- settings->setDefault("screenshot_path", ".");
- settings->setDefault("screenshot_format", "png");
- settings->setDefault("screenshot_quality", "0");
settings->setDefault("view_bobbing_amount", "1.0");
settings->setDefault("fall_bobbing_amount", "0.0");
settings->setDefault("enable_3d_clouds", "true");
@@ -138,11 +150,11 @@ void set_default_settings(Settings *settings)
settings->setDefault("cloud_radius", "12");
settings->setDefault("menu_clouds", "true");
settings->setDefault("opaque_water", "false");
+ settings->setDefault("console_height", "1.0");
settings->setDefault("console_color", "(0,0,0)");
settings->setDefault("console_alpha", "200");
settings->setDefault("selectionbox_color", "(0,0,0)");
settings->setDefault("selectionbox_width", "2");
- settings->setDefault("inventory_items_animations", "false");
settings->setDefault("node_highlighting", "box");
settings->setDefault("crosshair_color", "(255,255,255)");
settings->setDefault("crosshair_alpha", "255");
@@ -150,20 +162,27 @@ void set_default_settings(Settings *settings)
settings->setDefault("gui_scaling", "1.0");
settings->setDefault("gui_scaling_filter", "false");
settings->setDefault("gui_scaling_filter_txr2img", "true");
- settings->setDefault("mouse_sensitivity", "0.2");
- settings->setDefault("enable_sound", "true");
- settings->setDefault("sound_volume", "0.8");
settings->setDefault("desynchronize_mapblock_texture_animation", "true");
settings->setDefault("hud_hotbar_max_width", "1.0");
settings->setDefault("enable_local_map_saving", "false");
settings->setDefault("show_entity_selectionbox", "true");
+ settings->setDefault("texture_clean_transparent", "false");
+ settings->setDefault("texture_min_size", "64");
+ settings->setDefault("ambient_occlusion_gamma", "2.2");
+ settings->setDefault("enable_shaders", "true");
+ settings->setDefault("enable_particles", "true");
+
+ settings->setDefault("enable_minimap", "true");
+ settings->setDefault("minimap_shape_round", "true");
+ settings->setDefault("minimap_double_scan_height", "true");
+ // Effects
+ settings->setDefault("directional_colored_fog", "true");
+ settings->setDefault("inventory_items_animations", "false");
settings->setDefault("mip_map", "false");
settings->setDefault("anisotropic_filter", "false");
settings->setDefault("bilinear_filter", "false");
settings->setDefault("trilinear_filter", "false");
- settings->setDefault("texture_clean_transparent", "false");
- settings->setDefault("texture_min_size", "64");
settings->setDefault("tone_mapping", "false");
settings->setDefault("enable_bumpmapping", "false");
settings->setDefault("enable_parallax_occlusion", "false");
@@ -180,82 +199,80 @@ void set_default_settings(Settings *settings)
settings->setDefault("water_wave_speed", "5.0");
settings->setDefault("enable_waving_leaves", "false");
settings->setDefault("enable_waving_plants", "false");
- settings->setDefault("ambient_occlusion_gamma", "2.2");
- settings->setDefault("enable_shaders", "true");
- settings->setDefault("repeat_rightclick_time", "0.25");
- settings->setDefault("enable_particles", "true");
- settings->setDefault("enable_mesh_cache", "false");
- settings->setDefault("enable_vbo", "true");
- settings->setDefault("enable_minimap", "true");
- settings->setDefault("minimap_shape_round", "true");
- settings->setDefault("minimap_double_scan_height", "true");
-
- settings->setDefault("send_pre_v25_init", "false");
- settings->setDefault("curl_timeout", "5000");
- settings->setDefault("curl_parallel_limit", "8");
- settings->setDefault("curl_file_download_timeout", "300000");
- settings->setDefault("curl_verify_cert", "true");
-
- settings->setDefault("enable_remote_media_server", "true");
+ // Input
+ settings->setDefault("invert_mouse", "false");
+ settings->setDefault("mouse_sensitivity", "0.2");
+ settings->setDefault("repeat_rightclick_time", "0.25");
+ settings->setDefault("random_input", "false");
+ settings->setDefault("aux1_descends", "false");
+ settings->setDefault("doubletap_jump", "false");
+ settings->setDefault("always_fly_fast", "true");
+ settings->setDefault("continuous_forward", "false");
+ settings->setDefault("enable_joysticks", "false");
+ settings->setDefault("joystick_id", "0");
+ settings->setDefault("joystick_type", "");
+ settings->setDefault("repeat_joystick_button_time", "0.17");
+ settings->setDefault("joystick_frustum_sensitivity", "170");
- settings->setDefault("serverlist_url", "servers.minetest.net");
+ // Main menu
+ settings->setDefault("main_menu_path", "");
+ settings->setDefault("main_menu_mod_mgr", "1");
+ settings->setDefault("main_menu_game_mgr", "0");
+ settings->setDefault("modstore_download_url", "https://forum.minetest.net/media/");
+ settings->setDefault("modstore_listmods_url", "https://forum.minetest.net/mmdb/mods/");
+ settings->setDefault("modstore_details_url", "https://forum.minetest.net/mmdb/mod/*/");
settings->setDefault("serverlist_file", "favoriteservers.txt");
- settings->setDefault("server_announce", "false");
- settings->setDefault("server_url", "");
- settings->setDefault("server_address", "");
- settings->setDefault("server_name", "");
- settings->setDefault("server_description", "");
-
- settings->setDefault("disable_escape_sequences", "false");
#if USE_FREETYPE
settings->setDefault("freetype", "true");
- settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "liberationsans.ttf"));
+ settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "Arimo-Regular.ttf"));
settings->setDefault("font_shadow", "1");
settings->setDefault("font_shadow_alpha", "127");
- settings->setDefault("mono_font_path", porting::getDataPath("fonts" DIR_DELIM "liberationmono.ttf"));
+ settings->setDefault("mono_font_path", porting::getDataPath("fonts" DIR_DELIM "Cousine-Regular.ttf"));
settings->setDefault("fallback_font_path", porting::getDataPath("fonts" DIR_DELIM "DroidSansFallbackFull.ttf"));
settings->setDefault("fallback_font_shadow", "1");
settings->setDefault("fallback_font_shadow_alpha", "128");
- std::stringstream fontsize;
- fontsize << TTF_DEFAULT_FONT_SIZE;
+ std::string font_size_str = std::to_string(TTF_DEFAULT_FONT_SIZE);
- settings->setDefault("font_size", fontsize.str());
- settings->setDefault("mono_font_size", fontsize.str());
- settings->setDefault("fallback_font_size", fontsize.str());
+ settings->setDefault("fallback_font_size", font_size_str);
#else
settings->setDefault("freetype", "false");
- settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "lucida_sans"));
+ settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "mono_dejavu_sans"));
settings->setDefault("mono_font_path", porting::getDataPath("fonts" DIR_DELIM "mono_dejavu_sans"));
- std::stringstream fontsize;
- fontsize << DEFAULT_FONT_SIZE;
-
- settings->setDefault("font_size", fontsize.str());
- settings->setDefault("mono_font_size", fontsize.str());
+ std::string font_size_str = std::to_string(DEFAULT_FONT_SIZE);
#endif
+ settings->setDefault("font_size", font_size_str);
+ settings->setDefault("mono_font_size", font_size_str);
+
+
+ // Server
+ settings->setDefault("disable_escape_sequences", "false");
- // Server stuff
- // "map-dir" doesn't exist by default.
+ // Network
+ settings->setDefault("enable_ipv6", "true");
+ settings->setDefault("ipv6_server", "false");
settings->setDefault("workaround_window_size","5");
settings->setDefault("max_packets_per_iteration","1024");
settings->setDefault("port", "30000");
- settings->setDefault("bind_address", "");
+ settings->setDefault("strict_protocol_version_checking", "false");
+ settings->setDefault("player_transfer_distance", "0");
+ settings->setDefault("max_simultaneous_block_sends_per_client", "10");
+ settings->setDefault("max_simultaneous_block_sends_server_total", "40");
+ settings->setDefault("time_send_interval", "5");
+
settings->setDefault("default_game", "minetest");
settings->setDefault("motd", "");
settings->setDefault("max_users", "15");
- settings->setDefault("strict_protocol_version_checking", "false");
settings->setDefault("creative_mode", "false");
+ settings->setDefault("show_statusline_on_connect", "true");
settings->setDefault("enable_damage", "true");
- settings->setDefault("fixed_map_seed", "");
- settings->setDefault("give_initial_stuff", "false");
settings->setDefault("default_password", "");
settings->setDefault("default_privs", "interact, shout");
- settings->setDefault("player_transfer_distance", "0");
settings->setDefault("enable_pvp", "true");
settings->setDefault("disallow_empty_password", "false");
settings->setDefault("disable_anticheat", "false");
@@ -271,18 +288,14 @@ void set_default_settings(Settings *settings)
settings->setDefault("ask_reconnect_on_crash", "false");
settings->setDefault("profiler_print_interval", "0");
- settings->setDefault("enable_mapgen_debug_info", "false");
settings->setDefault("active_object_send_range_blocks", "3");
- settings->setDefault("active_block_range", "2");
+ settings->setDefault("active_block_range", "3");
//settings->setDefault("max_simultaneous_block_sends_per_client", "1");
// This causes frametime jitter on client side, or does it?
- settings->setDefault("max_simultaneous_block_sends_per_client", "10");
- settings->setDefault("max_simultaneous_block_sends_server_total", "40");
settings->setDefault("max_block_send_distance", "9");
- settings->setDefault("max_block_generate_distance", "7");
settings->setDefault("block_send_optimize_distance", "4");
+ settings->setDefault("server_side_occlusion_culling", "true");
settings->setDefault("max_clearobjects_extra_loaded_blocks", "4096");
- settings->setDefault("time_send_interval", "5");
settings->setDefault("time_speed", "72");
settings->setDefault("server_unload_unused_data_timeout", "29");
settings->setDefault("max_objects_per_block", "64");
@@ -295,7 +308,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("dedicated_server_step", "0.1");
settings->setDefault("active_block_mgmt_interval", "2.0");
settings->setDefault("abm_interval", "1.0");
- settings->setDefault("nodetimer_interval", "1.0");
+ settings->setDefault("nodetimer_interval", "0.2");
settings->setDefault("ignore_world_load_errors", "false");
settings->setDefault("remote_media", "");
settings->setDefault("debug_log_level", "action");
@@ -303,49 +316,48 @@ void set_default_settings(Settings *settings)
settings->setDefault("emergequeue_limit_diskonly", "32");
settings->setDefault("emergequeue_limit_generate", "32");
settings->setDefault("num_emerge_threads", "1");
- settings->setDefault("secure.enable_security", "false");
+ settings->setDefault("secure.enable_security", "true");
settings->setDefault("secure.trusted_mods", "");
settings->setDefault("secure.http_mods", "");
- // physics stuff
+ // Physics
settings->setDefault("movement_acceleration_default", "3");
settings->setDefault("movement_acceleration_air", "2");
settings->setDefault("movement_acceleration_fast", "10");
settings->setDefault("movement_speed_walk", "4");
settings->setDefault("movement_speed_crouch", "1.35");
settings->setDefault("movement_speed_fast", "20");
- settings->setDefault("movement_speed_climb", "2");
+ settings->setDefault("movement_speed_climb", "3");
settings->setDefault("movement_speed_jump", "6.5");
settings->setDefault("movement_liquid_fluidity", "1");
settings->setDefault("movement_liquid_fluidity_smooth", "0.5");
settings->setDefault("movement_liquid_sink", "10");
settings->setDefault("movement_gravity", "9.81");
- //liquid stuff
+ // Liquids
settings->setDefault("liquid_loop_max", "100000");
settings->setDefault("liquid_queue_purge_time", "0");
settings->setDefault("liquid_update", "1.0");
- //mapgen stuff
+ // Mapgen
settings->setDefault("mg_name", "v7");
settings->setDefault("water_level", "1");
+ settings->setDefault("mapgen_limit", "31000");
settings->setDefault("chunksize", "5");
settings->setDefault("mg_flags", "dungeons");
+ settings->setDefault("fixed_map_seed", "");
+ settings->setDefault("max_block_generate_distance", "7");
+ settings->setDefault("enable_mapgen_debug_info", "false");
- // IPv6
- settings->setDefault("enable_ipv6", "true");
- settings->setDefault("ipv6_server", "false");
-
- settings->setDefault("main_menu_path", "");
- settings->setDefault("main_menu_mod_mgr", "1");
- settings->setDefault("main_menu_game_mgr", "0");
- settings->setDefault("modstore_download_url", "https://forum.minetest.net/media/");
- settings->setDefault("modstore_listmods_url", "https://forum.minetest.net/mmdb/mods/");
- settings->setDefault("modstore_details_url", "https://forum.minetest.net/mmdb/mod/*/");
+ // Server list announcing
+ settings->setDefault("server_announce", "false");
+ settings->setDefault("server_url", "");
+ settings->setDefault("server_address", "");
+ settings->setDefault("server_name", "");
+ settings->setDefault("server_description", "");
settings->setDefault("high_precision_fpu", "true");
-
- settings->setDefault("language", "");
+ settings->setDefault("enable_console", "false");
#ifdef __ANDROID__
settings->setDefault("screenW", "0");
@@ -375,13 +387,12 @@ void set_default_settings(Settings *settings)
settings->setDefault("viewing_range", "25");
settings->setDefault("inventory_image_hack", "false");
- //check for device with small screen
+ // Check for a device with a small screen
float x_inches = ((double) porting::getDisplaySize().X /
(160 * porting::getDisplayDensity()));
if (x_inches < 3.5) {
settings->setDefault("hud_scaling", "0.6");
- }
- else if (x_inches < 4.5) {
+ } else if (x_inches < 4.5) {
settings->setDefault("hud_scaling", "0.7");
}
settings->setDefault("curl_verify_cert","false");
@@ -393,7 +404,7 @@ void set_default_settings(Settings *settings)
void override_default_settings(Settings *settings, Settings *from)
{
std::vector<std::string> names = from->getNames();
- for(size_t i=0; i<names.size(); i++){
+ for (size_t i = 0; i < names.size(); i++) {
const std::string &name = names[i];
settings->setDefault(name, from->get(name));
}
diff --git a/src/defaultsettings.h b/src/defaultsettings.h
index 20274a003..21c51396f 100644
--- a/src/defaultsettings.h
+++ b/src/defaultsettings.h
@@ -36,4 +36,3 @@ void set_default_settings(Settings *settings);
void override_default_settings(Settings *settings, Settings *from);
#endif
-
diff --git a/src/drawscene.cpp b/src/drawscene.cpp
index c6abda4ac..59f9b8375 100644
--- a/src/drawscene.cpp
+++ b/src/drawscene.cpp
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/timetaker.h"
#include "fontengine.h"
#include "guiscalingfilter.h"
+#include "filesys.h"
typedef enum {
LEFT = -1,
@@ -383,6 +384,10 @@ void draw_pageflip_3d_mode(Camera& camera, bool show_hud,
bool draw_wield_tool, Client& client, gui::IGUIEnvironment* guienv,
video::SColor skycolor)
{
+#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8
+ errorstream << "Pageflip 3D mode is not supported"
+ << " with your Irrlicht version!" << std::endl;
+#else
/* preserve old setup*/
irr::core::vector3df oldPosition = camera.getCameraNode()->getPosition();
irr::core::vector3df oldTarget = camera.getCameraNode()->getTarget();
@@ -451,12 +456,40 @@ void draw_pageflip_3d_mode(Camera& camera, bool show_hud,
camera.getCameraNode()->setPosition(oldPosition);
camera.getCameraNode()->setTarget(oldTarget);
+#endif
+}
+
+// returns (size / coef), rounded upwards
+inline int scaledown(int coef, int size)
+{
+ return (size + coef - 1) / coef;
}
-void draw_plain(Camera &camera, bool show_hud, Hud &hud,
- video::IVideoDriver *driver, bool draw_wield_tool,
- Client &client, gui::IGUIEnvironment *guienv)
+void draw_plain(Camera &camera, bool show_hud,
+ Hud &hud, video::IVideoDriver *driver,
+ scene::ISceneManager *smgr, const v2u32 &screensize,
+ bool draw_wield_tool, Client &client, gui::IGUIEnvironment *guienv,
+ video::SColor skycolor)
{
+ // Undersampling-specific stuff
+ static video::ITexture *image = NULL;
+ static v2u32 last_pixelated_size = v2u32(0, 0);
+ int undersampling = g_settings->getU16("undersampling");
+ v2u32 pixelated_size;
+ v2u32 dest_size;
+ if (undersampling > 0) {
+ pixelated_size = v2u32(scaledown(undersampling, screensize.X),
+ scaledown(undersampling, screensize.Y));
+ dest_size = v2u32(undersampling * pixelated_size.X, undersampling * pixelated_size.Y);
+ if (pixelated_size != last_pixelated_size) {
+ init_texture(driver, pixelated_size, &image, "mt_drawimage_img1");
+ last_pixelated_size = pixelated_size;
+ }
+ driver->setRenderTarget(image, true, true, skycolor);
+ }
+
+ // Render
+ smgr->drawAll();
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
if (show_hud) {
hud.drawSelectionMesh();
@@ -464,11 +497,19 @@ void draw_plain(Camera &camera, bool show_hud, Hud &hud,
camera.drawWieldedTool();
}
}
+
+ // Upscale lowres render
+ if (undersampling > 0) {
+ driver->setRenderTarget(0, true, true);
+ driver->draw2DImage(image,
+ irr::core::rect<s32>(0, 0, dest_size.X, dest_size.Y),
+ irr::core::rect<s32>(0, 0, pixelated_size.X, pixelated_size.Y));
+ }
}
void draw_scene(video::IVideoDriver *driver, scene::ISceneManager *smgr,
- Camera &camera, Client& client, LocalPlayer *player, Hud &hud,
- Mapper &mapper, gui::IGUIEnvironment *guienv,
+ Camera &camera, Client &client, LocalPlayer *player, Hud &hud,
+ Minimap *mapper, gui::IGUIEnvironment *guienv,
const v2u32 &screensize, const video::SColor &skycolor,
bool show_hud, bool show_minimap)
{
@@ -488,9 +529,7 @@ void draw_scene(video::IVideoDriver *driver, scene::ISceneManager *smgr,
catch(SettingNotFoundException) {}
#endif
- std::string draw_mode = g_settings->get("3d_mode");
-
- smgr->drawAll();
+ const std::string &draw_mode = g_settings->get("3d_mode");
if (draw_mode == "anaglyph")
{
@@ -525,7 +564,7 @@ void draw_scene(video::IVideoDriver *driver, scene::ISceneManager *smgr,
}
else {
draw_plain(camera, show_hud, hud, driver,
- draw_wield_tool, client, guienv);
+ smgr, screensize, draw_wield_tool, client, guienv, skycolor);
}
/*
@@ -545,8 +584,8 @@ void draw_scene(video::IVideoDriver *driver, scene::ISceneManager *smgr,
hud.drawLuaElements(camera.getOffset());
camera.drawNametags();
- if (show_minimap)
- mapper.drawMinimap();
+ if (mapper && show_minimap)
+ mapper->drawMinimap();
}
guienv->drawAll();
@@ -560,7 +599,8 @@ void draw_scene(video::IVideoDriver *driver, scene::ISceneManager *smgr,
Additionally, a progressbar can be drawn when percent is set between 0 and 100.
*/
void draw_load_screen(const std::wstring &text, IrrlichtDevice* device,
- gui::IGUIEnvironment* guienv, float dtime, int percent, bool clouds )
+ gui::IGUIEnvironment* guienv, ITextureSource *tsrc,
+ float dtime, int percent, bool clouds)
{
video::IVideoDriver* driver = device->getVideoDriver();
v2u32 screensize = porting::getWindowSize();
@@ -585,30 +625,49 @@ void draw_load_screen(const std::wstring &text, IrrlichtDevice* device,
driver->beginScene(true, true, video::SColor(255, 0, 0, 0));
// draw progress bar
- if ((percent >= 0) && (percent <= 100))
- {
- v2s32 barsize(
- // 342 is (approximately) 256/0.75 to keep bar on same size as
- // before with default settings
- 342 * porting::getDisplayDensity() *
- g_settings->getFloat("gui_scaling"),
- g_fontengine->getTextHeight() * 2);
-
- core::rect<s32> barrect(center - barsize / 2, center + barsize / 2);
- driver->draw2DRectangle(video::SColor(255, 255, 255, 255),barrect, NULL); // border
- driver->draw2DRectangle(video::SColor(255, 64, 64, 64), core::rect<s32> (
- barrect.UpperLeftCorner + 1,
- barrect.LowerRightCorner-1), NULL); // black inside the bar
- driver->draw2DRectangle(video::SColor(255, 128, 128, 128), core::rect<s32> (
- barrect.UpperLeftCorner + 1,
- core::vector2d<s32>(
- barrect.LowerRightCorner.X -
- (barsize.X - 1) + percent * (barsize.X - 2) / 100,
- barrect.LowerRightCorner.Y - 1)), NULL); // the actual progress
+ if ((percent >= 0) && (percent <= 100)) {
+ video::ITexture *progress_img = tsrc->getTexture("progress_bar.png");
+ video::ITexture *progress_img_bg = tsrc->getTexture("progress_bar_bg.png");
+
+ if (progress_img && progress_img_bg) {
+#ifndef __ANDROID__
+ const core::dimension2d<u32> &img_size = progress_img_bg->getSize();
+ u32 imgW = rangelim(img_size.Width, 200, 600);
+ u32 imgH = rangelim(img_size.Height, 24, 72);
+#else
+ const core::dimension2d<u32> img_size(256, 48);
+ float imgRatio = (float) img_size.Height / img_size.Width;
+ u32 imgW = screensize.X / 2.2f;
+ u32 imgH = floor(imgW * imgRatio);
+#endif
+ v2s32 img_pos((screensize.X - imgW) / 2, (screensize.Y - imgH) / 2);
+
+ draw2DImageFilterScaled(
+ driver, progress_img_bg,
+ core::rect<s32>(img_pos.X,
+ img_pos.Y,
+ img_pos.X + imgW,
+ img_pos.Y + imgH),
+ core::rect<s32>(0, 0,
+ img_size.Width,
+ img_size.Height),
+ 0, 0, true);
+
+ draw2DImageFilterScaled(
+ driver, progress_img,
+ core::rect<s32>(img_pos.X,
+ img_pos.Y,
+ img_pos.X + (percent * imgW) / 100,
+ img_pos.Y + imgH),
+ core::rect<s32>(0, 0,
+ (percent * img_size.Width) / 100,
+ img_size.Height),
+ 0, 0, true);
+ }
}
+
guienv->drawAll();
driver->endScene();
-
guitext->remove();
//return guitext;
diff --git a/src/drawscene.h b/src/drawscene.h
index 364fcd499..99ff1a6bc 100644
--- a/src/drawscene.h
+++ b/src/drawscene.h
@@ -27,12 +27,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
void draw_load_screen(const std::wstring &text, IrrlichtDevice *device,
- gui::IGUIEnvironment *guienv, float dtime = 0, int percent = 0,
- bool clouds = true);
+ gui::IGUIEnvironment *guienv, ITextureSource *tsrc, float dtime = 0,
+ int percent = 0, bool clouds = true);
void draw_scene(video::IVideoDriver *driver, scene::ISceneManager *smgr,
Camera &camera, Client &client, LocalPlayer *player,
- Hud &hud, Mapper &mapper, gui::IGUIEnvironment *guienv,
+ Hud &hud, Minimap *mapper, gui::IGUIEnvironment *guienv,
const v2u32 &screensize, const video::SColor &skycolor,
bool show_hud, bool show_minimap);
diff --git a/src/dungeongen.cpp b/src/dungeongen.cpp
index 78573da04..6cef3f88d 100644
--- a/src/dungeongen.cpp
+++ b/src/dungeongen.cpp
@@ -52,6 +52,7 @@ DungeonGen::DungeonGen(INodeDefManager *ndef,
if (dparams) {
memcpy(&dp, dparams, sizeof(dp));
} else {
+ // Default dungeon parameters
dp.seed = 0;
dp.c_water = ndef->getId("mapgen_water_source");
@@ -63,14 +64,20 @@ DungeonGen::DungeonGen(INodeDefManager *ndef,
if (dp.c_river_water == CONTENT_IGNORE)
dp.c_river_water = ndef->getId("mapgen_water_source");
- dp.diagonal_dirs = false;
- dp.holesize = v3s16(1, 2, 1);
- dp.roomsize = v3s16(0, 0, 0);
- dp.rooms_min = 2;
- dp.rooms_max = 16;
- dp.y_min = -MAX_MAP_GENERATION_LIMIT;
- dp.y_max = MAX_MAP_GENERATION_LIMIT;
- dp.notifytype = GENNOTIFY_DUNGEON;
+ dp.diagonal_dirs = false;
+ dp.only_in_ground = true;
+ dp.holesize = v3s16(1, 2, 1);
+ dp.corridor_len_min = 1;
+ dp.corridor_len_max = 13;
+ dp.room_size_min = v3s16(4, 4, 4);
+ dp.room_size_max = v3s16(8, 6, 8);
+ dp.room_size_large_min = v3s16(8, 8, 8);
+ dp.room_size_large_max = v3s16(16, 16, 16);
+ dp.rooms_min = 2;
+ dp.rooms_max = 16;
+ dp.y_min = -MAX_MAP_GENERATION_LIMIT;
+ dp.y_max = MAX_MAP_GENERATION_LIMIT;
+ dp.notifytype = GENNOTIFY_DUNGEON;
dp.np_density = nparams_dungeon_density;
dp.np_alt_wall = nparams_dungeon_alt_wall;
@@ -97,16 +104,19 @@ void DungeonGen::generate(MMVManip *vm, u32 bseed, v3s16 nmin, v3s16 nmax)
// Dungeon generator doesn't modify places which have this set
vm->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE | VMANIP_FLAG_DUNGEON_PRESERVE);
- // Set all air and water to be untouchable
- // to make dungeons open to caves and open air
- for (s16 z = nmin.Z; z <= nmax.Z; z++) {
- for (s16 y = nmin.Y; y <= nmax.Y; y++) {
- u32 i = vm->m_area.index(nmin.X, y, z);
- for (s16 x = nmin.X; x <= nmax.X; x++) {
- content_t c = vm->m_data[i].getContent();
- if (c == CONTENT_AIR || c == dp.c_water || c == dp.c_river_water)
- vm->m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
- i++;
+ if (dp.only_in_ground) {
+ // Set all air and water to be untouchable
+ // to make dungeons open to caves and open air
+ for (s16 z = nmin.Z; z <= nmax.Z; z++) {
+ for (s16 y = nmin.Y; y <= nmax.Y; y++) {
+ u32 i = vm->m_area.index(nmin.X, y, z);
+ for (s16 x = nmin.X; x <= nmax.X; x++) {
+ content_t c = vm->m_data[i].getContent();
+ if (c == CONTENT_AIR || c == dp.c_water ||
+ c == dp.c_river_water)
+ vm->m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
+ i++;
+ }
}
}
}
@@ -142,21 +152,25 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
v3s16 roomplace;
/*
- Find place for first room
+ Find place for first room.
+ There is a 1 in 4 chance of the first room being 'large',
+ all other rooms are not 'large'.
*/
bool fits = false;
for (u32 i = 0; i < 100 && !fits; i++) {
bool is_large_room = ((random.next() & 3) == 1);
if (is_large_room) {
- roomsize.Z = random.range(8, 16);
- roomsize.Y = random.range(8, 16);
- roomsize.X = random.range(8, 16);
+ roomsize.Z = random.range(
+ dp.room_size_large_min.Z, dp.room_size_large_max.Z);
+ roomsize.Y = random.range(
+ dp.room_size_large_min.Y, dp.room_size_large_max.Y);
+ roomsize.X = random.range(
+ dp.room_size_large_min.X, dp.room_size_large_max.X);
} else {
- roomsize.Z = random.range(4, 8);
- roomsize.Y = random.range(4, 6);
- roomsize.X = random.range(4, 8);
+ roomsize.Z = random.range(dp.room_size_min.Z, dp.room_size_max.Z);
+ roomsize.Y = random.range(dp.room_size_min.Y, dp.room_size_max.Y);
+ roomsize.X = random.range(dp.room_size_min.X, dp.room_size_max.X);
}
- roomsize += dp.roomsize;
// start_padding is used to disallow starting the generation of
// a dungeon in a neighboring generation chunk
@@ -246,10 +260,9 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
makeCorridor(doorplace, doordir, corridor_end, corridor_end_dir);
// Find a place for a random sized room
- roomsize.Z = random.range(4, 8);
- roomsize.Y = random.range(4, 6);
- roomsize.X = random.range(4, 8);
- roomsize += dp.roomsize;
+ roomsize.Z = random.range(dp.room_size_min.Z, dp.room_size_max.Z);
+ roomsize.Y = random.range(dp.room_size_min.Y, dp.room_size_max.Y);
+ roomsize.X = random.range(dp.room_size_min.X, dp.room_size_max.X);
m_pos = corridor_end;
m_dir = corridor_end_dir;
@@ -397,13 +410,8 @@ void DungeonGen::makeCorridor(v3s16 doorplace, v3s16 doordir,
makeHole(doorplace);
v3s16 p0 = doorplace;
v3s16 dir = doordir;
- u32 length;
- /*if (random.next() % 2)
- length = random.range(1, 13);
- else
- length = random.range(1, 6);*/
- length = random.range(1, 13);
- u32 partlength = random.range(1, 13);
+ u32 length = random.range(dp.corridor_len_min, dp.corridor_len_max);
+ u32 partlength = random.range(dp.corridor_len_min, dp.corridor_len_max);
u32 partcount = 0;
s16 make_stairs = 0;
@@ -415,8 +423,8 @@ void DungeonGen::makeCorridor(v3s16 doorplace, v3s16 doordir,
if (partcount != 0)
p.Y += make_stairs;
- if (vm->m_area.contains(p) && vm->m_area.contains(p + v3s16(0, 1, 0)) &&
- vm->m_area.contains(v3s16(p.X - dir.X, p.Y - 1, p.Z - dir.Z))) {
+ // Check segment of minimum size corridor is in voxelmanip
+ if (vm->m_area.contains(p) && vm->m_area.contains(p + v3s16(0, 1, 0))) {
if (make_stairs) {
makeFill(p + v3s16(-1, -1, -1),
dp.holesize + v3s16(2, 3, 2),
@@ -437,14 +445,24 @@ void DungeonGen::makeCorridor(v3s16 doorplace, v3s16 doordir,
// rotate face 180 deg if
// making stairs backwards
int facedir = dir_to_facedir(dir * make_stairs);
-
- u32 vi = vm->m_area.index(p.X - dir.X, p.Y - 1, p.Z - dir.Z);
- if (vm->m_data[vi].getContent() == dp.c_wall)
- vm->m_data[vi] = MapNode(dp.c_stair, 0, facedir);
-
- vi = vm->m_area.index(p.X, p.Y, p.Z);
- if (vm->m_data[vi].getContent() == dp.c_wall)
- vm->m_data[vi] = MapNode(dp.c_stair, 0, facedir);
+ v3s16 ps = p;
+ u16 stair_width = (dir.Z != 0) ? dp.holesize.X : dp.holesize.Z;
+ // Stair width direction vector
+ v3s16 swv = (dir.Z != 0) ? v3s16(1, 0, 0) : v3s16(0, 0, 1);
+
+ for (u16 st = 0; st < stair_width; st++) {
+ u32 vi = vm->m_area.index(ps.X - dir.X, ps.Y - 1, ps.Z - dir.Z);
+ if (vm->m_area.contains(ps + v3s16(-dir.X, -1, -dir.Z)) &&
+ vm->m_data[vi].getContent() == dp.c_wall)
+ vm->m_data[vi] = MapNode(dp.c_stair, 0, facedir);
+
+ vi = vm->m_area.index(ps.X, ps.Y, ps.Z);
+ if (vm->m_area.contains(ps) &&
+ vm->m_data[vi].getContent() == dp.c_wall)
+ vm->m_data[vi] = MapNode(dp.c_stair, 0, facedir);
+
+ ps += swv;
+ }
}
} else {
makeFill(p + v3s16(-1, -1, -1),
@@ -546,7 +564,6 @@ bool DungeonGen::findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
continue;
v3s16 roomplace;
// X east, Z north, Y up
-#if 1
if (doordir == v3s16(1, 0, 0)) // X+
roomplace = doorplace +
v3s16(0, -1, random.range(-roomsize.Z + 2, -2));
@@ -559,17 +576,6 @@ bool DungeonGen::findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
if (doordir == v3s16(0, 0, -1)) // Z-
roomplace = doorplace +
v3s16(random.range(-roomsize.X + 2, -2), -1, -roomsize.Z + 1);
-#endif
-#if 0
- if (doordir == v3s16(1, 0, 0)) // X+
- roomplace = doorplace + v3s16(0, -1, -roomsize.Z / 2);
- if (doordir == v3s16(-1, 0, 0)) // X-
- roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z / 2);
- if (doordir == v3s16(0, 0, 1)) // Z+
- roomplace = doorplace + v3s16(-roomsize.X / 2, -1, 0);
- if (doordir == v3s16(0, 0, -1)) // Z-
- roomplace = doorplace + v3s16(-roomsize.X / 2, -1, -roomsize.Z + 1);
-#endif
// Check fit
bool fits = true;
@@ -612,7 +618,7 @@ v3s16 rand_ortho_dir(PseudoRandom &random, bool diagonal_dirs)
dir.Z = random.next() % 3 - 1;
dir.Y = 0;
dir.X = random.next() % 3 - 1;
- } while ((dir.X == 0 && dir.Z == 0) && trycount < 10);
+ } while ((dir.X == 0 || dir.Z == 0) && trycount < 10);
return dir;
} else {
diff --git a/src/dungeongen.h b/src/dungeongen.h
index 30786b9f3..4bd208330 100644
--- a/src/dungeongen.h
+++ b/src/dungeongen.h
@@ -48,8 +48,14 @@ struct DungeonParams {
content_t c_stair;
bool diagonal_dirs;
+ bool only_in_ground;
v3s16 holesize;
- v3s16 roomsize;
+ u16 corridor_len_min;
+ u16 corridor_len_max;
+ v3s16 room_size_min;
+ v3s16 room_size_max;
+ v3s16 room_size_large_min;
+ v3s16 room_size_large_max;
u16 rooms_min;
u16 rooms_max;
s16 y_min;
diff --git a/src/emerge.cpp b/src/emerge.cpp
index 25b2e924b..d24971e44 100644
--- a/src/emerge.cpp
+++ b/src/emerge.cpp
@@ -40,7 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mg_schematic.h"
#include "nodedef.h"
#include "profiler.h"
-#include "scripting_game.h"
+#include "scripting_server.h"
#include "server.h"
#include "serverobject.h"
#include "settings.h"
@@ -89,13 +89,13 @@ private:
//// EmergeManager
////
-EmergeManager::EmergeManager(IGameDef *gamedef)
+EmergeManager::EmergeManager(Server *server)
{
- this->ndef = gamedef->getNodeDefManager();
- this->biomemgr = new BiomeManager(gamedef);
- this->oremgr = new OreManager(gamedef);
- this->decomgr = new DecorationManager(gamedef);
- this->schemmgr = new SchematicManager(gamedef);
+ this->ndef = server->getNodeDefManager();
+ this->biomemgr = new BiomeManager(server);
+ this->oremgr = new OreManager(server);
+ this->decomgr = new DecorationManager(server);
+ this->schemmgr = new SchematicManager(server);
this->gen_notify_on = 0;
// Note that accesses to this variable are not synchronized.
@@ -128,7 +128,7 @@ EmergeManager::EmergeManager(IGameDef *gamedef)
m_qlimit_generate = 1;
for (s16 i = 0; i < nthreads; i++)
- m_threads.push_back(new EmergeThread((Server *)gamedef, i));
+ m_threads.push_back(new EmergeThread(server, i));
infostream << "EmergeManager: using " << nthreads << " threads" << std::endl;
}
@@ -174,6 +174,9 @@ bool EmergeManager::initMapgens(MapgenParams *params)
Mapgen *EmergeManager::getCurrentMapgen()
{
+ if (!m_threads_active)
+ return NULL;
+
for (u32 i = 0; i != m_threads.size(); i++) {
if (m_threads[i]->isCurrentThread())
return m_threads[i]->m_mapgen;
@@ -564,7 +567,7 @@ MapBlock *EmergeThread::finishGen(v3s16 pos, BlockMakeData *bmdata,
m_server->getScriptIface()->environment_OnGenerated(
minp, maxp, m_mapgen->blockseed);
} catch (LuaError &e) {
- m_server->setAsyncFatalError("Lua: " + std::string(e.what()));
+ m_server->setAsyncFatalError("Lua: finishGen" + std::string(e.what()));
}
EMERGE_DBG_OUT("ended up with: " << analyze_block(block));
@@ -603,7 +606,7 @@ void *EmergeThread::run()
continue;
}
- if (blockpos_over_limit(pos))
+ if (blockpos_over_max_limit(pos))
continue;
bool allow_gen = bedata.flags & BLOCK_EMERGE_ALLOW_GEN;
diff --git a/src/emerge.h b/src/emerge.h
index 71ad97da3..76653e6cd 100644
--- a/src/emerge.h
+++ b/src/emerge.h
@@ -42,6 +42,7 @@ class BiomeManager;
class OreManager;
class DecorationManager;
class SchematicManager;
+class Server;
// Structure containing inputs/outputs for chunk generation
struct BlockMakeData {
@@ -115,7 +116,7 @@ public:
SchematicManager *schemmgr;
// Methods
- EmergeManager(IGameDef *gamedef);
+ EmergeManager(Server *server);
~EmergeManager();
bool initMapgens(MapgenParams *mgparams);
diff --git a/src/environment.cpp b/src/environment.cpp
index 13c64b37c..4e782db81 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -19,47 +19,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <fstream>
#include "environment.h"
-#include "filesys.h"
-#include "porting.h"
#include "collision.h"
-#include "content_mapnode.h"
-#include "mapblock.h"
#include "serverobject.h"
-#include "content_sao.h"
-#include "settings.h"
-#include "log.h"
-#include "profiler.h"
-#include "scripting_game.h"
-#include "nodedef.h"
-#include "nodemetadata.h"
-#include "gamedef.h"
-#ifndef SERVER
-#include "clientmap.h"
-#include "localplayer.h"
-#include "mapblock_mesh.h"
-#include "event.h"
-#endif
+#include "scripting_server.h"
#include "server.h"
#include "daynightratio.h"
-#include "map.h"
#include "emerge.h"
-#include "util/serialize.h"
-#include "threading/mutex_auto_lock.h"
-#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
-#define LBM_NAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_:"
-
-// A number that is much smaller than the timeout for particle spawners should/could ever be
-#define PARTICLE_SPAWNER_NO_EXPIRY -1024.f
-
-Environment::Environment():
+Environment::Environment(IGameDef *gamedef):
m_time_of_day_speed(0),
m_time_of_day(9000),
m_time_of_day_f(9000./24000),
m_time_conversion_skew(0.0f),
m_enable_day_night_ratio_override(false),
- m_day_night_ratio_override(0.0f)
+ m_day_night_ratio_override(0.0f),
+ m_gamedef(gamedef)
{
m_cache_enable_shaders = g_settings->getBool("enable_shaders");
m_cache_active_block_mgmt_interval = g_settings->getFloat("active_block_mgmt_interval");
@@ -95,7 +70,7 @@ void Environment::setTimeOfDay(u32 time)
{
MutexAutoLock lock(this->m_time_lock);
if (m_time_of_day > time)
- m_day_count++;
+ ++m_day_count;
m_time_of_day = time;
m_time_of_day_f = (float)time / 24000.0;
}
@@ -128,7 +103,7 @@ void Environment::stepTimeOfDay(float dtime)
// Sync at overflow
if (m_time_of_day + units >= 24000) {
sync_f = true;
- m_day_count++;
+ ++m_day_count;
}
m_time_of_day = (m_time_of_day + units) % 24000;
if (sync_f)
@@ -151,2699 +126,3 @@ u32 Environment::getDayCount()
// Atomic<u32> counter
return m_day_count;
}
-
-
-/*
- ABMWithState
-*/
-
-ABMWithState::ABMWithState(ActiveBlockModifier *abm_):
- abm(abm_),
- timer(0)
-{
- // Initialize timer to random value to spread processing
- float itv = abm->getTriggerInterval();
- itv = MYMAX(0.001, itv); // No less than 1ms
- int minval = MYMAX(-0.51*itv, -60); // Clamp to
- int maxval = MYMIN(0.51*itv, 60); // +-60 seconds
- timer = myrand_range(minval, maxval);
-}
-
-/*
- LBMManager
-*/
-
-void LBMContentMapping::deleteContents()
-{
- for (std::vector<LoadingBlockModifierDef *>::iterator it = lbm_list.begin();
- it != lbm_list.end(); ++it) {
- delete *it;
- }
-}
-
-void LBMContentMapping::addLBM(LoadingBlockModifierDef *lbm_def, IGameDef *gamedef)
-{
- // Add the lbm_def to the LBMContentMapping.
- // Unknown names get added to the global NameIdMapping.
- INodeDefManager *nodedef = gamedef->ndef();
-
- lbm_list.push_back(lbm_def);
-
- for (std::set<std::string>::const_iterator it = lbm_def->trigger_contents.begin();
- it != lbm_def->trigger_contents.end(); ++it) {
- std::set<content_t> c_ids;
- bool found = nodedef->getIds(*it, c_ids);
- if (!found) {
- content_t c_id = gamedef->allocateUnknownNodeId(*it);
- if (c_id == CONTENT_IGNORE) {
- // Seems it can't be allocated.
- warningstream << "Could not internalize node name \"" << *it
- << "\" while loading LBM \"" << lbm_def->name << "\"." << std::endl;
- continue;
- }
- c_ids.insert(c_id);
- }
-
- for (std::set<content_t>::const_iterator iit =
- c_ids.begin(); iit != c_ids.end(); ++iit) {
- content_t c_id = *iit;
- map[c_id].push_back(lbm_def);
- }
- }
-}
-
-const std::vector<LoadingBlockModifierDef *> *
- LBMContentMapping::lookup(content_t c) const
-{
- container_map::const_iterator it = map.find(c);
- if (it == map.end())
- return NULL;
- // This first dereferences the iterator, returning
- // a std::vector<LoadingBlockModifierDef *>
- // reference, then we convert it to a pointer.
- return &(it->second);
-}
-
-LBMManager::~LBMManager()
-{
- for (std::map<std::string, LoadingBlockModifierDef *>::iterator it =
- m_lbm_defs.begin(); it != m_lbm_defs.end(); ++it) {
- delete it->second;
- }
- for (lbm_lookup_map::iterator it = m_lbm_lookup.begin();
- it != m_lbm_lookup.end(); ++it) {
- (it->second).deleteContents();
- }
-}
-
-void LBMManager::addLBMDef(LoadingBlockModifierDef *lbm_def)
-{
- // Precondition, in query mode the map isn't used anymore
- FATAL_ERROR_IF(m_query_mode == true,
- "attempted to modify LBMManager in query mode");
-
- if (!string_allowed(lbm_def->name, LBM_NAME_ALLOWED_CHARS)) {
- throw ModError("Error adding LBM \"" + lbm_def->name +
- "\": Does not follow naming conventions: "
- "Only chararacters [a-z0-9_:] are allowed.");
- }
-
- m_lbm_defs[lbm_def->name] = lbm_def;
-}
-
-void LBMManager::loadIntroductionTimes(const std::string &times,
- IGameDef *gamedef, u32 now)
-{
- m_query_mode = true;
-
- // name -> time map.
- // Storing it in a map first instead of
- // handling the stuff directly in the loop
- // removes all duplicate entries.
- // TODO make this std::unordered_map
- std::map<std::string, u32> introduction_times;
-
- /*
- The introduction times string consists of name~time entries,
- with each entry terminated by a semicolon. The time is decimal.
- */
-
- size_t idx = 0;
- size_t idx_new;
- while ((idx_new = times.find(";", idx)) != std::string::npos) {
- std::string entry = times.substr(idx, idx_new - idx);
- std::vector<std::string> components = str_split(entry, '~');
- if (components.size() != 2)
- throw SerializationError("Introduction times entry \""
- + entry + "\" requires exactly one '~'!");
- const std::string &name = components[0];
- u32 time = from_string<u32>(components[1]);
- introduction_times[name] = time;
- idx = idx_new + 1;
- }
-
- // Put stuff from introduction_times into m_lbm_lookup
- for (std::map<std::string, u32>::const_iterator it = introduction_times.begin();
- it != introduction_times.end(); ++it) {
- const std::string &name = it->first;
- u32 time = it->second;
-
- std::map<std::string, LoadingBlockModifierDef *>::iterator def_it =
- m_lbm_defs.find(name);
- if (def_it == m_lbm_defs.end()) {
- // This seems to be an LBM entry for
- // an LBM we haven't loaded. Discard it.
- continue;
- }
- LoadingBlockModifierDef *lbm_def = def_it->second;
- if (lbm_def->run_at_every_load) {
- // This seems to be an LBM entry for
- // an LBM that runs at every load.
- // Don't add it just yet.
- continue;
- }
-
- m_lbm_lookup[time].addLBM(lbm_def, gamedef);
-
- // Erase the entry so that we know later
- // what elements didn't get put into m_lbm_lookup
- m_lbm_defs.erase(name);
- }
-
- // Now also add the elements from m_lbm_defs to m_lbm_lookup
- // that weren't added in the previous step.
- // They are introduced first time to this world,
- // or are run at every load (introducement time hardcoded to U32_MAX).
-
- LBMContentMapping &lbms_we_introduce_now = m_lbm_lookup[now];
- LBMContentMapping &lbms_running_always = m_lbm_lookup[U32_MAX];
-
- for (std::map<std::string, LoadingBlockModifierDef *>::iterator it =
- m_lbm_defs.begin(); it != m_lbm_defs.end(); ++it) {
- if (it->second->run_at_every_load) {
- lbms_running_always.addLBM(it->second, gamedef);
- } else {
- lbms_we_introduce_now.addLBM(it->second, gamedef);
- }
- }
-
- // Clear the list, so that we don't delete remaining elements
- // twice in the destructor
- m_lbm_defs.clear();
-}
-
-std::string LBMManager::createIntroductionTimesString()
-{
- // Precondition, we must be in query mode
- FATAL_ERROR_IF(m_query_mode == false,
- "attempted to query on non fully set up LBMManager");
-
- std::ostringstream oss;
- for (lbm_lookup_map::iterator it = m_lbm_lookup.begin();
- it != m_lbm_lookup.end(); ++it) {
- u32 time = it->first;
- std::vector<LoadingBlockModifierDef *> &lbm_list = it->second.lbm_list;
- for (std::vector<LoadingBlockModifierDef *>::iterator iit = lbm_list.begin();
- iit != lbm_list.end(); ++iit) {
- // Don't add if the LBM runs at every load,
- // then introducement time is hardcoded
- // and doesn't need to be stored
- if ((*iit)->run_at_every_load)
- continue;
- oss << (*iit)->name << "~" << time << ";";
- }
- }
- return oss.str();
-}
-
-void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, u32 stamp)
-{
- // Precondition, we need m_lbm_lookup to be initialized
- FATAL_ERROR_IF(m_query_mode == false,
- "attempted to query on non fully set up LBMManager");
- v3s16 pos_of_block = block->getPosRelative();
- v3s16 pos;
- MapNode n;
- content_t c;
- lbm_lookup_map::const_iterator it = getLBMsIntroducedAfter(stamp);
- for (pos.X = 0; pos.X < MAP_BLOCKSIZE; pos.X++)
- for (pos.Y = 0; pos.Y < MAP_BLOCKSIZE; pos.Y++)
- for (pos.Z = 0; pos.Z < MAP_BLOCKSIZE; pos.Z++)
- {
- n = block->getNodeNoEx(pos);
- c = n.getContent();
- for (LBMManager::lbm_lookup_map::const_iterator iit = it;
- iit != m_lbm_lookup.end(); ++iit) {
- const std::vector<LoadingBlockModifierDef *> *lbm_list =
- iit->second.lookup(c);
- if (!lbm_list)
- continue;
- for (std::vector<LoadingBlockModifierDef *>::const_iterator iit =
- lbm_list->begin(); iit != lbm_list->end(); ++iit) {
- (*iit)->trigger(env, pos + pos_of_block, n);
- }
- }
- }
-}
-
-/*
- ActiveBlockList
-*/
-
-void fillRadiusBlock(v3s16 p0, s16 r, std::set<v3s16> &list)
-{
- v3s16 p;
- for(p.X=p0.X-r; p.X<=p0.X+r; p.X++)
- for(p.Y=p0.Y-r; p.Y<=p0.Y+r; p.Y++)
- for(p.Z=p0.Z-r; p.Z<=p0.Z+r; p.Z++)
- {
- // Set in list
- list.insert(p);
- }
-}
-
-void ActiveBlockList::update(std::vector<v3s16> &active_positions,
- s16 radius,
- std::set<v3s16> &blocks_removed,
- std::set<v3s16> &blocks_added)
-{
- /*
- Create the new list
- */
- std::set<v3s16> newlist = m_forceloaded_list;
- for(std::vector<v3s16>::iterator i = active_positions.begin();
- i != active_positions.end(); ++i)
- {
- fillRadiusBlock(*i, radius, newlist);
- }
-
- /*
- Find out which blocks on the old list are not on the new list
- */
- // Go through old list
- for(std::set<v3s16>::iterator i = m_list.begin();
- i != m_list.end(); ++i)
- {
- v3s16 p = *i;
- // If not on new list, it's been removed
- if(newlist.find(p) == newlist.end())
- blocks_removed.insert(p);
- }
-
- /*
- Find out which blocks on the new list are not on the old list
- */
- // Go through new list
- for(std::set<v3s16>::iterator i = newlist.begin();
- i != newlist.end(); ++i)
- {
- v3s16 p = *i;
- // If not on old list, it's been added
- if(m_list.find(p) == m_list.end())
- blocks_added.insert(p);
- }
-
- /*
- Update m_list
- */
- m_list.clear();
- for(std::set<v3s16>::iterator i = newlist.begin();
- i != newlist.end(); ++i)
- {
- v3s16 p = *i;
- m_list.insert(p);
- }
-}
-
-/*
- ServerEnvironment
-*/
-
-ServerEnvironment::ServerEnvironment(ServerMap *map,
- GameScripting *scriptIface, IGameDef *gamedef,
- const std::string &path_world) :
- m_map(map),
- m_script(scriptIface),
- m_gamedef(gamedef),
- m_path_world(path_world),
- m_send_recommended_timer(0),
- m_active_block_interval_overload_skip(0),
- m_game_time(0),
- m_game_time_fraction_counter(0),
- m_last_clear_objects_time(0),
- m_recommended_send_interval(0.1),
- m_max_lag_estimate(0.1)
-{
-}
-
-ServerEnvironment::~ServerEnvironment()
-{
- // Clear active block list.
- // This makes the next one delete all active objects.
- m_active_blocks.clear();
-
- // Convert all objects to static and delete the active objects
- deactivateFarObjects(true);
-
- // Drop/delete map
- m_map->drop();
-
- // Delete ActiveBlockModifiers
- for (std::vector<ABMWithState>::iterator
- i = m_abms.begin(); i != m_abms.end(); ++i){
- delete i->abm;
- }
-
- // Deallocate players
- for (std::vector<RemotePlayer *>::iterator i = m_players.begin();
- i != m_players.end(); ++i) {
- delete (*i);
- }
-}
-
-Map & ServerEnvironment::getMap()
-{
- return *m_map;
-}
-
-ServerMap & ServerEnvironment::getServerMap()
-{
- return *m_map;
-}
-
-RemotePlayer *ServerEnvironment::getPlayer(const u16 peer_id)
-{
- for (std::vector<RemotePlayer *>::iterator i = m_players.begin();
- i != m_players.end(); ++i) {
- RemotePlayer *player = *i;
- if (player->peer_id == peer_id)
- return player;
- }
- return NULL;
-}
-
-RemotePlayer *ServerEnvironment::getPlayer(const char* name)
-{
- for (std::vector<RemotePlayer *>::iterator i = m_players.begin();
- i != m_players.end(); ++i) {
- RemotePlayer *player = *i;
- if (strcmp(player->getName(), name) == 0)
- return player;
- }
- return NULL;
-}
-
-void ServerEnvironment::addPlayer(RemotePlayer *player)
-{
- DSTACK(FUNCTION_NAME);
- /*
- Check that peer_ids are unique.
- Also check that names are unique.
- Exception: there can be multiple players with peer_id=0
- */
- // If peer id is non-zero, it has to be unique.
- if (player->peer_id != 0)
- FATAL_ERROR_IF(getPlayer(player->peer_id) != NULL, "Peer id not unique");
- // Name has to be unique.
- FATAL_ERROR_IF(getPlayer(player->getName()) != NULL, "Player name not unique");
- // Add.
- m_players.push_back(player);
-}
-
-void ServerEnvironment::removePlayer(RemotePlayer *player)
-{
- for (std::vector<RemotePlayer *>::iterator it = m_players.begin();
- it != m_players.end(); ++it) {
- if ((*it) == player) {
- delete *it;
- m_players.erase(it);
- return;
- }
- }
-}
-
-bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, float stepsize, v3s16 *p)
-{
- float distance = pos1.getDistanceFrom(pos2);
-
- //calculate normalized direction vector
- v3f normalized_vector = v3f((pos2.X - pos1.X)/distance,
- (pos2.Y - pos1.Y)/distance,
- (pos2.Z - pos1.Z)/distance);
-
- //find out if there's a node on path between pos1 and pos2
- for (float i = 1; i < distance; i += stepsize) {
- v3s16 pos = floatToInt(v3f(normalized_vector.X * i,
- normalized_vector.Y * i,
- normalized_vector.Z * i) +pos1,BS);
-
- MapNode n = getMap().getNodeNoEx(pos);
-
- if(n.param0 != CONTENT_AIR) {
- if (p) {
- *p = pos;
- }
- return false;
- }
- }
- return true;
-}
-
-void ServerEnvironment::kickAllPlayers(AccessDeniedCode reason,
- const std::string &str_reason, bool reconnect)
-{
- for (std::vector<RemotePlayer *>::iterator it = m_players.begin();
- it != m_players.end(); ++it) {
- RemotePlayer *player = dynamic_cast<RemotePlayer *>(*it);
- ((Server*)m_gamedef)->DenyAccessVerCompliant(player->peer_id,
- player->protocol_version, reason, str_reason, reconnect);
- }
-}
-
-void ServerEnvironment::saveLoadedPlayers()
-{
- std::string players_path = m_path_world + DIR_DELIM "players";
- fs::CreateDir(players_path);
-
- for (std::vector<RemotePlayer *>::iterator it = m_players.begin();
- it != m_players.end();
- ++it) {
- if ((*it)->checkModified()) {
- (*it)->save(players_path, m_gamedef);
- }
- }
-}
-
-void ServerEnvironment::savePlayer(RemotePlayer *player)
-{
- std::string players_path = m_path_world + DIR_DELIM "players";
- fs::CreateDir(players_path);
-
- player->save(players_path, m_gamedef);
-}
-
-RemotePlayer *ServerEnvironment::loadPlayer(const std::string &playername, PlayerSAO *sao)
-{
- bool newplayer = false;
- bool found = false;
- std::string players_path = m_path_world + DIR_DELIM "players" DIR_DELIM;
- std::string path = players_path + playername;
-
- RemotePlayer *player = getPlayer(playername.c_str());
- if (!player) {
- player = new RemotePlayer("", m_gamedef->idef());
- newplayer = true;
- }
-
- for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) {
- //// Open file and deserialize
- std::ifstream is(path.c_str(), std::ios_base::binary);
- if (!is.good())
- continue;
-
- player->deSerialize(is, path, sao);
- is.close();
-
- if (player->getName() == playername) {
- found = true;
- break;
- }
-
- path = players_path + playername + itos(i);
- }
-
- if (!found) {
- infostream << "Player file for player " << playername
- << " not found" << std::endl;
- if (newplayer)
- delete player;
-
- return NULL;
- }
-
- if (newplayer) {
- addPlayer(player);
- }
- player->setModified(false);
- return player;
-}
-
-void ServerEnvironment::saveMeta()
-{
- std::string path = m_path_world + DIR_DELIM "env_meta.txt";
-
- // Open file and serialize
- std::ostringstream ss(std::ios_base::binary);
-
- Settings args;
- args.setU64("game_time", m_game_time);
- args.setU64("time_of_day", getTimeOfDay());
- args.setU64("last_clear_objects_time", m_last_clear_objects_time);
- args.setU64("lbm_introduction_times_version", 1);
- args.set("lbm_introduction_times",
- m_lbm_mgr.createIntroductionTimesString());
- args.setU64("day_count", m_day_count);
- args.writeLines(ss);
- ss<<"EnvArgsEnd\n";
-
- if(!fs::safeWriteToFile(path, ss.str()))
- {
- infostream<<"ServerEnvironment::saveMeta(): Failed to write "
- <<path<<std::endl;
- throw SerializationError("Couldn't save env meta");
- }
-}
-
-void ServerEnvironment::loadMeta()
-{
- std::string path = m_path_world + DIR_DELIM "env_meta.txt";
-
- // Open file and deserialize
- std::ifstream is(path.c_str(), std::ios_base::binary);
- if (!is.good()) {
- infostream << "ServerEnvironment::loadMeta(): Failed to open "
- << path << std::endl;
- throw SerializationError("Couldn't load env meta");
- }
-
- Settings args;
-
- if (!args.parseConfigLines(is, "EnvArgsEnd")) {
- throw SerializationError("ServerEnvironment::loadMeta(): "
- "EnvArgsEnd not found!");
- }
-
- try {
- m_game_time = args.getU64("game_time");
- } catch (SettingNotFoundException &e) {
- // Getting this is crucial, otherwise timestamps are useless
- throw SerializationError("Couldn't load env meta game_time");
- }
-
- setTimeOfDay(args.exists("time_of_day") ?
- // set day to morning by default
- args.getU64("time_of_day") : 9000);
-
- m_last_clear_objects_time = args.exists("last_clear_objects_time") ?
- // If missing, do as if clearObjects was never called
- args.getU64("last_clear_objects_time") : 0;
-
- std::string lbm_introduction_times = "";
- try {
- u64 ver = args.getU64("lbm_introduction_times_version");
- if (ver == 1) {
- lbm_introduction_times = args.get("lbm_introduction_times");
- } else {
- infostream << "ServerEnvironment::loadMeta(): Non-supported"
- << " introduction time version " << ver << std::endl;
- }
- } catch (SettingNotFoundException &e) {
- // No problem, this is expected. Just continue with an empty string
- }
- m_lbm_mgr.loadIntroductionTimes(lbm_introduction_times, m_gamedef, m_game_time);
-
- m_day_count = args.exists("day_count") ?
- args.getU64("day_count") : 0;
-}
-
-void ServerEnvironment::loadDefaultMeta()
-{
- m_lbm_mgr.loadIntroductionTimes("", m_gamedef, m_game_time);
-}
-
-struct ActiveABM
-{
- ActiveBlockModifier *abm;
- int chance;
- std::set<content_t> required_neighbors;
-};
-
-class ABMHandler
-{
-private:
- ServerEnvironment *m_env;
- std::map<content_t, std::vector<ActiveABM> > m_aabms;
-public:
- ABMHandler(std::vector<ABMWithState> &abms,
- float dtime_s, ServerEnvironment *env,
- bool use_timers):
- m_env(env)
- {
- if(dtime_s < 0.001)
- return;
- INodeDefManager *ndef = env->getGameDef()->ndef();
- for(std::vector<ABMWithState>::iterator
- i = abms.begin(); i != abms.end(); ++i) {
- ActiveBlockModifier *abm = i->abm;
- float trigger_interval = abm->getTriggerInterval();
- if(trigger_interval < 0.001)
- trigger_interval = 0.001;
- float actual_interval = dtime_s;
- if(use_timers){
- i->timer += dtime_s;
- if(i->timer < trigger_interval)
- continue;
- i->timer -= trigger_interval;
- actual_interval = trigger_interval;
- }
- float chance = abm->getTriggerChance();
- if(chance == 0)
- chance = 1;
- ActiveABM aabm;
- aabm.abm = abm;
- if(abm->getSimpleCatchUp()) {
- float intervals = actual_interval / trigger_interval;
- if(intervals == 0)
- continue;
- aabm.chance = chance / intervals;
- if(aabm.chance == 0)
- aabm.chance = 1;
- } else {
- aabm.chance = chance;
- }
- // Trigger neighbors
- std::set<std::string> required_neighbors_s
- = abm->getRequiredNeighbors();
- for(std::set<std::string>::iterator
- i = required_neighbors_s.begin();
- i != required_neighbors_s.end(); ++i)
- {
- ndef->getIds(*i, aabm.required_neighbors);
- }
- // Trigger contents
- std::set<std::string> contents_s = abm->getTriggerContents();
- for(std::set<std::string>::iterator
- i = contents_s.begin(); i != contents_s.end(); ++i)
- {
- std::set<content_t> ids;
- ndef->getIds(*i, ids);
- for(std::set<content_t>::const_iterator k = ids.begin();
- k != ids.end(); ++k)
- {
- content_t c = *k;
- std::map<content_t, std::vector<ActiveABM> >::iterator j;
- j = m_aabms.find(c);
- if(j == m_aabms.end()){
- std::vector<ActiveABM> aabmlist;
- m_aabms[c] = aabmlist;
- j = m_aabms.find(c);
- }
- j->second.push_back(aabm);
- }
- }
- }
- }
- // Find out how many objects the given block and its neighbours contain.
- // Returns the number of objects in the block, and also in 'wider' the
- // number of objects in the block and all its neighbours. The latter
- // may an estimate if any neighbours are unloaded.
- u32 countObjects(MapBlock *block, ServerMap * map, u32 &wider)
- {
- wider = 0;
- u32 wider_unknown_count = 0;
- for(s16 x=-1; x<=1; x++)
- for(s16 y=-1; y<=1; y++)
- for(s16 z=-1; z<=1; z++)
- {
- MapBlock *block2 = map->getBlockNoCreateNoEx(
- block->getPos() + v3s16(x,y,z));
- if(block2==NULL){
- wider_unknown_count++;
- continue;
- }
- wider += block2->m_static_objects.m_active.size()
- + block2->m_static_objects.m_stored.size();
- }
- // Extrapolate
- u32 active_object_count = block->m_static_objects.m_active.size();
- u32 wider_known_count = 3*3*3 - wider_unknown_count;
- wider += wider_unknown_count * wider / wider_known_count;
- return active_object_count;
-
- }
- void apply(MapBlock *block)
- {
- if(m_aabms.empty())
- return;
-
- ServerMap *map = &m_env->getServerMap();
-
- u32 active_object_count_wider;
- u32 active_object_count = this->countObjects(block, map, active_object_count_wider);
- m_env->m_added_objects = 0;
-
- v3s16 p0;
- for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
- for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
- for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
- {
- MapNode n = block->getNodeNoEx(p0);
- content_t c = n.getContent();
- v3s16 p = p0 + block->getPosRelative();
-
- std::map<content_t, std::vector<ActiveABM> >::iterator j;
- j = m_aabms.find(c);
- if(j == m_aabms.end())
- continue;
-
- for(std::vector<ActiveABM>::iterator
- i = j->second.begin(); i != j->second.end(); ++i) {
- if(myrand() % i->chance != 0)
- continue;
-
- // Check neighbors
- if(!i->required_neighbors.empty())
- {
- v3s16 p1;
- for(p1.X = p.X-1; p1.X <= p.X+1; p1.X++)
- for(p1.Y = p.Y-1; p1.Y <= p.Y+1; p1.Y++)
- for(p1.Z = p.Z-1; p1.Z <= p.Z+1; p1.Z++)
- {
- if(p1 == p)
- continue;
- MapNode n = map->getNodeNoEx(p1);
- content_t c = n.getContent();
- std::set<content_t>::const_iterator k;
- k = i->required_neighbors.find(c);
- if(k != i->required_neighbors.end()){
- goto neighbor_found;
- }
- }
- // No required neighbor found
- continue;
- }
-neighbor_found:
-
- // Call all the trigger variations
- i->abm->trigger(m_env, p, n);
- i->abm->trigger(m_env, p, n,
- active_object_count, active_object_count_wider);
-
- // Count surrounding objects again if the abms added any
- if(m_env->m_added_objects > 0) {
- active_object_count = countObjects(block, map, active_object_count_wider);
- m_env->m_added_objects = 0;
- }
- }
- }
- }
-};
-
-void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
-{
- // Reset usage timer immediately, otherwise a block that becomes active
- // again at around the same time as it would normally be unloaded will
- // get unloaded incorrectly. (I think this still leaves a small possibility
- // of a race condition between this and server::AsyncRunStep, which only
- // some kind of synchronisation will fix, but it at least reduces the window
- // of opportunity for it to break from seconds to nanoseconds)
- block->resetUsageTimer();
-
- // Get time difference
- u32 dtime_s = 0;
- u32 stamp = block->getTimestamp();
- if (m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
- dtime_s = m_game_time - stamp;
- dtime_s += additional_dtime;
-
- /*infostream<<"ServerEnvironment::activateBlock(): block timestamp: "
- <<stamp<<", game time: "<<m_game_time<<std::endl;*/
-
- // Remove stored static objects if clearObjects was called since block's timestamp
- if (stamp == BLOCK_TIMESTAMP_UNDEFINED || stamp < m_last_clear_objects_time) {
- block->m_static_objects.m_stored.clear();
- // do not set changed flag to avoid unnecessary mapblock writes
- }
-
- // Set current time as timestamp
- block->setTimestampNoChangedFlag(m_game_time);
-
- /*infostream<<"ServerEnvironment::activateBlock(): block is "
- <<dtime_s<<" seconds old."<<std::endl;*/
-
- // Activate stored objects
- activateObjects(block, dtime_s);
-
- /* Handle LoadingBlockModifiers */
- m_lbm_mgr.applyLBMs(this, block, stamp);
-
- // Run node timers
- std::vector<NodeTimer> elapsed_timers =
- block->m_node_timers.step((float)dtime_s);
- if (!elapsed_timers.empty()) {
- MapNode n;
- for (std::vector<NodeTimer>::iterator
- i = elapsed_timers.begin();
- i != elapsed_timers.end(); ++i){
- n = block->getNodeNoEx(i->position);
- v3s16 p = i->position + block->getPosRelative();
- if (m_script->node_on_timer(p, n, i->elapsed))
- block->setNodeTimer(NodeTimer(i->timeout, 0, i->position));
- }
- }
-
- /* Handle ActiveBlockModifiers */
- ABMHandler abmhandler(m_abms, dtime_s, this, false);
- abmhandler.apply(block);
-}
-
-void ServerEnvironment::addActiveBlockModifier(ActiveBlockModifier *abm)
-{
- m_abms.push_back(ABMWithState(abm));
-}
-
-void ServerEnvironment::addLoadingBlockModifierDef(LoadingBlockModifierDef *lbm)
-{
- m_lbm_mgr.addLBMDef(lbm);
-}
-
-bool ServerEnvironment::setNode(v3s16 p, const MapNode &n)
-{
- INodeDefManager *ndef = m_gamedef->ndef();
- MapNode n_old = m_map->getNodeNoEx(p);
-
- // Call destructor
- if (ndef->get(n_old).has_on_destruct)
- m_script->node_on_destruct(p, n_old);
-
- // Replace node
- if (!m_map->addNodeWithEvent(p, n))
- return false;
-
- // Update active VoxelManipulator if a mapgen thread
- m_map->updateVManip(p);
-
- // Call post-destructor
- if (ndef->get(n_old).has_after_destruct)
- m_script->node_after_destruct(p, n_old);
-
- // Call constructor
- if (ndef->get(n).has_on_construct)
- m_script->node_on_construct(p, n);
-
- return true;
-}
-
-bool ServerEnvironment::removeNode(v3s16 p)
-{
- INodeDefManager *ndef = m_gamedef->ndef();
- MapNode n_old = m_map->getNodeNoEx(p);
-
- // Call destructor
- if (ndef->get(n_old).has_on_destruct)
- m_script->node_on_destruct(p, n_old);
-
- // Replace with air
- // This is slightly optimized compared to addNodeWithEvent(air)
- if (!m_map->removeNodeWithEvent(p))
- return false;
-
- // Update active VoxelManipulator if a mapgen thread
- m_map->updateVManip(p);
-
- // Call post-destructor
- if (ndef->get(n_old).has_after_destruct)
- m_script->node_after_destruct(p, n_old);
-
- // Air doesn't require constructor
- return true;
-}
-
-bool ServerEnvironment::swapNode(v3s16 p, const MapNode &n)
-{
- if (!m_map->addNodeWithEvent(p, n, false))
- return false;
-
- // Update active VoxelManipulator if a mapgen thread
- m_map->updateVManip(p);
-
- return true;
-}
-
-void ServerEnvironment::getObjectsInsideRadius(std::vector<u16> &objects, v3f pos, float radius)
-{
- for (ActiveObjectMap::iterator i = m_active_objects.begin();
- i != m_active_objects.end(); ++i) {
- ServerActiveObject* obj = i->second;
- u16 id = i->first;
- v3f objectpos = obj->getBasePosition();
- if (objectpos.getDistanceFrom(pos) > radius)
- continue;
- objects.push_back(id);
- }
-}
-
-void ServerEnvironment::clearObjects(ClearObjectsMode mode)
-{
- infostream << "ServerEnvironment::clearObjects(): "
- << "Removing all active objects" << std::endl;
- std::vector<u16> objects_to_remove;
- for (ActiveObjectMap::iterator i = m_active_objects.begin();
- i != m_active_objects.end(); ++i) {
- ServerActiveObject* obj = i->second;
- if (obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
- continue;
- u16 id = i->first;
- // Delete static object if block is loaded
- if (obj->m_static_exists) {
- MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
- if (block) {
- block->m_static_objects.remove(id);
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_CLEAR_ALL_OBJECTS);
- obj->m_static_exists = false;
- }
- }
- // If known by some client, don't delete immediately
- if (obj->m_known_by_count > 0) {
- obj->m_pending_deactivation = true;
- obj->m_removed = true;
- continue;
- }
-
- // Tell the object about removal
- obj->removingFromEnvironment();
- // Deregister in scripting api
- m_script->removeObjectReference(obj);
-
- // Delete active object
- if (obj->environmentDeletes())
- delete obj;
- // Id to be removed from m_active_objects
- objects_to_remove.push_back(id);
- }
-
- // Remove references from m_active_objects
- for (std::vector<u16>::iterator i = objects_to_remove.begin();
- i != objects_to_remove.end(); ++i) {
- m_active_objects.erase(*i);
- }
-
- // Get list of loaded blocks
- std::vector<v3s16> loaded_blocks;
- infostream << "ServerEnvironment::clearObjects(): "
- << "Listing all loaded blocks" << std::endl;
- m_map->listAllLoadedBlocks(loaded_blocks);
- infostream << "ServerEnvironment::clearObjects(): "
- << "Done listing all loaded blocks: "
- << loaded_blocks.size()<<std::endl;
-
- // Get list of loadable blocks
- std::vector<v3s16> loadable_blocks;
- if (mode == CLEAR_OBJECTS_MODE_FULL) {
- infostream << "ServerEnvironment::clearObjects(): "
- << "Listing all loadable blocks" << std::endl;
- m_map->listAllLoadableBlocks(loadable_blocks);
- infostream << "ServerEnvironment::clearObjects(): "
- << "Done listing all loadable blocks: "
- << loadable_blocks.size() << std::endl;
- } else {
- loadable_blocks = loaded_blocks;
- }
-
- infostream << "ServerEnvironment::clearObjects(): "
- << "Now clearing objects in " << loadable_blocks.size()
- << " blocks" << std::endl;
-
- // Grab a reference on each loaded block to avoid unloading it
- for (std::vector<v3s16>::iterator i = loaded_blocks.begin();
- i != loaded_blocks.end(); ++i) {
- v3s16 p = *i;
- MapBlock *block = m_map->getBlockNoCreateNoEx(p);
- assert(block != NULL);
- block->refGrab();
- }
-
- // Remove objects in all loadable blocks
- u32 unload_interval = U32_MAX;
- if (mode == CLEAR_OBJECTS_MODE_FULL) {
- unload_interval = g_settings->getS32("max_clearobjects_extra_loaded_blocks");
- unload_interval = MYMAX(unload_interval, 1);
- }
- u32 report_interval = loadable_blocks.size() / 10;
- u32 num_blocks_checked = 0;
- u32 num_blocks_cleared = 0;
- u32 num_objs_cleared = 0;
- for (std::vector<v3s16>::iterator i = loadable_blocks.begin();
- i != loadable_blocks.end(); ++i) {
- v3s16 p = *i;
- MapBlock *block = m_map->emergeBlock(p, false);
- if (!block) {
- errorstream << "ServerEnvironment::clearObjects(): "
- << "Failed to emerge block " << PP(p) << std::endl;
- continue;
- }
- u32 num_stored = block->m_static_objects.m_stored.size();
- u32 num_active = block->m_static_objects.m_active.size();
- if (num_stored != 0 || num_active != 0) {
- block->m_static_objects.m_stored.clear();
- block->m_static_objects.m_active.clear();
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_CLEAR_ALL_OBJECTS);
- num_objs_cleared += num_stored + num_active;
- num_blocks_cleared++;
- }
- num_blocks_checked++;
-
- if (report_interval != 0 &&
- num_blocks_checked % report_interval == 0) {
- float percent = 100.0 * (float)num_blocks_checked /
- loadable_blocks.size();
- infostream << "ServerEnvironment::clearObjects(): "
- << "Cleared " << num_objs_cleared << " objects"
- << " in " << num_blocks_cleared << " blocks ("
- << percent << "%)" << std::endl;
- }
- if (num_blocks_checked % unload_interval == 0) {
- m_map->unloadUnreferencedBlocks();
- }
- }
- m_map->unloadUnreferencedBlocks();
-
- // Drop references that were added above
- for (std::vector<v3s16>::iterator i = loaded_blocks.begin();
- i != loaded_blocks.end(); ++i) {
- v3s16 p = *i;
- MapBlock *block = m_map->getBlockNoCreateNoEx(p);
- assert(block);
- block->refDrop();
- }
-
- m_last_clear_objects_time = m_game_time;
-
- infostream << "ServerEnvironment::clearObjects(): "
- << "Finished: Cleared " << num_objs_cleared << " objects"
- << " in " << num_blocks_cleared << " blocks" << std::endl;
-}
-
-void ServerEnvironment::step(float dtime)
-{
- DSTACK(FUNCTION_NAME);
-
- //TimeTaker timer("ServerEnv step");
-
- /* Step time of day */
- stepTimeOfDay(dtime);
-
- // Update this one
- // NOTE: This is kind of funny on a singleplayer game, but doesn't
- // really matter that much.
- static const float server_step = g_settings->getFloat("dedicated_server_step");
- m_recommended_send_interval = server_step;
-
- /*
- Increment game time
- */
- {
- m_game_time_fraction_counter += dtime;
- u32 inc_i = (u32)m_game_time_fraction_counter;
- m_game_time += inc_i;
- m_game_time_fraction_counter -= (float)inc_i;
- }
-
- /*
- Handle players
- */
- {
- ScopeProfiler sp(g_profiler, "SEnv: handle players avg", SPT_AVG);
- for (std::vector<RemotePlayer *>::iterator i = m_players.begin();
- i != m_players.end(); ++i) {
- RemotePlayer *player = dynamic_cast<RemotePlayer *>(*i);
- assert(player);
-
- // Ignore disconnected players
- if(player->peer_id == 0)
- continue;
-
- // Move
- player->move(dtime, this, 100*BS);
- }
- }
-
- /*
- Manage active block list
- */
- if (m_active_blocks_management_interval.step(dtime, m_cache_active_block_mgmt_interval)) {
- ScopeProfiler sp(g_profiler, "SEnv: manage act. block list avg per interval", SPT_AVG);
- /*
- Get player block positions
- */
- std::vector<v3s16> players_blockpos;
- for (std::vector<RemotePlayer *>::iterator i = m_players.begin();
- i != m_players.end(); ++i) {
- RemotePlayer *player = dynamic_cast<RemotePlayer *>(*i);
- assert(player);
-
- // Ignore disconnected players
- if (player->peer_id == 0)
- continue;
-
- PlayerSAO *playersao = player->getPlayerSAO();
- assert(playersao);
-
- v3s16 blockpos = getNodeBlockPos(
- floatToInt(playersao->getBasePosition(), BS));
- players_blockpos.push_back(blockpos);
- }
-
- /*
- Update list of active blocks, collecting changes
- */
- static const s16 active_block_range = g_settings->getS16("active_block_range");
- std::set<v3s16> blocks_removed;
- std::set<v3s16> blocks_added;
- m_active_blocks.update(players_blockpos, active_block_range,
- blocks_removed, blocks_added);
-
- /*
- Handle removed blocks
- */
-
- // Convert active objects that are no more in active blocks to static
- deactivateFarObjects(false);
-
- for(std::set<v3s16>::iterator
- i = blocks_removed.begin();
- i != blocks_removed.end(); ++i) {
- v3s16 p = *i;
-
- /* infostream<<"Server: Block " << PP(p)
- << " became inactive"<<std::endl; */
-
- MapBlock *block = m_map->getBlockNoCreateNoEx(p);
- if(block==NULL)
- continue;
-
- // Set current time as timestamp (and let it set ChangedFlag)
- block->setTimestamp(m_game_time);
- }
-
- /*
- Handle added blocks
- */
-
- for(std::set<v3s16>::iterator
- i = blocks_added.begin();
- i != blocks_added.end(); ++i)
- {
- v3s16 p = *i;
-
- MapBlock *block = m_map->getBlockOrEmerge(p);
- if(block==NULL){
- m_active_blocks.m_list.erase(p);
- continue;
- }
-
- activateBlock(block);
- /* infostream<<"Server: Block " << PP(p)
- << " became active"<<std::endl; */
- }
- }
-
- /*
- Mess around in active blocks
- */
- if (m_active_blocks_nodemetadata_interval.step(dtime, m_cache_nodetimer_interval)) {
- ScopeProfiler sp(g_profiler, "SEnv: mess in act. blocks avg per interval", SPT_AVG);
-
- float dtime = m_cache_nodetimer_interval;
-
- for(std::set<v3s16>::iterator
- i = m_active_blocks.m_list.begin();
- i != m_active_blocks.m_list.end(); ++i)
- {
- v3s16 p = *i;
-
- /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
- <<") being handled"<<std::endl;*/
-
- MapBlock *block = m_map->getBlockNoCreateNoEx(p);
- if(block==NULL)
- continue;
-
- // Reset block usage timer
- block->resetUsageTimer();
-
- // Set current time as timestamp
- block->setTimestampNoChangedFlag(m_game_time);
- // If time has changed much from the one on disk,
- // set block to be saved when it is unloaded
- if(block->getTimestamp() > block->getDiskTimestamp() + 60)
- block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
- MOD_REASON_BLOCK_EXPIRED);
-
- // Run node timers
- std::vector<NodeTimer> elapsed_timers =
- block->m_node_timers.step((float)dtime);
- if (!elapsed_timers.empty()) {
- MapNode n;
- for (std::vector<NodeTimer>::iterator i = elapsed_timers.begin();
- i != elapsed_timers.end(); ++i) {
- n = block->getNodeNoEx(i->position);
- p = i->position + block->getPosRelative();
- if (m_script->node_on_timer(p, n, i->elapsed)) {
- block->setNodeTimer(NodeTimer(
- i->timeout, 0, i->position));
- }
- }
- }
- }
- }
-
- if (m_active_block_modifier_interval.step(dtime, m_cache_abm_interval))
- do{ // breakable
- if(m_active_block_interval_overload_skip > 0){
- ScopeProfiler sp(g_profiler, "SEnv: ABM overload skips");
- m_active_block_interval_overload_skip--;
- break;
- }
- ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg per interval", SPT_AVG);
- TimeTaker timer("modify in active blocks per interval");
-
- // Initialize handling of ActiveBlockModifiers
- ABMHandler abmhandler(m_abms, m_cache_abm_interval, this, true);
-
- for(std::set<v3s16>::iterator
- i = m_active_blocks.m_list.begin();
- i != m_active_blocks.m_list.end(); ++i)
- {
- v3s16 p = *i;
-
- /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
- <<") being handled"<<std::endl;*/
-
- MapBlock *block = m_map->getBlockNoCreateNoEx(p);
- if(block == NULL)
- continue;
-
- // Set current time as timestamp
- block->setTimestampNoChangedFlag(m_game_time);
-
- /* Handle ActiveBlockModifiers */
- abmhandler.apply(block);
- }
-
- u32 time_ms = timer.stop(true);
- u32 max_time_ms = 200;
- if(time_ms > max_time_ms){
- warningstream<<"active block modifiers took "
- <<time_ms<<"ms (longer than "
- <<max_time_ms<<"ms)"<<std::endl;
- m_active_block_interval_overload_skip = (time_ms / max_time_ms) + 1;
- }
- }while(0);
-
- /*
- Step script environment (run global on_step())
- */
- m_script->environment_Step(dtime);
-
- /*
- Step active objects
- */
- {
- ScopeProfiler sp(g_profiler, "SEnv: step act. objs avg", SPT_AVG);
- //TimeTaker timer("Step active objects");
-
- g_profiler->avg("SEnv: num of objects", m_active_objects.size());
-
- // This helps the objects to send data at the same time
- bool send_recommended = false;
- m_send_recommended_timer += dtime;
- if(m_send_recommended_timer > getSendRecommendedInterval())
- {
- m_send_recommended_timer -= getSendRecommendedInterval();
- send_recommended = true;
- }
-
- for(ActiveObjectMap::iterator i = m_active_objects.begin();
- i != m_active_objects.end(); ++i) {
- ServerActiveObject* obj = i->second;
- // Don't step if is to be removed or stored statically
- if(obj->m_removed || obj->m_pending_deactivation)
- continue;
- // Step object
- obj->step(dtime, send_recommended);
- // Read messages from object
- while(!obj->m_messages_out.empty())
- {
- m_active_object_messages.push(
- obj->m_messages_out.front());
- obj->m_messages_out.pop();
- }
- }
- }
-
- /*
- Manage active objects
- */
- if(m_object_management_interval.step(dtime, 0.5))
- {
- ScopeProfiler sp(g_profiler, "SEnv: remove removed objs avg /.5s", SPT_AVG);
- /*
- Remove objects that satisfy (m_removed && m_known_by_count==0)
- */
- removeRemovedObjects();
- }
-
- /*
- Manage particle spawner expiration
- */
- if (m_particle_management_interval.step(dtime, 1.0)) {
- for (UNORDERED_MAP<u32, float>::iterator i = m_particle_spawners.begin();
- i != m_particle_spawners.end(); ) {
- //non expiring spawners
- if (i->second == PARTICLE_SPAWNER_NO_EXPIRY) {
- ++i;
- continue;
- }
-
- i->second -= 1.0f;
- if (i->second <= 0.f)
- m_particle_spawners.erase(i++);
- else
- ++i;
- }
- }
-}
-
-u32 ServerEnvironment::addParticleSpawner(float exptime)
-{
- // Timers with lifetime 0 do not expire
- float time = exptime > 0.f ? exptime : PARTICLE_SPAWNER_NO_EXPIRY;
-
- u32 id = 0;
- for (;;) { // look for unused particlespawner id
- id++;
- UNORDERED_MAP<u32, float>::iterator f = m_particle_spawners.find(id);
- if (f == m_particle_spawners.end()) {
- m_particle_spawners[id] = time;
- break;
- }
- }
- return id;
-}
-
-u32 ServerEnvironment::addParticleSpawner(float exptime, u16 attached_id)
-{
- u32 id = addParticleSpawner(exptime);
- m_particle_spawner_attachments[id] = attached_id;
- if (ServerActiveObject *obj = getActiveObject(attached_id)) {
- obj->attachParticleSpawner(id);
- }
- return id;
-}
-
-void ServerEnvironment::deleteParticleSpawner(u32 id, bool remove_from_object)
-{
- m_particle_spawners.erase(id);
- UNORDERED_MAP<u32, u16>::iterator it = m_particle_spawner_attachments.find(id);
- if (it != m_particle_spawner_attachments.end()) {
- u16 obj_id = (*it).second;
- ServerActiveObject *sao = getActiveObject(obj_id);
- if (sao != NULL && remove_from_object) {
- sao->detachParticleSpawner(id);
- }
- m_particle_spawner_attachments.erase(id);
- }
-}
-
-ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
-{
- ActiveObjectMap::iterator n = m_active_objects.find(id);
- return (n != m_active_objects.end() ? n->second : NULL);
-}
-
-bool isFreeServerActiveObjectId(u16 id, ActiveObjectMap &objects)
-{
- if (id == 0)
- return false;
-
- return objects.find(id) == objects.end();
-}
-
-u16 getFreeServerActiveObjectId(ActiveObjectMap &objects)
-{
- //try to reuse id's as late as possible
- static u16 last_used_id = 0;
- u16 startid = last_used_id;
- for(;;)
- {
- last_used_id ++;
- if(isFreeServerActiveObjectId(last_used_id, objects))
- return last_used_id;
-
- if(last_used_id == startid)
- return 0;
- }
-}
-
-u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
-{
- assert(object); // Pre-condition
- m_added_objects++;
- u16 id = addActiveObjectRaw(object, true, 0);
- return id;
-}
-
-/*
- Finds out what new objects have been added to
- inside a radius around a position
-*/
-void ServerEnvironment::getAddedActiveObjects(PlayerSAO *playersao, s16 radius,
- s16 player_radius,
- std::set<u16> &current_objects,
- std::queue<u16> &added_objects)
-{
- f32 radius_f = radius * BS;
- f32 player_radius_f = player_radius * BS;
-
- if (player_radius_f < 0)
- player_radius_f = 0;
- /*
- Go through the object list,
- - discard m_removed objects,
- - discard objects that are too far away,
- - discard objects that are found in current_objects.
- - add remaining objects to added_objects
- */
- for (ActiveObjectMap::iterator i = m_active_objects.begin();
- i != m_active_objects.end(); ++i) {
- u16 id = i->first;
-
- // Get object
- ServerActiveObject *object = i->second;
- if (object == NULL)
- continue;
-
- // Discard if removed or deactivating
- if(object->m_removed || object->m_pending_deactivation)
- continue;
-
- f32 distance_f = object->getBasePosition().
- getDistanceFrom(playersao->getBasePosition());
- if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
- // Discard if too far
- if (distance_f > player_radius_f && player_radius_f != 0)
- continue;
- } else if (distance_f > radius_f)
- continue;
-
- // Discard if already on current_objects
- std::set<u16>::iterator n;
- n = current_objects.find(id);
- if(n != current_objects.end())
- continue;
- // Add to added_objects
- added_objects.push(id);
- }
-}
-
-/*
- Finds out what objects have been removed from
- inside a radius around a position
-*/
-void ServerEnvironment::getRemovedActiveObjects(PlayerSAO *playersao, s16 radius,
- s16 player_radius,
- std::set<u16> &current_objects,
- std::queue<u16> &removed_objects)
-{
- f32 radius_f = radius * BS;
- f32 player_radius_f = player_radius * BS;
-
- if (player_radius_f < 0)
- player_radius_f = 0;
- /*
- Go through current_objects; object is removed if:
- - object is not found in m_active_objects (this is actually an
- error condition; objects should be set m_removed=true and removed
- only after all clients have been informed about removal), or
- - object has m_removed=true, or
- - object is too far away
- */
- for(std::set<u16>::iterator
- i = current_objects.begin();
- i != current_objects.end(); ++i)
- {
- u16 id = *i;
- ServerActiveObject *object = getActiveObject(id);
-
- if (object == NULL) {
- infostream << "ServerEnvironment::getRemovedActiveObjects():"
- << " object in current_objects is NULL" << std::endl;
- removed_objects.push(id);
- continue;
- }
-
- if (object->m_removed || object->m_pending_deactivation) {
- removed_objects.push(id);
- continue;
- }
-
- f32 distance_f = object->getBasePosition().getDistanceFrom(playersao->getBasePosition());
- if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
- if (distance_f <= player_radius_f || player_radius_f == 0)
- continue;
- } else if (distance_f <= radius_f)
- continue;
-
- // Object is no longer visible
- removed_objects.push(id);
- }
-}
-
-void ServerEnvironment::setStaticForActiveObjectsInBlock(
- v3s16 blockpos, bool static_exists, v3s16 static_block)
-{
- MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
- if (!block)
- return;
-
- for (std::map<u16, StaticObject>::iterator
- so_it = block->m_static_objects.m_active.begin();
- so_it != block->m_static_objects.m_active.end(); ++so_it) {
- // Get the ServerActiveObject counterpart to this StaticObject
- ActiveObjectMap::iterator ao_it = m_active_objects.find(so_it->first);
- if (ao_it == m_active_objects.end()) {
- // If this ever happens, there must be some kind of nasty bug.
- errorstream << "ServerEnvironment::setStaticForObjectsInBlock(): "
- "Object from MapBlock::m_static_objects::m_active not found "
- "in m_active_objects";
- continue;
- }
-
- ServerActiveObject *sao = ao_it->second;
- sao->m_static_exists = static_exists;
- sao->m_static_block = static_block;
- }
-}
-
-ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
-{
- if(m_active_object_messages.empty())
- return ActiveObjectMessage(0);
-
- ActiveObjectMessage message = m_active_object_messages.front();
- m_active_object_messages.pop();
- return message;
-}
-
-/*
- ************ Private methods *************
-*/
-
-u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
- bool set_changed, u32 dtime_s)
-{
- assert(object); // Pre-condition
- if(object->getId() == 0){
- u16 new_id = getFreeServerActiveObjectId(m_active_objects);
- if(new_id == 0)
- {
- errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
- <<"no free ids available"<<std::endl;
- if(object->environmentDeletes())
- delete object;
- return 0;
- }
- object->setId(new_id);
- }
- else{
- verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
- <<"supplied with id "<<object->getId()<<std::endl;
- }
-
- if(!isFreeServerActiveObjectId(object->getId(), m_active_objects)) {
- errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
- <<"id is not free ("<<object->getId()<<")"<<std::endl;
- if(object->environmentDeletes())
- delete object;
- return 0;
- }
-
- if (objectpos_over_limit(object->getBasePosition())) {
- v3f p = object->getBasePosition();
- errorstream << "ServerEnvironment::addActiveObjectRaw(): "
- << "object position (" << p.X << "," << p.Y << "," << p.Z
- << ") outside maximum range" << std::endl;
- if (object->environmentDeletes())
- delete object;
- return 0;
- }
-
- /*infostream<<"ServerEnvironment::addActiveObjectRaw(): "
- <<"added (id="<<object->getId()<<")"<<std::endl;*/
-
- m_active_objects[object->getId()] = object;
-
- verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
- <<"Added id="<<object->getId()<<"; there are now "
- <<m_active_objects.size()<<" active objects."
- <<std::endl;
-
- // Register reference in scripting api (must be done before post-init)
- m_script->addObjectReference(object);
- // Post-initialize object
- object->addedToEnvironment(dtime_s);
-
- // Add static data to block
- if(object->isStaticAllowed())
- {
- // Add static object to active static list of the block
- v3f objectpos = object->getBasePosition();
- std::string staticdata = object->getStaticData();
- StaticObject s_obj(object->getType(), objectpos, staticdata);
- // Add to the block where the object is located in
- v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
- MapBlock *block = m_map->emergeBlock(blockpos);
- if(block){
- block->m_static_objects.m_active[object->getId()] = s_obj;
- object->m_static_exists = true;
- object->m_static_block = blockpos;
-
- if(set_changed)
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_ADD_ACTIVE_OBJECT_RAW);
- } else {
- v3s16 p = floatToInt(objectpos, BS);
- errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
- <<"could not emerge block for storing id="<<object->getId()
- <<" statically (pos="<<PP(p)<<")"<<std::endl;
- }
- }
-
- return object->getId();
-}
-
-/*
- Remove objects that satisfy (m_removed && m_known_by_count==0)
-*/
-void ServerEnvironment::removeRemovedObjects()
-{
- std::vector<u16> objects_to_remove;
- for(ActiveObjectMap::iterator i = m_active_objects.begin();
- i != m_active_objects.end(); ++i) {
- u16 id = i->first;
- ServerActiveObject* obj = i->second;
- // This shouldn't happen but check it
- if(obj == NULL)
- {
- infostream<<"NULL object found in ServerEnvironment"
- <<" while finding removed objects. id="<<id<<std::endl;
- // Id to be removed from m_active_objects
- objects_to_remove.push_back(id);
- continue;
- }
-
- /*
- We will delete objects that are marked as removed or thatare
- waiting for deletion after deactivation
- */
- if (!obj->m_removed && !obj->m_pending_deactivation)
- continue;
-
- /*
- Delete static data from block if is marked as removed
- */
- if(obj->m_static_exists && obj->m_removed)
- {
- MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
- if (block) {
- block->m_static_objects.remove(id);
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_REMOVE_OBJECTS_REMOVE);
- obj->m_static_exists = false;
- } else {
- infostream<<"Failed to emerge block from which an object to "
- <<"be removed was loaded from. id="<<id<<std::endl;
- }
- }
-
- // If m_known_by_count > 0, don't actually remove. On some future
- // invocation this will be 0, which is when removal will continue.
- if(obj->m_known_by_count > 0)
- continue;
-
- /*
- Move static data from active to stored if not marked as removed
- */
- if(obj->m_static_exists && !obj->m_removed){
- MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
- if (block) {
- std::map<u16, StaticObject>::iterator i =
- block->m_static_objects.m_active.find(id);
- if(i != block->m_static_objects.m_active.end()){
- block->m_static_objects.m_stored.push_back(i->second);
- block->m_static_objects.m_active.erase(id);
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_REMOVE_OBJECTS_DEACTIVATE);
- }
- } else {
- infostream<<"Failed to emerge block from which an object to "
- <<"be deactivated was loaded from. id="<<id<<std::endl;
- }
- }
-
- // Tell the object about removal
- obj->removingFromEnvironment();
- // Deregister in scripting api
- m_script->removeObjectReference(obj);
-
- // Delete
- if(obj->environmentDeletes())
- delete obj;
-
- // Id to be removed from m_active_objects
- objects_to_remove.push_back(id);
- }
- // Remove references from m_active_objects
- for(std::vector<u16>::iterator i = objects_to_remove.begin();
- i != objects_to_remove.end(); ++i) {
- m_active_objects.erase(*i);
- }
-}
-
-static void print_hexdump(std::ostream &o, const std::string &data)
-{
- const int linelength = 16;
- for(int l=0; ; l++){
- int i0 = linelength * l;
- bool at_end = false;
- int thislinelength = linelength;
- if(i0 + thislinelength > (int)data.size()){
- thislinelength = data.size() - i0;
- at_end = true;
- }
- for(int di=0; di<linelength; di++){
- int i = i0 + di;
- char buf[4];
- if(di<thislinelength)
- snprintf(buf, 4, "%.2x ", data[i]);
- else
- snprintf(buf, 4, " ");
- o<<buf;
- }
- o<<" ";
- for(int di=0; di<thislinelength; di++){
- int i = i0 + di;
- if(data[i] >= 32)
- o<<data[i];
- else
- o<<".";
- }
- o<<std::endl;
- if(at_end)
- break;
- }
-}
-
-/*
- Convert stored objects from blocks near the players to active.
-*/
-void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
-{
- if(block == NULL)
- return;
-
- // Ignore if no stored objects (to not set changed flag)
- if(block->m_static_objects.m_stored.empty())
- return;
-
- verbosestream<<"ServerEnvironment::activateObjects(): "
- <<"activating objects of block "<<PP(block->getPos())
- <<" ("<<block->m_static_objects.m_stored.size()
- <<" objects)"<<std::endl;
- bool large_amount = (block->m_static_objects.m_stored.size() > g_settings->getU16("max_objects_per_block"));
- if (large_amount) {
- errorstream<<"suspiciously large amount of objects detected: "
- <<block->m_static_objects.m_stored.size()<<" in "
- <<PP(block->getPos())
- <<"; removing all of them."<<std::endl;
- // Clear stored list
- block->m_static_objects.m_stored.clear();
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_TOO_MANY_OBJECTS);
- return;
- }
-
- // Activate stored objects
- std::vector<StaticObject> new_stored;
- for (std::vector<StaticObject>::iterator
- i = block->m_static_objects.m_stored.begin();
- i != block->m_static_objects.m_stored.end(); ++i) {
- StaticObject &s_obj = *i;
-
- // Create an active object from the data
- ServerActiveObject *obj = ServerActiveObject::create
- ((ActiveObjectType) s_obj.type, this, 0, s_obj.pos, s_obj.data);
- // If couldn't create object, store static data back.
- if(obj == NULL) {
- errorstream<<"ServerEnvironment::activateObjects(): "
- <<"failed to create active object from static object "
- <<"in block "<<PP(s_obj.pos/BS)
- <<" type="<<(int)s_obj.type<<" data:"<<std::endl;
- print_hexdump(verbosestream, s_obj.data);
-
- new_stored.push_back(s_obj);
- continue;
- }
- verbosestream<<"ServerEnvironment::activateObjects(): "
- <<"activated static object pos="<<PP(s_obj.pos/BS)
- <<" type="<<(int)s_obj.type<<std::endl;
- // This will also add the object to the active static list
- addActiveObjectRaw(obj, false, dtime_s);
- }
- // Clear stored list
- block->m_static_objects.m_stored.clear();
- // Add leftover failed stuff to stored list
- for(std::vector<StaticObject>::iterator
- i = new_stored.begin();
- i != new_stored.end(); ++i) {
- StaticObject &s_obj = *i;
- block->m_static_objects.m_stored.push_back(s_obj);
- }
-
- // Turn the active counterparts of activated objects not pending for
- // deactivation
- for(std::map<u16, StaticObject>::iterator
- i = block->m_static_objects.m_active.begin();
- i != block->m_static_objects.m_active.end(); ++i)
- {
- u16 id = i->first;
- ServerActiveObject *object = getActiveObject(id);
- assert(object);
- object->m_pending_deactivation = false;
- }
-
- /*
- Note: Block hasn't really been modified here.
- The objects have just been activated and moved from the stored
- static list to the active static list.
- As such, the block is essentially the same.
- Thus, do not call block->raiseModified(MOD_STATE_WRITE_NEEDED).
- Otherwise there would be a huge amount of unnecessary I/O.
- */
-}
-
-/*
- Convert objects that are not standing inside active blocks to static.
-
- If m_known_by_count != 0, active object is not deleted, but static
- data is still updated.
-
- If force_delete is set, active object is deleted nevertheless. It
- shall only be set so in the destructor of the environment.
-
- If block wasn't generated (not in memory or on disk),
-*/
-void ServerEnvironment::deactivateFarObjects(bool force_delete)
-{
- std::vector<u16> objects_to_remove;
- for(ActiveObjectMap::iterator i = m_active_objects.begin();
- i != m_active_objects.end(); ++i) {
- ServerActiveObject* obj = i->second;
- assert(obj);
-
- // Do not deactivate if static data creation not allowed
- if(!force_delete && !obj->isStaticAllowed())
- continue;
-
- // If pending deactivation, let removeRemovedObjects() do it
- if(!force_delete && obj->m_pending_deactivation)
- continue;
-
- u16 id = i->first;
- v3f objectpos = obj->getBasePosition();
-
- // The block in which the object resides in
- v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
-
- // If object's static data is stored in a deactivated block and object
- // is actually located in an active block, re-save to the block in
- // which the object is actually located in.
- if(!force_delete &&
- obj->m_static_exists &&
- !m_active_blocks.contains(obj->m_static_block) &&
- m_active_blocks.contains(blockpos_o))
- {
- v3s16 old_static_block = obj->m_static_block;
-
- // Save to block where object is located
- MapBlock *block = m_map->emergeBlock(blockpos_o, false);
- if(!block){
- errorstream<<"ServerEnvironment::deactivateFarObjects(): "
- <<"Could not save object id="<<id
- <<" to it's current block "<<PP(blockpos_o)
- <<std::endl;
- continue;
- }
- std::string staticdata_new = obj->getStaticData();
- StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
- block->m_static_objects.insert(id, s_obj);
- obj->m_static_block = blockpos_o;
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_STATIC_DATA_ADDED);
-
- // Delete from block where object was located
- block = m_map->emergeBlock(old_static_block, false);
- if(!block){
- errorstream<<"ServerEnvironment::deactivateFarObjects(): "
- <<"Could not delete object id="<<id
- <<" from it's previous block "<<PP(old_static_block)
- <<std::endl;
- continue;
- }
- block->m_static_objects.remove(id);
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_STATIC_DATA_REMOVED);
- continue;
- }
-
- // If block is active, don't remove
- if(!force_delete && m_active_blocks.contains(blockpos_o))
- continue;
-
- verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
- <<"deactivating object id="<<id<<" on inactive block "
- <<PP(blockpos_o)<<std::endl;
-
- // If known by some client, don't immediately delete.
- bool pending_delete = (obj->m_known_by_count > 0 && !force_delete);
-
- /*
- Update the static data
- */
-
- if(obj->isStaticAllowed())
- {
- // Create new static object
- std::string staticdata_new = obj->getStaticData();
- StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
-
- bool stays_in_same_block = false;
- bool data_changed = true;
-
- if (obj->m_static_exists) {
- if (obj->m_static_block == blockpos_o)
- stays_in_same_block = true;
-
- MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
-
- if (block) {
- std::map<u16, StaticObject>::iterator n =
- block->m_static_objects.m_active.find(id);
- if (n != block->m_static_objects.m_active.end()) {
- StaticObject static_old = n->second;
-
- float save_movem = obj->getMinimumSavedMovement();
-
- if (static_old.data == staticdata_new &&
- (static_old.pos - objectpos).getLength() < save_movem)
- data_changed = false;
- } else {
- errorstream<<"ServerEnvironment::deactivateFarObjects(): "
- <<"id="<<id<<" m_static_exists=true but "
- <<"static data doesn't actually exist in "
- <<PP(obj->m_static_block)<<std::endl;
- }
- }
- }
-
- bool shall_be_written = (!stays_in_same_block || data_changed);
-
- // Delete old static object
- if(obj->m_static_exists)
- {
- MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
- if(block)
- {
- block->m_static_objects.remove(id);
- obj->m_static_exists = false;
- // Only mark block as modified if data changed considerably
- if(shall_be_written)
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_STATIC_DATA_CHANGED);
- }
- }
-
- // Add to the block where the object is located in
- v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
- // Get or generate the block
- MapBlock *block = NULL;
- try{
- block = m_map->emergeBlock(blockpos);
- } catch(InvalidPositionException &e){
- // Handled via NULL pointer
- // NOTE: emergeBlock's failure is usually determined by it
- // actually returning NULL
- }
-
- if(block)
- {
- if (block->m_static_objects.m_stored.size() >= g_settings->getU16("max_objects_per_block")) {
- warningstream << "ServerEnv: Trying to store id = " << obj->getId()
- << " statically but block " << PP(blockpos)
- << " already contains "
- << block->m_static_objects.m_stored.size()
- << " objects."
- << " Forcing delete." << std::endl;
- force_delete = true;
- } else {
- // If static counterpart already exists in target block,
- // remove it first.
- // This shouldn't happen because the object is removed from
- // the previous block before this according to
- // obj->m_static_block, but happens rarely for some unknown
- // reason. Unsuccessful attempts have been made to find
- // said reason.
- if(id && block->m_static_objects.m_active.find(id) != block->m_static_objects.m_active.end()){
- warningstream<<"ServerEnv: Performing hack #83274"
- <<std::endl;
- block->m_static_objects.remove(id);
- }
- // Store static data
- u16 store_id = pending_delete ? id : 0;
- block->m_static_objects.insert(store_id, s_obj);
-
- // Only mark block as modified if data changed considerably
- if(shall_be_written)
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_STATIC_DATA_CHANGED);
-
- obj->m_static_exists = true;
- obj->m_static_block = block->getPos();
- }
- }
- else{
- if(!force_delete){
- v3s16 p = floatToInt(objectpos, BS);
- errorstream<<"ServerEnv: Could not find or generate "
- <<"a block for storing id="<<obj->getId()
- <<" statically (pos="<<PP(p)<<")"<<std::endl;
- continue;
- }
- }
- }
-
- /*
- If known by some client, set pending deactivation.
- Otherwise delete it immediately.
- */
-
- if(pending_delete && !force_delete)
- {
- verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
- <<"object id="<<id<<" is known by clients"
- <<"; not deleting yet"<<std::endl;
-
- obj->m_pending_deactivation = true;
- continue;
- }
-
- verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
- <<"object id="<<id<<" is not known by clients"
- <<"; deleting"<<std::endl;
-
- // Tell the object about removal
- obj->removingFromEnvironment();
- // Deregister in scripting api
- m_script->removeObjectReference(obj);
-
- // Delete active object
- if(obj->environmentDeletes())
- delete obj;
- // Id to be removed from m_active_objects
- objects_to_remove.push_back(id);
- }
-
- // Remove references from m_active_objects
- for(std::vector<u16>::iterator i = objects_to_remove.begin();
- i != objects_to_remove.end(); ++i) {
- m_active_objects.erase(*i);
- }
-}
-
-#ifndef SERVER
-
-#include "clientsimpleobject.h"
-
-/*
- ClientEnvironment
-*/
-
-ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
- ITextureSource *texturesource, IGameDef *gamedef,
- IrrlichtDevice *irr):
- m_map(map),
- m_local_player(NULL),
- m_smgr(smgr),
- m_texturesource(texturesource),
- m_gamedef(gamedef),
- m_irr(irr)
-{
- char zero = 0;
- memset(attachement_parent_ids, zero, sizeof(attachement_parent_ids));
-}
-
-ClientEnvironment::~ClientEnvironment()
-{
- // delete active objects
- for (UNORDERED_MAP<u16, ClientActiveObject*>::iterator i = m_active_objects.begin();
- i != m_active_objects.end(); ++i) {
- delete i->second;
- }
-
- for(std::vector<ClientSimpleObject*>::iterator
- i = m_simple_objects.begin(); i != m_simple_objects.end(); ++i) {
- delete *i;
- }
-
- // Drop/delete map
- m_map->drop();
-}
-
-Map & ClientEnvironment::getMap()
-{
- return *m_map;
-}
-
-ClientMap & ClientEnvironment::getClientMap()
-{
- return *m_map;
-}
-
-void ClientEnvironment::setLocalPlayer(LocalPlayer *player)
-{
- DSTACK(FUNCTION_NAME);
- /*
- It is a failure if already is a local player
- */
- FATAL_ERROR_IF(m_local_player != NULL,
- "Local player already allocated");
-
- m_local_player = player;
-}
-
-void ClientEnvironment::step(float dtime)
-{
- DSTACK(FUNCTION_NAME);
-
- /* Step time of day */
- stepTimeOfDay(dtime);
-
- // Get some settings
- bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
- bool free_move = fly_allowed && g_settings->getBool("free_move");
-
- // Get local player
- LocalPlayer *lplayer = getLocalPlayer();
- assert(lplayer);
- // collision info queue
- std::vector<CollisionInfo> player_collisions;
-
- /*
- Get the speed the player is going
- */
- bool is_climbing = lplayer->is_climbing;
-
- f32 player_speed = lplayer->getSpeed().getLength();
-
- /*
- Maximum position increment
- */
- //f32 position_max_increment = 0.05*BS;
- f32 position_max_increment = 0.1*BS;
-
- // Maximum time increment (for collision detection etc)
- // time = distance / speed
- f32 dtime_max_increment = 1;
- if(player_speed > 0.001)
- dtime_max_increment = position_max_increment / player_speed;
-
- // Maximum time increment is 10ms or lower
- if(dtime_max_increment > 0.01)
- dtime_max_increment = 0.01;
-
- // Don't allow overly huge dtime
- if(dtime > 0.5)
- dtime = 0.5;
-
- f32 dtime_downcount = dtime;
-
- /*
- Stuff that has a maximum time increment
- */
-
- u32 loopcount = 0;
- do
- {
- loopcount++;
-
- f32 dtime_part;
- if(dtime_downcount > dtime_max_increment)
- {
- dtime_part = dtime_max_increment;
- dtime_downcount -= dtime_part;
- }
- else
- {
- dtime_part = dtime_downcount;
- /*
- Setting this to 0 (no -=dtime_part) disables an infinite loop
- when dtime_part is so small that dtime_downcount -= dtime_part
- does nothing
- */
- dtime_downcount = 0;
- }
-
- /*
- Handle local player
- */
-
- {
- // Apply physics
- if(!free_move && !is_climbing)
- {
- // Gravity
- v3f speed = lplayer->getSpeed();
- if(!lplayer->in_liquid)
- speed.Y -= lplayer->movement_gravity * lplayer->physics_override_gravity * dtime_part * 2;
-
- // Liquid floating / sinking
- if(lplayer->in_liquid && !lplayer->swimming_vertical)
- speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2;
-
- // Liquid resistance
- if(lplayer->in_liquid_stable || lplayer->in_liquid)
- {
- // How much the node's viscosity blocks movement, ranges between 0 and 1
- // Should match the scale at which viscosity increase affects other liquid attributes
- const f32 viscosity_factor = 0.3;
-
- v3f d_wanted = -speed / lplayer->movement_liquid_fluidity;
- f32 dl = d_wanted.getLength();
- if(dl > lplayer->movement_liquid_fluidity_smooth)
- dl = lplayer->movement_liquid_fluidity_smooth;
- dl *= (lplayer->liquid_viscosity * viscosity_factor) + (1 - viscosity_factor);
-
- v3f d = d_wanted.normalize() * dl;
- speed += d;
- }
-
- lplayer->setSpeed(speed);
- }
-
- /*
- Move the lplayer.
- This also does collision detection.
- */
- lplayer->move(dtime_part, this, position_max_increment,
- &player_collisions);
- }
- }
- while(dtime_downcount > 0.001);
-
- //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
-
- for(std::vector<CollisionInfo>::iterator i = player_collisions.begin();
- i != player_collisions.end(); ++i) {
- CollisionInfo &info = *i;
- v3f speed_diff = info.new_speed - info.old_speed;;
- // Handle only fall damage
- // (because otherwise walking against something in fast_move kills you)
- if(speed_diff.Y < 0 || info.old_speed.Y >= 0)
- continue;
- // Get rid of other components
- speed_diff.X = 0;
- speed_diff.Z = 0;
- f32 pre_factor = 1; // 1 hp per node/s
- f32 tolerance = BS*14; // 5 without damage
- f32 post_factor = 1; // 1 hp per node/s
- if(info.type == COLLISION_NODE)
- {
- const ContentFeatures &f = m_gamedef->ndef()->
- get(m_map->getNodeNoEx(info.node_p));
- // Determine fall damage multiplier
- int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
- pre_factor = 1.0 + (float)addp/100.0;
- }
- float speed = pre_factor * speed_diff.getLength();
- if(speed > tolerance)
- {
- f32 damage_f = (speed - tolerance)/BS * post_factor;
- u16 damage = (u16)(damage_f+0.5);
- if(damage != 0){
- damageLocalPlayer(damage, true);
- MtEvent *e = new SimpleTriggerEvent("PlayerFallingDamage");
- m_gamedef->event()->put(e);
- }
- }
- }
-
- /*
- A quick draft of lava damage
- */
- if(m_lava_hurt_interval.step(dtime, 1.0))
- {
- v3f pf = lplayer->getPosition();
-
- // Feet, middle and head
- v3s16 p1 = floatToInt(pf + v3f(0, BS*0.1, 0), BS);
- MapNode n1 = m_map->getNodeNoEx(p1);
- v3s16 p2 = floatToInt(pf + v3f(0, BS*0.8, 0), BS);
- MapNode n2 = m_map->getNodeNoEx(p2);
- v3s16 p3 = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
- MapNode n3 = m_map->getNodeNoEx(p3);
-
- u32 damage_per_second = 0;
- damage_per_second = MYMAX(damage_per_second,
- m_gamedef->ndef()->get(n1).damage_per_second);
- damage_per_second = MYMAX(damage_per_second,
- m_gamedef->ndef()->get(n2).damage_per_second);
- damage_per_second = MYMAX(damage_per_second,
- m_gamedef->ndef()->get(n3).damage_per_second);
-
- if(damage_per_second != 0)
- {
- damageLocalPlayer(damage_per_second, true);
- }
- }
-
- /*
- Drowning
- */
- if(m_drowning_interval.step(dtime, 2.0))
- {
- v3f pf = lplayer->getPosition();
-
- // head
- v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
- MapNode n = m_map->getNodeNoEx(p);
- ContentFeatures c = m_gamedef->ndef()->get(n);
- u8 drowning_damage = c.drowning;
- if(drowning_damage > 0 && lplayer->hp > 0){
- u16 breath = lplayer->getBreath();
- if(breath > 10){
- breath = 11;
- }
- if(breath > 0){
- breath -= 1;
- }
- lplayer->setBreath(breath);
- updateLocalPlayerBreath(breath);
- }
-
- if(lplayer->getBreath() == 0 && drowning_damage > 0){
- damageLocalPlayer(drowning_damage, true);
- }
- }
- if(m_breathing_interval.step(dtime, 0.5))
- {
- v3f pf = lplayer->getPosition();
-
- // head
- v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
- MapNode n = m_map->getNodeNoEx(p);
- ContentFeatures c = m_gamedef->ndef()->get(n);
- if (!lplayer->hp){
- lplayer->setBreath(11);
- }
- else if(c.drowning == 0){
- u16 breath = lplayer->getBreath();
- if(breath <= 10){
- breath += 1;
- lplayer->setBreath(breath);
- updateLocalPlayerBreath(breath);
- }
- }
- }
-
- // Update lighting on local player (used for wield item)
- u32 day_night_ratio = getDayNightRatio();
- {
- // Get node at head
-
- // On InvalidPositionException, use this as default
- // (day: LIGHT_SUN, night: 0)
- MapNode node_at_lplayer(CONTENT_AIR, 0x0f, 0);
-
- v3s16 p = lplayer->getLightPosition();
- node_at_lplayer = m_map->getNodeNoEx(p);
-
- u16 light = getInteriorLight(node_at_lplayer, 0, m_gamedef->ndef());
- u8 day = light & 0xff;
- u8 night = (light >> 8) & 0xff;
- finalColorBlend(lplayer->light_color, day, night, day_night_ratio);
- }
-
- /*
- Step active objects and update lighting of them
- */
-
- g_profiler->avg("CEnv: num of objects", m_active_objects.size());
- bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21);
- for (UNORDERED_MAP<u16, ClientActiveObject*>::iterator i = m_active_objects.begin();
- i != m_active_objects.end(); ++i) {
- ClientActiveObject* obj = i->second;
- // Step object
- obj->step(dtime, this);
-
- if(update_lighting)
- {
- // Update lighting
- u8 light = 0;
- bool pos_ok;
-
- // Get node at head
- v3s16 p = obj->getLightPosition();
- MapNode n = m_map->getNodeNoEx(p, &pos_ok);
- if (pos_ok)
- light = n.getLightBlend(day_night_ratio, m_gamedef->ndef());
- else
- light = blend_light(day_night_ratio, LIGHT_SUN, 0);
-
- obj->updateLight(light);
- }
- }
-
- /*
- Step and handle simple objects
- */
- g_profiler->avg("CEnv: num of simple objects", m_simple_objects.size());
- for(std::vector<ClientSimpleObject*>::iterator
- i = m_simple_objects.begin(); i != m_simple_objects.end();) {
- std::vector<ClientSimpleObject*>::iterator cur = i;
- ClientSimpleObject *simple = *cur;
-
- simple->step(dtime);
- if(simple->m_to_be_removed) {
- delete simple;
- i = m_simple_objects.erase(cur);
- }
- else {
- ++i;
- }
- }
-}
-
-void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)
-{
- m_simple_objects.push_back(simple);
-}
-
-GenericCAO* ClientEnvironment::getGenericCAO(u16 id)
-{
- ClientActiveObject *obj = getActiveObject(id);
- if (obj && obj->getType() == ACTIVEOBJECT_TYPE_GENERIC)
- return (GenericCAO*) obj;
- else
- return NULL;
-}
-
-ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
-{
- UNORDERED_MAP<u16, ClientActiveObject*>::iterator n = m_active_objects.find(id);
- if (n == m_active_objects.end())
- return NULL;
- return n->second;
-}
-
-bool isFreeClientActiveObjectId(const u16 id,
- UNORDERED_MAP<u16, ClientActiveObject*> &objects)
-{
- if(id == 0)
- return false;
-
- return objects.find(id) == objects.end();
-}
-
-u16 getFreeClientActiveObjectId(UNORDERED_MAP<u16, ClientActiveObject*> &objects)
-{
- //try to reuse id's as late as possible
- static u16 last_used_id = 0;
- u16 startid = last_used_id;
- for(;;) {
- last_used_id ++;
- if (isFreeClientActiveObjectId(last_used_id, objects))
- return last_used_id;
-
- if (last_used_id == startid)
- return 0;
- }
-}
-
-u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
-{
- assert(object); // Pre-condition
- if(object->getId() == 0)
- {
- u16 new_id = getFreeClientActiveObjectId(m_active_objects);
- if(new_id == 0)
- {
- infostream<<"ClientEnvironment::addActiveObject(): "
- <<"no free ids available"<<std::endl;
- delete object;
- return 0;
- }
- object->setId(new_id);
- }
- if (!isFreeClientActiveObjectId(object->getId(), m_active_objects)) {
- infostream<<"ClientEnvironment::addActiveObject(): "
- <<"id is not free ("<<object->getId()<<")"<<std::endl;
- delete object;
- return 0;
- }
- infostream<<"ClientEnvironment::addActiveObject(): "
- <<"added (id="<<object->getId()<<")"<<std::endl;
- m_active_objects[object->getId()] = object;
- object->addToScene(m_smgr, m_texturesource, m_irr);
- { // Update lighting immediately
- u8 light = 0;
- bool pos_ok;
-
- // Get node at head
- v3s16 p = object->getLightPosition();
- MapNode n = m_map->getNodeNoEx(p, &pos_ok);
- if (pos_ok)
- light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
- else
- light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
-
- object->updateLight(light);
- }
- return object->getId();
-}
-
-void ClientEnvironment::addActiveObject(u16 id, u8 type,
- const std::string &init_data)
-{
- ClientActiveObject* obj =
- ClientActiveObject::create((ActiveObjectType) type, m_gamedef, this);
- if(obj == NULL)
- {
- infostream<<"ClientEnvironment::addActiveObject(): "
- <<"id="<<id<<" type="<<type<<": Couldn't create object"
- <<std::endl;
- return;
- }
-
- obj->setId(id);
-
- try
- {
- obj->initialize(init_data);
- }
- catch(SerializationError &e)
- {
- errorstream<<"ClientEnvironment::addActiveObject():"
- <<" id="<<id<<" type="<<type
- <<": SerializationError in initialize(): "
- <<e.what()
- <<": init_data="<<serializeJsonString(init_data)
- <<std::endl;
- }
-
- addActiveObject(obj);
-}
-
-void ClientEnvironment::removeActiveObject(u16 id)
-{
- verbosestream<<"ClientEnvironment::removeActiveObject(): "
- <<"id="<<id<<std::endl;
- ClientActiveObject* obj = getActiveObject(id);
- if (obj == NULL) {
- infostream<<"ClientEnvironment::removeActiveObject(): "
- <<"id="<<id<<" not found"<<std::endl;
- return;
- }
- obj->removeFromScene(true);
- delete obj;
- m_active_objects.erase(id);
-}
-
-void ClientEnvironment::processActiveObjectMessage(u16 id, const std::string &data)
-{
- ClientActiveObject *obj = getActiveObject(id);
- if (obj == NULL) {
- infostream << "ClientEnvironment::processActiveObjectMessage():"
- << " got message for id=" << id << ", which doesn't exist."
- << std::endl;
- return;
- }
-
- try {
- obj->processMessage(data);
- } catch (SerializationError &e) {
- errorstream<<"ClientEnvironment::processActiveObjectMessage():"
- << " id=" << id << " type=" << obj->getType()
- << " SerializationError in processMessage(): " << e.what()
- << std::endl;
- }
-}
-
-/*
- Callbacks for activeobjects
-*/
-
-void ClientEnvironment::damageLocalPlayer(u8 damage, bool handle_hp)
-{
- LocalPlayer *lplayer = getLocalPlayer();
- assert(lplayer);
-
- if (handle_hp) {
- if (lplayer->hp > damage)
- lplayer->hp -= damage;
- else
- lplayer->hp = 0;
- }
-
- ClientEnvEvent event;
- event.type = CEE_PLAYER_DAMAGE;
- event.player_damage.amount = damage;
- event.player_damage.send_to_server = handle_hp;
- m_client_event_queue.push(event);
-}
-
-void ClientEnvironment::updateLocalPlayerBreath(u16 breath)
-{
- ClientEnvEvent event;
- event.type = CEE_PLAYER_BREATH;
- event.player_breath.amount = breath;
- m_client_event_queue.push(event);
-}
-
-/*
- Client likes to call these
-*/
-
-void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
- std::vector<DistanceSortedActiveObject> &dest)
-{
- for (UNORDERED_MAP<u16, ClientActiveObject*>::iterator i = m_active_objects.begin();
- i != m_active_objects.end(); ++i) {
- ClientActiveObject* obj = i->second;
-
- f32 d = (obj->getPosition() - origin).getLength();
-
- if(d > max_d)
- continue;
-
- DistanceSortedActiveObject dso(obj, d);
-
- dest.push_back(dso);
- }
-}
-
-ClientEnvEvent ClientEnvironment::getClientEvent()
-{
- ClientEnvEvent event;
- if(m_client_event_queue.empty())
- event.type = CEE_NONE;
- else {
- event = m_client_event_queue.front();
- m_client_event_queue.pop();
- }
- return event;
-}
-
-#endif // #ifndef SERVER
diff --git a/src/environment.h b/src/environment.h
index 4bee40e57..1de13e9ed 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -30,37 +30,24 @@ with this program; if not, write to the Free Software Foundation, Inc.,
- etc.
*/
-#include <set>
#include <list>
#include <queue>
#include <map>
#include "irr_v3d.h"
#include "activeobject.h"
#include "util/numeric.h"
-#include "mapnode.h"
-#include "mapblock.h"
#include "threading/mutex.h"
#include "threading/atomic.h"
#include "network/networkprotocol.h" // for AccessDeniedCode
-class ServerEnvironment;
-class ActiveBlockModifier;
-class ServerActiveObject;
-class ITextureSource;
class IGameDef;
class Map;
-class ServerMap;
-class ClientMap;
-class GameScripting;
-class Player;
-class RemotePlayer;
-class PlayerSAO;
class Environment
{
public:
// Environment will delete the map passed to the constructor
- Environment();
+ Environment(IGameDef *gamedef);
virtual ~Environment();
/*
@@ -71,7 +58,7 @@ public:
*/
virtual void step(f32 dtime) = 0;
- virtual Map & getMap() = 0;
+ virtual Map &getMap() = 0;
u32 getDayNightRatio();
@@ -91,6 +78,7 @@ public:
// counter used internally when triggering ABMs
u32 m_added_objects;
+ IGameDef *getGameDef() { return m_gamedef; }
protected:
GenericAtomic<float> m_time_of_day_speed;
@@ -128,532 +116,12 @@ protected:
float m_cache_abm_interval;
float m_cache_nodetimer_interval;
+ IGameDef *m_gamedef;
+
private:
Mutex m_time_lock;
DISABLE_CLASS_COPY(Environment);
};
-/*
- {Active, Loading} block modifier interface.
-
- These are fed into ServerEnvironment at initialization time;
- ServerEnvironment handles deleting them.
-*/
-
-class ActiveBlockModifier
-{
-public:
- ActiveBlockModifier(){};
- virtual ~ActiveBlockModifier(){};
-
- // Set of contents to trigger on
- virtual std::set<std::string> getTriggerContents()=0;
- // Set of required neighbors (trigger doesn't happen if none are found)
- // Empty = do not check neighbors
- virtual std::set<std::string> getRequiredNeighbors()
- { return std::set<std::string>(); }
- // Trigger interval in seconds
- virtual float getTriggerInterval() = 0;
- // Random chance of (1 / return value), 0 is disallowed
- virtual u32 getTriggerChance() = 0;
- // Whether to modify chance to simulate time lost by an unnattended block
- virtual bool getSimpleCatchUp() = 0;
- // This is called usually at interval for 1/chance of the nodes
- virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n){};
- virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n,
- u32 active_object_count, u32 active_object_count_wider){};
-};
-
-struct ABMWithState
-{
- ActiveBlockModifier *abm;
- float timer;
-
- ABMWithState(ActiveBlockModifier *abm_);
-};
-
-struct LoadingBlockModifierDef
-{
- // Set of contents to trigger on
- std::set<std::string> trigger_contents;
- std::string name;
- bool run_at_every_load;
-
- virtual ~LoadingBlockModifierDef() {}
- virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n){};
-};
-
-struct LBMContentMapping
-{
- typedef std::map<content_t, std::vector<LoadingBlockModifierDef *> > container_map;
- container_map map;
-
- std::vector<LoadingBlockModifierDef *> lbm_list;
-
- // Needs to be separate method (not inside destructor),
- // because the LBMContentMapping may be copied and destructed
- // many times during operation in the lbm_lookup_map.
- void deleteContents();
- void addLBM(LoadingBlockModifierDef *lbm_def, IGameDef *gamedef);
- const std::vector<LoadingBlockModifierDef *> *lookup(content_t c) const;
-};
-
-class LBMManager
-{
-public:
- LBMManager():
- m_query_mode(false)
- {}
-
- ~LBMManager();
-
- // Don't call this after loadIntroductionTimes() ran.
- void addLBMDef(LoadingBlockModifierDef *lbm_def);
-
- void loadIntroductionTimes(const std::string &times,
- IGameDef *gamedef, u32 now);
-
- // Don't call this before loadIntroductionTimes() ran.
- std::string createIntroductionTimesString();
-
- // Don't call this before loadIntroductionTimes() ran.
- void applyLBMs(ServerEnvironment *env, MapBlock *block, u32 stamp);
-
- // Warning: do not make this std::unordered_map, order is relevant here
- typedef std::map<u32, LBMContentMapping> lbm_lookup_map;
-
-private:
- // Once we set this to true, we can only query,
- // not modify
- bool m_query_mode;
-
- // For m_query_mode == false:
- // The key of the map is the LBM def's name.
- // TODO make this std::unordered_map
- std::map<std::string, LoadingBlockModifierDef *> m_lbm_defs;
-
- // For m_query_mode == true:
- // The key of the map is the LBM def's first introduction time.
- lbm_lookup_map m_lbm_lookup;
-
- // Returns an iterator to the LBMs that were introduced
- // after the given time. This is guaranteed to return
- // valid values for everything
- lbm_lookup_map::const_iterator getLBMsIntroducedAfter(u32 time)
- { return m_lbm_lookup.lower_bound(time); }
-};
-
-/*
- List of active blocks, used by ServerEnvironment
-*/
-
-class ActiveBlockList
-{
-public:
- void update(std::vector<v3s16> &active_positions,
- s16 radius,
- std::set<v3s16> &blocks_removed,
- std::set<v3s16> &blocks_added);
-
- bool contains(v3s16 p){
- return (m_list.find(p) != m_list.end());
- }
-
- void clear(){
- m_list.clear();
- }
-
- std::set<v3s16> m_list;
- std::set<v3s16> m_forceloaded_list;
-
-private:
-};
-
-/*
- Operation mode for ServerEnvironment::clearObjects()
-*/
-enum ClearObjectsMode {
- // Load and go through every mapblock, clearing objects
- CLEAR_OBJECTS_MODE_FULL,
-
- // Clear objects immediately in loaded mapblocks;
- // clear objects in unloaded mapblocks only when the mapblocks are next activated.
- CLEAR_OBJECTS_MODE_QUICK,
-};
-
-/*
- The server-side environment.
-
- This is not thread-safe. Server uses an environment mutex.
-*/
-
-typedef UNORDERED_MAP<u16, ServerActiveObject *> ActiveObjectMap;
-
-class ServerEnvironment : public Environment
-{
-public:
- ServerEnvironment(ServerMap *map, GameScripting *scriptIface,
- IGameDef *gamedef, const std::string &path_world);
- ~ServerEnvironment();
-
- Map & getMap();
-
- ServerMap & getServerMap();
-
- //TODO find way to remove this fct!
- GameScripting* getScriptIface()
- { return m_script; }
-
- IGameDef *getGameDef()
- { return m_gamedef; }
-
- float getSendRecommendedInterval()
- { return m_recommended_send_interval; }
-
- void kickAllPlayers(AccessDeniedCode reason,
- const std::string &str_reason, bool reconnect);
- // Save players
- void saveLoadedPlayers();
- void savePlayer(RemotePlayer *player);
- RemotePlayer *loadPlayer(const std::string &playername, PlayerSAO *sao);
- void addPlayer(RemotePlayer *player);
- void removePlayer(RemotePlayer *player);
-
- /*
- Save and load time of day and game timer
- */
- void saveMeta();
- void loadMeta();
- // to be called instead of loadMeta if
- // env_meta.txt doesn't exist (e.g. new world)
- void loadDefaultMeta();
-
- u32 addParticleSpawner(float exptime);
- u32 addParticleSpawner(float exptime, u16 attached_id);
- void deleteParticleSpawner(u32 id, bool remove_from_object = true);
-
- /*
- External ActiveObject interface
- -------------------------------------------
- */
-
- ServerActiveObject* getActiveObject(u16 id);
-
- /*
- Add an active object to the environment.
- Environment handles deletion of object.
- Object may be deleted by environment immediately.
- If id of object is 0, assigns a free id to it.
- Returns the id of the object.
- Returns 0 if not added and thus deleted.
- */
- 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.
- (note: not used, pending removal from engine)
- */
- //bool addActiveObjectAsStatic(ServerActiveObject *object);
-
- /*
- Find out what new objects have been added to
- inside a radius around a position
- */
- void getAddedActiveObjects(PlayerSAO *playersao, s16 radius,
- s16 player_radius,
- std::set<u16> &current_objects,
- std::queue<u16> &added_objects);
-
- /*
- Find out what new objects have been removed from
- inside a radius around a position
- */
- void getRemovedActiveObjects(PlayerSAO *playersao, s16 radius,
- s16 player_radius,
- std::set<u16> &current_objects,
- std::queue<u16> &removed_objects);
-
- /*
- Get the next message emitted by some active object.
- Returns a message with id=0 if no messages are available.
- */
- ActiveObjectMessage getActiveObjectMessage();
-
- /*
- Activate objects and dynamically modify for the dtime determined
- from timestamp and additional_dtime
- */
- void activateBlock(MapBlock *block, u32 additional_dtime=0);
-
- /*
- {Active,Loading}BlockModifiers
- -------------------------------------------
- */
-
- void addActiveBlockModifier(ActiveBlockModifier *abm);
- void addLoadingBlockModifierDef(LoadingBlockModifierDef *lbm);
-
- /*
- Other stuff
- -------------------------------------------
- */
-
- // Script-aware node setters
- bool setNode(v3s16 p, const MapNode &n);
- bool removeNode(v3s16 p);
- bool swapNode(v3s16 p, const MapNode &n);
-
- // Find all active objects inside a radius around a point
- void getObjectsInsideRadius(std::vector<u16> &objects, v3f pos, float radius);
-
- // Clear objects, loading and going through every MapBlock
- void clearObjects(ClearObjectsMode mode);
-
- // This makes stuff happen
- void step(f32 dtime);
-
- //check if there's a line of sight between two positions
- bool line_of_sight(v3f pos1, v3f pos2, float stepsize=1.0, v3s16 *p=NULL);
-
- u32 getGameTime() { return m_game_time; }
-
- void reportMaxLagEstimate(float f) { m_max_lag_estimate = f; }
- float getMaxLagEstimate() { return m_max_lag_estimate; }
-
- std::set<v3s16>* getForceloadedBlocks() { return &m_active_blocks.m_forceloaded_list; };
-
- // Sets the static object status all the active objects in the specified block
- // This is only really needed for deleting blocks from the map
- void setStaticForActiveObjectsInBlock(v3s16 blockpos,
- bool static_exists, v3s16 static_block=v3s16(0,0,0));
-
- RemotePlayer *getPlayer(const u16 peer_id);
- RemotePlayer *getPlayer(const char* name);
-private:
-
- /*
- Internal ActiveObject interface
- -------------------------------------------
- */
-
- /*
- Add an active object to the environment.
-
- Called by addActiveObject.
-
- Object may be deleted by environment immediately.
- If id of object is 0, assigns a free id to it.
- Returns the id of the object.
- Returns 0 if not added and thus deleted.
- */
- u16 addActiveObjectRaw(ServerActiveObject *object, bool set_changed, u32 dtime_s);
-
- /*
- Remove all objects that satisfy (m_removed && m_known_by_count==0)
- */
- void removeRemovedObjects();
-
- /*
- Convert stored objects from block to active
- */
- void activateObjects(MapBlock *block, u32 dtime_s);
-
- /*
- Convert objects that are not in active blocks to static.
-
- If m_known_by_count != 0, active object is not deleted, but static
- data is still updated.
-
- If force_delete is set, active object is deleted nevertheless. It
- shall only be set so in the destructor of the environment.
- */
- void deactivateFarObjects(bool force_delete);
-
- /*
- Member variables
- */
-
- // The map
- ServerMap *m_map;
- // Lua state
- GameScripting* m_script;
- // Game definition
- IGameDef *m_gamedef;
- // World path
- const std::string m_path_world;
- // Active object list
- ActiveObjectMap m_active_objects;
- // Outgoing network message buffer for active objects
- std::queue<ActiveObjectMessage> m_active_object_messages;
- // Some timers
- float m_send_recommended_timer;
- IntervalLimiter m_object_management_interval;
- // List of active blocks
- ActiveBlockList m_active_blocks;
- IntervalLimiter m_active_blocks_management_interval;
- IntervalLimiter m_active_block_modifier_interval;
- IntervalLimiter m_active_blocks_nodemetadata_interval;
- int m_active_block_interval_overload_skip;
- // Time from the beginning of the game in seconds.
- // Incremented in step().
- u32 m_game_time;
- // A helper variable for incrementing the latter
- float m_game_time_fraction_counter;
- // Time of last clearObjects call (game time).
- // When a mapblock older than this is loaded, its objects are cleared.
- u32 m_last_clear_objects_time;
- // Active block modifiers
- std::vector<ABMWithState> m_abms;
- LBMManager m_lbm_mgr;
- // An interval for generally sending object positions and stuff
- float m_recommended_send_interval;
- // Estimate for general maximum lag as determined by server.
- // Can raise to high values like 15s with eg. map generation mods.
- float m_max_lag_estimate;
-
- // peer_ids in here should be unique, except that there may be many 0s
- std::vector<RemotePlayer*> m_players;
-
- // Particles
- IntervalLimiter m_particle_management_interval;
- UNORDERED_MAP<u32, float> m_particle_spawners;
- UNORDERED_MAP<u32, u16> m_particle_spawner_attachments;
-};
-
-#ifndef SERVER
-
-#include "clientobject.h"
-#include "content_cao.h"
-
-class ClientSimpleObject;
-
-/*
- The client-side environment.
-
- This is not thread-safe.
- Must be called from main (irrlicht) thread (uses the SceneManager)
- Client uses an environment mutex.
-*/
-
-enum ClientEnvEventType
-{
- CEE_NONE,
- CEE_PLAYER_DAMAGE,
- CEE_PLAYER_BREATH
-};
-
-struct ClientEnvEvent
-{
- ClientEnvEventType type;
- union {
- //struct{
- //} none;
- struct{
- u8 amount;
- bool send_to_server;
- } player_damage;
- struct{
- u16 amount;
- } player_breath;
- };
-};
-
-class ClientEnvironment : public Environment
-{
-public:
- ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
- ITextureSource *texturesource, IGameDef *gamedef,
- IrrlichtDevice *device);
- ~ClientEnvironment();
-
- Map & getMap();
- ClientMap & getClientMap();
-
- IGameDef *getGameDef()
- { return m_gamedef; }
-
- void step(f32 dtime);
-
- virtual void setLocalPlayer(LocalPlayer *player);
- LocalPlayer *getLocalPlayer() { return m_local_player; }
-
- /*
- ClientSimpleObjects
- */
-
- void addSimpleObject(ClientSimpleObject *simple);
-
- /*
- ActiveObjects
- */
-
- GenericCAO* getGenericCAO(u16 id);
- ClientActiveObject* getActiveObject(u16 id);
-
- /*
- Adds an active object to the environment.
- Environment handles deletion of object.
- Object may be deleted by environment immediately.
- If id of object is 0, assigns a free id to it.
- Returns the id of the object.
- Returns 0 if not added and thus deleted.
- */
- u16 addActiveObject(ClientActiveObject *object);
-
- void addActiveObject(u16 id, u8 type, const std::string &init_data);
- void removeActiveObject(u16 id);
-
- void processActiveObjectMessage(u16 id, const std::string &data);
-
- /*
- Callbacks for activeobjects
- */
-
- void damageLocalPlayer(u8 damage, bool handle_hp=true);
- void updateLocalPlayerBreath(u16 breath);
-
- /*
- Client likes to call these
- */
-
- // Get all nearby objects
- void getActiveObjects(v3f origin, f32 max_d,
- std::vector<DistanceSortedActiveObject> &dest);
-
- // Get event from queue. CEE_NONE is returned if queue is empty.
- ClientEnvEvent getClientEvent();
-
- u16 attachement_parent_ids[USHRT_MAX + 1];
-
- const std::list<std::string> &getPlayerNames() { return m_player_names; }
- void addPlayerName(const std::string &name) { m_player_names.push_back(name); }
- void removePlayerName(const std::string &name) { m_player_names.remove(name); }
- void updateCameraOffset(v3s16 camera_offset)
- { m_camera_offset = camera_offset; }
- v3s16 getCameraOffset() const { return m_camera_offset; }
-private:
- ClientMap *m_map;
- LocalPlayer *m_local_player;
- scene::ISceneManager *m_smgr;
- ITextureSource *m_texturesource;
- IGameDef *m_gamedef;
- IrrlichtDevice *m_irr;
- UNORDERED_MAP<u16, ClientActiveObject*> m_active_objects;
- std::vector<ClientSimpleObject*> m_simple_objects;
- std::queue<ClientEnvEvent> m_client_event_queue;
- IntervalLimiter m_active_object_light_update_interval;
- IntervalLimiter m_lava_hurt_interval;
- IntervalLimiter m_drowning_interval;
- IntervalLimiter m_breathing_interval;
- std::list<std::string> m_player_names;
- v3s16 m_camera_offset;
-};
-
#endif
-
-#endif
-
diff --git a/src/exceptions.h b/src/exceptions.h
index 67a2d0df6..1b39c6725 100644
--- a/src/exceptions.h
+++ b/src/exceptions.h
@@ -27,10 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class BaseException : public std::exception
{
public:
- BaseException(const std::string &s) throw()
- {
- m_s = s;
- }
+ BaseException(const std::string &s) throw(): m_s(s) {}
~BaseException() throw() {}
virtual const char * what() const throw()
{
@@ -122,12 +119,12 @@ public:
class ClientStateError : public BaseException {
public:
- ClientStateError(std::string s): BaseException(s) {}
+ ClientStateError(const std::string &s): BaseException(s) {}
};
class PrngException : public BaseException {
public:
- PrngException(std::string s): BaseException(s) {}
+ PrngException(const std::string &s): BaseException(s) {}
};
class ModError : public BaseException {
diff --git a/src/face_position_cache.cpp b/src/face_position_cache.cpp
new file mode 100644
index 000000000..f57e75da9
--- /dev/null
+++ b/src/face_position_cache.cpp
@@ -0,0 +1,110 @@
+/*
+Minetest
+Copyright (C) 2015 Nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "face_position_cache.h"
+#include "threading/mutex_auto_lock.h"
+
+
+UNORDERED_MAP<u16, std::vector<v3s16> > FacePositionCache::cache;
+Mutex FacePositionCache::cache_mutex;
+
+// Calculate the borders of a "d-radius" cube
+const std::vector<v3s16> &FacePositionCache::getFacePositions(u16 d)
+{
+ MutexAutoLock lock(cache_mutex);
+ UNORDERED_MAP<u16, std::vector<v3s16> >::iterator it = cache.find(d);
+ if (it != cache.end())
+ return it->second;
+
+ return generateFacePosition(d);
+}
+
+const std::vector<v3s16> &FacePositionCache::generateFacePosition(u16 d)
+{
+ cache[d] = std::vector<v3s16>();
+ std::vector<v3s16> &c = cache[d];
+ if (d == 0) {
+ c.push_back(v3s16(0,0,0));
+ return c;
+ }
+ if (d == 1) {
+ // This is an optimized sequence of coordinates.
+ c.push_back(v3s16( 0, 1, 0)); // Top
+ c.push_back(v3s16( 0, 0, 1)); // Back
+ c.push_back(v3s16(-1, 0, 0)); // Left
+ c.push_back(v3s16( 1, 0, 0)); // Right
+ c.push_back(v3s16( 0, 0,-1)); // Front
+ c.push_back(v3s16( 0,-1, 0)); // Bottom
+ // 6
+ c.push_back(v3s16(-1, 0, 1)); // Back left
+ c.push_back(v3s16( 1, 0, 1)); // Back right
+ c.push_back(v3s16(-1, 0,-1)); // Front left
+ c.push_back(v3s16( 1, 0,-1)); // Front right
+ c.push_back(v3s16(-1,-1, 0)); // Bottom left
+ c.push_back(v3s16( 1,-1, 0)); // Bottom right
+ c.push_back(v3s16( 0,-1, 1)); // Bottom back
+ c.push_back(v3s16( 0,-1,-1)); // Bottom front
+ c.push_back(v3s16(-1, 1, 0)); // Top left
+ c.push_back(v3s16( 1, 1, 0)); // Top right
+ c.push_back(v3s16( 0, 1, 1)); // Top back
+ c.push_back(v3s16( 0, 1,-1)); // Top front
+ // 18
+ c.push_back(v3s16(-1, 1, 1)); // Top back-left
+ c.push_back(v3s16( 1, 1, 1)); // Top back-right
+ c.push_back(v3s16(-1, 1,-1)); // Top front-left
+ c.push_back(v3s16( 1, 1,-1)); // Top front-right
+ c.push_back(v3s16(-1,-1, 1)); // Bottom back-left
+ c.push_back(v3s16( 1,-1, 1)); // Bottom back-right
+ c.push_back(v3s16(-1,-1,-1)); // Bottom front-left
+ c.push_back(v3s16( 1,-1,-1)); // Bottom front-right
+ // 26
+ return c;
+ }
+
+ // Take blocks in all sides, starting from y=0 and going +-y
+ for (s16 y = 0; y <= d - 1; y++) {
+ // Left and right side, including borders
+ for (s16 z =- d; z <= d; z++) {
+ c.push_back(v3s16( d, y, z));
+ c.push_back(v3s16(-d, y, z));
+ if (y != 0) {
+ c.push_back(v3s16( d, -y, z));
+ c.push_back(v3s16(-d, -y, z));
+ }
+ }
+ // Back and front side, excluding borders
+ for (s16 x = -d + 1; x <= d - 1; x++) {
+ c.push_back(v3s16(x, y, d));
+ c.push_back(v3s16(x, y, -d));
+ if (y != 0) {
+ c.push_back(v3s16(x, -y, d));
+ c.push_back(v3s16(x, -y, -d));
+ }
+ }
+ }
+
+ // Take the bottom and top face with borders
+ // -d < x < d, y = +-d, -d < z < d
+ for (s16 x = -d; x <= d; x++)
+ for (s16 z = -d; z <= d; z++) {
+ c.push_back(v3s16(x, -d, z));
+ c.push_back(v3s16(x, d, z));
+ }
+ return c;
+}
diff --git a/src/face_position_cache.h b/src/face_position_cache.h
new file mode 100644
index 000000000..c1d2841c4
--- /dev/null
+++ b/src/face_position_cache.h
@@ -0,0 +1,44 @@
+/*
+Minetest
+Copyright (C) 2015 Nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 FACE_POSITION_CACHE_HEADER
+#define FACE_POSITION_CACHE_HEADER
+
+#include "irr_v3d.h"
+#include "threading/mutex.h"
+#include "util/cpp11_container.h"
+
+#include <map>
+#include <vector>
+
+/*
+ * This class permits caching getFacePosition call results.
+ * This reduces CPU usage and vector calls.
+ */
+class FacePositionCache {
+public:
+ static const std::vector<v3s16> &getFacePositions(u16 d);
+
+private:
+ static const std::vector<v3s16> &generateFacePosition(u16 d);
+ static UNORDERED_MAP<u16, std::vector<v3s16> > cache;
+ static Mutex cache_mutex;
+};
+
+#endif
diff --git a/src/filecache.h b/src/filecache.h
index a913a06ac..627ab45ed 100644
--- a/src/filecache.h
+++ b/src/filecache.h
@@ -21,8 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef FILECACHE_HEADER
#define FILECACHE_HEADER
-#include <string>
#include <iostream>
+#include <string>
class FileCache
{
@@ -30,13 +30,11 @@ public:
/*
'dir' is the file cache directory to use.
*/
- FileCache(std::string dir):
- m_dir(dir)
- {
- }
-
+ FileCache(const std::string &dir) : m_dir(dir) {}
+
bool update(const std::string &name, const std::string &data);
bool load(const std::string &name, std::ostream &os);
+
private:
std::string m_dir;
diff --git a/src/fontengine.cpp b/src/fontengine.cpp
index 55ff001e7..da327c3f6 100644
--- a/src/fontengine.cpp
+++ b/src/fontengine.cpp
@@ -343,11 +343,31 @@ void FontEngine::initFont(unsigned int basesize, FontMode mode)
if (font != NULL) {
m_font_cache[mode][basesize] = font;
+ return;
}
- else {
- errorstream << "FontEngine: failed to load freetype font: "
- << font_path << std::endl;
+
+ // try fallback font
+ errorstream << "FontEngine: failed to load: " << font_path << ", trying to fall back "
+ "to fallback font" << std::endl;
+
+ font_path = g_settings->get(font_config_prefix + "fallback_font_path");
+
+ font = gui::CGUITTFont::createTTFont(m_env,
+ font_path.c_str(), size, true, true, font_shadow,
+ font_shadow_alpha);
+
+ if (font != NULL) {
+ m_font_cache[mode][basesize] = font;
+ return;
}
+
+ // give up
+ errorstream << "FontEngine: failed to load freetype font: "
+ << font_path << std::endl;
+ errorstream << "minetest can not continue without a valid font. Please correct "
+ "the 'font_path' setting or install the font file in the proper "
+ "location" << std::endl;
+ abort();
}
#endif
}
diff --git a/src/game.cpp b/src/game.cpp
index 966c23073..ff473e022 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <iomanip>
#include "camera.h"
#include "client.h"
+#include "client/inputhandler.h"
#include "client/tile.h" // For TextureSource
#include "client/keys.h"
#include "client/joystick_controller.h"
@@ -41,7 +42,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiKeyChangeMenu.h"
#include "guiPasswordChange.h"
#include "guiVolumeChange.h"
-#include "hud.h"
#include "mainmenumanager.h"
#include "mapblock.h"
#include "nodedef.h" // Needed for determining pointing to nodes
@@ -51,27 +51,20 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "quicktune_shortcutter.h"
#include "server.h"
#include "settings.h"
-#include "shader.h" // For ShaderSource
#include "sky.h"
#include "subgame.h"
#include "tool.h"
+#include "util/basic_macros.h"
#include "util/directiontables.h"
#include "util/pointedthing.h"
#include "irrlicht_changes/static_text.h"
#include "version.h"
-#include "minimap.h"
-#include "mapblock_mesh.h"
-
-#include "sound.h"
+#include "script/scripting_client.h"
#if USE_SOUND
#include "sound_openal.h"
#endif
-#ifdef HAVE_TOUCHSCREENGUI
- #include "touchscreengui.h"
-#endif
-
extern Settings *g_settings;
extern Profiler *g_profiler;
@@ -79,14 +72,15 @@ extern Profiler *g_profiler;
Text input system
*/
-struct TextDestNodeMetadata : public TextDest {
+struct TextDestNodeMetadata : public TextDest
+{
TextDestNodeMetadata(v3s16 p, Client *client)
{
m_p = p;
m_client = client;
}
// This is deprecated I guess? -celeron55
- void gotText(std::wstring text)
+ void gotText(const std::wstring &text)
{
std::string ntext = wide_to_utf8(text);
infostream << "Submitting 'text' field of node at (" << m_p.X << ","
@@ -104,13 +98,14 @@ struct TextDestNodeMetadata : public TextDest {
Client *m_client;
};
-struct TextDestPlayerInventory : public TextDest {
+struct TextDestPlayerInventory : public TextDest
+{
TextDestPlayerInventory(Client *client)
{
m_client = client;
m_formname = "";
}
- TextDestPlayerInventory(Client *client, std::string formname)
+ TextDestPlayerInventory(Client *client, const std::string &formname)
{
m_client = client;
m_formname = formname;
@@ -123,25 +118,20 @@ struct TextDestPlayerInventory : public TextDest {
Client *m_client;
};
-struct LocalFormspecHandler : public TextDest {
- LocalFormspecHandler();
- LocalFormspecHandler(std::string formname) :
- m_client(0)
+struct LocalFormspecHandler : public TextDest
+{
+ LocalFormspecHandler(const std::string &formname):
+ m_client(NULL)
{
m_formname = formname;
}
- LocalFormspecHandler(std::string formname, Client *client) :
+ LocalFormspecHandler(const std::string &formname, Client *client):
m_client(client)
{
m_formname = formname;
}
- void gotText(std::wstring message)
- {
- errorstream << "LocalFormspecHandler::gotText old style message received" << std::endl;
- }
-
void gotText(const StringMap &fields)
{
if (m_formname == "MT_PAUSE_MENU") {
@@ -179,38 +169,8 @@ struct LocalFormspecHandler : public TextDest {
}
}
- if (m_formname == "MT_DEATH_SCREEN") {
- assert(m_client != 0);
-
- if ((fields.find("btn_respawn") != fields.end())) {
- m_client->sendRespawn();
- return;
- }
-
- if (fields.find("quit") != fields.end()) {
- m_client->sendRespawn();
- return;
- }
- }
-
- // don't show error message for unhandled cursor keys
- if ((fields.find("key_up") != fields.end()) ||
- (fields.find("key_down") != fields.end()) ||
- (fields.find("key_left") != fields.end()) ||
- (fields.find("key_right") != fields.end())) {
- return;
- }
-
- errorstream << "LocalFormspecHandler::gotText unhandled >"
- << m_formname << "< event" << std::endl;
-
- int i = 0;
- StringMap::const_iterator it;
- for (it = fields.begin(); it != fields.end(); ++it) {
- errorstream << "\t" << i << ": " << it->first
- << "=" << it->second << std::endl;
- i++;
- }
+ // Don't disable this part when modding is disabled, it's used in builtin
+ m_client->getScript()->on_formspec_input(m_formname, fields);
}
Client *m_client;
@@ -235,7 +195,8 @@ public:
return meta->getString("formspec");
}
- std::string resolveText(std::string str)
+
+ virtual std::string resolveText(const std::string &str)
{
NodeMetadata *meta = m_map->getNodeMetadata(m_p);
@@ -265,271 +226,6 @@ public:
Client *m_client;
};
-/*
- Check if a node is pointable
-*/
-inline bool isPointableNode(const MapNode &n,
- Client *client, bool liquids_pointable)
-{
- const ContentFeatures &features = client->getNodeDefManager()->get(n);
- return features.pointable ||
- (liquids_pointable && features.isLiquid());
-}
-
-static inline void getNeighborConnectingFace(v3s16 p, INodeDefManager *nodedef,
- ClientMap *map, MapNode n, u8 bitmask, u8 *neighbors)
-{
- MapNode n2 = map->getNodeNoEx(p);
- if (nodedef->nodeboxConnects(n, n2, bitmask))
- *neighbors |= bitmask;
-}
-
-static inline u8 getNeighbors(v3s16 p, INodeDefManager *nodedef, ClientMap *map, MapNode n)
-{
- u8 neighbors = 0;
- const ContentFeatures &f = nodedef->get(n);
- // locate possible neighboring nodes to connect to
- if (f.drawtype == NDT_NODEBOX && f.node_box.type == NODEBOX_CONNECTED) {
- v3s16 p2 = p;
-
- p2.Y++;
- getNeighborConnectingFace(p2, nodedef, map, n, 1, &neighbors);
-
- p2 = p;
- p2.Y--;
- getNeighborConnectingFace(p2, nodedef, map, n, 2, &neighbors);
-
- p2 = p;
- p2.Z--;
- getNeighborConnectingFace(p2, nodedef, map, n, 4, &neighbors);
-
- p2 = p;
- p2.X--;
- getNeighborConnectingFace(p2, nodedef, map, n, 8, &neighbors);
-
- p2 = p;
- p2.Z++;
- getNeighborConnectingFace(p2, nodedef, map, n, 16, &neighbors);
-
- p2 = p;
- p2.X++;
- getNeighborConnectingFace(p2, nodedef, map, n, 32, &neighbors);
- }
-
- return neighbors;
-}
-
-/*
- Find what the player is pointing at
-*/
-PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_position,
- const v3f &camera_direction, const v3f &camera_position,
- core::line3d<f32> shootline, f32 d, bool liquids_pointable,
- bool look_for_object, const v3s16 &camera_offset,
- ClientActiveObject *&selected_object)
-{
- PointedThing result;
-
- std::vector<aabb3f> *selectionboxes = hud->getSelectionBoxes();
- selectionboxes->clear();
- static const bool show_entity_selectionbox = g_settings->getBool("show_entity_selectionbox");
-
- selected_object = NULL;
-
- INodeDefManager *nodedef = client->getNodeDefManager();
- ClientMap &map = client->getEnv().getClientMap();
-
- f32 min_distance = BS * 1001;
-
- // First try to find a pointed at active object
- if (look_for_object) {
- selected_object = client->getSelectedActiveObject(d * BS,
- camera_position, shootline);
-
- if (selected_object != NULL) {
- if (show_entity_selectionbox &&
- selected_object->doShowSelectionBox()) {
- aabb3f *selection_box = selected_object->getSelectionBox();
- // Box should exist because object was
- // returned in the first place
- assert(selection_box);
-
- v3f pos = selected_object->getPosition();
- selectionboxes->push_back(aabb3f(
- selection_box->MinEdge, selection_box->MaxEdge));
- hud->setSelectionPos(pos, camera_offset);
- }
-
- min_distance = (selected_object->getPosition() - camera_position).getLength();
-
- hud->setSelectedFaceNormal(v3f(0.0, 0.0, 0.0));
- result.type = POINTEDTHING_OBJECT;
- result.object_id = selected_object->getId();
- }
- }
-
- // That didn't work, try to find a pointed at node
-
- v3s16 pos_i = floatToInt(player_position, BS);
-
- /*infostream<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
- <<std::endl;*/
-
- s16 a = d;
- s16 ystart = pos_i.Y - (camera_direction.Y < 0 ? a : 1);
- s16 zstart = pos_i.Z - (camera_direction.Z < 0 ? a : 1);
- s16 xstart = pos_i.X - (camera_direction.X < 0 ? a : 1);
- s16 yend = pos_i.Y + 1 + (camera_direction.Y > 0 ? a : 1);
- s16 zend = pos_i.Z + (camera_direction.Z > 0 ? a : 1);
- s16 xend = pos_i.X + (camera_direction.X > 0 ? a : 1);
-
- // Prevent signed number overflow
- if (yend == 32767)
- yend = 32766;
-
- if (zend == 32767)
- zend = 32766;
-
- if (xend == 32767)
- xend = 32766;
-
- v3s16 pointed_pos(0, 0, 0);
-
- for (s16 y = ystart; y <= yend; y++) {
- for (s16 z = zstart; z <= zend; z++) {
- for (s16 x = xstart; x <= xend; x++) {
- MapNode n;
- bool is_valid_position;
- v3s16 p(x, y, z);
-
- n = map.getNodeNoEx(p, &is_valid_position);
- if (!is_valid_position) {
- continue;
- }
- if (!isPointableNode(n, client, liquids_pointable)) {
- continue;
- }
-
- std::vector<aabb3f> boxes;
- n.getSelectionBoxes(nodedef, &boxes, getNeighbors(p, nodedef, &map, n));
-
- v3s16 np(x, y, z);
- v3f npf = intToFloat(np, BS);
- for (std::vector<aabb3f>::const_iterator
- i = boxes.begin();
- i != boxes.end(); ++i) {
- aabb3f box = *i;
- box.MinEdge += npf;
- box.MaxEdge += npf;
-
- v3f centerpoint = box.getCenter();
- f32 distance = (centerpoint - camera_position).getLength();
- if (distance >= min_distance) {
- continue;
- }
- if (!box.intersectsWithLine(shootline)) {
- continue;
- }
- result.type = POINTEDTHING_NODE;
- min_distance = distance;
- pointed_pos = np;
- }
- }
- }
- }
-
- if (result.type == POINTEDTHING_NODE) {
- f32 d = 0.001 * BS;
- MapNode n = map.getNodeNoEx(pointed_pos);
- v3f npf = intToFloat(pointed_pos, BS);
- std::vector<aabb3f> boxes;
- n.getSelectionBoxes(nodedef, &boxes, getNeighbors(pointed_pos, nodedef, &map, n));
- f32 face_min_distance = 1000 * BS;
- for (std::vector<aabb3f>::const_iterator
- i = boxes.begin();
- i != boxes.end(); ++i) {
- aabb3f box = *i;
- box.MinEdge += npf;
- box.MaxEdge += npf;
- for (u16 j = 0; j < 6; j++) {
- v3s16 facedir = g_6dirs[j];
- aabb3f facebox = box;
- if (facedir.X > 0) {
- facebox.MinEdge.X = facebox.MaxEdge.X - d;
- } else if (facedir.X < 0) {
- facebox.MaxEdge.X = facebox.MinEdge.X + d;
- } else if (facedir.Y > 0) {
- facebox.MinEdge.Y = facebox.MaxEdge.Y - d;
- } else if (facedir.Y < 0) {
- facebox.MaxEdge.Y = facebox.MinEdge.Y + d;
- } else if (facedir.Z > 0) {
- facebox.MinEdge.Z = facebox.MaxEdge.Z - d;
- } else if (facedir.Z < 0) {
- facebox.MaxEdge.Z = facebox.MinEdge.Z + d;
- }
- v3f centerpoint = facebox.getCenter();
- f32 distance = (centerpoint - camera_position).getLength();
- if (distance >= face_min_distance)
- continue;
- if (!facebox.intersectsWithLine(shootline))
- continue;
- result.node_abovesurface = pointed_pos + facedir;
- hud->setSelectedFaceNormal(v3f(facedir.X, facedir.Y, facedir.Z));
- face_min_distance = distance;
- }
- }
- selectionboxes->clear();
- for (std::vector<aabb3f>::const_iterator
- i = boxes.begin();
- i != boxes.end(); ++i) {
- aabb3f box = *i;
- box.MinEdge += v3f(-d, -d, -d);
- box.MaxEdge += v3f(d, d, d);
- selectionboxes->push_back(box);
- }
- hud->setSelectionPos(intToFloat(pointed_pos, BS), camera_offset);
- result.node_undersurface = pointed_pos;
- }
-
- // Update selection mesh light level and vertex colors
- if (selectionboxes->size() > 0) {
- v3f pf = hud->getSelectionPos();
- v3s16 p = floatToInt(pf, BS);
-
- // Get selection mesh light level
- MapNode n = map.getNodeNoEx(p);
- u16 node_light = getInteriorLight(n, -1, nodedef);
- u16 light_level = node_light;
-
- for (u8 i = 0; i < 6; i++) {
- n = map.getNodeNoEx(p + g_6dirs[i]);
- node_light = getInteriorLight(n, -1, nodedef);
- if (node_light > light_level)
- light_level = node_light;
- }
-
- video::SColor c = MapBlock_LightColor(255, light_level, 0);
- u8 day = c.getRed();
- u8 night = c.getGreen();
- u32 daynight_ratio = client->getEnv().getDayNightRatio();
- finalColorBlend(c, day, night, daynight_ratio);
-
- // Modify final color a bit with time
- u32 timer = porting::getTimeMs() % 5000;
- float timerf = (float)(irr::core::PI * ((timer / 2500.0) - 0.5));
- float sin_r = 0.08 * sin(timerf);
- float sin_g = 0.08 * sin(timerf + irr::core::PI * 0.5);
- float sin_b = 0.08 * sin(timerf + irr::core::PI);
- c.setRed(core::clamp(core::round32(c.getRed() * (0.8 + sin_r)), 0, 255));
- c.setGreen(core::clamp(core::round32(c.getGreen() * (0.8 + sin_g)), 0, 255));
- c.setBlue(core::clamp(core::round32(c.getBlue() * (0.8 + sin_b)), 0, 255));
-
- // Set mesh final color
- hud->setSelectionMeshColor(c);
- }
- return result;
-}
-
/* Profiler display */
void update_profiler_gui(gui::IGUIStaticText *guitext_profiler, FontEngine *fe,
@@ -773,6 +469,7 @@ class SoundMaker
ISoundManager *m_sound;
INodeDefManager *m_ndef;
public:
+ bool makes_footstep_sound;
float m_player_step_timer;
SimpleSoundSpec m_player_step_sound;
@@ -782,6 +479,7 @@ public:
SoundMaker(ISoundManager *sound, INodeDefManager *ndef):
m_sound(sound),
m_ndef(ndef),
+ makes_footstep_sound(true),
m_player_step_timer(0)
{
}
@@ -790,7 +488,8 @@ public:
{
if (m_player_step_timer <= 0 && m_player_step_sound.exists()) {
m_player_step_timer = 0.03;
- m_sound->playSound(m_player_step_sound, false);
+ if (makes_footstep_sound)
+ m_sound->playSound(m_player_step_sound, false);
}
}
@@ -864,27 +563,35 @@ public:
class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
{
std::set<std::string> m_fetched;
+private:
+ void paths_insert(std::set<std::string> &dst_paths,
+ const std::string &base,
+ const std::string &name)
+ {
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".0.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".1.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".2.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".3.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".4.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".5.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".6.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".7.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".8.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".9.ogg");
+ }
public:
void fetchSounds(const std::string &name,
- std::set<std::string> &dst_paths,
- std::set<std::string> &dst_datas)
+ std::set<std::string> &dst_paths,
+ std::set<std::string> &dst_datas)
{
if (m_fetched.count(name))
return;
m_fetched.insert(name);
- std::string base = porting::path_share + DIR_DELIM + "sounds";
- dst_paths.insert(base + DIR_DELIM + name + ".ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".0.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".1.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".2.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".3.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".4.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".5.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".6.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".7.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".8.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".9.ogg");
+
+ paths_insert(dst_paths, porting::path_share, name);
+ paths_insert(dst_paths, porting::path_user, name);
}
};
@@ -907,7 +614,7 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
CachedPixelShaderSetting<float> m_fog_distance;
CachedVertexShaderSetting<float> m_animation_timer_vertex;
CachedPixelShaderSetting<float> m_animation_timer_pixel;
- CachedPixelShaderSetting<float> m_day_night_ratio;
+ CachedPixelShaderSetting<float, 3> m_day_light;
CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
CachedPixelShaderSetting<float, 3> m_minimap_yaw;
@@ -939,7 +646,7 @@ public:
m_fog_distance("fogDistance"),
m_animation_timer_vertex("animationTimer"),
m_animation_timer_pixel("animationTimer"),
- m_day_night_ratio("dayNightRatio"),
+ m_day_light("dayLight"),
m_eye_position_pixel("eyePosition"),
m_eye_position_vertex("eyePosition"),
m_minimap_yaw("yawVec"),
@@ -982,8 +689,14 @@ public:
m_fog_distance.set(&fog_distance, services);
- float daynight_ratio = (float)m_client->getEnv().getDayNightRatio() / 1000.f;
- m_day_night_ratio.set(&daynight_ratio, services);
+ u32 daynight_ratio = (float)m_client->getEnv().getDayNightRatio();
+ video::SColorf sunlight;
+ get_sunlight_color(&sunlight, daynight_ratio);
+ float dnc[3] = {
+ sunlight.r,
+ sunlight.g,
+ sunlight.b };
+ m_day_light.set(dnc, services);
u32 animation_timer = porting::getTimeMs() % 100000;
float animation_timer_f = (float)animation_timer / 100000.f;
@@ -1002,16 +715,19 @@ public:
m_eye_position_pixel.set(eye_position_array, services);
m_eye_position_vertex.set(eye_position_array, services);
- float minimap_yaw_array[3];
- v3f minimap_yaw = m_client->getMapper()->getYawVec();
+ if (m_client->getMinimap()) {
+ float minimap_yaw_array[3];
+ v3f minimap_yaw = m_client->getMinimap()->getYawVec();
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
- minimap_yaw_array[0] = minimap_yaw.X;
- minimap_yaw_array[1] = minimap_yaw.Y;
- minimap_yaw_array[2] = minimap_yaw.Z;
+ minimap_yaw_array[0] = minimap_yaw.X;
+ minimap_yaw_array[1] = minimap_yaw.Y;
+ minimap_yaw_array[2] = minimap_yaw.Z;
#else
- minimap_yaw.getAs3Values(minimap_yaw_array);
+ minimap_yaw.getAs3Values(minimap_yaw_array);
#endif
- m_minimap_yaw.set(minimap_yaw_array, services);
+ m_minimap_yaw.set(minimap_yaw_array, services);
+
+ }
SamplerLayer_t base_tex = 0,
normal_tex = 1,
@@ -1105,7 +821,8 @@ bool nodePlacementPrediction(Client &client,
// Predict param2 for facedir and wallmounted nodes
u8 param2 = 0;
- if (nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED) {
+ if (nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED ||
+ nodedef->get(id).param_type_2 == CPT2_COLORED_WALLMOUNTED) {
v3s16 dir = nodepos - neighbourpos;
if (abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))) {
@@ -1117,7 +834,8 @@ bool nodePlacementPrediction(Client &client,
}
}
- if (nodedef->get(id).param_type_2 == CPT2_FACEDIR) {
+ if (nodedef->get(id).param_type_2 == CPT2_FACEDIR ||
+ nodedef->get(id).param_type_2 == CPT2_COLORED_FACEDIR) {
v3s16 dir = nodepos - floatToInt(client.getEnv().getLocalPlayer()->getPosition(), BS);
if (abs(dir.X) > abs(dir.Z)) {
@@ -1141,7 +859,8 @@ bool nodePlacementPrediction(Client &client,
};
v3s16 pp;
- if (nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED)
+ if (nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED ||
+ nodedef->get(id).param_type_2 == CPT2_COLORED_WALLMOUNTED)
pp = p + wallmounted_dirs[param2];
else
pp = p + v3s16(0, -1, 0);
@@ -1181,16 +900,14 @@ bool nodePlacementPrediction(Client &client,
}
static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec,
- InventoryManager *invmgr, IGameDef *gamedef,
- IWritableTextureSource *tsrc, IrrlichtDevice *device,
- JoystickController *joystick,
- IFormSource *fs_src, TextDest *txt_dest, Client *client)
+ Client *client, IrrlichtDevice *device, JoystickController *joystick,
+ IFormSource *fs_src, TextDest *txt_dest)
{
if (*cur_formspec == 0) {
*cur_formspec = new GUIFormSpecMenu(device, joystick,
- guiroot, -1, &g_menumgr, invmgr, gamedef, tsrc,
- fs_src, txt_dest, client);
+ guiroot, -1, &g_menumgr, client, client->getTextureSource(),
+ fs_src, txt_dest);
(*cur_formspec)->doPause = false;
/*
@@ -1214,105 +931,6 @@ static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec,
#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
#endif
-static void show_deathscreen(GUIFormSpecMenu **cur_formspec,
- InventoryManager *invmgr, IGameDef *gamedef,
- IWritableTextureSource *tsrc, IrrlichtDevice *device,
- JoystickController *joystick, Client *client)
-{
- std::string formspec =
- std::string(FORMSPEC_VERSION_STRING) +
- SIZE_TAG
- "bgcolor[#320000b4;true]"
- "label[4.85,1.35;" + gettext("You died.") + "]"
- "button_exit[4,3;3,0.5;btn_respawn;" + gettext("Respawn") + "]"
- ;
-
- /* Create menu */
- /* Note: FormspecFormSource and LocalFormspecHandler
- * are deleted by guiFormSpecMenu */
- FormspecFormSource *fs_src = new FormspecFormSource(formspec);
- LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client);
-
- create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device,
- joystick, fs_src, txt_dst, NULL);
-}
-
-/******************************************************************************/
-static void show_pause_menu(GUIFormSpecMenu **cur_formspec,
- InventoryManager *invmgr, IGameDef *gamedef,
- IWritableTextureSource *tsrc, IrrlichtDevice *device,
- JoystickController *joystick, bool singleplayermode)
-{
-#ifdef __ANDROID__
- std::string control_text = strgettext("Default Controls:\n"
- "No menu visible:\n"
- "- single tap: button activate\n"
- "- double tap: place/use\n"
- "- slide finger: look around\n"
- "Menu/Inventory visible:\n"
- "- double tap (outside):\n"
- " -->close\n"
- "- touch stack, touch slot:\n"
- " --> move stack\n"
- "- touch&drag, tap 2nd finger\n"
- " --> place single item to slot\n"
- );
-#else
- std::string control_text = strgettext("Default Controls:\n"
- "- WASD: move\n"
- "- Space: jump/climb\n"
- "- Shift: sneak/go down\n"
- "- Q: drop item\n"
- "- I: inventory\n"
- "- Mouse: turn/look\n"
- "- Mouse left: dig/punch\n"
- "- Mouse right: place/use\n"
- "- Mouse wheel: select item\n"
- "- T: chat\n"
- );
-#endif
-
- float ypos = singleplayermode ? 0.5 : 0.1;
- std::ostringstream os;
-
- os << FORMSPEC_VERSION_STRING << SIZE_TAG
- << "button_exit[4," << (ypos++) << ";3,0.5;btn_continue;"
- << strgettext("Continue") << "]";
-
- if (!singleplayermode) {
- os << "button_exit[4," << (ypos++) << ";3,0.5;btn_change_password;"
- << strgettext("Change Password") << "]";
- }
-
-#ifndef __ANDROID__
- os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
- << strgettext("Sound Volume") << "]";
- os << "button_exit[4," << (ypos++) << ";3,0.5;btn_key_config;"
- << strgettext("Change Keys") << "]";
-#endif
- os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_menu;"
- << strgettext("Exit to Menu") << "]";
- os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_os;"
- << strgettext("Exit to OS") << "]"
- << "textarea[7.5,0.25;3.9,6.25;;" << control_text << ";]"
- << "textarea[0.4,0.25;3.5,6;;" << PROJECT_NAME_C "\n"
- << g_build_info << "\n"
- << "path_user = " << wrap_rows(porting::path_user, 20)
- << "\n;]";
-
- /* Create menu */
- /* Note: FormspecFormSource and LocalFormspecHandler *
- * are deleted by guiFormSpecMenu */
- FormspecFormSource *fs_src = new FormspecFormSource(os.str());
- LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU");
-
- create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device,
- joystick, fs_src, txt_dst, NULL);
- std::string con("btn_continue");
- (*cur_formspec)->setFocus(con);
- (*cur_formspec)->doPause = true;
-}
-
/******************************************************************************/
static void updateChat(Client &client, f32 dtime, bool show_debug,
const v2u32 &screensize, bool show_chat, u32 show_profiler,
@@ -1421,11 +1039,17 @@ void KeyCache::populate()
key[KeyType::INVENTORY] = getKeySetting("keymap_inventory");
key[KeyType::CHAT] = getKeySetting("keymap_chat");
key[KeyType::CMD] = getKeySetting("keymap_cmd");
+ key[KeyType::CMD_LOCAL] = getKeySetting("keymap_cmd_local");
key[KeyType::CONSOLE] = getKeySetting("keymap_console");
key[KeyType::MINIMAP] = getKeySetting("keymap_minimap");
key[KeyType::FREEMOVE] = getKeySetting("keymap_freemove");
key[KeyType::FASTMOVE] = getKeySetting("keymap_fastmove");
key[KeyType::NOCLIP] = getKeySetting("keymap_noclip");
+ key[KeyType::HOTBAR_PREV] = getKeySetting("keymap_hotbar_previous");
+ key[KeyType::HOTBAR_NEXT] = getKeySetting("keymap_hotbar_next");
+ key[KeyType::MUTE] = getKeySetting("keymap_mute");
+ key[KeyType::INC_VOLUME] = getKeySetting("keymap_increase_volume");
+ key[KeyType::DEC_VOLUME] = getKeySetting("keymap_decrease_volume");
key[KeyType::CINEMATIC] = getKeySetting("keymap_cinematic");
key[KeyType::SCREENSHOT] = getKeySetting("keymap_screenshot");
key[KeyType::TOGGLE_HUD] = getKeySetting("keymap_toggle_hud");
@@ -1497,6 +1121,7 @@ struct GameRunData {
PointedThing pointed_old;
bool digging;
bool ldown_for_dig;
+ bool dig_instantly;
bool left_punch;
bool update_wielded_item_trigger;
bool reset_jump_timer;
@@ -1530,28 +1155,10 @@ struct Jitter {
struct RunStats {
u32 drawtime;
- u32 beginscenetime;
- u32 endscenetime;
Jitter dtime_jitter, busy_time_jitter;
};
-/* Flags that can, or may, change during main game loop
- */
-struct VolatileRunFlags {
- bool invert_mouse;
- bool show_chat;
- bool show_hud;
- bool show_minimap;
- bool force_fog_off;
- bool show_debug;
- bool show_profiler_graph;
- bool disable_camera_update;
- bool first_loop_after_window_activation;
- bool camera_offset_changed;
-};
-
-
/****************************************************************************
THE GAME
****************************************************************************/
@@ -1594,7 +1201,7 @@ protected:
u16 port,
const SubgameSpec &gamespec);
bool initSound();
- bool createSingleplayerServer(const std::string map_dir,
+ bool createSingleplayerServer(const std::string &map_dir,
const SubgameSpec &gamespec, u16 port, std::string *address);
// Client creation
@@ -1610,79 +1217,75 @@ protected:
// Main loop
- void updateInteractTimers(GameRunData *runData, f32 dtime);
+ void updateInteractTimers(f32 dtime);
bool checkConnection();
bool handleCallbacks();
void processQueues();
- void updateProfilers(const GameRunData &runData, const RunStats &stats,
- const FpsControl &draw_times, f32 dtime);
- void addProfilerGraphs(const RunStats &stats, const FpsControl &draw_times,
- f32 dtime);
+ void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
+ void addProfilerGraphs(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
// Input related
- void processUserInput(VolatileRunFlags *flags, GameRunData *runData,
- f32 dtime);
- void processKeyInput(VolatileRunFlags *flags,
- float *statustext_time,
- float *jump_timer,
- bool *reset_jump_timer,
- u32 *profiler_current_page,
- u32 profiler_max_page);
+ void processUserInput(f32 dtime);
+ void processKeyInput();
void processItemSelection(u16 *new_playeritem);
void dropSelectedItem();
void openInventory();
- void openConsole(float height, const wchar_t *line=NULL);
- void toggleFreeMove(float *statustext_time);
- void toggleFreeMoveAlt(float *statustext_time, float *jump_timer);
- void toggleFast(float *statustext_time);
- void toggleNoClip(float *statustext_time);
- void toggleCinematic(float *statustext_time);
- void toggleAutorun(float *statustext_time);
-
- void toggleChat(float *statustext_time, bool *flag);
- void toggleHud(float *statustext_time, bool *flag);
- void toggleMinimap(float *statustext_time, bool *flag, bool show_hud,
- bool shift_pressed);
- void toggleFog(float *statustext_time, bool *flag);
- void toggleDebug(float *statustext_time, bool *show_debug,
- bool *show_profiler_graph, bool *show_wireframe);
- void toggleUpdateCamera(float *statustext_time, bool *flag);
- void toggleProfiler(float *statustext_time, u32 *profiler_current_page,
- u32 profiler_max_page);
-
- void increaseViewRange(float *statustext_time);
- void decreaseViewRange(float *statustext_time);
- void toggleFullViewRange(float *statustext_time);
-
- void updateCameraDirection(CameraOrientation *cam, VolatileRunFlags *flags,
- float dtime);
- void updateCameraOrientation(CameraOrientation *cam,
- const VolatileRunFlags &flags, float dtime);
+ void openConsole(float scale, const wchar_t *line=NULL);
+ void toggleFreeMove();
+ void toggleFreeMoveAlt();
+ void toggleFast();
+ void toggleNoClip();
+ void toggleCinematic();
+ void toggleAutorun();
+
+ void toggleChat();
+ void toggleHud();
+ void toggleMinimap(bool shift_pressed);
+ void toggleFog();
+ void toggleDebug();
+ void toggleUpdateCamera();
+ void toggleProfiler();
+
+ void increaseViewRange();
+ void decreaseViewRange();
+ void toggleFullViewRange();
+
+ void updateCameraDirection(CameraOrientation *cam, float dtime);
+ void updateCameraOrientation(CameraOrientation *cam, float dtime);
void updatePlayerControl(const CameraOrientation &cam);
void step(f32 *dtime);
- void processClientEvents(CameraOrientation *cam, float *damage_flash);
- void updateCamera(VolatileRunFlags *flags, u32 busy_time, f32 dtime,
- float time_from_last_punch);
+ void processClientEvents(CameraOrientation *cam);
+ void updateCamera(u32 busy_time, f32 dtime);
void updateSound(f32 dtime);
- void processPlayerInteraction(GameRunData *runData, f32 dtime, bool show_hud,
- bool show_debug);
- void handlePointingAtNothing(GameRunData *runData, const ItemStack &playerItem);
- void handlePointingAtNode(GameRunData *runData,
- const PointedThing &pointed, const ItemDefinition &playeritem_def,
+ void processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug);
+ /*!
+ * Returns the object or node the player is pointing at.
+ * Also updates the selected thing in the Hud.
+ *
+ * @param[in] shootline the shootline, starting from
+ * the camera position. This also gives the maximal distance
+ * of the search.
+ * @param[in] liquids_pointable if false, liquids are ignored
+ * @param[in] look_for_object if false, objects are ignored
+ * @param[in] camera_offset offset of the camera
+ * @param[out] selected_object the selected object or
+ * NULL if not found
+ */
+ PointedThing updatePointedThing(
+ const core::line3d<f32> &shootline, bool liquids_pointable,
+ bool look_for_object, const v3s16 &camera_offset);
+ void handlePointingAtNothing(const ItemStack &playerItem);
+ void handlePointingAtNode(const PointedThing &pointed, const ItemDefinition &playeritem_def,
const ToolCapabilities &playeritem_toolcap, f32 dtime);
- void handlePointingAtObject(GameRunData *runData,
- const PointedThing &pointed, const ItemStack &playeritem,
+ void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
const v3f &player_position, bool show_debug);
- void handleDigging(GameRunData *runData, const PointedThing &pointed,
- const v3s16 &nodepos, const ToolCapabilities &playeritem_toolcap,
- f32 dtime);
- void updateFrame(ProfilerGraph *graph, RunStats *stats, GameRunData *runData,
- f32 dtime, const VolatileRunFlags &flags, const CameraOrientation &cam);
- void updateGui(float *statustext_time, const RunStats &stats,
- const GameRunData& runData, f32 dtime, const VolatileRunFlags &flags,
+ void handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
+ const ToolCapabilities &playeritem_toolcap, f32 dtime);
+ void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
const CameraOrientation &cam);
+ void updateGui(const RunStats &stats, f32 dtime, const CameraOrientation &cam);
void updateProfilerGraphs(ProfilerGraph *graph);
// Misc
@@ -1734,6 +1337,8 @@ protected:
#endif
private:
+ void showPauseMenu();
+
InputHandler *input;
Client *client;
@@ -1767,10 +1372,10 @@ private:
Sky *sky; // Free using ->Drop()
Inventory *local_inventory;
Hud *hud;
- Mapper *mapper;
+ Minimap *mapper;
GameRunData runData;
- VolatileRunFlags flags;
+ GameUIFlags flags;
/* 'cache'
This class does take ownership/responsibily for cleaning up etc of any of
@@ -1782,7 +1387,6 @@ private:
bool *kill;
std::string *error_message;
bool *reconnect_requested;
- IGameDef *gamedef; // Convenience (same as *client)
scene::ISceneNode *skybox;
bool random_input;
@@ -1803,7 +1407,7 @@ private:
gui::IGUIStaticText *guitext_profiler; // Profiler text
std::wstring infotext;
- std::wstring statustext;
+ std::wstring m_statustext;
KeyCache keycache;
@@ -1828,6 +1432,10 @@ private:
f32 m_cache_cam_smoothing;
f32 m_cache_fog_start;
+ bool m_invert_mouse;
+ bool m_first_loop_after_window_activation;
+ bool m_camera_offset_changed;
+
#ifdef __ANDROID__
bool m_cache_hold_aux1;
bool m_android_chat_open;
@@ -1856,7 +1464,10 @@ Game::Game() :
sky(NULL),
local_inventory(NULL),
hud(NULL),
- mapper(NULL)
+ mapper(NULL),
+ m_invert_mouse(false),
+ m_first_loop_after_window_activation(false),
+ m_camera_offset_changed(false)
{
g_settings->registerChangedCallback("doubletap_jump",
&settingChangedCallback, this);
@@ -1987,8 +1598,8 @@ bool Game::startup(bool *kill,
flags.show_chat = true;
flags.show_hud = true;
flags.show_debug = g_settings->getBool("show_debug");
- flags.invert_mouse = g_settings->getBool("invert_mouse");
- flags.first_loop_after_window_activation = true;
+ m_invert_mouse = g_settings->getBool("invert_mouse");
+ m_first_loop_after_window_activation = true;
if (!init(map_dir, address, port, gamespec))
return false;
@@ -2022,17 +1633,33 @@ void Game::run()
&& client->checkPrivilege("fast");
#endif
+ irr::core::dimension2d<u32> previous_screen_size(g_settings->getU16("screenW"),
+ g_settings->getU16("screenH"));
+
while (device->run()
&& !(*kill || g_gamecallback->shutdown_requested
|| (server && server->getShutdownRequested()))) {
+ const irr::core::dimension2d<u32> &current_screen_size =
+ device->getVideoDriver()->getScreenSize();
+ // Verify if window size has changed and save it if it's the case
+ // Ensure evaluating settings->getBool after verifying screensize
+ // First condition is cheaper
+ if (previous_screen_size != current_screen_size &&
+ current_screen_size != irr::core::dimension2d<u32>(0,0) &&
+ g_settings->getBool("autosave_screensize")) {
+ g_settings->setU16("screenW", current_screen_size.Width);
+ g_settings->setU16("screenH", current_screen_size.Height);
+ previous_screen_size = current_screen_size;
+ }
+
/* Must be called immediately after a device->run() call because it
* uses device->getTimer()->getTime()
*/
limitFps(&draw_times, &dtime);
updateStats(&stats, draw_times, dtime);
- updateInteractTimers(&runData, dtime);
+ updateInteractTimers(dtime);
if (!checkConnection())
break;
@@ -2044,36 +1671,38 @@ void Game::run()
infotext = L"";
hud->resizeHotbar();
- updateProfilers(runData, stats, draw_times, dtime);
- processUserInput(&flags, &runData, dtime);
+ updateProfilers(stats, draw_times, dtime);
+ processUserInput(dtime);
// Update camera before player movement to avoid camera lag of one frame
- updateCameraDirection(&cam_view_target, &flags, dtime);
+ updateCameraDirection(&cam_view_target, dtime);
cam_view.camera_yaw += (cam_view_target.camera_yaw -
cam_view.camera_yaw) * m_cache_cam_smoothing;
cam_view.camera_pitch += (cam_view_target.camera_pitch -
cam_view.camera_pitch) * m_cache_cam_smoothing;
updatePlayerControl(cam_view);
step(&dtime);
- processClientEvents(&cam_view_target, &runData.damage_flash);
- updateCamera(&flags, draw_times.busy_time, dtime,
- runData.time_from_last_punch);
+ processClientEvents(&cam_view_target);
+ updateCamera(draw_times.busy_time, dtime);
updateSound(dtime);
- processPlayerInteraction(&runData, dtime, flags.show_hud,
- flags.show_debug);
- updateFrame(&graph, &stats, &runData, dtime, flags, cam_view);
+ processPlayerInteraction(dtime, flags.show_hud, flags.show_debug);
+ updateFrame(&graph, &stats, dtime, cam_view);
updateProfilerGraphs(&graph);
// Update if minimap has been disabled by the server
- flags.show_minimap &= !client->isMinimapDisabledByServer();
+ flags.show_minimap &= client->shouldShowMinimap();
}
}
void Game::shutdown()
{
+#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 8
if (g_settings->get("3d_mode") == "pageflip") {
driver->setRenderTarget(irr::video::ERT_STEREO_BOTH_BUFFERS);
}
+#endif
+ if (current_formspec)
+ current_formspec->quitMenu();
showOverlayMessage(wgettext("Shutting down..."), 0, 0, false);
@@ -2125,9 +1754,10 @@ bool Game::init(
u16 port,
const SubgameSpec &gamespec)
{
+ texture_src = createTextureSource(device);
+
showOverlayMessage(wgettext("Loading..."), 0, 0);
- texture_src = createTextureSource(device);
shader_src = createShaderSource(device);
itemdef_manager = createItemDefManager();
@@ -2179,7 +1809,7 @@ bool Game::initSound()
return true;
}
-bool Game::createSingleplayerServer(const std::string map_dir,
+bool Game::createSingleplayerServer(const std::string &map_dir,
const SubgameSpec &gamespec, u16 port, std::string *address)
{
showOverlayMessage(wgettext("Creating server..."), 0, 5);
@@ -2208,7 +1838,7 @@ bool Game::createSingleplayerServer(const std::string map_dir,
}
server = new Server(map_dir, gamespec, simple_singleplayer_mode,
- bind_addr.isIPv6());
+ bind_addr.isIPv6(), false);
server->start(bind_addr);
@@ -2257,7 +1887,7 @@ bool Game::createClient(const std::string &playername,
/* Camera
*/
- camera = new Camera(smgr, *draw_control, gamedef);
+ camera = new Camera(smgr, *draw_control, client);
if (!camera || !camera->successfullyCreated(*error_message))
return false;
client->setCamera(camera);
@@ -2314,7 +1944,7 @@ bool Game::createClient(const std::string &playername,
player->hurt_tilt_timer = 0;
player->hurt_tilt_strength = 0;
- hud = new Hud(driver, smgr, guienv, gamedef, player, local_inventory);
+ hud = new Hud(driver, smgr, guienv, client, player, local_inventory);
if (!hud) {
*error_message = "Memory error: could not create HUD";
@@ -2322,8 +1952,9 @@ bool Game::createClient(const std::string &playername,
return false;
}
- mapper = client->getMapper();
- mapper->setMinimapMode(MINIMAP_MODE_OFF);
+ mapper = client->getMinimap();
+ if (mapper)
+ mapper->setMinimapMode(MINIMAP_MODE_OFF);
return true;
}
@@ -2436,21 +2067,19 @@ bool Game::connectToServer(const std::string &playername,
}
client = new Client(device,
- playername.c_str(), password,
+ playername.c_str(), password, *address,
*draw_control, texture_src, shader_src,
itemdef_manager, nodedef_manager, sound, eventmgr,
- connect_address.isIPv6());
+ connect_address.isIPv6(), &flags);
if (!client)
return false;
- gamedef = client; // Client acts as our GameDef
-
infostream << "Connecting to server at ";
connect_address.print(&infostream);
infostream << std::endl;
- client->connect(connect_address, *address,
+ client->connect(connect_address,
simple_singleplayer_mode || local_server_mode);
/*
@@ -2466,6 +2095,8 @@ bool Game::connectToServer(const std::string &playername,
fps_control.last_time = device->getTimer()->getTime();
+ client->initMods();
+
while (device->run()) {
limitFps(&fps_control, &dtime);
@@ -2583,17 +2214,21 @@ bool Game::getServerContent(bool *aborted)
if (!client->itemdefReceived()) {
const wchar_t *text = wgettext("Item definitions...");
progress = 25;
- draw_load_screen(text, device, guienv, dtime, progress);
+ draw_load_screen(text, device, guienv, texture_src,
+ dtime, progress);
delete[] text;
} else if (!client->nodedefReceived()) {
const wchar_t *text = wgettext("Node definitions...");
progress = 30;
- draw_load_screen(text, device, guienv, dtime, progress);
+ draw_load_screen(text, device, guienv, texture_src,
+ dtime, progress);
delete[] text;
} else {
std::stringstream message;
- message.precision(3);
- message << gettext("Media...");
+ std::fixed(message);
+ message.precision(0);
+ message << gettext("Media...") << " " << (client->mediaReceiveProgress()*100) << "%";
+ message.precision(2);
if ((USE_CURL == 0) ||
(!g_settings->getBool("enable_remote_media_server"))) {
@@ -2610,7 +2245,7 @@ bool Game::getServerContent(bool *aborted)
progress = 30 + client->mediaReceiveProgress() * 35 + 0.5;
draw_load_screen(utf8_to_wide(message.str()), device,
- guienv, dtime, progress);
+ guienv, texture_src, dtime, progress);
}
}
@@ -2624,15 +2259,15 @@ bool Game::getServerContent(bool *aborted)
****************************************************************************/
/****************************************************************************/
-inline void Game::updateInteractTimers(GameRunData *runData, f32 dtime)
+inline void Game::updateInteractTimers(f32 dtime)
{
- if (runData->nodig_delay_timer >= 0)
- runData->nodig_delay_timer -= dtime;
+ if (runData.nodig_delay_timer >= 0)
+ runData.nodig_delay_timer -= dtime;
- if (runData->object_hit_delay_timer >= 0)
- runData->object_hit_delay_timer -= dtime;
+ if (runData.object_hit_delay_timer >= 0)
+ runData.object_hit_delay_timer -= dtime;
- runData->time_from_last_punch += dtime;
+ runData.time_from_last_punch += dtime;
}
@@ -2691,13 +2326,12 @@ inline bool Game::handleCallbacks()
void Game::processQueues()
{
texture_src->processQueue();
- itemdef_manager->processQueue(gamedef);
+ itemdef_manager->processQueue(client);
shader_src->processQueue();
}
-void Game::updateProfilers(const GameRunData &runData, const RunStats &stats,
- const FpsControl &draw_times, f32 dtime)
+void Game::updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime)
{
float profiler_print_interval =
g_settings->getFloat("profiler_print_interval");
@@ -2795,13 +2429,10 @@ void Game::updateStats(RunStats *stats, const FpsControl &draw_times,
Input handling
****************************************************************************/
-void Game::processUserInput(VolatileRunFlags *flags,
- GameRunData *runData, f32 dtime)
+void Game::processUserInput(f32 dtime)
{
// Reset input if window not active or some menu is active
- if (device->isWindowActive() == false
- || noMenuActive() == false
- || guienv->hasFocus(gui_chat_console)) {
+ if (!device->isWindowActive() || isMenuActive() || guienv->hasFocus(gui_chat_console)) {
input->clear();
#ifdef HAVE_TOUCHSCREENGUI
g_touchscreengui->hide();
@@ -2830,84 +2461,90 @@ void Game::processUserInput(VolatileRunFlags *flags,
#endif
// Increase timer for double tap of "keymap_jump"
- if (m_cache_doubletap_jump && runData->jump_timer <= 0.2)
- runData->jump_timer += dtime;
-
- processKeyInput(
- flags,
- &runData->statustext_time,
- &runData->jump_timer,
- &runData->reset_jump_timer,
- &runData->profiler_current_page,
- runData->profiler_max_page);
-
- processItemSelection(&runData->new_playeritem);
+ if (m_cache_doubletap_jump && runData.jump_timer <= 0.2f)
+ runData.jump_timer += dtime;
+
+ processKeyInput();
+ processItemSelection(&runData.new_playeritem);
}
-void Game::processKeyInput(VolatileRunFlags *flags,
- float *statustext_time,
- float *jump_timer,
- bool *reset_jump_timer,
- u32 *profiler_current_page,
- u32 profiler_max_page)
+void Game::processKeyInput()
{
-
- //TimeTaker tt("process kybd input", NULL, PRECISION_NANO);
-
if (wasKeyDown(KeyType::DROP)) {
dropSelectedItem();
} else if (wasKeyDown(KeyType::AUTORUN)) {
- toggleAutorun(statustext_time);
+ toggleAutorun();
} else if (wasKeyDown(KeyType::INVENTORY)) {
openInventory();
} else if (wasKeyDown(KeyType::ESC) || input->wasKeyDown(CancelKey)) {
if (!gui_chat_console->isOpenInhibited()) {
- show_pause_menu(&current_formspec, client, gamedef,
- texture_src, device, &input->joystick,
- simple_singleplayer_mode);
+ showPauseMenu();
}
} else if (wasKeyDown(KeyType::CHAT)) {
openConsole(0.2, L"");
} else if (wasKeyDown(KeyType::CMD)) {
openConsole(0.2, L"/");
+ } else if (wasKeyDown(KeyType::CMD_LOCAL)) {
+ openConsole(0.2, L".");
} else if (wasKeyDown(KeyType::CONSOLE)) {
- openConsole(1);
+ openConsole(core::clamp(g_settings->getFloat("console_height"), 0.1f, 1.0f));
} else if (wasKeyDown(KeyType::FREEMOVE)) {
- toggleFreeMove(statustext_time);
+ toggleFreeMove();
} else if (wasKeyDown(KeyType::JUMP)) {
- toggleFreeMoveAlt(statustext_time, jump_timer);
- *reset_jump_timer = true;
+ toggleFreeMoveAlt();
} else if (wasKeyDown(KeyType::FASTMOVE)) {
- toggleFast(statustext_time);
+ toggleFast();
} else if (wasKeyDown(KeyType::NOCLIP)) {
- toggleNoClip(statustext_time);
+ toggleNoClip();
+ } else if (wasKeyDown(KeyType::MUTE)) {
+ float volume = g_settings->getFloat("sound_volume");
+ if (volume < 0.001f) {
+ g_settings->setFloat("sound_volume", 1.0f);
+ m_statustext = narrow_to_wide(gettext("Volume changed to 100%"));
+ } else {
+ g_settings->setFloat("sound_volume", 0.0f);
+ m_statustext = narrow_to_wide(gettext("Volume changed to 0%"));
+ }
+ runData.statustext_time = 0;
+ } else if (wasKeyDown(KeyType::INC_VOLUME)) {
+ float new_volume = rangelim(g_settings->getFloat("sound_volume") + 0.1f, 0.0f, 1.0f);
+ char buf[100];
+ g_settings->setFloat("sound_volume", new_volume);
+ snprintf(buf, sizeof(buf), gettext("Volume changed to %d%%"), myround(new_volume * 100));
+ m_statustext = narrow_to_wide(buf);
+ runData.statustext_time = 0;
+ } else if (wasKeyDown(KeyType::DEC_VOLUME)) {
+ float new_volume = rangelim(g_settings->getFloat("sound_volume") - 0.1f, 0.0f, 1.0f);
+ char buf[100];
+ g_settings->setFloat("sound_volume", new_volume);
+ snprintf(buf, sizeof(buf), gettext("Volume changed to %d%%"), myround(new_volume * 100));
+ m_statustext = narrow_to_wide(buf);
+ runData.statustext_time = 0;
} else if (wasKeyDown(KeyType::CINEMATIC)) {
- toggleCinematic(statustext_time);
+ toggleCinematic();
} else if (wasKeyDown(KeyType::SCREENSHOT)) {
client->makeScreenshot(device);
} else if (wasKeyDown(KeyType::TOGGLE_HUD)) {
- toggleHud(statustext_time, &flags->show_hud);
+ toggleHud();
} else if (wasKeyDown(KeyType::MINIMAP)) {
- toggleMinimap(statustext_time, &flags->show_minimap, flags->show_hud,
- isKeyDown(KeyType::SNEAK));
+ toggleMinimap(isKeyDown(KeyType::SNEAK));
} else if (wasKeyDown(KeyType::TOGGLE_CHAT)) {
- toggleChat(statustext_time, &flags->show_chat);
+ toggleChat();
} else if (wasKeyDown(KeyType::TOGGLE_FORCE_FOG_OFF)) {
- toggleFog(statustext_time, &flags->force_fog_off);
+ toggleFog();
} else if (wasKeyDown(KeyType::TOGGLE_UPDATE_CAMERA)) {
- toggleUpdateCamera(statustext_time, &flags->disable_camera_update);
+ toggleUpdateCamera();
} else if (wasKeyDown(KeyType::TOGGLE_DEBUG)) {
- toggleDebug(statustext_time, &flags->show_debug, &flags->show_profiler_graph,
- &draw_control->show_wireframe);
+ toggleDebug();
} else if (wasKeyDown(KeyType::TOGGLE_PROFILER)) {
- toggleProfiler(statustext_time, profiler_current_page, profiler_max_page);
+ toggleProfiler();
} else if (wasKeyDown(KeyType::INCREASE_VIEWING_RANGE)) {
- increaseViewRange(statustext_time);
+ increaseViewRange();
} else if (wasKeyDown(KeyType::DECREASE_VIEWING_RANGE)) {
- decreaseViewRange(statustext_time);
+ decreaseViewRange();
} else if (wasKeyDown(KeyType::RANGESELECT)) {
- toggleFullViewRange(statustext_time);
+ toggleFullViewRange();
} else if (wasKeyDown(KeyType::QUICKTUNE_NEXT)) {
quicktune->next();
} else if (wasKeyDown(KeyType::QUICKTUNE_PREV)) {
@@ -2926,17 +2563,14 @@ void Game::processKeyInput(VolatileRunFlags *flags,
debug_stacks_print();
}
- if (!isKeyDown(KeyType::JUMP) && *reset_jump_timer) {
- *reset_jump_timer = false;
- *jump_timer = 0.0;
+ if (!isKeyDown(KeyType::JUMP) && runData.reset_jump_timer) {
+ runData.reset_jump_timer = false;
+ runData.jump_timer = 0.0f;
}
- //tt.stop();
-
if (quicktune->hasMessage()) {
- std::string msg = quicktune->getMessage();
- statustext = utf8_to_wide(msg);
- *statustext_time = 0;
+ m_statustext = utf8_to_wide(quicktune->getMessage());
+ runData.statustext_time = 0.0f;
}
}
@@ -2954,11 +2588,13 @@ void Game::processItemSelection(u16 *new_playeritem)
s32 dir = wheel;
- if (input->joystick.wasKeyDown(KeyType::SCROLL_DOWN)) {
+ if (input->joystick.wasKeyDown(KeyType::SCROLL_DOWN) ||
+ wasKeyDown(KeyType::HOTBAR_NEXT)) {
dir = -1;
}
- if (input->joystick.wasKeyDown(KeyType::SCROLL_UP)) {
+ if (input->joystick.wasKeyDown(KeyType::SCROLL_UP) ||
+ wasKeyDown(KeyType::HOTBAR_PREV)) {
dir = 1;
}
@@ -3015,8 +2651,7 @@ void Game::openInventory()
PlayerInventoryFormSource *fs_src = new PlayerInventoryFormSource(client);
TextDest *txt_dst = new TextDestPlayerInventory(client);
- create_formspec_menu(&current_formspec, client, gamedef, texture_src,
- device, &input->joystick, fs_src, txt_dst, client);
+ create_formspec_menu(&current_formspec, client, device, &input->joystick, fs_src, txt_dst);
cur_formname = "";
InventoryLocation inventoryloc;
@@ -3025,15 +2660,17 @@ void Game::openInventory()
}
-void Game::openConsole(float height, const wchar_t *line)
+void Game::openConsole(float scale, const wchar_t *line)
{
+ assert(scale > 0.0f && scale <= 1.0f);
+
#ifdef __ANDROID__
porting::showInputDialog(gettext("ok"), "", "", 2);
m_android_chat_open = true;
#else
if (gui_chat_console->isOpenInhibited())
return;
- gui_chat_console->openConsole(height);
+ gui_chat_console->openConsole(scale);
if (line) {
gui_chat_console->setCloseOnEnter(true);
gui_chat_console->replaceAndAddToHistory(line);
@@ -3052,40 +2689,42 @@ void Game::handleAndroidChatInput()
#endif
-void Game::toggleFreeMove(float *statustext_time)
+void Game::toggleFreeMove()
{
static const wchar_t *msg[] = { L"free_move disabled", L"free_move enabled" };
bool free_move = !g_settings->getBool("free_move");
g_settings->set("free_move", bool_to_cstr(free_move));
- *statustext_time = 0;
- statustext = msg[free_move];
+ runData.statustext_time = 0;
+ m_statustext = msg[free_move];
if (free_move && !client->checkPrivilege("fly"))
- statustext += L" (note: no 'fly' privilege)";
+ m_statustext += L" (note: no 'fly' privilege)";
}
-void Game::toggleFreeMoveAlt(float *statustext_time, float *jump_timer)
+void Game::toggleFreeMoveAlt()
{
- if (m_cache_doubletap_jump && *jump_timer < 0.2f)
- toggleFreeMove(statustext_time);
+ if (m_cache_doubletap_jump && runData.jump_timer < 0.2f)
+ toggleFreeMove();
+
+ runData.reset_jump_timer = true;
}
-void Game::toggleFast(float *statustext_time)
+void Game::toggleFast()
{
static const wchar_t *msg[] = { L"fast_move disabled", L"fast_move enabled" };
bool fast_move = !g_settings->getBool("fast_move");
g_settings->set("fast_move", bool_to_cstr(fast_move));
- *statustext_time = 0;
- statustext = msg[fast_move];
+ runData.statustext_time = 0;
+ m_statustext = msg[fast_move];
bool has_fast_privs = client->checkPrivilege("fast");
if (fast_move && !has_fast_privs)
- statustext += L" (note: no 'fast' privilege)";
+ m_statustext += L" (note: no 'fast' privilege)";
#ifdef __ANDROID__
m_cache_hold_aux1 = fast_move && has_fast_privs;
@@ -3093,63 +2732,62 @@ void Game::toggleFast(float *statustext_time)
}
-void Game::toggleNoClip(float *statustext_time)
+void Game::toggleNoClip()
{
static const wchar_t *msg[] = { L"noclip disabled", L"noclip enabled" };
bool noclip = !g_settings->getBool("noclip");
g_settings->set("noclip", bool_to_cstr(noclip));
- *statustext_time = 0;
- statustext = msg[noclip];
+ runData.statustext_time = 0;
+ m_statustext = msg[noclip];
if (noclip && !client->checkPrivilege("noclip"))
- statustext += L" (note: no 'noclip' privilege)";
+ m_statustext += L" (note: no 'noclip' privilege)";
}
-void Game::toggleCinematic(float *statustext_time)
+void Game::toggleCinematic()
{
static const wchar_t *msg[] = { L"cinematic disabled", L"cinematic enabled" };
bool cinematic = !g_settings->getBool("cinematic");
g_settings->set("cinematic", bool_to_cstr(cinematic));
- *statustext_time = 0;
- statustext = msg[cinematic];
+ runData.statustext_time = 0;
+ m_statustext = msg[cinematic];
}
// Add WoW-style autorun by toggling continuous forward.
-void Game::toggleAutorun(float *statustext_time)
+void Game::toggleAutorun()
{
static const wchar_t *msg[] = { L"autorun disabled", L"autorun enabled" };
bool autorun_enabled = !g_settings->getBool("continuous_forward");
g_settings->set("continuous_forward", bool_to_cstr(autorun_enabled));
- *statustext_time = 0;
- statustext = msg[autorun_enabled ? 1 : 0];
+ runData.statustext_time = 0;
+ m_statustext = msg[autorun_enabled ? 1 : 0];
}
-void Game::toggleChat(float *statustext_time, bool *flag)
+void Game::toggleChat()
{
static const wchar_t *msg[] = { L"Chat hidden", L"Chat shown" };
- *flag = !*flag;
- *statustext_time = 0;
- statustext = msg[*flag];
+ flags.show_chat = !flags.show_chat;
+ runData.statustext_time = 0;
+ m_statustext = msg[flags.show_chat];
}
-void Game::toggleHud(float *statustext_time, bool *flag)
+void Game::toggleHud()
{
static const wchar_t *msg[] = { L"HUD hidden", L"HUD shown" };
- *flag = !*flag;
- *statustext_time = 0;
- statustext = msg[*flag];
+ flags.show_hud = !flags.show_hud;
+ runData.statustext_time = 0;
+ m_statustext = msg[flags.show_hud];
}
-void Game::toggleMinimap(float *statustext_time, bool *flag,
- bool show_hud, bool shift_pressed)
+void Game::toggleMinimap(bool shift_pressed)
{
- if (!show_hud || !g_settings->getBool("enable_minimap"))
+ if (!mapper || !flags.show_hud || !g_settings->getBool("enable_minimap"))
return;
if (shift_pressed) {
@@ -3165,151 +2803,150 @@ void Game::toggleMinimap(float *statustext_time, bool *flag,
mode = (MinimapMode)((int)mode + 1);
}
- *flag = true;
+ flags.show_minimap = true;
switch (mode) {
case MINIMAP_MODE_SURFACEx1:
- statustext = L"Minimap in surface mode, Zoom x1";
+ m_statustext = L"Minimap in surface mode, Zoom x1";
break;
case MINIMAP_MODE_SURFACEx2:
- statustext = L"Minimap in surface mode, Zoom x2";
+ m_statustext = L"Minimap in surface mode, Zoom x2";
break;
case MINIMAP_MODE_SURFACEx4:
- statustext = L"Minimap in surface mode, Zoom x4";
+ m_statustext = L"Minimap in surface mode, Zoom x4";
break;
case MINIMAP_MODE_RADARx1:
- statustext = L"Minimap in radar mode, Zoom x1";
+ m_statustext = L"Minimap in radar mode, Zoom x1";
break;
case MINIMAP_MODE_RADARx2:
- statustext = L"Minimap in radar mode, Zoom x2";
+ m_statustext = L"Minimap in radar mode, Zoom x2";
break;
case MINIMAP_MODE_RADARx4:
- statustext = L"Minimap in radar mode, Zoom x4";
+ m_statustext = L"Minimap in radar mode, Zoom x4";
break;
default:
mode = MINIMAP_MODE_OFF;
- *flag = false;
- statustext = (hud_flags & HUD_FLAG_MINIMAP_VISIBLE) ?
+ flags.show_minimap = false;
+ m_statustext = (hud_flags & HUD_FLAG_MINIMAP_VISIBLE) ?
L"Minimap hidden" : L"Minimap disabled by server";
}
- *statustext_time = 0;
+ runData.statustext_time = 0;
mapper->setMinimapMode(mode);
}
-void Game::toggleFog(float *statustext_time, bool *flag)
+void Game::toggleFog()
{
static const wchar_t *msg[] = { L"Fog enabled", L"Fog disabled" };
- *flag = !*flag;
- *statustext_time = 0;
- statustext = msg[*flag];
+ flags.force_fog_off = !flags.force_fog_off;
+ runData.statustext_time = 0;
+ m_statustext = msg[flags.force_fog_off];
}
-void Game::toggleDebug(float *statustext_time, bool *show_debug,
- bool *show_profiler_graph, bool *show_wireframe)
+void Game::toggleDebug()
{
// Initial / 4x toggle: Chat only
// 1x toggle: Debug text with chat
// 2x toggle: Debug text with profiler graph
// 3x toggle: Debug text and wireframe
- if (!*show_debug) {
- *show_debug = true;
- *show_profiler_graph = false;
- *show_wireframe = false;
- statustext = L"Debug info shown";
- } else if (!*show_profiler_graph && !*show_wireframe) {
- *show_profiler_graph = true;
- statustext = L"Profiler graph shown";
- } else if (!*show_wireframe && client->checkPrivilege("debug")) {
- *show_profiler_graph = false;
- *show_wireframe = true;
- statustext = L"Wireframe shown";
+ if (!flags.show_debug) {
+ flags.show_debug = true;
+ flags.show_profiler_graph = false;
+ draw_control->show_wireframe = false;
+ m_statustext = L"Debug info shown";
+ } else if (!flags.show_profiler_graph && !draw_control->show_wireframe) {
+ flags.show_profiler_graph = true;
+ m_statustext = L"Profiler graph shown";
+ } else if (!draw_control->show_wireframe && client->checkPrivilege("debug")) {
+ flags.show_profiler_graph = false;
+ draw_control->show_wireframe = true;
+ m_statustext = L"Wireframe shown";
} else {
- *show_debug = false;
- *show_profiler_graph = false;
- *show_wireframe = false;
+ flags.show_debug = false;
+ flags.show_profiler_graph = false;
+ draw_control->show_wireframe = false;
if (client->checkPrivilege("debug")) {
- statustext = L"Debug info, profiler graph, and wireframe hidden";
+ m_statustext = L"Debug info, profiler graph, and wireframe hidden";
} else {
- statustext = L"Debug info and profiler graph hidden";
+ m_statustext = L"Debug info and profiler graph hidden";
}
}
- *statustext_time = 0;
+ runData.statustext_time = 0;
}
-void Game::toggleUpdateCamera(float *statustext_time, bool *flag)
+void Game::toggleUpdateCamera()
{
static const wchar_t *msg[] = {
L"Camera update enabled",
L"Camera update disabled"
};
- *flag = !*flag;
- *statustext_time = 0;
- statustext = msg[*flag];
+ flags.disable_camera_update = !flags.disable_camera_update;
+ runData.statustext_time = 0;
+ m_statustext = msg[flags.disable_camera_update];
}
-void Game::toggleProfiler(float *statustext_time, u32 *profiler_current_page,
- u32 profiler_max_page)
+void Game::toggleProfiler()
{
- *profiler_current_page = (*profiler_current_page + 1) % (profiler_max_page + 1);
+ runData.profiler_current_page =
+ (runData.profiler_current_page + 1) % (runData.profiler_max_page + 1);
// FIXME: This updates the profiler with incomplete values
- update_profiler_gui(guitext_profiler, g_fontengine, *profiler_current_page,
- profiler_max_page, driver->getScreenSize().Height);
+ update_profiler_gui(guitext_profiler, g_fontengine, runData.profiler_current_page,
+ runData.profiler_max_page, driver->getScreenSize().Height);
- if (*profiler_current_page != 0) {
+ if (runData.profiler_current_page != 0) {
std::wstringstream sstr;
- sstr << "Profiler shown (page " << *profiler_current_page
- << " of " << profiler_max_page << ")";
- statustext = sstr.str();
+ sstr << "Profiler shown (page " << runData.profiler_current_page
+ << " of " << runData.profiler_max_page << ")";
+ m_statustext = sstr.str();
} else {
- statustext = L"Profiler hidden";
+ m_statustext = L"Profiler hidden";
}
- *statustext_time = 0;
+ runData.statustext_time = 0;
}
-void Game::increaseViewRange(float *statustext_time)
+void Game::increaseViewRange()
{
s16 range = g_settings->getS16("viewing_range");
s16 range_new = range + 10;
if (range_new > 4000) {
range_new = 4000;
- statustext = utf8_to_wide("Viewing range is at maximum: "
+ m_statustext = utf8_to_wide("Viewing range is at maximum: "
+ itos(range_new));
} else {
- statustext = utf8_to_wide("Viewing range changed to "
+ m_statustext = utf8_to_wide("Viewing range changed to "
+ itos(range_new));
}
g_settings->set("viewing_range", itos(range_new));
- *statustext_time = 0;
+ runData.statustext_time = 0;
}
-void Game::decreaseViewRange(float *statustext_time)
+void Game::decreaseViewRange()
{
s16 range = g_settings->getS16("viewing_range");
s16 range_new = range - 10;
if (range_new < 20) {
range_new = 20;
- statustext = utf8_to_wide("Viewing range is at minimum: "
+ m_statustext = utf8_to_wide("Viewing range is at minimum: "
+ itos(range_new));
} else {
- statustext = utf8_to_wide("Viewing range changed to "
+ m_statustext = utf8_to_wide("Viewing range changed to "
+ itos(range_new));
}
g_settings->set("viewing_range", itos(range_new));
- *statustext_time = 0;
+ runData.statustext_time = 0;
}
-void Game::toggleFullViewRange(float *statustext_time)
+void Game::toggleFullViewRange()
{
static const wchar_t *msg[] = {
L"Disabled full viewing range",
@@ -3318,15 +2955,15 @@ void Game::toggleFullViewRange(float *statustext_time)
draw_control->range_all = !draw_control->range_all;
infostream << msg[draw_control->range_all] << std::endl;
- statustext = msg[draw_control->range_all];
- *statustext_time = 0;
+ m_statustext = msg[draw_control->range_all];
+ runData.statustext_time = 0;
}
-void Game::updateCameraDirection(CameraOrientation *cam,
- VolatileRunFlags *flags, float dtime)
+void Game::updateCameraDirection(CameraOrientation *cam, float dtime)
{
- if ((device->isWindowActive() && noMenuActive()) || random_input) {
+ if ((device->isWindowActive() && device->isWindowFocused()
+ && !isMenuActive()) || random_input) {
#ifndef __ANDROID__
if (!random_input) {
@@ -3336,10 +2973,10 @@ void Game::updateCameraDirection(CameraOrientation *cam,
}
#endif
- if (flags->first_loop_after_window_activation)
- flags->first_loop_after_window_activation = false;
+ if (m_first_loop_after_window_activation)
+ m_first_loop_after_window_activation = false;
else
- updateCameraOrientation(cam, *flags, dtime);
+ updateCameraOrientation(cam, dtime);
input->setMousePos((driver->getScreenSize().Width / 2),
(driver->getScreenSize().Height / 2));
@@ -3347,18 +2984,16 @@ void Game::updateCameraDirection(CameraOrientation *cam,
#ifndef ANDROID
// Mac OSX gets upset if this is set every frame
- if (device->getCursorControl()->isVisible() == false)
+ if (!device->getCursorControl()->isVisible())
device->getCursorControl()->setVisible(true);
#endif
- if (!flags->first_loop_after_window_activation)
- flags->first_loop_after_window_activation = true;
+ m_first_loop_after_window_activation = true;
}
}
-void Game::updateCameraOrientation(CameraOrientation *cam,
- const VolatileRunFlags &flags, float dtime)
+void Game::updateCameraOrientation(CameraOrientation *cam, float dtime)
{
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui) {
@@ -3370,8 +3005,7 @@ void Game::updateCameraOrientation(CameraOrientation *cam,
s32 dx = input->getMousePos().X - (driver->getScreenSize().Width / 2);
s32 dy = input->getMousePos().Y - (driver->getScreenSize().Height / 2);
- if (flags.invert_mouse
- || camera->getCameraMode() == CAMERA_MODE_THIRD_FRONT) {
+ if (m_invert_mouse || camera->getCameraMode() == CAMERA_MODE_THIRD_FRONT) {
dy = -dy;
}
@@ -3384,10 +3018,8 @@ void Game::updateCameraOrientation(CameraOrientation *cam,
if (m_cache_enable_joysticks) {
f32 c = m_cache_joystick_frustum_sensitivity * (1.f / 32767.f) * dtime;
- cam->camera_yaw -= input->joystick.getAxisWithoutDead(JA_FRUSTUM_HORIZONTAL) *
- c;
- cam->camera_pitch += input->joystick.getAxisWithoutDead(JA_FRUSTUM_VERTICAL) *
- c;
+ cam->camera_yaw -= input->joystick.getAxisWithoutDead(JA_FRUSTUM_HORIZONTAL) * c;
+ cam->camera_pitch += input->joystick.getAxisWithoutDead(JA_FRUSTUM_VERTICAL) * c;
}
cam->camera_pitch = rangelim(cam->camera_pitch, -89.5, 89.5);
@@ -3470,43 +3102,47 @@ inline void Game::step(f32 *dtime)
}
-void Game::processClientEvents(CameraOrientation *cam, float *damage_flash)
+void Game::processClientEvents(CameraOrientation *cam)
{
- ClientEvent event = client->getClientEvent();
-
LocalPlayer *player = client->getEnv().getLocalPlayer();
- for ( ; event.type != CE_NONE; event = client->getClientEvent()) {
+ while (client->hasClientEvents()) {
+ ClientEvent event = client->getClientEvent();
- if (event.type == CE_PLAYER_DAMAGE &&
- client->getHP() != 0) {
- //u16 damage = event.player_damage.amount;
- //infostream<<"Player damage: "<<damage<<std::endl;
+ switch (event.type) {
+ case CE_PLAYER_DAMAGE:
+ if (client->getHP() == 0)
+ break;
+ if (client->moddingEnabled()) {
+ client->getScript()->on_damage_taken(event.player_damage.amount);
+ }
- *damage_flash += 95.0 + 3.2 * event.player_damage.amount;
- *damage_flash = MYMIN(*damage_flash, 127.0);
+ runData.damage_flash += 95.0 + 3.2 * event.player_damage.amount;
+ runData.damage_flash = MYMIN(runData.damage_flash, 127.0);
player->hurt_tilt_timer = 1.5;
player->hurt_tilt_strength =
rangelim(event.player_damage.amount / 4, 1.0, 4.0);
- MtEvent *e = new SimpleTriggerEvent("PlayerDamage");
- gamedef->event()->put(e);
- } else if (event.type == CE_PLAYER_FORCE_MOVE) {
+ client->event()->put(new SimpleTriggerEvent("PlayerDamage"));
+ break;
+
+ case CE_PLAYER_FORCE_MOVE:
cam->camera_yaw = event.player_force_move.yaw;
cam->camera_pitch = event.player_force_move.pitch;
- } else if (event.type == CE_DEATHSCREEN) {
- show_deathscreen(&current_formspec, client, gamedef, texture_src,
- device, &input->joystick, client);
+ break;
- chat_backend->addMessage(L"", L"You died.");
+ case CE_DEATHSCREEN:
+ // This should be enabled for death formspec in builtin
+ client->getScript()->on_death();
/* Handle visualization */
- *damage_flash = 0;
+ runData.damage_flash = 0;
player->hurt_tilt_timer = 0;
player->hurt_tilt_strength = 0;
+ break;
- } else if (event.type == CE_SHOW_FORMSPEC) {
+ case CE_SHOW_FORMSPEC:
if (*(event.show_formspec.formspec) == "") {
if (current_formspec && ( *(event.show_formspec.formname) == "" || *(event.show_formspec.formname) == cur_formname) ){
current_formspec->quitMenu();
@@ -3517,54 +3153,69 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash)
TextDestPlayerInventory *txt_dst =
new TextDestPlayerInventory(client, *(event.show_formspec.formname));
- create_formspec_menu(&current_formspec, client, gamedef,
- texture_src, device, &input->joystick,
- fs_src, txt_dst, client);
+ create_formspec_menu(&current_formspec, client, device, &input->joystick,
+ fs_src, txt_dst);
cur_formname = *(event.show_formspec.formname);
}
- delete(event.show_formspec.formspec);
- delete(event.show_formspec.formname);
- } else if ((event.type == CE_SPAWN_PARTICLE) ||
- (event.type == CE_ADD_PARTICLESPAWNER) ||
- (event.type == CE_DELETE_PARTICLESPAWNER)) {
- client->getParticleManager()->handleParticleEvent(&event, gamedef,
- smgr, player);
- } else if (event.type == CE_HUDADD) {
- u32 id = event.hudadd.id;
-
- LocalPlayer *player = client->getEnv().getLocalPlayer();
- HudElement *e = player->getHud(id);
-
- if (e != NULL) {
- delete event.hudadd.pos;
- delete event.hudadd.name;
- delete event.hudadd.scale;
- delete event.hudadd.text;
- delete event.hudadd.align;
- delete event.hudadd.offset;
- delete event.hudadd.world_pos;
- delete event.hudadd.size;
- continue;
+ delete event.show_formspec.formspec;
+ delete event.show_formspec.formname;
+ break;
+
+ case CE_SHOW_LOCAL_FORMSPEC:
+ {
+ FormspecFormSource *fs_src = new FormspecFormSource(*event.show_formspec.formspec);
+ LocalFormspecHandler *txt_dst = new LocalFormspecHandler(*event.show_formspec.formname, client);
+ create_formspec_menu(&current_formspec, client, device, &input->joystick,
+ fs_src, txt_dst);
}
+ delete event.show_formspec.formspec;
+ delete event.show_formspec.formname;
+ break;
- e = new HudElement;
- e->type = (HudElementType)event.hudadd.type;
- e->pos = *event.hudadd.pos;
- e->name = *event.hudadd.name;
- e->scale = *event.hudadd.scale;
- e->text = *event.hudadd.text;
- e->number = event.hudadd.number;
- e->item = event.hudadd.item;
- e->dir = event.hudadd.dir;
- e->align = *event.hudadd.align;
- e->offset = *event.hudadd.offset;
- e->world_pos = *event.hudadd.world_pos;
- e->size = *event.hudadd.size;
-
- u32 new_id = player->addHud(e);
- //if this isn't true our huds aren't consistent
- sanity_check(new_id == id);
+ case CE_SPAWN_PARTICLE:
+ case CE_ADD_PARTICLESPAWNER:
+ case CE_DELETE_PARTICLESPAWNER:
+ client->getParticleManager()->handleParticleEvent(&event, client,
+ smgr, player);
+ break;
+
+ case CE_HUDADD:
+ {
+ u32 id = event.hudadd.id;
+
+ HudElement *e = player->getHud(id);
+
+ if (e != NULL) {
+ delete event.hudadd.pos;
+ delete event.hudadd.name;
+ delete event.hudadd.scale;
+ delete event.hudadd.text;
+ delete event.hudadd.align;
+ delete event.hudadd.offset;
+ delete event.hudadd.world_pos;
+ delete event.hudadd.size;
+ continue;
+ }
+
+ e = new HudElement;
+ e->type = (HudElementType)event.hudadd.type;
+ e->pos = *event.hudadd.pos;
+ e->name = *event.hudadd.name;
+ e->scale = *event.hudadd.scale;
+ e->text = *event.hudadd.text;
+ e->number = event.hudadd.number;
+ e->item = event.hudadd.item;
+ e->dir = event.hudadd.dir;
+ e->align = *event.hudadd.align;
+ e->offset = *event.hudadd.offset;
+ e->world_pos = *event.hudadd.world_pos;
+ e->size = *event.hudadd.size;
+
+ u32 new_id = player->addHud(e);
+ //if this isn't true our huds aren't consistent
+ sanity_check(new_id == id);
+ }
delete event.hudadd.pos;
delete event.hudadd.name;
@@ -3574,75 +3225,87 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash)
delete event.hudadd.offset;
delete event.hudadd.world_pos;
delete event.hudadd.size;
- } else if (event.type == CE_HUDRM) {
- HudElement *e = player->removeHud(event.hudrm.id);
-
- if (e != NULL)
- delete(e);
- } else if (event.type == CE_HUDCHANGE) {
- u32 id = event.hudchange.id;
- HudElement *e = player->getHud(id);
-
- if (e == NULL) {
- delete event.hudchange.v3fdata;
- delete event.hudchange.v2fdata;
- delete event.hudchange.sdata;
- delete event.hudchange.v2s32data;
- continue;
+ break;
+
+ case CE_HUDRM:
+ {
+ HudElement *e = player->removeHud(event.hudrm.id);
+
+ if (e != NULL)
+ delete e;
}
+ break;
- switch (event.hudchange.stat) {
- case HUD_STAT_POS:
- e->pos = *event.hudchange.v2fdata;
- break;
+ case CE_HUDCHANGE:
+ {
+ u32 id = event.hudchange.id;
+ HudElement *e = player->getHud(id);
- case HUD_STAT_NAME:
- e->name = *event.hudchange.sdata;
- break;
+ if (e == NULL) {
+ delete event.hudchange.v3fdata;
+ delete event.hudchange.v2fdata;
+ delete event.hudchange.sdata;
+ delete event.hudchange.v2s32data;
+ continue;
+ }
- case HUD_STAT_SCALE:
- e->scale = *event.hudchange.v2fdata;
- break;
+ switch (event.hudchange.stat) {
+ case HUD_STAT_POS:
+ e->pos = *event.hudchange.v2fdata;
+ break;
- case HUD_STAT_TEXT:
- e->text = *event.hudchange.sdata;
- break;
+ case HUD_STAT_NAME:
+ e->name = *event.hudchange.sdata;
+ break;
- case HUD_STAT_NUMBER:
- e->number = event.hudchange.data;
- break;
+ case HUD_STAT_SCALE:
+ e->scale = *event.hudchange.v2fdata;
+ break;
- case HUD_STAT_ITEM:
- e->item = event.hudchange.data;
- break;
+ case HUD_STAT_TEXT:
+ e->text = *event.hudchange.sdata;
+ break;
- case HUD_STAT_DIR:
- e->dir = event.hudchange.data;
- break;
+ case HUD_STAT_NUMBER:
+ e->number = event.hudchange.data;
+ break;
- case HUD_STAT_ALIGN:
- e->align = *event.hudchange.v2fdata;
- break;
+ case HUD_STAT_ITEM:
+ e->item = event.hudchange.data;
+ break;
- case HUD_STAT_OFFSET:
- e->offset = *event.hudchange.v2fdata;
- break;
+ case HUD_STAT_DIR:
+ e->dir = event.hudchange.data;
+ break;
- case HUD_STAT_WORLD_POS:
- e->world_pos = *event.hudchange.v3fdata;
- break;
+ case HUD_STAT_ALIGN:
+ e->align = *event.hudchange.v2fdata;
+ break;
- case HUD_STAT_SIZE:
- e->size = *event.hudchange.v2s32data;
- break;
+ case HUD_STAT_OFFSET:
+ e->offset = *event.hudchange.v2fdata;
+ break;
+
+ case HUD_STAT_WORLD_POS:
+ e->world_pos = *event.hudchange.v3fdata;
+ break;
+
+ case HUD_STAT_SIZE:
+ e->size = *event.hudchange.v2s32data;
+ break;
+ }
}
delete event.hudchange.v3fdata;
delete event.hudchange.v2fdata;
delete event.hudchange.sdata;
delete event.hudchange.v2s32data;
- } else if (event.type == CE_SET_SKY) {
+ break;
+
+ case CE_SET_SKY:
sky->setVisible(false);
+ // Whether clouds are visible in front of a custom skybox
+ sky->setCloudsEnabled(event.set_sky.clouds);
if (skybox) {
skybox->remove();
@@ -3652,6 +3315,7 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash)
// Handle according to type
if (*event.set_sky.type == "regular") {
sky->setVisible(true);
+ sky->setCloudsEnabled(true);
} else if (*event.set_sky.type == "skybox" &&
event.set_sky.params->size() == 6) {
sky->setFallbackBgColor(*event.set_sky.bgcolor);
@@ -3675,17 +3339,37 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash)
delete event.set_sky.bgcolor;
delete event.set_sky.type;
delete event.set_sky.params;
- } else if (event.type == CE_OVERRIDE_DAY_NIGHT_RATIO) {
- bool enable = event.override_day_night_ratio.do_override;
- u32 value = event.override_day_night_ratio.ratio_f * 1000;
- client->getEnv().setDayNightRatioOverride(enable, value);
+ break;
+
+ case CE_OVERRIDE_DAY_NIGHT_RATIO:
+ client->getEnv().setDayNightRatioOverride(
+ event.override_day_night_ratio.do_override,
+ event.override_day_night_ratio.ratio_f * 1000);
+ break;
+
+ case CE_CLOUD_PARAMS:
+ if (clouds) {
+ clouds->setDensity(event.cloud_params.density);
+ clouds->setColorBright(video::SColor(event.cloud_params.color_bright));
+ clouds->setColorAmbient(video::SColor(event.cloud_params.color_ambient));
+ clouds->setHeight(event.cloud_params.height);
+ clouds->setThickness(event.cloud_params.thickness);
+ clouds->setSpeed(v2f(
+ event.cloud_params.speed_x,
+ event.cloud_params.speed_y));
+ }
+ break;
+
+ default:
+ // unknown or unhandled type
+ break;
+
}
}
}
-void Game::updateCamera(VolatileRunFlags *flags, u32 busy_time,
- f32 dtime, float time_from_last_punch)
+void Game::updateCamera(u32 busy_time, f32 dtime)
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
@@ -3702,6 +3386,7 @@ void Game::updateCamera(VolatileRunFlags *flags, u32 busy_time,
if (mlist && client->getPlayerItem() < mlist->getSize())
playeritem = mlist->getItem(client->getPlayerItem());
}
+
if (playeritem.getDefinition(itemdef_manager).name.empty()) { // override the hand
InventoryList *hlist = local_inventory->getList("hand");
if (hlist)
@@ -3728,7 +3413,7 @@ void Game::updateCamera(VolatileRunFlags *flags, u32 busy_time,
}
float full_punch_interval = playeritem_toolcap.full_punch_interval;
- float tool_reload_ratio = time_from_last_punch / full_punch_interval;
+ float tool_reload_ratio = runData.time_from_last_punch / full_punch_interval;
tool_reload_ratio = MYMIN(tool_reload_ratio, 1.0);
camera->update(player, dtime, busy_time / 1000.0f, tool_reload_ratio,
@@ -3740,13 +3425,13 @@ void Game::updateCamera(VolatileRunFlags *flags, u32 busy_time,
f32 camera_fov = camera->getFovMax();
v3s16 camera_offset = camera->getOffset();
- flags->camera_offset_changed = (camera_offset != old_camera_offset);
+ m_camera_offset_changed = (camera_offset != old_camera_offset);
- if (!flags->disable_camera_update) {
+ if (!flags.disable_camera_update) {
client->getEnv().getClientMap().updateCamera(camera_position,
camera_direction, camera_fov, camera_offset);
- if (flags->camera_offset_changed) {
+ if (m_camera_offset_changed) {
client->updateCameraOffset(camera_offset);
client->getEnv().updateCameraOffset(camera_offset);
@@ -3765,22 +3450,32 @@ void Game::updateSound(f32 dtime)
v3f(0, 0, 0), // velocity
camera->getDirection(),
camera->getCameraNode()->getUpVector());
- sound->setListenerGain(g_settings->getFloat("sound_volume"));
+ // Check if volume is in the proper range, else fix it.
+ float old_volume = g_settings->getFloat("sound_volume");
+ float new_volume = rangelim(old_volume, 0.0f, 1.0f);
+ sound->setListenerGain(new_volume);
- // Update sound maker
- soundmaker->step(dtime);
+ if (old_volume != new_volume) {
+ g_settings->setFloat("sound_volume", new_volume);
+ }
LocalPlayer *player = client->getEnv().getLocalPlayer();
+ // Tell the sound maker whether to make footstep sounds
+ soundmaker->makes_footstep_sound = player->makes_footstep_sound;
+
+ // Update sound maker
+ if (player->makes_footstep_sound)
+ soundmaker->step(dtime);
+
ClientMap &map = client->getEnv().getClientMap();
- MapNode n = map.getNodeNoEx(player->getStandingNodePos());
+ MapNode n = map.getNodeNoEx(player->getFootstepNodePos());
soundmaker->m_player_step_sound = nodedef_manager->get(n).sound_footstep;
}
-void Game::processPlayerInteraction(GameRunData *runData,
- f32 dtime, bool show_hud, bool show_debug)
+void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
@@ -3792,13 +3487,11 @@ void Game::processPlayerInteraction(GameRunData *runData,
playeritem = mlist->getItem(client->getPlayerItem());
}
- if (playeritem.getDefinition(itemdef_manager).name.empty()) { // override the hand
- InventoryList *hlist = local_inventory->getList("hand");
- if (hlist)
- playeritem = hlist->getItem(0);
- }
const ItemDefinition &playeritem_def =
playeritem.getDefinition(itemdef_manager);
+ InventoryList *hlist = local_inventory->getList("hand");
+ const ItemDefinition &hand_def =
+ hlist ? hlist->getItem(0).getDefinition(itemdef_manager) : itemdef_manager->get("");
v3f player_position = player->getPosition();
v3f camera_position = camera->getPosition();
@@ -3811,7 +3504,7 @@ void Game::processPlayerInteraction(GameRunData *runData,
*/
f32 d = playeritem_def.range; // max. distance
- f32 d_hand = itemdef_manager->get("").range;
+ f32 d_hand = hand_def.range;
if (d < 0 && d_hand >= 0)
d = d_hand;
@@ -3821,14 +3514,11 @@ void Game::processPlayerInteraction(GameRunData *runData,
core::line3d<f32> shootline;
if (camera->getCameraMode() != CAMERA_MODE_THIRD_FRONT) {
-
shootline = core::line3d<f32>(camera_position,
- camera_position + camera_direction * BS * (d + 1));
-
+ camera_position + camera_direction * BS * d);
} else {
// prevent player pointing anything in front-view
- if (camera->getCameraMode() == CAMERA_MODE_THIRD_FRONT)
- shootline = core::line3d<f32>(0, 0, 0, 0, 0, 0);
+ shootline = core::line3d<f32>(camera_position,camera_position);
}
#ifdef HAVE_TOUCHSCREENGUI
@@ -3841,17 +3531,12 @@ void Game::processPlayerInteraction(GameRunData *runData,
#endif
- PointedThing pointed = getPointedThing(
- // input
- client, hud, player_position, camera_direction,
- camera_position, shootline, d,
+ PointedThing pointed = updatePointedThing(shootline,
playeritem_def.liquids_pointable,
- !runData->ldown_for_dig,
- camera_offset,
- // output
- runData->selected_object);
+ !runData.ldown_for_dig,
+ camera_offset);
- if (pointed != runData->pointed_old) {
+ if (pointed != runData.pointed_old) {
infostream << "Pointing at " << pointed.dump() << std::endl;
hud->updateSelectionMesh(camera_offset);
}
@@ -3861,67 +3546,73 @@ void Game::processPlayerInteraction(GameRunData *runData,
- releasing left mouse button
- pointing away from node
*/
- if (runData->digging) {
+ if (runData.digging) {
if (getLeftReleased()) {
infostream << "Left button released"
<< " (stopped digging)" << std::endl;
- runData->digging = false;
- } else if (pointed != runData->pointed_old) {
+ runData.digging = false;
+ } else if (pointed != runData.pointed_old) {
if (pointed.type == POINTEDTHING_NODE
- && runData->pointed_old.type == POINTEDTHING_NODE
+ && runData.pointed_old.type == POINTEDTHING_NODE
&& pointed.node_undersurface
- == runData->pointed_old.node_undersurface) {
+ == runData.pointed_old.node_undersurface) {
// Still pointing to the same node, but a different face.
// Don't reset.
} else {
infostream << "Pointing away from node"
<< " (stopped digging)" << std::endl;
- runData->digging = false;
+ runData.digging = false;
hud->updateSelectionMesh(camera_offset);
}
}
- if (!runData->digging) {
- client->interact(1, runData->pointed_old);
+ if (!runData.digging) {
+ client->interact(1, runData.pointed_old);
client->setCrack(-1, v3s16(0, 0, 0));
- runData->dig_time = 0.0;
+ runData.dig_time = 0.0;
}
+ } else if (runData.dig_instantly && getLeftReleased()) {
+ // Remove e.g. torches faster when clicking instead of holding LMB
+ runData.nodig_delay_timer = 0;
+ runData.dig_instantly = false;
}
- if (!runData->digging && runData->ldown_for_dig && !isLeftPressed()) {
- runData->ldown_for_dig = false;
+ if (!runData.digging && runData.ldown_for_dig && !isLeftPressed()) {
+ runData.ldown_for_dig = false;
}
- runData->left_punch = false;
+ runData.left_punch = false;
soundmaker->m_player_leftpunch_sound.name = "";
if (isRightPressed())
- runData->repeat_rightclick_timer += dtime;
+ runData.repeat_rightclick_timer += dtime;
else
- runData->repeat_rightclick_timer = 0;
+ runData.repeat_rightclick_timer = 0;
if (playeritem_def.usable && isLeftPressed()) {
- if (getLeftClicked())
+ if (getLeftClicked() && (!client->moddingEnabled()
+ || !client->getScript()->on_item_use(playeritem, pointed)))
client->interact(4, pointed);
} else if (pointed.type == POINTEDTHING_NODE) {
ToolCapabilities playeritem_toolcap =
playeritem.getToolCapabilities(itemdef_manager);
- handlePointingAtNode(runData, pointed, playeritem_def,
- playeritem_toolcap, dtime);
+ if (playeritem.name.empty()) {
+ playeritem_toolcap = *hand_def.tool_capabilities;
+ }
+ handlePointingAtNode(pointed, playeritem_def, playeritem_toolcap, dtime);
} else if (pointed.type == POINTEDTHING_OBJECT) {
- handlePointingAtObject(runData, pointed, playeritem,
- player_position, show_debug);
+ handlePointingAtObject(pointed, playeritem, player_position, show_debug);
} else if (isLeftPressed()) {
// When button is held down in air, show continuous animation
- runData->left_punch = true;
+ runData.left_punch = true;
} else if (getRightClicked()) {
- handlePointingAtNothing(runData, playeritem);
+ handlePointingAtNothing(playeritem);
}
- runData->pointed_old = pointed;
+ runData.pointed_old = pointed;
- if (runData->left_punch || getLeftClicked())
+ if (runData.left_punch || getLeftClicked())
camera->setDigging(0); // left click animation
input->resetLeftClicked();
@@ -3938,7 +3629,104 @@ void Game::processPlayerInteraction(GameRunData *runData,
}
-void Game::handlePointingAtNothing(GameRunData *runData, const ItemStack &playerItem)
+PointedThing Game::updatePointedThing(
+ const core::line3d<f32> &shootline,
+ bool liquids_pointable,
+ bool look_for_object,
+ const v3s16 &camera_offset)
+{
+ std::vector<aabb3f> *selectionboxes = hud->getSelectionBoxes();
+ selectionboxes->clear();
+ hud->setSelectedFaceNormal(v3f(0.0, 0.0, 0.0));
+ static const bool show_entity_selectionbox = g_settings->getBool(
+ "show_entity_selectionbox");
+
+ ClientMap &map = client->getEnv().getClientMap();
+ INodeDefManager *nodedef=client->getNodeDefManager();
+
+ runData.selected_object = NULL;
+
+ PointedThing result=client->getEnv().getPointedThing(
+ shootline, liquids_pointable, look_for_object);
+ if (result.type == POINTEDTHING_OBJECT) {
+ runData.selected_object = client->getEnv().getActiveObject(result.object_id);
+ if (show_entity_selectionbox && runData.selected_object->doShowSelectionBox()) {
+ aabb3f *selection_box = runData.selected_object->getSelectionBox();
+
+ // Box should exist because object was
+ // returned in the first place
+
+ assert(selection_box);
+
+ v3f pos = runData.selected_object->getPosition();
+ selectionboxes->push_back(aabb3f(
+ selection_box->MinEdge, selection_box->MaxEdge));
+ selectionboxes->push_back(
+ aabb3f(selection_box->MinEdge, selection_box->MaxEdge));
+ hud->setSelectionPos(pos, camera_offset);
+ }
+ } else if (result.type == POINTEDTHING_NODE) {
+ // Update selection boxes
+ MapNode n = map.getNodeNoEx(result.node_undersurface);
+ std::vector<aabb3f> boxes;
+ n.getSelectionBoxes(nodedef, &boxes,
+ n.getNeighbors(result.node_undersurface, &map));
+
+ f32 d = 0.002 * BS;
+ for (std::vector<aabb3f>::const_iterator i = boxes.begin();
+ i != boxes.end(); ++i) {
+ aabb3f box = *i;
+ box.MinEdge -= v3f(d, d, d);
+ box.MaxEdge += v3f(d, d, d);
+ selectionboxes->push_back(box);
+ }
+ hud->setSelectionPos(intToFloat(result.node_undersurface, BS),
+ camera_offset);
+ hud->setSelectedFaceNormal(v3f(
+ result.intersection_normal.X,
+ result.intersection_normal.Y,
+ result.intersection_normal.Z));
+ }
+
+ // Update selection mesh light level and vertex colors
+ if (selectionboxes->size() > 0) {
+ v3f pf = hud->getSelectionPos();
+ v3s16 p = floatToInt(pf, BS);
+
+ // Get selection mesh light level
+ MapNode n = map.getNodeNoEx(p);
+ u16 node_light = getInteriorLight(n, -1, nodedef);
+ u16 light_level = node_light;
+
+ for (u8 i = 0; i < 6; i++) {
+ n = map.getNodeNoEx(p + g_6dirs[i]);
+ node_light = getInteriorLight(n, -1, nodedef);
+ if (node_light > light_level)
+ light_level = node_light;
+ }
+
+ u32 daynight_ratio = client->getEnv().getDayNightRatio();
+ video::SColor c;
+ final_color_blend(&c, light_level, daynight_ratio);
+
+ // Modify final color a bit with time
+ u32 timer = porting::getTimeMs() % 5000;
+ float timerf = (float) (irr::core::PI * ((timer / 2500.0) - 0.5));
+ float sin_r = 0.08 * sin(timerf);
+ float sin_g = 0.08 * sin(timerf + irr::core::PI * 0.5);
+ float sin_b = 0.08 * sin(timerf + irr::core::PI);
+ c.setRed(core::clamp(core::round32(c.getRed() * (0.8 + sin_r)), 0, 255));
+ c.setGreen(core::clamp(core::round32(c.getGreen() * (0.8 + sin_g)), 0, 255));
+ c.setBlue(core::clamp(core::round32(c.getBlue() * (0.8 + sin_b)), 0, 255));
+
+ // Set mesh final color
+ hud->setSelectionMeshColor(c);
+ }
+ return result;
+}
+
+
+void Game::handlePointingAtNothing(const ItemStack &playerItem)
{
infostream << "Right Clicked in Air" << std::endl;
PointedThing fauxPointed;
@@ -3947,8 +3735,7 @@ void Game::handlePointingAtNothing(GameRunData *runData, const ItemStack &player
}
-void Game::handlePointingAtNode(GameRunData *runData,
- const PointedThing &pointed, const ItemDefinition &playeritem_def,
+void Game::handlePointingAtNode(const PointedThing &pointed, const ItemDefinition &playeritem_def,
const ToolCapabilities &playeritem_toolcap, f32 dtime)
{
v3s16 nodepos = pointed.node_undersurface;
@@ -3959,6 +3746,13 @@ void Game::handlePointingAtNode(GameRunData *runData,
*/
ClientMap &map = client->getEnv().getClientMap();
+
+ if (runData.nodig_delay_timer <= 0.0 && isLeftPressed()
+ && client->checkPrivilege("interact")) {
+ handleDigging(pointed, nodepos, playeritem_toolcap, dtime);
+ }
+
+ // This should be done after digging handling
NodeMetadata *meta = map.getNodeMetadata(nodepos);
if (meta) {
@@ -3972,15 +3766,10 @@ void Game::handlePointingAtNode(GameRunData *runData,
}
}
- if (runData->nodig_delay_timer <= 0.0 && isLeftPressed()
- && client->checkPrivilege("interact")) {
- handleDigging(runData, pointed, nodepos, playeritem_toolcap, dtime);
- }
-
if ((getRightClicked() ||
- runData->repeat_rightclick_timer >= m_repeat_right_click_time) &&
+ runData.repeat_rightclick_timer >= m_repeat_right_click_time) &&
client->checkPrivilege("interact")) {
- runData->repeat_rightclick_timer = 0;
+ runData.repeat_rightclick_timer = 0;
infostream << "Ground right-clicked" << std::endl;
if (meta && meta->getString("formspec") != "" && !random_input
@@ -3994,8 +3783,8 @@ void Game::handlePointingAtNode(GameRunData *runData,
&client->getEnv().getClientMap(), nodepos);
TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client);
- create_formspec_menu(&current_formspec, client, gamedef,
- texture_src, device, &input->joystick, fs_src, txt_dst, client);
+ create_formspec_menu(&current_formspec, client,
+ device, &input->joystick, fs_src, txt_dst);
cur_formname = "";
current_formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
@@ -4016,6 +3805,9 @@ void Game::handlePointingAtNode(GameRunData *runData,
// Read the sound
soundmaker->m_player_rightpunch_sound =
playeritem_def.sound_place;
+
+ if (client->moddingEnabled())
+ client->getScript()->on_placenode(pointed, playeritem_def);
} else {
soundmaker->m_player_rightpunch_sound =
SimpleSoundSpec();
@@ -4033,31 +3825,28 @@ void Game::handlePointingAtNode(GameRunData *runData,
}
-void Game::handlePointingAtObject(GameRunData *runData,
- const PointedThing &pointed,
- const ItemStack &playeritem,
- const v3f &player_position,
- bool show_debug)
+void Game::handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
+ const v3f &player_position, bool show_debug)
{
infotext = unescape_enriched(
- utf8_to_wide(runData->selected_object->infoText()));
+ utf8_to_wide(runData.selected_object->infoText()));
if (show_debug) {
if (infotext != L"") {
infotext += L"\n";
}
infotext += unescape_enriched(utf8_to_wide(
- runData->selected_object->debugInfoText()));
+ runData.selected_object->debugInfoText()));
}
if (isLeftPressed()) {
bool do_punch = false;
bool do_punch_damage = false;
- if (runData->object_hit_delay_timer <= 0.0) {
+ if (runData.object_hit_delay_timer <= 0.0) {
do_punch = true;
do_punch_damage = true;
- runData->object_hit_delay_timer = object_hit_delay;
+ runData.object_hit_delay_timer = object_hit_delay;
}
if (getLeftClicked())
@@ -4065,17 +3854,24 @@ void Game::handlePointingAtObject(GameRunData *runData,
if (do_punch) {
infostream << "Left-clicked object" << std::endl;
- runData->left_punch = true;
+ runData.left_punch = true;
}
if (do_punch_damage) {
// Report direct punch
- v3f objpos = runData->selected_object->getPosition();
+ v3f objpos = runData.selected_object->getPosition();
v3f dir = (objpos - player_position).normalize();
+ ItemStack item = playeritem;
+ if (playeritem.name.empty()) {
+ InventoryList *hlist = local_inventory->getList("hand");
+ if (hlist) {
+ item = hlist->getItem(0);
+ }
+ }
- bool disable_send = runData->selected_object->directReportPunch(
- dir, &playeritem, runData->time_from_last_punch);
- runData->time_from_last_punch = 0;
+ bool disable_send = runData.selected_object->directReportPunch(
+ dir, &item, runData.time_from_last_punch);
+ runData.time_from_last_punch = 0;
if (!disable_send)
client->interact(0, pointed);
@@ -4087,17 +3883,9 @@ void Game::handlePointingAtObject(GameRunData *runData,
}
-void Game::handleDigging(GameRunData *runData,
- const PointedThing &pointed, const v3s16 &nodepos,
+void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
const ToolCapabilities &playeritem_toolcap, f32 dtime)
{
- if (!runData->digging) {
- infostream << "Started digging" << std::endl;
- client->interact(0, pointed);
- runData->digging = true;
- runData->ldown_for_dig = true;
- }
-
LocalPlayer *player = client->getEnv().getLocalPlayer();
ClientMap &map = client->getEnv().getClientMap();
MapNode n = client->getEnv().getClientMap().getNodeNoEx(nodepos);
@@ -4110,34 +3898,46 @@ void Game::handleDigging(GameRunData *runData,
// If can't dig, try hand
if (!params.diggable) {
- const ItemDefinition &hand = itemdef_manager->get("");
+ InventoryList *hlist = local_inventory->getList("hand");
+ const ItemDefinition &hand =
+ hlist ? hlist->getItem(0).getDefinition(itemdef_manager) : itemdef_manager->get("");
const ToolCapabilities *tp = hand.tool_capabilities;
if (tp)
params = getDigParams(nodedef_manager->get(n).groups, tp);
}
- if (params.diggable == false) {
+ if (!params.diggable) {
// I guess nobody will wait for this long
- runData->dig_time_complete = 10000000.0;
+ runData.dig_time_complete = 10000000.0;
} else {
- runData->dig_time_complete = params.time;
+ runData.dig_time_complete = params.time;
if (m_cache_enable_particles) {
const ContentFeatures &features =
client->getNodeDefManager()->get(n);
- client->getParticleManager()->addPunchingParticles(gamedef, smgr,
- player, nodepos, features.tiles);
+ client->getParticleManager()->addPunchingParticles(client, smgr,
+ player, nodepos, n, features);
}
}
- if (runData->dig_time_complete >= 0.001) {
- runData->dig_index = (float)crack_animation_length
- * runData->dig_time
- / runData->dig_time_complete;
+ if (!runData.digging) {
+ infostream << "Started digging" << std::endl;
+ runData.dig_instantly = runData.dig_time_complete == 0;
+ if (client->moddingEnabled() && client->getScript()->on_punchnode(nodepos, n))
+ return;
+ client->interact(0, pointed);
+ runData.digging = true;
+ runData.ldown_for_dig = true;
+ }
+
+ if (!runData.dig_instantly) {
+ runData.dig_index = (float)crack_animation_length
+ * runData.dig_time
+ / runData.dig_time_complete;
} else {
- // This is for torches
- runData->dig_index = crack_animation_length;
+ // This is for e.g. torches
+ runData.dig_index = crack_animation_length;
}
SimpleSoundSpec sound_dig = nodedef_manager->get(n).sound_dig;
@@ -4156,54 +3956,57 @@ void Game::handleDigging(GameRunData *runData,
}
// Don't show cracks if not diggable
- if (runData->dig_time_complete >= 100000.0) {
- } else if (runData->dig_index < crack_animation_length) {
+ if (runData.dig_time_complete >= 100000.0) {
+ } else if (runData.dig_index < crack_animation_length) {
//TimeTaker timer("client.setTempMod");
//infostream<<"dig_index="<<dig_index<<std::endl;
- client->setCrack(runData->dig_index, nodepos);
+ client->setCrack(runData.dig_index, nodepos);
} else {
infostream << "Digging completed" << std::endl;
- client->interact(2, pointed);
client->setCrack(-1, v3s16(0, 0, 0));
+
+ runData.dig_time = 0;
+ runData.digging = false;
+
+ runData.nodig_delay_timer =
+ runData.dig_time_complete / (float)crack_animation_length;
+
+ // We don't want a corresponding delay to very time consuming nodes
+ // and nodes without digging time (e.g. torches) get a fixed delay.
+ if (runData.nodig_delay_timer > 0.3)
+ runData.nodig_delay_timer = 0.3;
+ else if (runData.dig_instantly)
+ runData.nodig_delay_timer = 0.15;
+
bool is_valid_position;
MapNode wasnode = map.getNodeNoEx(nodepos, &is_valid_position);
- if (is_valid_position)
+ if (is_valid_position) {
+ if (client->moddingEnabled() &&
+ client->getScript()->on_dignode(nodepos, wasnode)) {
+ return;
+ }
client->removeNode(nodepos);
+ }
+
+ client->interact(2, pointed);
if (m_cache_enable_particles) {
const ContentFeatures &features =
client->getNodeDefManager()->get(wasnode);
- client->getParticleManager()->addDiggingParticles(gamedef, smgr,
- player, nodepos, features.tiles);
+ client->getParticleManager()->addDiggingParticles(client, smgr,
+ player, nodepos, wasnode, features);
}
- runData->dig_time = 0;
- runData->digging = false;
-
- runData->nodig_delay_timer =
- runData->dig_time_complete / (float)crack_animation_length;
-
- // We don't want a corresponding delay to
- // very time consuming nodes
- if (runData->nodig_delay_timer > 0.3)
- runData->nodig_delay_timer = 0.3;
-
- // We want a slight delay to very little
- // time consuming nodes
- const float mindelay = 0.15;
-
- if (runData->nodig_delay_timer < mindelay)
- runData->nodig_delay_timer = mindelay;
// Send event to trigger sound
MtEvent *e = new NodeDugEvent(nodepos, wasnode);
- gamedef->event()->put(e);
+ client->event()->put(e);
}
- if (runData->dig_time_complete < 100000.0) {
- runData->dig_time += dtime;
+ if (runData.dig_time_complete < 100000.0) {
+ runData.dig_time += dtime;
} else {
- runData->dig_time = 0;
+ runData.dig_time = 0;
client->setCrack(-1, nodepos);
}
@@ -4211,8 +4014,7 @@ void Game::handleDigging(GameRunData *runData,
}
-void Game::updateFrame(ProfilerGraph *graph, RunStats *stats,
- GameRunData *runData, f32 dtime, const VolatileRunFlags &flags,
+void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
const CameraOrientation &cam)
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
@@ -4222,9 +4024,9 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats,
*/
if (draw_control->range_all) {
- runData->fog_range = 100000 * BS;
+ runData.fog_range = 100000 * BS;
} else {
- runData->fog_range = draw_control->wanted_range * BS;
+ runData.fog_range = draw_control->wanted_range * BS;
}
/*
@@ -4242,18 +4044,16 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats,
ScopeProfiler sp(g_profiler, "Detecting background light", SPT_AVG);
float old_brightness = sky->getBrightness();
direct_brightness = client->getEnv().getClientMap()
- .getBackgroundBrightness(MYMIN(runData->fog_range * 1.2, 60 * BS),
+ .getBackgroundBrightness(MYMIN(runData.fog_range * 1.2, 60 * BS),
daynight_ratio, (int)(old_brightness * 255.5), &sunlight_seen)
/ 255.0;
}
- float time_of_day = runData->time_of_day;
- float time_of_day_smooth = runData->time_of_day_smooth;
-
- time_of_day = client->getEnv().getTimeOfDayF();
+ float time_of_day_smooth = runData.time_of_day_smooth;
+ float time_of_day = client->getEnv().getTimeOfDayF();
- const float maxsm = 0.05;
- const float todsm = 0.05;
+ static const float maxsm = 0.05;
+ static const float todsm = 0.05;
if (fabs(time_of_day - time_of_day_smooth) > maxsm &&
fabs(time_of_day - time_of_day_smooth + 1.0) > maxsm &&
@@ -4267,8 +4067,8 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats,
time_of_day_smooth = time_of_day_smooth * (1.0 - todsm)
+ time_of_day * todsm;
- runData->time_of_day = time_of_day;
- runData->time_of_day_smooth = time_of_day_smooth;
+ runData.time_of_day = time_of_day;
+ runData.time_of_day_smooth = time_of_day_smooth;
sky->update(time_of_day_smooth, time_brightness, direct_brightness,
sunlight_seen, camera->getCameraMode(), player->getYaw(),
@@ -4302,8 +4102,8 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats,
driver->setFog(
sky->getBgColor(),
video::EFT_FOG_LINEAR,
- runData->fog_range * m_cache_fog_start,
- runData->fog_range * 1.0,
+ runData.fog_range * m_cache_fog_start,
+ runData.fog_range * 1.0,
0.01,
false, // pixel fog
true // range fog
@@ -4327,24 +4127,24 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats,
v2u32 screensize = driver->getScreenSize();
updateChat(*client, dtime, flags.show_debug, screensize,
- flags.show_chat, runData->profiler_current_page,
+ flags.show_chat, runData.profiler_current_page,
*chat_backend, guitext_chat);
/*
Inventory
*/
- if (client->getPlayerItem() != runData->new_playeritem)
- client->selectPlayerItem(runData->new_playeritem);
+ if (client->getPlayerItem() != runData.new_playeritem)
+ client->selectPlayerItem(runData.new_playeritem);
// Update local inventory if it has changed
if (client->getLocalInventoryUpdated()) {
//infostream<<"Updating local inventory"<<std::endl;
client->getLocalInventory(*local_inventory);
- runData->update_wielded_item_trigger = true;
+ runData.update_wielded_item_trigger = true;
}
- if (runData->update_wielded_item_trigger) {
+ if (runData.update_wielded_item_trigger) {
// Update wielded tool
InventoryList *mlist = local_inventory->getList("main");
@@ -4358,25 +4158,25 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats,
camera->wield(item);
}
- runData->update_wielded_item_trigger = false;
+ runData.update_wielded_item_trigger = false;
}
/*
Update block draw list every 200ms or when camera direction has
changed much
*/
- runData->update_draw_list_timer += dtime;
+ runData.update_draw_list_timer += dtime;
v3f camera_direction = camera->getDirection();
- if (runData->update_draw_list_timer >= 0.2
- || runData->update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2
- || flags.camera_offset_changed) {
- runData->update_draw_list_timer = 0;
+ if (runData.update_draw_list_timer >= 0.2
+ || runData.update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2
+ || m_camera_offset_changed) {
+ runData.update_draw_list_timer = 0;
client->getEnv().getClientMap().updateDrawList(driver);
- runData->update_draw_list_last_cam_dir = camera_direction;
+ runData.update_draw_list_last_cam_dir = camera_direction;
}
- updateGui(&runData->statustext_time, *stats, *runData, dtime, flags, cam);
+ updateGui(*stats, dtime, cam);
/*
make sure menu is on top
@@ -4387,7 +4187,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats,
if (current_formspec->getReferenceCount() == 1) {
current_formspec->drop();
current_formspec = NULL;
- } else if (!noMenuActive()) {
+ } else if (isMenuActive()) {
guiroot->bringToFront(current_formspec);
}
}
@@ -4396,16 +4196,12 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats,
Drawing begins
*/
- video::SColor skycolor = sky->getSkyColor();
+ const video::SColor &skycolor = sky->getSkyColor();
TimeTaker tt_draw("mainloop: draw");
- {
- TimeTaker timer("beginScene");
- driver->beginScene(true, true, skycolor);
- stats->beginscenetime = timer.stop(true);
- }
+ driver->beginScene(true, true, skycolor);
- draw_scene(driver, smgr, *camera, *client, player, *hud, *mapper,
+ draw_scene(driver, smgr, *camera, *client, player, *hud, mapper,
guienv, screensize, skycolor, flags.show_hud,
flags.show_minimap);
@@ -4418,13 +4214,13 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats,
/*
Damage flash
*/
- if (runData->damage_flash > 0.0) {
- video::SColor color(runData->damage_flash, 180, 0, 0);
+ if (runData.damage_flash > 0.0) {
+ video::SColor color(runData.damage_flash, 180, 0, 0);
driver->draw2DRectangle(color,
core::rect<s32>(0, 0, screensize.X, screensize.Y),
NULL);
- runData->damage_flash -= 100.0 * dtime;
+ runData.damage_flash -= 100.0 * dtime;
}
/*
@@ -4440,7 +4236,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats,
/*
Update minimap pos and rotation
*/
- if (flags.show_minimap && flags.show_hud) {
+ if (mapper && flags.show_minimap && flags.show_hud) {
mapper->setPos(floatToInt(player->getPosition(), BS));
mapper->setAngle(player->getYaw());
}
@@ -4448,11 +4244,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats,
/*
End scene
*/
- {
- TimeTaker timer("endScene");
- driver->endScene();
- stats->endscenetime = timer.stop(true);
- }
+ driver->endScene();
stats->drawtime = tt_draw.stop(true);
g_profiler->graphAdd("mainloop_draw", stats->drawtime / 1000.0f);
@@ -4470,9 +4262,7 @@ inline static const char *yawToDirectionString(int yaw)
}
-void Game::updateGui(float *statustext_time, const RunStats &stats,
- const GameRunData& runData, f32 dtime, const VolatileRunFlags &flags,
- const CameraOrientation &cam)
+void Game::updateGui(const RunStats &stats, f32 dtime, const CameraOrientation &cam)
{
v2u32 screensize = driver->getScreenSize();
LocalPlayer *player = client->getEnv().getLocalPlayer();
@@ -4483,7 +4273,6 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
drawtime_avg = drawtime_avg * 0.95 + stats.drawtime * 0.05;
u16 fps = 1.0 / stats.dtime_jitter.avg;
- //s32 fps = driver->getFPS();
std::ostringstream os(std::ios_base::binary);
os << std::fixed
@@ -4553,19 +4342,19 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
float statustext_time_max = 1.5;
- if (!statustext.empty()) {
- *statustext_time += dtime;
+ if (!m_statustext.empty()) {
+ runData.statustext_time += dtime;
- if (*statustext_time >= statustext_time_max) {
- statustext = L"";
- *statustext_time = 0;
+ if (runData.statustext_time >= statustext_time_max) {
+ m_statustext = L"";
+ runData.statustext_time = 0;
}
}
- setStaticText(guitext_status, statustext.c_str());
- guitext_status->setVisible(!statustext.empty());
+ setStaticText(guitext_status, m_statustext.c_str());
+ guitext_status->setVisible(!m_statustext.empty());
- if (!statustext.empty()) {
+ if (!m_statustext.empty()) {
s32 status_width = guitext_status->getTextWidth();
s32 status_height = guitext_status->getTextHeight();
s32 status_y = screensize.Y - 150;
@@ -4586,7 +4375,7 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
final_color.setAlpha(0);
video::SColor fade_color = initial_color.getInterpolated_quadratic(
initial_color, final_color,
- pow(*statustext_time / statustext_time_max, 2.0f));
+ pow(runData.statustext_time / statustext_time_max, 2.0f));
guitext_status->setOverrideColor(fade_color);
guitext_status->enableOverrideColor(true);
}
@@ -4655,7 +4444,8 @@ inline void Game::limitFps(FpsControl *fps_timings, f32 *dtime)
void Game::showOverlayMessage(const wchar_t *msg, float dtime,
int percent, bool draw_clouds)
{
- draw_load_screen(msg, device, guienv, dtime, percent, draw_clouds);
+ draw_load_screen(msg, device, guienv, texture_src, dtime, percent,
+ draw_clouds);
delete[] msg;
}
@@ -4719,6 +4509,131 @@ void Game::extendedResourceCleanup()
<< " (note: irrlicht doesn't support removing renderers)" << std::endl;
}
+#define GET_KEY_NAME(KEY) gettext(getKeySetting(#KEY).name())
+void Game::showPauseMenu()
+{
+#ifdef __ANDROID__
+ static const std::string control_text = strgettext("Default Controls:\n"
+ "No menu visible:\n"
+ "- single tap: button activate\n"
+ "- double tap: place/use\n"
+ "- slide finger: look around\n"
+ "Menu/Inventory visible:\n"
+ "- double tap (outside):\n"
+ " -->close\n"
+ "- touch stack, touch slot:\n"
+ " --> move stack\n"
+ "- touch&drag, tap 2nd finger\n"
+ " --> place single item to slot\n"
+ );
+#else
+ static const std::string control_text_template = strgettext("Controls:\n"
+ "- %s: move forwards\n"
+ "- %s: move backwards\n"
+ "- %s: move left\n"
+ "- %s: move right\n"
+ "- %s: jump/climb\n"
+ "- %s: sneak/go down\n"
+ "- %s: drop item\n"
+ "- %s: inventory\n"
+ "- Mouse: turn/look\n"
+ "- Mouse left: dig/punch\n"
+ "- Mouse right: place/use\n"
+ "- Mouse wheel: select item\n"
+ "- %s: chat\n"
+ );
+
+ char control_text_buf[600];
+
+ snprintf(control_text_buf, ARRLEN(control_text_buf), control_text_template.c_str(),
+ GET_KEY_NAME(keymap_forward),
+ GET_KEY_NAME(keymap_backward),
+ GET_KEY_NAME(keymap_left),
+ GET_KEY_NAME(keymap_right),
+ GET_KEY_NAME(keymap_jump),
+ GET_KEY_NAME(keymap_sneak),
+ GET_KEY_NAME(keymap_drop),
+ GET_KEY_NAME(keymap_inventory),
+ GET_KEY_NAME(keymap_chat)
+ );
+
+ std::string control_text = std::string(control_text_buf);
+ str_formspec_escape(control_text);
+#endif
+
+ float ypos = simple_singleplayer_mode ? 0.7f : 0.1f;
+ std::ostringstream os;
+
+ os << FORMSPEC_VERSION_STRING << SIZE_TAG
+ << "button_exit[4," << (ypos++) << ";3,0.5;btn_continue;"
+ << strgettext("Continue") << "]";
+
+ if (!simple_singleplayer_mode) {
+ os << "button_exit[4," << (ypos++) << ";3,0.5;btn_change_password;"
+ << strgettext("Change Password") << "]";
+ } else {
+ os << "field[4.95,0;5,1.5;;" << strgettext("Game paused") << ";]";
+ }
+
+#ifndef __ANDROID__
+ os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
+ << strgettext("Sound Volume") << "]";
+ os << "button_exit[4," << (ypos++) << ";3,0.5;btn_key_config;"
+ << strgettext("Change Keys") << "]";
+#endif
+ os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_menu;"
+ << strgettext("Exit to Menu") << "]";
+ os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_os;"
+ << strgettext("Exit to OS") << "]"
+ << "textarea[7.5,0.25;3.9,6.25;;" << control_text << ";]"
+ << "textarea[0.4,0.25;3.9,6.25;;" << PROJECT_NAME_C " " VERSION_STRING "\n"
+ << "\n"
+ << strgettext("Game info:") << "\n";
+ const std::string &address = client->getAddressName();
+ static const std::string mode = strgettext("- Mode: ");
+ if (!simple_singleplayer_mode) {
+ Address serverAddress = client->getServerAddress();
+ if (address != "") {
+ os << mode << strgettext("Remote server") << "\n"
+ << strgettext("- Address: ") << address;
+ } else {
+ os << mode << strgettext("Hosting server");
+ }
+ os << "\n" << strgettext("- Port: ") << serverAddress.getPort() << "\n";
+ } else {
+ os << mode << strgettext("Singleplayer") << "\n";
+ }
+ if (simple_singleplayer_mode || address == "") {
+ static const std::string on = strgettext("On");
+ static const std::string off = strgettext("Off");
+ const std::string &damage = g_settings->getBool("enable_damage") ? on : off;
+ const std::string &creative = g_settings->getBool("creative_mode") ? on : off;
+ const std::string &announced = g_settings->getBool("server_announce") ? on : off;
+ os << strgettext("- Damage: ") << damage << "\n"
+ << strgettext("- Creative Mode: ") << creative << "\n";
+ if (!simple_singleplayer_mode) {
+ const std::string &pvp = g_settings->getBool("enable_pvp") ? on : off;
+ os << strgettext("- PvP: ") << pvp << "\n"
+ << strgettext("- Public: ") << announced << "\n";
+ std::string server_name = g_settings->get("server_name");
+ str_formspec_escape(server_name);
+ if (announced == on && server_name != "")
+ os << strgettext("- Server Name: ") << server_name;
+
+ }
+ }
+ os << ";]";
+
+ /* Create menu */
+ /* Note: FormspecFormSource and LocalFormspecHandler *
+ * are deleted by guiFormSpecMenu */
+ FormspecFormSource *fs_src = new FormspecFormSource(os.str());
+ LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU");
+
+ create_formspec_menu(&current_formspec, client, device, &input->joystick, fs_src, txt_dst);
+ current_formspec->setFocus("btn_continue");
+ current_formspec->doPause = true;
+}
/****************************************************************************/
/****************************************************************************
diff --git a/src/game.h b/src/game.h
index df32e3397..4fb198be8 100644
--- a/src/game.h
+++ b/src/game.h
@@ -22,127 +22,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h"
#include <string>
-#include "client/keys.h"
-#include "client/joystick_controller.h"
-#include "keycode.h"
-#include <list>
-class KeyList : protected std::list<KeyPress>
-{
- typedef std::list<KeyPress> super;
- typedef super::iterator iterator;
- typedef super::const_iterator const_iterator;
-
- virtual const_iterator find(const KeyPress &key) const
- {
- const_iterator f(begin());
- const_iterator e(end());
-
- while (f != e) {
- if (*f == key)
- return f;
-
- ++f;
- }
-
- return e;
- }
-
- virtual iterator find(const KeyPress &key)
- {
- iterator f(begin());
- iterator e(end());
-
- while (f != e) {
- if (*f == key)
- return f;
-
- ++f;
- }
-
- return e;
- }
-
-public:
- void clear()
- {
- super::clear();
- }
-
- void set(const KeyPress &key)
- {
- if (find(key) == end())
- push_back(key);
- }
-
- void unset(const KeyPress &key)
- {
- iterator p(find(key));
-
- if (p != end())
- erase(p);
- }
-
- void toggle(const KeyPress &key)
- {
- iterator p(this->find(key));
-
- if (p != end())
- erase(p);
- else
- push_back(key);
- }
-
- bool operator[](const KeyPress &key) const
- {
- return find(key) != end();
- }
-};
+class InputHandler;
+class ChatBackend; /* to avoid having to include chat.h */
+struct SubgameSpec;
-class InputHandler
+// Flags that can, or may, change during main game loop
+struct GameUIFlags
{
-public:
- InputHandler()
- {
- }
- virtual ~InputHandler()
- {
- }
-
- virtual bool isKeyDown(const KeyPress &keyCode) = 0;
- virtual bool wasKeyDown(const KeyPress &keyCode) = 0;
-
- virtual void listenForKey(const KeyPress &keyCode) {}
- virtual void dontListenForKeys() {}
-
- virtual v2s32 getMousePos() = 0;
- virtual void setMousePos(s32 x, s32 y) = 0;
-
- virtual bool getLeftState() = 0;
- virtual bool getRightState() = 0;
-
- virtual bool getLeftClicked() = 0;
- virtual bool getRightClicked() = 0;
- virtual void resetLeftClicked() = 0;
- virtual void resetRightClicked() = 0;
-
- virtual bool getLeftReleased() = 0;
- virtual bool getRightReleased() = 0;
- virtual void resetLeftReleased() = 0;
- virtual void resetRightReleased() = 0;
-
- virtual s32 getMouseWheel() = 0;
-
- virtual void step(float dtime) {}
-
- virtual void clear() {}
-
- JoystickController joystick;
+ bool show_chat;
+ bool show_hud;
+ bool show_minimap;
+ bool force_fog_off;
+ bool show_debug;
+ bool show_profiler_graph;
+ bool disable_camera_update;
};
-class ChatBackend; /* to avoid having to include chat.h */
-struct SubgameSpec;
-
void the_game(bool *kill,
bool random_input,
InputHandler *input,
@@ -159,4 +55,3 @@ void the_game(bool *kill,
bool simple_singleplayer_mode);
#endif
-
diff --git a/src/gamedef.h b/src/gamedef.h
index 7e3da4cac..6cd01305f 100644
--- a/src/gamedef.h
+++ b/src/gamedef.h
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define GAMEDEF_HEADER
#include <string>
+#include <vector>
#include "irrlichttypes.h"
class IItemDefManager;
@@ -33,12 +34,14 @@ class MtEventManager;
class IRollbackManager;
class EmergeManager;
class Camera;
+class ModMetadata;
namespace irr { namespace scene {
class IAnimatedMesh;
class ISceneManager;
}}
+struct ModSpec;
/*
An interface for fetching game-global definitions like tool and
mapnode properties
@@ -53,47 +56,29 @@ public:
virtual INodeDefManager* getNodeDefManager()=0;
virtual ICraftDefManager* getCraftDefManager()=0;
- // This is always thread-safe, but referencing the irrlicht texture
- // pointers in other threads than main thread will make things explode.
- virtual ITextureSource* getTextureSource()=0;
-
- virtual IShaderSource* getShaderSource()=0;
-
// Used for keeping track of names/ids of unknown nodes
virtual u16 allocateUnknownNodeId(const std::string &name)=0;
- // Only usable on the client
- virtual ISoundManager* getSoundManager()=0;
virtual MtEventManager* getEventManager()=0;
- virtual scene::IAnimatedMesh* getMesh(const std::string &filename)
- { return NULL; }
- virtual scene::ISceneManager* getSceneManager()=0;
-
- virtual Camera* getCamera()
- { return NULL; }
- virtual void setCamera(Camera *camera) {}
// Only usable on the server, and NOT thread-safe. It is usable from the
// environment thread.
- virtual IRollbackManager* getRollbackManager(){return NULL;}
-
- // Only usable on the server. Thread safe if not written while running threads.
- virtual EmergeManager *getEmergeManager() { return NULL; }
-
- // Used on the client
- virtual bool checkLocalPrivilege(const std::string &priv)
- { return false; }
+ virtual IRollbackManager* getRollbackManager() { return NULL; }
// Shorthands
IItemDefManager *idef() { return getItemDefManager(); }
INodeDefManager *ndef() { return getNodeDefManager(); }
ICraftDefManager *cdef() { return getCraftDefManager(); }
- ITextureSource *tsrc() { return getTextureSource(); }
- ISoundManager *sound() { return getSoundManager(); }
- IShaderSource *shsrc() { return getShaderSource(); }
+
MtEventManager *event() { return getEventManager(); }
- IRollbackManager *rollback() { return getRollbackManager();}
- EmergeManager *emerge() { return getEmergeManager(); }
+ IRollbackManager *rollback() { return getRollbackManager(); }
+
+ virtual const std::vector<ModSpec> &getMods() const = 0;
+ virtual const ModSpec* getModSpec(const std::string &modname) const = 0;
+ virtual std::string getWorldPath() const { return ""; }
+ virtual std::string getModStoragePath() const = 0;
+ virtual bool registerModStorage(ModMetadata *storage) = 0;
+ virtual void unregisterModStorage(const std::string &name) = 0;
};
#endif
diff --git a/src/gameparams.h b/src/gameparams.h
index bf9953c39..4afc0fdce 100644
--- a/src/gameparams.h
+++ b/src/gameparams.h
@@ -24,7 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
struct SubgameSpec;
-struct GameParams {
+struct GameParams
+{
u16 socket_port;
std::string world_path;
SubgameSpec game_spec;
diff --git a/src/genericobject.cpp b/src/genericobject.cpp
index c4660cf44..58f4b997e 100644
--- a/src/genericobject.cpp
+++ b/src/genericobject.cpp
@@ -68,7 +68,7 @@ std::string gob_cmd_update_position(
std::string gob_cmd_set_texture_mod(const std::string &mod)
{
std::ostringstream os(std::ios::binary);
- // command
+ // command
writeU8(os, GENERIC_CMD_SET_TEXTURE_MOD);
// parameters
os<<serializeString(mod);
@@ -95,7 +95,7 @@ std::string gob_cmd_set_sprite(
std::string gob_cmd_punched(s16 damage, s16 result_hp)
{
std::ostringstream os(std::ios::binary);
- // command
+ // command
writeU8(os, GENERIC_CMD_PUNCHED);
// damage
writeS16(os, damage);
@@ -118,10 +118,10 @@ std::string gob_cmd_update_armor_groups(const ItemGroupList &armor_groups)
}
std::string gob_cmd_update_physics_override(float physics_override_speed, float physics_override_jump,
- float physics_override_gravity, bool sneak, bool sneak_glitch)
+ float physics_override_gravity, bool sneak, bool sneak_glitch, bool new_move)
{
std::ostringstream os(std::ios::binary);
- // command
+ // command
writeU8(os, GENERIC_CMD_SET_PHYSICS_OVERRIDE);
// parameters
writeF1000(os, physics_override_speed);
@@ -130,13 +130,14 @@ std::string gob_cmd_update_physics_override(float physics_override_speed, float
// these are sent inverted so we get true when the server sends nothing
writeU8(os, !sneak);
writeU8(os, !sneak_glitch);
+ writeU8(os, !new_move);
return os.str();
}
std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_blend, bool frame_loop)
{
std::ostringstream os(std::ios::binary);
- // command
+ // command
writeU8(os, GENERIC_CMD_SET_ANIMATION);
// parameters
writeV2F1000(os, frames);
@@ -147,10 +148,11 @@ std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_
return os.str();
}
-std::string gob_cmd_update_bone_position(std::string bone, v3f position, v3f rotation)
+std::string gob_cmd_update_bone_position(const std::string &bone, v3f position,
+ v3f rotation)
{
std::ostringstream os(std::ios::binary);
- // command
+ // command
writeU8(os, GENERIC_CMD_SET_BONE_POSITION);
// parameters
os<<serializeString(bone);
@@ -159,10 +161,11 @@ std::string gob_cmd_update_bone_position(std::string bone, v3f position, v3f rot
return os.str();
}
-std::string gob_cmd_update_attachment(int parent_id, std::string bone, v3f position, v3f rotation)
+std::string gob_cmd_update_attachment(int parent_id, const std::string &bone,
+ v3f position, v3f rotation)
{
std::ostringstream os(std::ios::binary);
- // command
+ // command
writeU8(os, GENERIC_CMD_ATTACH_TO);
// parameters
writeS16(os, parent_id);
@@ -183,10 +186,11 @@ std::string gob_cmd_update_nametag_attributes(video::SColor color)
return os.str();
}
-std::string gob_cmd_update_infant(u16 id, u8 type, std::string client_initialization_data)
+std::string gob_cmd_update_infant(u16 id, u8 type,
+ const std::string &client_initialization_data)
{
std::ostringstream os(std::ios::binary);
- // command
+ // command
writeU8(os, GENERIC_CMD_SPAWN_INFANT);
// parameters
writeU16(os, id);
diff --git a/src/genericobject.h b/src/genericobject.h
index 48e71db75..d82650f0e 100644
--- a/src/genericobject.h
+++ b/src/genericobject.h
@@ -68,17 +68,21 @@ std::string gob_cmd_punched(s16 damage, s16 result_hp);
std::string gob_cmd_update_armor_groups(const ItemGroupList &armor_groups);
std::string gob_cmd_update_physics_override(float physics_override_speed,
- float physics_override_jump, float physics_override_gravity, bool sneak, bool sneak_glitch);
+ float physics_override_jump, float physics_override_gravity,
+ bool sneak, bool sneak_glitch, bool new_move);
std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_blend, bool frame_loop);
-std::string gob_cmd_update_bone_position(std::string bone, v3f position, v3f rotation);
+std::string gob_cmd_update_bone_position(const std::string &bone, v3f position,
+ v3f rotation);
-std::string gob_cmd_update_attachment(int parent_id, std::string bone, v3f position, v3f rotation);
+std::string gob_cmd_update_attachment(int parent_id, const std::string &bone,
+ v3f position, v3f rotation);
std::string gob_cmd_update_nametag_attributes(video::SColor color);
-std::string gob_cmd_update_infant(u16 id, u8 type, std::string client_initialization_data);
+std::string gob_cmd_update_infant(u16 id, u8 type,
+ const std::string &client_initialization_data);
#endif
diff --git a/src/gettime.h b/src/gettime.h
index 44c159026..4d5a02e1e 100644
--- a/src/gettime.h
+++ b/src/gettime.h
@@ -21,43 +21,26 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define GETTIME_HEADER
#include "irrlichttypes.h"
+#include <time.h>
+#include <string>
-/*
- Get a millisecond counter value.
- Precision depends on implementation.
- Overflows at any value above 10000000.
-
- Implementation of this is done in:
- Normal build: main.cpp
- Server build: servermain.cpp
-*/
-enum TimePrecision {
- PRECISION_SECONDS = 0,
+enum TimePrecision
+{
+ PRECISION_SECONDS,
PRECISION_MILLI,
PRECISION_MICRO,
PRECISION_NANO
};
-extern u32 getTimeMs();
-extern u32 getTime(TimePrecision prec);
-
-/*
- Timestamp stuff
-*/
-
-#include <time.h>
-#include <string>
-
inline std::string getTimestamp()
{
time_t t = time(NULL);
// This is not really thread-safe but it won't break anything
// except its own output, so just go with it.
struct tm *tm = localtime(&t);
- char cs[20]; //YYYY-MM-DD HH:MM:SS + '\0'
+ char cs[20]; // YYYY-MM-DD HH:MM:SS + '\0'
strftime(cs, 20, "%Y-%m-%d %H:%M:%S", tm);
return cs;
}
-
#endif
diff --git a/src/gmp/CMakeLists.txt b/src/gmp/CMakeLists.txt
deleted file mode 100644
index 96ae8191d..000000000
--- a/src/gmp/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-if(MSVC)
- set(CMAKE_C_FLAGS_RELEASE "/MT /O2 /Ob2 /D NDEBUG")
-endif()
-
-add_library(gmp mini-gmp.c)
-target_link_libraries(gmp)
-
diff --git a/src/gmp/mini-gmp.c b/src/gmp/mini-gmp.c
deleted file mode 100644
index f3b43fbe8..000000000
--- a/src/gmp/mini-gmp.c
+++ /dev/null
@@ -1,4130 +0,0 @@
-/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
-
- Contributed to the GNU project by Niels Möller
-
-Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
-2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
-Free Software Foundation, Inc.
-
-This file is part of the GNU MP Library.
-
-The GNU MP Library is free software; you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 3 of the License, or (at your
-option) any later version.
-
-The GNU MP Library 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 Lesser General Public
-License for more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
-
-/* NOTE: All functions in this file which are not declared in
- mini-gmp.h are internal, and are not intended to be compatible
- neither with GMP nor with future versions of mini-gmp. */
-
-/* Much of the material copied from GMP files, including: gmp-impl.h,
- longlong.h, mpn/generic/add_n.c, mpn/generic/addmul_1.c,
- mpn/generic/lshift.c, mpn/generic/mul_1.c,
- mpn/generic/mul_basecase.c, mpn/generic/rshift.c,
- mpn/generic/sbpi1_div_qr.c, mpn/generic/sub_n.c,
- mpn/generic/submul_1.c. */
-
-#include <assert.h>
-#include <ctype.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "mini-gmp.h"
-
-
-/* Macros */
-#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
-
-#define GMP_LIMB_MAX (~ (mp_limb_t) 0)
-#define GMP_LIMB_HIGHBIT ((mp_limb_t) 1 << (GMP_LIMB_BITS - 1))
-
-#define GMP_HLIMB_BIT ((mp_limb_t) 1 << (GMP_LIMB_BITS / 2))
-#define GMP_LLIMB_MASK (GMP_HLIMB_BIT - 1)
-
-#define GMP_ULONG_BITS (sizeof(unsigned long) * CHAR_BIT)
-#define GMP_ULONG_HIGHBIT ((unsigned long) 1 << (GMP_ULONG_BITS - 1))
-
-#define GMP_ABS(x) ((x) >= 0 ? (x) : -(x))
-#define GMP_NEG_CAST(T,x) (-((T)((x) + 1) - 1))
-
-#define GMP_MIN(a, b) ((a) < (b) ? (a) : (b))
-#define GMP_MAX(a, b) ((a) > (b) ? (a) : (b))
-
-#define gmp_assert_nocarry(x) do { \
- mp_limb_t __cy = x; \
- assert (__cy == 0); \
- } while (0)
-
-#define gmp_clz(count, x) do { \
- mp_limb_t __clz_x = (x); \
- unsigned __clz_c; \
- for (__clz_c = 0; \
- (__clz_x & ((mp_limb_t) 0xff << (GMP_LIMB_BITS - 8))) == 0; \
- __clz_c += 8) \
- __clz_x <<= 8; \
- for (; (__clz_x & GMP_LIMB_HIGHBIT) == 0; __clz_c++) \
- __clz_x <<= 1; \
- (count) = __clz_c; \
- } while (0)
-
-#define gmp_ctz(count, x) do { \
- mp_limb_t __ctz_x = (x); \
- unsigned __ctz_c = 0; \
- gmp_clz (__ctz_c, __ctz_x & - __ctz_x); \
- (count) = GMP_LIMB_BITS - 1 - __ctz_c; \
- } while (0)
-
-#define gmp_add_ssaaaa(sh, sl, ah, al, bh, bl) \
- do { \
- mp_limb_t __x; \
- __x = (al) + (bl); \
- (sh) = (ah) + (bh) + (__x < (al)); \
- (sl) = __x; \
- } while (0)
-
-#define gmp_sub_ddmmss(sh, sl, ah, al, bh, bl) \
- do { \
- mp_limb_t __x; \
- __x = (al) - (bl); \
- (sh) = (ah) - (bh) - ((al) < (bl)); \
- (sl) = __x; \
- } while (0)
-
-#define gmp_umul_ppmm(w1, w0, u, v) \
- do { \
- mp_limb_t __x0, __x1, __x2, __x3; \
- unsigned __ul, __vl, __uh, __vh; \
- mp_limb_t __u = (u), __v = (v); \
- \
- __ul = __u & GMP_LLIMB_MASK; \
- __uh = __u >> (GMP_LIMB_BITS / 2); \
- __vl = __v & GMP_LLIMB_MASK; \
- __vh = __v >> (GMP_LIMB_BITS / 2); \
- \
- __x0 = (mp_limb_t) __ul * __vl; \
- __x1 = (mp_limb_t) __ul * __vh; \
- __x2 = (mp_limb_t) __uh * __vl; \
- __x3 = (mp_limb_t) __uh * __vh; \
- \
- __x1 += __x0 >> (GMP_LIMB_BITS / 2);/* this can't give carry */ \
- __x1 += __x2; /* but this indeed can */ \
- if (__x1 < __x2) /* did we get it? */ \
- __x3 += GMP_HLIMB_BIT; /* yes, add it in the proper pos. */ \
- \
- (w1) = __x3 + (__x1 >> (GMP_LIMB_BITS / 2)); \
- (w0) = (__x1 << (GMP_LIMB_BITS / 2)) + (__x0 & GMP_LLIMB_MASK); \
- } while (0)
-
-#define gmp_udiv_qrnnd_preinv(q, r, nh, nl, d, di) \
- do { \
- mp_limb_t _qh, _ql, _r, _mask; \
- gmp_umul_ppmm (_qh, _ql, (nh), (di)); \
- gmp_add_ssaaaa (_qh, _ql, _qh, _ql, (nh) + 1, (nl)); \
- _r = (nl) - _qh * (d); \
- _mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */ \
- _qh += _mask; \
- _r += _mask & (d); \
- if (_r >= (d)) \
- { \
- _r -= (d); \
- _qh++; \
- } \
- \
- (r) = _r; \
- (q) = _qh; \
- } while (0)
-
-#define gmp_udiv_qr_3by2(q, r1, r0, n2, n1, n0, d1, d0, dinv) \
- do { \
- mp_limb_t _q0, _t1, _t0, _mask; \
- gmp_umul_ppmm ((q), _q0, (n2), (dinv)); \
- gmp_add_ssaaaa ((q), _q0, (q), _q0, (n2), (n1)); \
- \
- /* Compute the two most significant limbs of n - q'd */ \
- (r1) = (n1) - (d1) * (q); \
- gmp_sub_ddmmss ((r1), (r0), (r1), (n0), (d1), (d0)); \
- gmp_umul_ppmm (_t1, _t0, (d0), (q)); \
- gmp_sub_ddmmss ((r1), (r0), (r1), (r0), _t1, _t0); \
- (q)++; \
- \
- /* Conditionally adjust q and the remainders */ \
- _mask = - (mp_limb_t) ((r1) >= _q0); \
- (q) += _mask; \
- gmp_add_ssaaaa ((r1), (r0), (r1), (r0), _mask & (d1), _mask & (d0)); \
- if ((r1) >= (d1)) \
- { \
- if ((r1) > (d1) || (r0) >= (d0)) \
- { \
- (q)++; \
- gmp_sub_ddmmss ((r1), (r0), (r1), (r0), (d1), (d0)); \
- } \
- } \
- } while (0)
-
-/* Swap macros. */
-#define MP_LIMB_T_SWAP(x, y) \
- do { \
- mp_limb_t __mp_limb_t_swap__tmp = (x); \
- (x) = (y); \
- (y) = __mp_limb_t_swap__tmp; \
- } while (0)
-#define MP_SIZE_T_SWAP(x, y) \
- do { \
- mp_size_t __mp_size_t_swap__tmp = (x); \
- (x) = (y); \
- (y) = __mp_size_t_swap__tmp; \
- } while (0)
-#define MP_BITCNT_T_SWAP(x,y) \
- do { \
- mp_bitcnt_t __mp_bitcnt_t_swap__tmp = (x); \
- (x) = (y); \
- (y) = __mp_bitcnt_t_swap__tmp; \
- } while (0)
-#define MP_PTR_SWAP(x, y) \
- do { \
- mp_ptr __mp_ptr_swap__tmp = (x); \
- (x) = (y); \
- (y) = __mp_ptr_swap__tmp; \
- } while (0)
-#define MP_SRCPTR_SWAP(x, y) \
- do { \
- mp_srcptr __mp_srcptr_swap__tmp = (x); \
- (x) = (y); \
- (y) = __mp_srcptr_swap__tmp; \
- } while (0)
-
-#define MPN_PTR_SWAP(xp,xs, yp,ys) \
- do { \
- MP_PTR_SWAP (xp, yp); \
- MP_SIZE_T_SWAP (xs, ys); \
- } while(0)
-#define MPN_SRCPTR_SWAP(xp,xs, yp,ys) \
- do { \
- MP_SRCPTR_SWAP (xp, yp); \
- MP_SIZE_T_SWAP (xs, ys); \
- } while(0)
-
-#define MPZ_PTR_SWAP(x, y) \
- do { \
- mpz_ptr __mpz_ptr_swap__tmp = (x); \
- (x) = (y); \
- (y) = __mpz_ptr_swap__tmp; \
- } while (0)
-#define MPZ_SRCPTR_SWAP(x, y) \
- do { \
- mpz_srcptr __mpz_srcptr_swap__tmp = (x); \
- (x) = (y); \
- (y) = __mpz_srcptr_swap__tmp; \
- } while (0)
-
-
-/* Memory allocation and other helper functions. */
-static void
-gmp_die (const char *msg)
-{
- fprintf (stderr, "%s\n", msg);
- abort();
-}
-
-static void *
-gmp_default_alloc (size_t size)
-{
- void *p;
-
- assert (size > 0);
-
- p = malloc (size);
- if (!p)
- gmp_die("gmp_default_alloc: Virtual memory exhausted.");
-
- return p;
-}
-
-static void *
-gmp_default_realloc (void *old, size_t old_size, size_t new_size)
-{
- mp_ptr p;
-
- p = realloc (old, new_size);
-
- if (!p)
- gmp_die("gmp_default_realoc: Virtual memory exhausted.");
-
- return p;
-}
-
-static void
-gmp_default_free (void *p, size_t size)
-{
- free (p);
-}
-
-static void * (*gmp_allocate_func) (size_t) = gmp_default_alloc;
-static void * (*gmp_reallocate_func) (void *, size_t, size_t) = gmp_default_realloc;
-static void (*gmp_free_func) (void *, size_t) = gmp_default_free;
-
-void
-mp_get_memory_functions (void *(**alloc_func) (size_t),
- void *(**realloc_func) (void *, size_t, size_t),
- void (**free_func) (void *, size_t))
-{
- if (alloc_func)
- *alloc_func = gmp_allocate_func;
-
- if (realloc_func)
- *realloc_func = gmp_reallocate_func;
-
- if (free_func)
- *free_func = gmp_free_func;
-}
-
-void
-mp_set_memory_functions (void *(*alloc_func) (size_t),
- void *(*realloc_func) (void *, size_t, size_t),
- void (*free_func) (void *, size_t))
-{
- if (!alloc_func)
- alloc_func = gmp_default_alloc;
- if (!realloc_func)
- realloc_func = gmp_default_realloc;
- if (!free_func)
- free_func = gmp_default_free;
-
- gmp_allocate_func = alloc_func;
- gmp_reallocate_func = realloc_func;
- gmp_free_func = free_func;
-}
-
-#define gmp_xalloc(size) ((*gmp_allocate_func)((size)))
-#define gmp_free(p) ((*gmp_free_func) ((p), 0))
-
-static mp_ptr
-gmp_xalloc_limbs (mp_size_t size)
-{
- return gmp_xalloc (size * sizeof (mp_limb_t));
-}
-
-static mp_ptr
-gmp_xrealloc_limbs (mp_ptr old, mp_size_t size)
-{
- assert (size > 0);
- return (*gmp_reallocate_func) (old, 0, size * sizeof (mp_limb_t));
-}
-
-
-/* MPN interface */
-
-void
-mpn_copyi (mp_ptr d, mp_srcptr s, mp_size_t n)
-{
- mp_size_t i;
- for (i = 0; i < n; i++)
- d[i] = s[i];
-}
-
-void
-mpn_copyd (mp_ptr d, mp_srcptr s, mp_size_t n)
-{
- while (n-- > 0)
- d[n] = s[n];
-}
-
-int
-mpn_cmp (mp_srcptr ap, mp_srcptr bp, mp_size_t n)
-{
- for (; n > 0; n--)
- {
- if (ap[n-1] < bp[n-1])
- return -1;
- else if (ap[n-1] > bp[n-1])
- return 1;
- }
- return 0;
-}
-
-static int
-mpn_cmp4 (mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
-{
- if (an > bn)
- return 1;
- else if (an < bn)
- return -1;
- else
- return mpn_cmp (ap, bp, an);
-}
-
-static mp_size_t
-mpn_normalized_size (mp_srcptr xp, mp_size_t n)
-{
- for (; n > 0 && xp[n-1] == 0; n--)
- ;
- return n;
-}
-
-#define mpn_zero_p(xp, n) (mpn_normalized_size ((xp), (n)) == 0)
-
-mp_limb_t
-mpn_add_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
-{
- mp_size_t i;
-
- assert (n > 0);
-
- for (i = 0; i < n; i++)
- {
- mp_limb_t r = ap[i] + b;
- /* Carry out */
- b = (r < b);
- rp[i] = r;
- }
- return b;
-}
-
-mp_limb_t
-mpn_add_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
-{
- mp_size_t i;
- mp_limb_t cy;
-
- for (i = 0, cy = 0; i < n; i++)
- {
- mp_limb_t a, b, r;
- a = ap[i]; b = bp[i];
- r = a + cy;
- cy = (r < cy);
- r += b;
- cy += (r < b);
- rp[i] = r;
- }
- return cy;
-}
-
-mp_limb_t
-mpn_add (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
-{
- mp_limb_t cy;
-
- assert (an >= bn);
-
- cy = mpn_add_n (rp, ap, bp, bn);
- if (an > bn)
- cy = mpn_add_1 (rp + bn, ap + bn, an - bn, cy);
- return cy;
-}
-
-mp_limb_t
-mpn_sub_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
-{
- mp_size_t i;
-
- assert (n > 0);
-
- for (i = 0; i < n; i++)
- {
- mp_limb_t a = ap[i];
- /* Carry out */
- mp_limb_t cy = a < b;;
- rp[i] = a - b;
- b = cy;
- }
- return b;
-}
-
-mp_limb_t
-mpn_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
-{
- mp_size_t i;
- mp_limb_t cy;
-
- for (i = 0, cy = 0; i < n; i++)
- {
- mp_limb_t a, b;
- a = ap[i]; b = bp[i];
- b += cy;
- cy = (b < cy);
- cy += (a < b);
- rp[i] = a - b;
- }
- return cy;
-}
-
-mp_limb_t
-mpn_sub (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
-{
- mp_limb_t cy;
-
- assert (an >= bn);
-
- cy = mpn_sub_n (rp, ap, bp, bn);
- if (an > bn)
- cy = mpn_sub_1 (rp + bn, ap + bn, an - bn, cy);
- return cy;
-}
-
-mp_limb_t
-mpn_mul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
-{
- mp_limb_t ul, cl, hpl, lpl;
-
- assert (n >= 1);
-
- cl = 0;
- do
- {
- ul = *up++;
- gmp_umul_ppmm (hpl, lpl, ul, vl);
-
- lpl += cl;
- cl = (lpl < cl) + hpl;
-
- *rp++ = lpl;
- }
- while (--n != 0);
-
- return cl;
-}
-
-mp_limb_t
-mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
-{
- mp_limb_t ul, cl, hpl, lpl, rl;
-
- assert (n >= 1);
-
- cl = 0;
- do
- {
- ul = *up++;
- gmp_umul_ppmm (hpl, lpl, ul, vl);
-
- lpl += cl;
- cl = (lpl < cl) + hpl;
-
- rl = *rp;
- lpl = rl + lpl;
- cl += lpl < rl;
- *rp++ = lpl;
- }
- while (--n != 0);
-
- return cl;
-}
-
-mp_limb_t
-mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
-{
- mp_limb_t ul, cl, hpl, lpl, rl;
-
- assert (n >= 1);
-
- cl = 0;
- do
- {
- ul = *up++;
- gmp_umul_ppmm (hpl, lpl, ul, vl);
-
- lpl += cl;
- cl = (lpl < cl) + hpl;
-
- rl = *rp;
- lpl = rl - lpl;
- cl += lpl > rl;
- *rp++ = lpl;
- }
- while (--n != 0);
-
- return cl;
-}
-
-mp_limb_t
-mpn_mul (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn)
-{
- assert (un >= vn);
- assert (vn >= 1);
-
- /* We first multiply by the low order limb. This result can be
- stored, not added, to rp. We also avoid a loop for zeroing this
- way. */
-
- rp[un] = mpn_mul_1 (rp, up, un, vp[0]);
- rp += 1, vp += 1, vn -= 1;
-
- /* Now accumulate the product of up[] and the next higher limb from
- vp[]. */
-
- while (vn >= 1)
- {
- rp[un] = mpn_addmul_1 (rp, up, un, vp[0]);
- rp += 1, vp += 1, vn -= 1;
- }
- return rp[un - 1];
-}
-
-void
-mpn_mul_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
-{
- mpn_mul (rp, ap, n, bp, n);
-}
-
-void
-mpn_sqr (mp_ptr rp, mp_srcptr ap, mp_size_t n)
-{
- mpn_mul (rp, ap, n, ap, n);
-}
-
-mp_limb_t
-mpn_lshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
-{
- mp_limb_t high_limb, low_limb;
- unsigned int tnc;
- mp_size_t i;
- mp_limb_t retval;
-
- assert (n >= 1);
- assert (cnt >= 1);
- assert (cnt < GMP_LIMB_BITS);
-
- up += n;
- rp += n;
-
- tnc = GMP_LIMB_BITS - cnt;
- low_limb = *--up;
- retval = low_limb >> tnc;
- high_limb = (low_limb << cnt);
-
- for (i = n - 1; i != 0; i--)
- {
- low_limb = *--up;
- *--rp = high_limb | (low_limb >> tnc);
- high_limb = (low_limb << cnt);
- }
- *--rp = high_limb;
-
- return retval;
-}
-
-mp_limb_t
-mpn_rshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
-{
- mp_limb_t high_limb, low_limb;
- unsigned int tnc;
- mp_size_t i;
- mp_limb_t retval;
-
- assert (n >= 1);
- assert (cnt >= 1);
- assert (cnt < GMP_LIMB_BITS);
-
- tnc = GMP_LIMB_BITS - cnt;
- high_limb = *up++;
- retval = (high_limb << tnc);
- low_limb = high_limb >> cnt;
-
- for (i = n - 1; i != 0; i--)
- {
- high_limb = *up++;
- *rp++ = low_limb | (high_limb << tnc);
- low_limb = high_limb >> cnt;
- }
- *rp = low_limb;
-
- return retval;
-}
-
-
-/* MPN division interface. */
-mp_limb_t
-mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0)
-{
- mp_limb_t r, p, m;
- unsigned ul, uh;
- unsigned ql, qh;
-
- /* First, do a 2/1 inverse. */
- /* The inverse m is defined as floor( (B^2 - 1 - u1)/u1 ), so that 0 <
- * B^2 - (B + m) u1 <= u1 */
- assert (u1 >= GMP_LIMB_HIGHBIT);
-
- ul = u1 & GMP_LLIMB_MASK;
- uh = u1 >> (GMP_LIMB_BITS / 2);
-
- qh = ~u1 / uh;
- r = ((~u1 - (mp_limb_t) qh * uh) << (GMP_LIMB_BITS / 2)) | GMP_LLIMB_MASK;
-
- p = (mp_limb_t) qh * ul;
- /* Adjustment steps taken from udiv_qrnnd_c */
- if (r < p)
- {
- qh--;
- r += u1;
- if (r >= u1) /* i.e. we didn't get carry when adding to r */
- if (r < p)
- {
- qh--;
- r += u1;
- }
- }
- r -= p;
-
- /* Do a 3/2 division (with half limb size) */
- p = (r >> (GMP_LIMB_BITS / 2)) * qh + r;
- ql = (p >> (GMP_LIMB_BITS / 2)) + 1;
-
- /* By the 3/2 method, we don't need the high half limb. */
- r = (r << (GMP_LIMB_BITS / 2)) + GMP_LLIMB_MASK - ql * u1;
-
- if (r >= (p << (GMP_LIMB_BITS / 2)))
- {
- ql--;
- r += u1;
- }
- m = ((mp_limb_t) qh << (GMP_LIMB_BITS / 2)) + ql;
- if (r >= u1)
- {
- m++;
- r -= u1;
- }
-
- if (u0 > 0)
- {
- mp_limb_t th, tl;
- r = ~r;
- r += u0;
- if (r < u0)
- {
- m--;
- if (r >= u1)
- {
- m--;
- r -= u1;
- }
- r -= u1;
- }
- gmp_umul_ppmm (th, tl, u0, m);
- r += th;
- if (r < th)
- {
- m--;
- if (r > u1 || (r == u1 && tl > u0))
- m--;
- }
- }
-
- return m;
-}
-
-struct gmp_div_inverse
-{
- /* Normalization shift count. */
- unsigned shift;
- /* Normalized divisor (d0 unused for mpn_div_qr_1) */
- mp_limb_t d1, d0;
- /* Inverse, for 2/1 or 3/2. */
- mp_limb_t di;
-};
-
-static void
-mpn_div_qr_1_invert (struct gmp_div_inverse *inv, mp_limb_t d)
-{
- unsigned shift;
-
- assert (d > 0);
- gmp_clz (shift, d);
- inv->shift = shift;
- inv->d1 = d << shift;
- inv->di = mpn_invert_limb (inv->d1);
-}
-
-static void
-mpn_div_qr_2_invert (struct gmp_div_inverse *inv,
- mp_limb_t d1, mp_limb_t d0)
-{
- unsigned shift;
-
- assert (d1 > 0);
- gmp_clz (shift, d1);
- inv->shift = shift;
- if (shift > 0)
- {
- d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
- d0 <<= shift;
- }
- inv->d1 = d1;
- inv->d0 = d0;
- inv->di = mpn_invert_3by2 (d1, d0);
-}
-
-static void
-mpn_div_qr_invert (struct gmp_div_inverse *inv,
- mp_srcptr dp, mp_size_t dn)
-{
- assert (dn > 0);
-
- if (dn == 1)
- mpn_div_qr_1_invert (inv, dp[0]);
- else if (dn == 2)
- mpn_div_qr_2_invert (inv, dp[1], dp[0]);
- else
- {
- unsigned shift;
- mp_limb_t d1, d0;
-
- d1 = dp[dn-1];
- d0 = dp[dn-2];
- assert (d1 > 0);
- gmp_clz (shift, d1);
- inv->shift = shift;
- if (shift > 0)
- {
- d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
- d0 = (d0 << shift) | (dp[dn-3] >> (GMP_LIMB_BITS - shift));
- }
- inv->d1 = d1;
- inv->d0 = d0;
- inv->di = mpn_invert_3by2 (d1, d0);
- }
-}
-
-/* Not matching current public gmp interface, rather corresponding to
- the sbpi1_div_* functions. */
-static mp_limb_t
-mpn_div_qr_1_preinv (mp_ptr qp, mp_srcptr np, mp_size_t nn,
- const struct gmp_div_inverse *inv)
-{
- mp_limb_t d, di;
- mp_limb_t r;
- mp_ptr tp = NULL;
-
- if (inv->shift > 0)
- {
- tp = gmp_xalloc_limbs (nn);
- r = mpn_lshift (tp, np, nn, inv->shift);
- np = tp;
- }
- else
- r = 0;
-
- d = inv->d1;
- di = inv->di;
- while (nn-- > 0)
- {
- mp_limb_t q;
-
- gmp_udiv_qrnnd_preinv (q, r, r, np[nn], d, di);
- if (qp)
- qp[nn] = q;
- }
- if (inv->shift > 0)
- gmp_free (tp);
-
- return r >> inv->shift;
-}
-
-static mp_limb_t
-mpn_div_qr_1 (mp_ptr qp, mp_srcptr np, mp_size_t nn, mp_limb_t d)
-{
- assert (d > 0);
-
- /* Special case for powers of two. */
- if (d > 1 && (d & (d-1)) == 0)
- {
- unsigned shift;
- mp_limb_t r = np[0] & (d-1);
- gmp_ctz (shift, d);
- if (qp)
- mpn_rshift (qp, np, nn, shift);
-
- return r;
- }
- else
- {
- struct gmp_div_inverse inv;
- mpn_div_qr_1_invert (&inv, d);
- return mpn_div_qr_1_preinv (qp, np, nn, &inv);
- }
-}
-
-static void
-mpn_div_qr_2_preinv (mp_ptr qp, mp_ptr rp, mp_srcptr np, mp_size_t nn,
- const struct gmp_div_inverse *inv)
-{
- unsigned shift;
- mp_size_t i;
- mp_limb_t d1, d0, di, r1, r0;
- mp_ptr tp;
-
- assert (nn >= 2);
- shift = inv->shift;
- d1 = inv->d1;
- d0 = inv->d0;
- di = inv->di;
-
- if (shift > 0)
- {
- tp = gmp_xalloc_limbs (nn);
- r1 = mpn_lshift (tp, np, nn, shift);
- np = tp;
- }
- else
- r1 = 0;
-
- r0 = np[nn - 1];
-
- for (i = nn - 2; i >= 0; i--)
- {
- mp_limb_t n0, q;
- n0 = np[i];
- gmp_udiv_qr_3by2 (q, r1, r0, r1, r0, n0, d1, d0, di);
-
- if (qp)
- qp[i] = q;
- }
-
- if (shift > 0)
- {
- assert ((r0 << (GMP_LIMB_BITS - shift)) == 0);
- r0 = (r0 >> shift) | (r1 << (GMP_LIMB_BITS - shift));
- r1 >>= shift;
-
- gmp_free (tp);
- }
-
- rp[1] = r1;
- rp[0] = r0;
-}
-
-#if 0
-static void
-mpn_div_qr_2 (mp_ptr qp, mp_ptr rp, mp_srcptr np, mp_size_t nn,
- mp_limb_t d1, mp_limb_t d0)
-{
- struct gmp_div_inverse inv;
- assert (nn >= 2);
-
- mpn_div_qr_2_invert (&inv, d1, d0);
- mpn_div_qr_2_preinv (qp, rp, np, nn, &inv);
-}
-#endif
-
-static void
-mpn_div_qr_pi1 (mp_ptr qp,
- mp_ptr np, mp_size_t nn, mp_limb_t n1,
- mp_srcptr dp, mp_size_t dn,
- mp_limb_t dinv)
-{
- mp_size_t i;
-
- mp_limb_t d1, d0;
- mp_limb_t cy, cy1;
- mp_limb_t q;
-
- assert (dn > 2);
- assert (nn >= dn);
-
- d1 = dp[dn - 1];
- d0 = dp[dn - 2];
-
- assert ((d1 & GMP_LIMB_HIGHBIT) != 0);
- /* Iteration variable is the index of the q limb.
- *
- * We divide <n1, np[dn-1+i], np[dn-2+i], np[dn-3+i],..., np[i]>
- * by <d1, d0, dp[dn-3], ..., dp[0] >
- */
-
- for (i = nn - dn; i >= 0; i--)
- {
- mp_limb_t n0 = np[dn-1+i];
-
- if (n1 == d1 && n0 == d0)
- {
- q = GMP_LIMB_MAX;
- mpn_submul_1 (np+i, dp, dn, q);
- n1 = np[dn-1+i]; /* update n1, last loop's value will now be invalid */
- }
- else
- {
- gmp_udiv_qr_3by2 (q, n1, n0, n1, n0, np[dn-2+i], d1, d0, dinv);
-
- cy = mpn_submul_1 (np + i, dp, dn-2, q);
-
- cy1 = n0 < cy;
- n0 = n0 - cy;
- cy = n1 < cy1;
- n1 = n1 - cy1;
- np[dn-2+i] = n0;
-
- if (cy != 0)
- {
- n1 += d1 + mpn_add_n (np + i, np + i, dp, dn - 1);
- q--;
- }
- }
-
- if (qp)
- qp[i] = q;
- }
-
- np[dn - 1] = n1;
-}
-
-static void
-mpn_div_qr_preinv (mp_ptr qp, mp_ptr np, mp_size_t nn,
- mp_srcptr dp, mp_size_t dn,
- const struct gmp_div_inverse *inv)
-{
- assert (dn > 0);
- assert (nn >= dn);
-
- if (dn == 1)
- np[0] = mpn_div_qr_1_preinv (qp, np, nn, inv);
- else if (dn == 2)
- mpn_div_qr_2_preinv (qp, np, np, nn, inv);
- else
- {
- mp_limb_t nh;
- unsigned shift;
-
- assert (inv->d1 == dp[dn-1]);
- assert (inv->d0 == dp[dn-2]);
- assert ((inv->d1 & GMP_LIMB_HIGHBIT) != 0);
-
- shift = inv->shift;
- if (shift > 0)
- nh = mpn_lshift (np, np, nn, shift);
- else
- nh = 0;
-
- mpn_div_qr_pi1 (qp, np, nn, nh, dp, dn, inv->di);
-
- if (shift > 0)
- gmp_assert_nocarry (mpn_rshift (np, np, dn, shift));
- }
-}
-
-static void
-mpn_div_qr (mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)
-{
- struct gmp_div_inverse inv;
- mp_ptr tp = NULL;
-
- assert (dn > 0);
- assert (nn >= dn);
-
- mpn_div_qr_invert (&inv, dp, dn);
- if (dn > 2 && inv.shift > 0)
- {
- tp = gmp_xalloc_limbs (dn);
- gmp_assert_nocarry (mpn_lshift (tp, dp, dn, inv.shift));
- dp = tp;
- }
- mpn_div_qr_preinv (qp, np, nn, dp, dn, &inv);
- if (tp)
- gmp_free (tp);
-}
-
-
-/* MPN base conversion. */
-static unsigned
-mpn_base_power_of_two_p (unsigned b)
-{
- switch (b)
- {
- case 2: return 1;
- case 4: return 2;
- case 8: return 3;
- case 16: return 4;
- case 32: return 5;
- case 64: return 6;
- case 128: return 7;
- case 256: return 8;
- default: return 0;
- }
-}
-
-struct mpn_base_info
-{
- /* bb is the largest power of the base which fits in one limb, and
- exp is the corresponding exponent. */
- unsigned exp;
- mp_limb_t bb;
-};
-
-static void
-mpn_get_base_info (struct mpn_base_info *info, mp_limb_t b)
-{
- mp_limb_t m;
- mp_limb_t p;
- unsigned exp;
-
- m = GMP_LIMB_MAX / b;
- for (exp = 1, p = b; p <= m; exp++)
- p *= b;
-
- info->exp = exp;
- info->bb = p;
-}
-
-static mp_bitcnt_t
-mpn_limb_size_in_base_2 (mp_limb_t u)
-{
- unsigned shift;
-
- assert (u > 0);
- gmp_clz (shift, u);
- return GMP_LIMB_BITS - shift;
-}
-
-static size_t
-mpn_get_str_bits (unsigned char *sp, unsigned bits, mp_srcptr up, mp_size_t un)
-{
- unsigned char mask;
- size_t sn, j;
- mp_size_t i;
- int shift;
-
- sn = ((un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1])
- + bits - 1) / bits;
-
- mask = (1U << bits) - 1;
-
- for (i = 0, j = sn, shift = 0; j-- > 0;)
- {
- unsigned char digit = up[i] >> shift;
-
- shift += bits;
-
- if (shift >= GMP_LIMB_BITS && ++i < un)
- {
- shift -= GMP_LIMB_BITS;
- digit |= up[i] << (bits - shift);
- }
- sp[j] = digit & mask;
- }
- return sn;
-}
-
-/* We generate digits from the least significant end, and reverse at
- the end. */
-static size_t
-mpn_limb_get_str (unsigned char *sp, mp_limb_t w,
- const struct gmp_div_inverse *binv)
-{
- mp_size_t i;
- for (i = 0; w > 0; i++)
- {
- mp_limb_t h, l, r;
-
- h = w >> (GMP_LIMB_BITS - binv->shift);
- l = w << binv->shift;
-
- gmp_udiv_qrnnd_preinv (w, r, h, l, binv->d1, binv->di);
- assert ( (r << (GMP_LIMB_BITS - binv->shift)) == 0);
- r >>= binv->shift;
-
- sp[i] = r;
- }
- return i;
-}
-
-static size_t
-mpn_get_str_other (unsigned char *sp,
- int base, const struct mpn_base_info *info,
- mp_ptr up, mp_size_t un)
-{
- struct gmp_div_inverse binv;
- size_t sn;
- size_t i;
-
- mpn_div_qr_1_invert (&binv, base);
-
- sn = 0;
-
- if (un > 1)
- {
- struct gmp_div_inverse bbinv;
- mpn_div_qr_1_invert (&bbinv, info->bb);
-
- do
- {
- mp_limb_t w;
- size_t done;
- w = mpn_div_qr_1_preinv (up, up, un, &bbinv);
- un -= (up[un-1] == 0);
- done = mpn_limb_get_str (sp + sn, w, &binv);
-
- for (sn += done; done < info->exp; done++)
- sp[sn++] = 0;
- }
- while (un > 1);
- }
- sn += mpn_limb_get_str (sp + sn, up[0], &binv);
-
- /* Reverse order */
- for (i = 0; 2*i + 1 < sn; i++)
- {
- unsigned char t = sp[i];
- sp[i] = sp[sn - i - 1];
- sp[sn - i - 1] = t;
- }
-
- return sn;
-}
-
-size_t
-mpn_get_str (unsigned char *sp, int base, mp_ptr up, mp_size_t un)
-{
- unsigned bits;
-
- assert (un > 0);
- assert (up[un-1] > 0);
-
- bits = mpn_base_power_of_two_p (base);
- if (bits)
- return mpn_get_str_bits (sp, bits, up, un);
- else
- {
- struct mpn_base_info info;
-
- mpn_get_base_info (&info, base);
- return mpn_get_str_other (sp, base, &info, up, un);
- }
-}
-
-static mp_size_t
-mpn_set_str_bits (mp_ptr rp, const unsigned char *sp, size_t sn,
- unsigned bits)
-{
- mp_size_t rn;
- size_t j;
- unsigned shift;
-
- for (j = sn, rn = 0, shift = 0; j-- > 0; )
- {
- if (shift == 0)
- {
- rp[rn++] = sp[j];
- shift += bits;
- }
- else
- {
- rp[rn-1] |= (mp_limb_t) sp[j] << shift;
- shift += bits;
- if (shift >= GMP_LIMB_BITS)
- {
- shift -= GMP_LIMB_BITS;
- if (shift > 0)
- rp[rn++] = (mp_limb_t) sp[j] >> (bits - shift);
- }
- }
- }
- rn = mpn_normalized_size (rp, rn);
- return rn;
-}
-
-static mp_size_t
-mpn_set_str_other (mp_ptr rp, const unsigned char *sp, size_t sn,
- mp_limb_t b, const struct mpn_base_info *info)
-{
- mp_size_t rn;
- mp_limb_t w;
- unsigned first;
- unsigned k;
- size_t j;
-
- first = 1 + (sn - 1) % info->exp;
-
- j = 0;
- w = sp[j++];
- for (k = 1; k < first; k++)
- w = w * b + sp[j++];
-
- rp[0] = w;
-
- for (rn = (w > 0); j < sn;)
- {
- mp_limb_t cy;
-
- w = sp[j++];
- for (k = 1; k < info->exp; k++)
- w = w * b + sp[j++];
-
- cy = mpn_mul_1 (rp, rp, rn, info->bb);
- cy += mpn_add_1 (rp, rp, rn, w);
- if (cy > 0)
- rp[rn++] = cy;
- }
- assert (j == sn);
-
- return rn;
-}
-
-mp_size_t
-mpn_set_str (mp_ptr rp, const unsigned char *sp, size_t sn, int base)
-{
- unsigned bits;
-
- if (sn == 0)
- return 0;
-
- bits = mpn_base_power_of_two_p (base);
- if (bits)
- return mpn_set_str_bits (rp, sp, sn, bits);
- else
- {
- struct mpn_base_info info;
-
- mpn_get_base_info (&info, base);
- return mpn_set_str_other (rp, sp, sn, base, &info);
- }
-}
-
-
-/* MPZ interface */
-void
-mpz_init (mpz_t r)
-{
- r->_mp_alloc = 1;
- r->_mp_size = 0;
- r->_mp_d = gmp_xalloc_limbs (1);
-}
-
-/* The utility of this function is a bit limited, since many functions
- assings the result variable using mpz_swap. */
-void
-mpz_init2 (mpz_t r, mp_bitcnt_t bits)
-{
- mp_size_t rn;
-
- bits -= (bits != 0); /* Round down, except if 0 */
- rn = 1 + bits / GMP_LIMB_BITS;
-
- r->_mp_alloc = rn;
- r->_mp_size = 0;
- r->_mp_d = gmp_xalloc_limbs (rn);
-}
-
-void
-mpz_clear (mpz_t r)
-{
- gmp_free (r->_mp_d);
-}
-
-static void *
-mpz_realloc (mpz_t r, mp_size_t size)
-{
- size = GMP_MAX (size, 1);
-
- r->_mp_d = gmp_xrealloc_limbs (r->_mp_d, size);
- r->_mp_alloc = size;
-
- if (GMP_ABS (r->_mp_size) > size)
- r->_mp_size = 0;
-
- return r->_mp_d;
-}
-
-/* Realloc for an mpz_t WHAT if it has less than NEEDED limbs. */
-#define MPZ_REALLOC(z,n) ((n) > (z)->_mp_alloc \
- ? mpz_realloc(z,n) \
- : (z)->_mp_d)
-
-/* MPZ assignment and basic conversions. */
-void
-mpz_set_si (mpz_t r, signed long int x)
-{
- if (x >= 0)
- mpz_set_ui (r, x);
- else /* (x < 0) */
- {
- r->_mp_size = -1;
- r->_mp_d[0] = GMP_NEG_CAST (unsigned long int, x);
- }
-}
-
-void
-mpz_set_ui (mpz_t r, unsigned long int x)
-{
- if (x > 0)
- {
- r->_mp_size = 1;
- r->_mp_d[0] = x;
- }
- else
- r->_mp_size = 0;
-}
-
-void
-mpz_set (mpz_t r, const mpz_t x)
-{
- /* Allow the NOP r == x */
- if (r != x)
- {
- mp_size_t n;
- mp_ptr rp;
-
- n = GMP_ABS (x->_mp_size);
- rp = MPZ_REALLOC (r, n);
-
- mpn_copyi (rp, x->_mp_d, n);
- r->_mp_size = x->_mp_size;
- }
-}
-
-void
-mpz_init_set_si (mpz_t r, signed long int x)
-{
- mpz_init (r);
- mpz_set_si (r, x);
-}
-
-void
-mpz_init_set_ui (mpz_t r, unsigned long int x)
-{
- mpz_init (r);
- mpz_set_ui (r, x);
-}
-
-void
-mpz_init_set (mpz_t r, const mpz_t x)
-{
- mpz_init (r);
- mpz_set (r, x);
-}
-
-int
-mpz_fits_slong_p (const mpz_t u)
-{
- mp_size_t us = u->_mp_size;
-
- if (us == 0)
- return 1;
- else if (us == 1)
- return u->_mp_d[0] < GMP_LIMB_HIGHBIT;
- else if (us == -1)
- return u->_mp_d[0] <= GMP_LIMB_HIGHBIT;
- else
- return 0;
-}
-
-int
-mpz_fits_ulong_p (const mpz_t u)
-{
- mp_size_t us = u->_mp_size;
-
- return us == 0 || us == 1;
-}
-
-long int
-mpz_get_si (const mpz_t u)
-{
- mp_size_t us = u->_mp_size;
-
- if (us > 0)
- return (long) (u->_mp_d[0] & ~GMP_LIMB_HIGHBIT);
- else if (us < 0)
- return (long) (- u->_mp_d[0] | GMP_LIMB_HIGHBIT);
- else
- return 0;
-}
-
-unsigned long int
-mpz_get_ui (const mpz_t u)
-{
- return u->_mp_size == 0 ? 0 : u->_mp_d[0];
-}
-
-size_t
-mpz_size (const mpz_t u)
-{
- return GMP_ABS (u->_mp_size);
-}
-
-mp_limb_t
-mpz_getlimbn (const mpz_t u, mp_size_t n)
-{
- if (n >= 0 && n < GMP_ABS (u->_mp_size))
- return u->_mp_d[n];
- else
- return 0;
-}
-
-
-/* Conversions and comparison to double. */
-void
-mpz_set_d (mpz_t r, double x)
-{
- int sign;
- mp_ptr rp;
- mp_size_t rn, i;
- double B;
- double Bi;
- mp_limb_t f;
-
- /* x != x is true when x is a NaN, and x == x * 0.5 is true when x is
- zero or infinity. */
- if (x == 0.0 || x != x || x == x * 0.5)
- {
- r->_mp_size = 0;
- return;
- }
-
- if (x < 0.0)
- {
- x = - x;
- sign = 1;
- }
- else
- sign = 0;
-
- if (x < 1.0)
- {
- r->_mp_size = 0;
- return;
- }
- B = 2.0 * (double) GMP_LIMB_HIGHBIT;
- Bi = 1.0 / B;
- for (rn = 1; x >= B; rn++)
- x *= Bi;
-
- rp = MPZ_REALLOC (r, rn);
-
- f = (mp_limb_t) x;
- x -= f;
- assert (x < 1.0);
- rp[rn-1] = f;
- for (i = rn-1; i-- > 0; )
- {
- x = B * x;
- f = (mp_limb_t) x;
- x -= f;
- assert (x < 1.0);
- rp[i] = f;
- }
-
- r->_mp_size = sign ? - rn : rn;
-}
-
-void
-mpz_init_set_d (mpz_t r, double x)
-{
- mpz_init (r);
- mpz_set_d (r, x);
-}
-
-double
-mpz_get_d (const mpz_t u)
-{
- mp_size_t un;
- double x;
- double B = 2.0 * (double) GMP_LIMB_HIGHBIT;
-
- un = GMP_ABS (u->_mp_size);
-
- if (un == 0)
- return 0.0;
-
- x = u->_mp_d[--un];
- while (un > 0)
- x = B*x + u->_mp_d[--un];
-
- if (u->_mp_size < 0)
- x = -x;
-
- return x;
-}
-
-int
-mpz_cmpabs_d (const mpz_t x, double d)
-{
- mp_size_t xn;
- double B, Bi;
- mp_size_t i;
-
- xn = x->_mp_size;
- d = GMP_ABS (d);
-
- if (xn != 0)
- {
- xn = GMP_ABS (xn);
-
- B = 2.0 * (double) GMP_LIMB_HIGHBIT;
- Bi = 1.0 / B;
-
- /* Scale d so it can be compared with the top limb. */
- for (i = 1; i < xn; i++)
- d *= Bi;
-
- if (d >= B)
- return -1;
-
- /* Compare floor(d) to top limb, subtract and cancel when equal. */
- for (i = xn; i-- > 0;)
- {
- mp_limb_t f, xl;
-
- f = (mp_limb_t) d;
- xl = x->_mp_d[i];
- if (xl > f)
- return 1;
- else if (xl < f)
- return -1;
- d = B * (d - f);
- }
- }
- return - (d > 0.0);
-}
-
-int
-mpz_cmp_d (const mpz_t x, double d)
-{
- if (x->_mp_size < 0)
- {
- if (d >= 0.0)
- return -1;
- else
- return -mpz_cmpabs_d (x, d);
- }
- else
- {
- if (d < 0.0)
- return 1;
- else
- return mpz_cmpabs_d (x, d);
- }
-}
-
-
-/* MPZ comparisons and the like. */
-int
-mpz_sgn (const mpz_t u)
-{
- mp_size_t usize = u->_mp_size;
-
- if (usize > 0)
- return 1;
- else if (usize < 0)
- return -1;
- else
- return 0;
-}
-
-int
-mpz_cmp_si (const mpz_t u, long v)
-{
- mp_size_t usize = u->_mp_size;
-
- if (usize < -1)
- return -1;
- else if (v >= 0)
- return mpz_cmp_ui (u, v);
- else if (usize >= 0)
- return 1;
- else /* usize == -1 */
- {
- mp_limb_t ul = u->_mp_d[0];
- if ((mp_limb_t)GMP_NEG_CAST (unsigned long int, v) < ul)
- return -1;
- else if ( (mp_limb_t)GMP_NEG_CAST (unsigned long int, v) > ul)
- return 1;
- }
- return 0;
-}
-
-int
-mpz_cmp_ui (const mpz_t u, unsigned long v)
-{
- mp_size_t usize = u->_mp_size;
-
- if (usize > 1)
- return 1;
- else if (usize < 0)
- return -1;
- else
- {
- mp_limb_t ul = (usize > 0) ? u->_mp_d[0] : 0;
- if (ul > v)
- return 1;
- else if (ul < v)
- return -1;
- }
- return 0;
-}
-
-int
-mpz_cmp (const mpz_t a, const mpz_t b)
-{
- mp_size_t asize = a->_mp_size;
- mp_size_t bsize = b->_mp_size;
-
- if (asize > bsize)
- return 1;
- else if (asize < bsize)
- return -1;
- else if (asize > 0)
- return mpn_cmp (a->_mp_d, b->_mp_d, asize);
- else if (asize < 0)
- return -mpn_cmp (a->_mp_d, b->_mp_d, -asize);
- else
- return 0;
-}
-
-int
-mpz_cmpabs_ui (const mpz_t u, unsigned long v)
-{
- mp_size_t un = GMP_ABS (u->_mp_size);
- mp_limb_t ul;
-
- if (un > 1)
- return 1;
-
- ul = (un == 1) ? u->_mp_d[0] : 0;
-
- if (ul > v)
- return 1;
- else if (ul < v)
- return -1;
- else
- return 0;
-}
-
-int
-mpz_cmpabs (const mpz_t u, const mpz_t v)
-{
- return mpn_cmp4 (u->_mp_d, GMP_ABS (u->_mp_size),
- v->_mp_d, GMP_ABS (v->_mp_size));
-}
-
-void
-mpz_abs (mpz_t r, const mpz_t u)
-{
- if (r != u)
- mpz_set (r, u);
-
- r->_mp_size = GMP_ABS (r->_mp_size);
-}
-
-void
-mpz_neg (mpz_t r, const mpz_t u)
-{
- if (r != u)
- mpz_set (r, u);
-
- r->_mp_size = -r->_mp_size;
-}
-
-void
-mpz_swap (mpz_t u, mpz_t v)
-{
- MP_SIZE_T_SWAP (u->_mp_size, v->_mp_size);
- MP_SIZE_T_SWAP (u->_mp_alloc, v->_mp_alloc);
- MP_PTR_SWAP (u->_mp_d, v->_mp_d);
-}
-
-
-/* MPZ addition and subtraction */
-
-/* Adds to the absolute value. Returns new size, but doesn't store it. */
-static mp_size_t
-mpz_abs_add_ui (mpz_t r, const mpz_t a, unsigned long b)
-{
- mp_size_t an;
- mp_ptr rp;
- mp_limb_t cy;
-
- an = GMP_ABS (a->_mp_size);
- if (an == 0)
- {
- r->_mp_d[0] = b;
- return b > 0;
- }
-
- rp = MPZ_REALLOC (r, an + 1);
-
- cy = mpn_add_1 (rp, a->_mp_d, an, b);
- rp[an] = cy;
- an += (cy > 0);
-
- return an;
-}
-
-/* Subtract from the absolute value. Returns new size, (or -1 on underflow),
- but doesn't store it. */
-static mp_size_t
-mpz_abs_sub_ui (mpz_t r, const mpz_t a, unsigned long b)
-{
- mp_size_t an = GMP_ABS (a->_mp_size);
- mp_ptr rp = MPZ_REALLOC (r, an);
-
- if (an == 0)
- {
- rp[0] = b;
- return -(b > 0);
- }
- else if (an == 1 && a->_mp_d[0] < b)
- {
- rp[0] = b - a->_mp_d[0];
- return -1;
- }
- else
- {
- gmp_assert_nocarry (mpn_sub_1 (rp, a->_mp_d, an, b));
- return mpn_normalized_size (rp, an);
- }
-}
-
-void
-mpz_add_ui (mpz_t r, const mpz_t a, unsigned long b)
-{
- if (a->_mp_size >= 0)
- r->_mp_size = mpz_abs_add_ui (r, a, b);
- else
- r->_mp_size = -mpz_abs_sub_ui (r, a, b);
-}
-
-void
-mpz_sub_ui (mpz_t r, const mpz_t a, unsigned long b)
-{
- if (a->_mp_size < 0)
- r->_mp_size = -mpz_abs_add_ui (r, a, b);
- else
- r->_mp_size = mpz_abs_sub_ui (r, a, b);
-}
-
-void
-mpz_ui_sub (mpz_t r, unsigned long a, const mpz_t b)
-{
- if (b->_mp_size < 0)
- r->_mp_size = mpz_abs_add_ui (r, b, a);
- else
- r->_mp_size = -mpz_abs_sub_ui (r, b, a);
-}
-
-static mp_size_t
-mpz_abs_add (mpz_t r, const mpz_t a, const mpz_t b)
-{
- mp_size_t an = GMP_ABS (a->_mp_size);
- mp_size_t bn = GMP_ABS (b->_mp_size);
- mp_size_t rn;
- mp_ptr rp;
- mp_limb_t cy;
-
- rn = GMP_MAX (an, bn);
- rp = MPZ_REALLOC (r, rn + 1);
- if (an >= bn)
- cy = mpn_add (rp, a->_mp_d, an, b->_mp_d, bn);
- else
- cy = mpn_add (rp, b->_mp_d, bn, a->_mp_d, an);
-
- rp[rn] = cy;
-
- return rn + (cy > 0);
-}
-
-static mp_size_t
-mpz_abs_sub (mpz_t r, const mpz_t a, const mpz_t b)
-{
- mp_size_t an = GMP_ABS (a->_mp_size);
- mp_size_t bn = GMP_ABS (b->_mp_size);
- int cmp;
- mp_ptr rp;
-
- cmp = mpn_cmp4 (a->_mp_d, an, b->_mp_d, bn);
- if (cmp > 0)
- {
- rp = MPZ_REALLOC (r, an);
- gmp_assert_nocarry (mpn_sub (rp, a->_mp_d, an, b->_mp_d, bn));
- return mpn_normalized_size (rp, an);
- }
- else if (cmp < 0)
- {
- rp = MPZ_REALLOC (r, bn);
- gmp_assert_nocarry (mpn_sub (rp, b->_mp_d, bn, a->_mp_d, an));
- return -mpn_normalized_size (rp, bn);
- }
- else
- return 0;
-}
-
-void
-mpz_add (mpz_t r, const mpz_t a, const mpz_t b)
-{
- mp_size_t rn;
-
- if ( (a->_mp_size ^ b->_mp_size) >= 0)
- rn = mpz_abs_add (r, a, b);
- else
- rn = mpz_abs_sub (r, a, b);
-
- r->_mp_size = a->_mp_size >= 0 ? rn : - rn;
-}
-
-void
-mpz_sub (mpz_t r, const mpz_t a, const mpz_t b)
-{
- mp_size_t rn;
-
- if ( (a->_mp_size ^ b->_mp_size) >= 0)
- rn = mpz_abs_sub (r, a, b);
- else
- rn = mpz_abs_add (r, a, b);
-
- r->_mp_size = a->_mp_size >= 0 ? rn : - rn;
-}
-
-
-/* MPZ multiplication */
-void
-mpz_mul_si (mpz_t r, const mpz_t u, long int v)
-{
- if (v < 0)
- {
- mpz_mul_ui (r, u, GMP_NEG_CAST (unsigned long int, v));
- mpz_neg (r, r);
- }
- else
- mpz_mul_ui (r, u, (unsigned long int) v);
-}
-
-void
-mpz_mul_ui (mpz_t r, const mpz_t u, unsigned long int v)
-{
- mp_size_t un;
- mpz_t t;
- mp_ptr tp;
- mp_limb_t cy;
-
- un = GMP_ABS (u->_mp_size);
-
- if (un == 0 || v == 0)
- {
- r->_mp_size = 0;
- return;
- }
-
- mpz_init2 (t, (un + 1) * GMP_LIMB_BITS);
-
- tp = t->_mp_d;
- cy = mpn_mul_1 (tp, u->_mp_d, un, v);
- tp[un] = cy;
-
- t->_mp_size = un + (cy > 0);
- if (u->_mp_size < 0)
- t->_mp_size = - t->_mp_size;
-
- mpz_swap (r, t);
- mpz_clear (t);
-}
-
-void
-mpz_mul (mpz_t r, const mpz_t u, const mpz_t v)
-{
- int sign;
- mp_size_t un, vn, rn;
- mpz_t t;
- mp_ptr tp;
-
- un = GMP_ABS (u->_mp_size);
- vn = GMP_ABS (v->_mp_size);
-
- if (un == 0 || vn == 0)
- {
- r->_mp_size = 0;
- return;
- }
-
- sign = (u->_mp_size ^ v->_mp_size) < 0;
-
- mpz_init2 (t, (un + vn) * GMP_LIMB_BITS);
-
- tp = t->_mp_d;
- if (un >= vn)
- mpn_mul (tp, u->_mp_d, un, v->_mp_d, vn);
- else
- mpn_mul (tp, v->_mp_d, vn, u->_mp_d, un);
-
- rn = un + vn;
- rn -= tp[rn-1] == 0;
-
- t->_mp_size = sign ? - rn : rn;
- mpz_swap (r, t);
- mpz_clear (t);
-}
-
-void
-mpz_mul_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bits)
-{
- mp_size_t un, rn;
- mp_size_t limbs;
- unsigned shift;
- mp_ptr rp;
-
- un = GMP_ABS (u->_mp_size);
- if (un == 0)
- {
- r->_mp_size = 0;
- return;
- }
-
- limbs = bits / GMP_LIMB_BITS;
- shift = bits % GMP_LIMB_BITS;
-
- rn = un + limbs + (shift > 0);
- rp = MPZ_REALLOC (r, rn);
- if (shift > 0)
- {
- mp_limb_t cy = mpn_lshift (rp + limbs, u->_mp_d, un, shift);
- rp[rn-1] = cy;
- rn -= (cy == 0);
- }
- else
- mpn_copyd (rp + limbs, u->_mp_d, un);
-
- while (limbs > 0)
- rp[--limbs] = 0;
-
- r->_mp_size = (u->_mp_size < 0) ? - rn : rn;
-}
-
-
-/* MPZ division */
-enum mpz_div_round_mode { GMP_DIV_FLOOR, GMP_DIV_CEIL, GMP_DIV_TRUNC };
-
-/* Allows q or r to be zero. Returns 1 iff remainder is non-zero. */
-static int
-mpz_div_qr (mpz_t q, mpz_t r,
- const mpz_t n, const mpz_t d, enum mpz_div_round_mode mode)
-{
- mp_size_t ns, ds, nn, dn, qs;
- ns = n->_mp_size;
- ds = d->_mp_size;
-
- if (ds == 0)
- gmp_die("mpz_div_qr: Divide by zero.");
-
- if (ns == 0)
- {
- if (q)
- q->_mp_size = 0;
- if (r)
- r->_mp_size = 0;
- return 0;
- }
-
- nn = GMP_ABS (ns);
- dn = GMP_ABS (ds);
-
- qs = ds ^ ns;
-
- if (nn < dn)
- {
- if (mode == GMP_DIV_CEIL && qs >= 0)
- {
- /* q = 1, r = n - d */
- if (r)
- mpz_sub (r, n, d);
- if (q)
- mpz_set_ui (q, 1);
- }
- else if (mode == GMP_DIV_FLOOR && qs < 0)
- {
- /* q = -1, r = n + d */
- if (r)
- mpz_add (r, n, d);
- if (q)
- mpz_set_si (q, -1);
- }
- else
- {
- /* q = 0, r = d */
- if (r)
- mpz_set (r, n);
- if (q)
- q->_mp_size = 0;
- }
- return 1;
- }
- else
- {
- mp_ptr np, qp;
- mp_size_t qn, rn;
- mpz_t tq, tr;
-
- mpz_init (tr);
- mpz_set (tr, n);
- np = tr->_mp_d;
-
- qn = nn - dn + 1;
-
- if (q)
- {
- mpz_init2 (tq, qn * GMP_LIMB_BITS);
- qp = tq->_mp_d;
- }
- else
- qp = NULL;
-
- mpn_div_qr (qp, np, nn, d->_mp_d, dn);
-
- if (qp)
- {
- qn -= (qp[qn-1] == 0);
-
- tq->_mp_size = qs < 0 ? -qn : qn;
- }
- rn = mpn_normalized_size (np, dn);
- tr->_mp_size = ns < 0 ? - rn : rn;
-
- if (mode == GMP_DIV_FLOOR && qs < 0 && rn != 0)
- {
- if (q)
- mpz_sub_ui (tq, tq, 1);
- if (r)
- mpz_add (tr, tr, d);
- }
- else if (mode == GMP_DIV_CEIL && qs >= 0 && rn != 0)
- {
- if (q)
- mpz_add_ui (tq, tq, 1);
- if (r)
- mpz_sub (tr, tr, d);
- }
-
- if (q)
- {
- mpz_swap (tq, q);
- mpz_clear (tq);
- }
- if (r)
- mpz_swap (tr, r);
-
- mpz_clear (tr);
-
- return rn != 0;
- }
-}
-
-void
-mpz_cdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
-{
- mpz_div_qr (q, r, n, d, GMP_DIV_CEIL);
-}
-
-void
-mpz_fdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
-{
- mpz_div_qr (q, r, n, d, GMP_DIV_FLOOR);
-}
-
-void
-mpz_tdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
-{
- mpz_div_qr (q, r, n, d, GMP_DIV_TRUNC);
-}
-
-void
-mpz_cdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
-{
- mpz_div_qr (q, NULL, n, d, GMP_DIV_CEIL);
-}
-
-void
-mpz_fdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
-{
- mpz_div_qr (q, NULL, n, d, GMP_DIV_FLOOR);
-}
-
-void
-mpz_tdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
-{
- mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC);
-}
-
-void
-mpz_cdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
-{
- mpz_div_qr (NULL, r, n, d, GMP_DIV_CEIL);
-}
-
-void
-mpz_fdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
-{
- mpz_div_qr (NULL, r, n, d, GMP_DIV_FLOOR);
-}
-
-void
-mpz_tdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
-{
- mpz_div_qr (NULL, r, n, d, GMP_DIV_TRUNC);
-}
-
-void
-mpz_mod (mpz_t r, const mpz_t n, const mpz_t d)
-{
- if (d->_mp_size >= 0)
- mpz_div_qr (NULL, r, n, d, GMP_DIV_FLOOR);
- else
- mpz_div_qr (NULL, r, n, d, GMP_DIV_CEIL);
-}
-
-static void
-mpz_div_q_2exp (mpz_t q, const mpz_t u, mp_bitcnt_t bit_index,
- enum mpz_div_round_mode mode)
-{
- mp_size_t un, qn;
- mp_size_t limb_cnt;
- mp_ptr qp;
- mp_limb_t adjust;
-
- un = u->_mp_size;
- if (un == 0)
- {
- q->_mp_size = 0;
- return;
- }
- limb_cnt = bit_index / GMP_LIMB_BITS;
- qn = GMP_ABS (un) - limb_cnt;
- bit_index %= GMP_LIMB_BITS;
-
- if (mode == ((un > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* un != 0 here. */
- /* Note: Below, the final indexing at limb_cnt is valid because at
- that point we have qn > 0. */
- adjust = (qn <= 0
- || !mpn_zero_p (u->_mp_d, limb_cnt)
- || (u->_mp_d[limb_cnt]
- & (((mp_limb_t) 1 << bit_index) - 1)));
- else
- adjust = 0;
-
- if (qn <= 0)
- qn = 0;
-
- else
- {
- qp = MPZ_REALLOC (q, qn);
-
- if (bit_index != 0)
- {
- mpn_rshift (qp, u->_mp_d + limb_cnt, qn, bit_index);
- qn -= qp[qn - 1] == 0;
- }
- else
- {
- mpn_copyi (qp, u->_mp_d + limb_cnt, qn);
- }
- }
-
- q->_mp_size = qn;
-
- mpz_add_ui (q, q, adjust);
- if (un < 0)
- mpz_neg (q, q);
-}
-
-static void
-mpz_div_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bit_index,
- enum mpz_div_round_mode mode)
-{
- mp_size_t us, un, rn;
- mp_ptr rp;
- mp_limb_t mask;
-
- us = u->_mp_size;
- if (us == 0 || bit_index == 0)
- {
- r->_mp_size = 0;
- return;
- }
- rn = (bit_index + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
- assert (rn > 0);
-
- rp = MPZ_REALLOC (r, rn);
- un = GMP_ABS (us);
-
- mask = GMP_LIMB_MAX >> (rn * GMP_LIMB_BITS - bit_index);
-
- if (rn > un)
- {
- /* Quotient (with truncation) is zero, and remainder is
- non-zero */
- if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */
- {
- /* Have to negate and sign extend. */
- mp_size_t i;
- mp_limb_t cy;
-
- for (cy = 1, i = 0; i < un; i++)
- {
- mp_limb_t s = ~u->_mp_d[i] + cy;
- cy = s < cy;
- rp[i] = s;
- }
- assert (cy == 0);
- for (; i < rn - 1; i++)
- rp[i] = GMP_LIMB_MAX;
-
- rp[rn-1] = mask;
- us = -us;
- }
- else
- {
- /* Just copy */
- if (r != u)
- mpn_copyi (rp, u->_mp_d, un);
-
- rn = un;
- }
- }
- else
- {
- if (r != u)
- mpn_copyi (rp, u->_mp_d, rn - 1);
-
- rp[rn-1] = u->_mp_d[rn-1] & mask;
-
- if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */
- {
- /* If r != 0, compute 2^{bit_count} - r. */
- mp_size_t i;
-
- for (i = 0; i < rn && rp[i] == 0; i++)
- ;
- if (i < rn)
- {
- /* r > 0, need to flip sign. */
- rp[i] = ~rp[i] + 1;
- for (i++; i < rn; i++)
- rp[i] = ~rp[i];
-
- rp[rn-1] &= mask;
-
- /* us is not used for anything else, so we can modify it
- here to indicate flipped sign. */
- us = -us;
- }
- }
- }
- rn = mpn_normalized_size (rp, rn);
- r->_mp_size = us < 0 ? -rn : rn;
-}
-
-void
-mpz_cdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
-{
- mpz_div_q_2exp (r, u, cnt, GMP_DIV_CEIL);
-}
-
-void
-mpz_fdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
-{
- mpz_div_q_2exp (r, u, cnt, GMP_DIV_FLOOR);
-}
-
-void
-mpz_tdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
-{
- mpz_div_q_2exp (r, u, cnt, GMP_DIV_TRUNC);
-}
-
-void
-mpz_cdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
-{
- mpz_div_r_2exp (r, u, cnt, GMP_DIV_CEIL);
-}
-
-void
-mpz_fdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
-{
- mpz_div_r_2exp (r, u, cnt, GMP_DIV_FLOOR);
-}
-
-void
-mpz_tdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
-{
- mpz_div_r_2exp (r, u, cnt, GMP_DIV_TRUNC);
-}
-
-void
-mpz_divexact (mpz_t q, const mpz_t n, const mpz_t d)
-{
- gmp_assert_nocarry (mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC));
-}
-
-int
-mpz_divisible_p (const mpz_t n, const mpz_t d)
-{
- return mpz_div_qr (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0;
-}
-
-static unsigned long
-mpz_div_qr_ui (mpz_t q, mpz_t r,
- const mpz_t n, unsigned long d, enum mpz_div_round_mode mode)
-{
- mp_size_t ns, qn;
- mp_ptr qp;
- mp_limb_t rl;
- mp_size_t rs;
-
- ns = n->_mp_size;
- if (ns == 0)
- {
- if (q)
- q->_mp_size = 0;
- if (r)
- r->_mp_size = 0;
- return 0;
- }
-
- qn = GMP_ABS (ns);
- if (q)
- qp = MPZ_REALLOC (q, qn);
- else
- qp = NULL;
-
- rl = mpn_div_qr_1 (qp, n->_mp_d, qn, d);
- assert (rl < d);
-
- rs = rl > 0;
- rs = (ns < 0) ? -rs : rs;
-
- if (rl > 0 && ( (mode == GMP_DIV_FLOOR && ns < 0)
- || (mode == GMP_DIV_CEIL && ns >= 0)))
- {
- if (q)
- gmp_assert_nocarry (mpn_add_1 (qp, qp, qn, 1));
- rl = d - rl;
- rs = -rs;
- }
-
- if (r)
- {
- r->_mp_d[0] = rl;
- r->_mp_size = rs;
- }
- if (q)
- {
- qn -= (qp[qn-1] == 0);
- assert (qn == 0 || qp[qn-1] > 0);
-
- q->_mp_size = (ns < 0) ? - qn : qn;
- }
-
- return rl;
-}
-
-unsigned long
-mpz_cdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
-{
- return mpz_div_qr_ui (q, r, n, d, GMP_DIV_CEIL);
-}
-
-unsigned long
-mpz_fdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
-{
- return mpz_div_qr_ui (q, r, n, d, GMP_DIV_FLOOR);
-}
-
-unsigned long
-mpz_tdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
-{
- return mpz_div_qr_ui (q, r, n, d, GMP_DIV_TRUNC);
-}
-
-unsigned long
-mpz_cdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
-{
- return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_CEIL);
-}
-
-unsigned long
-mpz_fdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
-{
- return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_FLOOR);
-}
-
-unsigned long
-mpz_tdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
-{
- return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC);
-}
-
-unsigned long
-mpz_cdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
-{
- return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_CEIL);
-}
-unsigned long
-mpz_fdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
-{
- return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR);
-}
-unsigned long
-mpz_tdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
-{
- return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_TRUNC);
-}
-
-unsigned long
-mpz_cdiv_ui (const mpz_t n, unsigned long d)
-{
- return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_CEIL);
-}
-
-unsigned long
-mpz_fdiv_ui (const mpz_t n, unsigned long d)
-{
- return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_FLOOR);
-}
-
-unsigned long
-mpz_tdiv_ui (const mpz_t n, unsigned long d)
-{
- return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC);
-}
-
-unsigned long
-mpz_mod_ui (mpz_t r, const mpz_t n, unsigned long d)
-{
- return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR);
-}
-
-void
-mpz_divexact_ui (mpz_t q, const mpz_t n, unsigned long d)
-{
- gmp_assert_nocarry (mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC));
-}
-
-int
-mpz_divisible_ui_p (const mpz_t n, unsigned long d)
-{
- return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0;
-}
-
-
-/* GCD */
-static mp_limb_t
-mpn_gcd_11 (mp_limb_t u, mp_limb_t v)
-{
- unsigned shift;
-
- assert ( (u | v) > 0);
-
- if (u == 0)
- return v;
- else if (v == 0)
- return u;
-
- gmp_ctz (shift, u | v);
-
- u >>= shift;
- v >>= shift;
-
- if ( (u & 1) == 0)
- MP_LIMB_T_SWAP (u, v);
-
- while ( (v & 1) == 0)
- v >>= 1;
-
- while (u != v)
- {
- if (u > v)
- {
- u -= v;
- do
- u >>= 1;
- while ( (u & 1) == 0);
- }
- else
- {
- v -= u;
- do
- v >>= 1;
- while ( (v & 1) == 0);
- }
- }
- return u << shift;
-}
-
-unsigned long
-mpz_gcd_ui (mpz_t g, const mpz_t u, unsigned long v)
-{
- mp_size_t un;
-
- if (v == 0)
- {
- if (g)
- mpz_abs (g, u);
- }
- else
- {
- un = GMP_ABS (u->_mp_size);
- if (un != 0)
- v = mpn_gcd_11 (mpn_div_qr_1 (NULL, u->_mp_d, un, v), v);
-
- if (g)
- mpz_set_ui (g, v);
- }
-
- return v;
-}
-
-static mp_bitcnt_t
-mpz_make_odd (mpz_t r, const mpz_t u)
-{
- mp_size_t un, rn, i;
- mp_ptr rp;
- unsigned shift;
-
- un = GMP_ABS (u->_mp_size);
- assert (un > 0);
-
- for (i = 0; u->_mp_d[i] == 0; i++)
- ;
-
- gmp_ctz (shift, u->_mp_d[i]);
-
- rn = un - i;
- rp = MPZ_REALLOC (r, rn);
- if (shift > 0)
- {
- mpn_rshift (rp, u->_mp_d + i, rn, shift);
- rn -= (rp[rn-1] == 0);
- }
- else
- mpn_copyi (rp, u->_mp_d + i, rn);
-
- r->_mp_size = rn;
- return i * GMP_LIMB_BITS + shift;
-}
-
-void
-mpz_gcd (mpz_t g, const mpz_t u, const mpz_t v)
-{
- mpz_t tu, tv;
- mp_bitcnt_t uz, vz, gz;
-
- if (u->_mp_size == 0)
- {
- mpz_abs (g, v);
- return;
- }
- if (v->_mp_size == 0)
- {
- mpz_abs (g, u);
- return;
- }
-
- mpz_init (tu);
- mpz_init (tv);
-
- uz = mpz_make_odd (tu, u);
- vz = mpz_make_odd (tv, v);
- gz = GMP_MIN (uz, vz);
-
- if (tu->_mp_size < tv->_mp_size)
- mpz_swap (tu, tv);
-
- mpz_tdiv_r (tu, tu, tv);
- if (tu->_mp_size == 0)
- {
- mpz_swap (g, tv);
- }
- else
- for (;;)
- {
- int c;
-
- mpz_make_odd (tu, tu);
- c = mpz_cmp (tu, tv);
- if (c == 0)
- {
- mpz_swap (g, tu);
- break;
- }
- if (c < 0)
- mpz_swap (tu, tv);
-
- if (tv->_mp_size == 1)
- {
- mp_limb_t vl = tv->_mp_d[0];
- mp_limb_t ul = mpz_tdiv_ui (tu, vl);
- mpz_set_ui (g, mpn_gcd_11 (ul, vl));
- break;
- }
- mpz_sub (tu, tu, tv);
- }
- mpz_clear (tu);
- mpz_clear (tv);
- mpz_mul_2exp (g, g, gz);
-}
-
-void
-mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v)
-{
- mpz_t tu, tv, s0, s1, t0, t1;
- mp_bitcnt_t uz, vz, gz;
- mp_bitcnt_t power;
-
- if (u->_mp_size == 0)
- {
- /* g = 0 u + sgn(v) v */
- signed long sign = mpz_sgn (v);
- mpz_abs (g, v);
- if (s)
- mpz_set_ui (s, 0);
- if (t)
- mpz_set_si (t, sign);
- return;
- }
-
- if (v->_mp_size == 0)
- {
- /* g = sgn(u) u + 0 v */
- signed long sign = mpz_sgn (u);
- mpz_abs (g, u);
- if (s)
- mpz_set_si (s, sign);
- if (t)
- mpz_set_ui (t, 0);
- return;
- }
-
- mpz_init (tu);
- mpz_init (tv);
- mpz_init (s0);
- mpz_init (s1);
- mpz_init (t0);
- mpz_init (t1);
-
- uz = mpz_make_odd (tu, u);
- vz = mpz_make_odd (tv, v);
- gz = GMP_MIN (uz, vz);
-
- uz -= gz;
- vz -= gz;
-
- /* Cofactors corresponding to odd gcd. gz handled later. */
- if (tu->_mp_size < tv->_mp_size)
- {
- mpz_swap (tu, tv);
- MPZ_SRCPTR_SWAP (u, v);
- MPZ_PTR_SWAP (s, t);
- MP_BITCNT_T_SWAP (uz, vz);
- }
-
- /* Maintain
- *
- * u = t0 tu + t1 tv
- * v = s0 tu + s1 tv
- *
- * where u and v denote the inputs with common factors of two
- * eliminated, and det (s0, t0; s1, t1) = 2^p. Then
- *
- * 2^p tu = s1 u - t1 v
- * 2^p tv = -s0 u + t0 v
- */
-
- /* After initial division, tu = q tv + tu', we have
- *
- * u = 2^uz (tu' + q tv)
- * v = 2^vz tv
- *
- * or
- *
- * t0 = 2^uz, t1 = 2^uz q
- * s0 = 0, s1 = 2^vz
- */
-
- mpz_setbit (t0, uz);
- mpz_tdiv_qr (t1, tu, tu, tv);
- mpz_mul_2exp (t1, t1, uz);
-
- mpz_setbit (s1, vz);
- power = uz + vz;
-
- if (tu->_mp_size > 0)
- {
- mp_bitcnt_t shift;
- shift = mpz_make_odd (tu, tu);
- mpz_mul_2exp (t0, t0, shift);
- mpz_mul_2exp (s0, s0, shift);
- power += shift;
-
- for (;;)
- {
- int c;
- c = mpz_cmp (tu, tv);
- if (c == 0)
- break;
-
- if (c < 0)
- {
- /* tv = tv' + tu
- *
- * u = t0 tu + t1 (tv' + tu) = (t0 + t1) tu + t1 tv'
- * v = s0 tu + s1 (tv' + tu) = (s0 + s1) tu + s1 tv' */
-
- mpz_sub (tv, tv, tu);
- mpz_add (t0, t0, t1);
- mpz_add (s0, s0, s1);
-
- shift = mpz_make_odd (tv, tv);
- mpz_mul_2exp (t1, t1, shift);
- mpz_mul_2exp (s1, s1, shift);
- }
- else
- {
- mpz_sub (tu, tu, tv);
- mpz_add (t1, t0, t1);
- mpz_add (s1, s0, s1);
-
- shift = mpz_make_odd (tu, tu);
- mpz_mul_2exp (t0, t0, shift);
- mpz_mul_2exp (s0, s0, shift);
- }
- power += shift;
- }
- }
-
- /* Now tv = odd part of gcd, and -s0 and t0 are corresponding
- cofactors. */
-
- mpz_mul_2exp (tv, tv, gz);
- mpz_neg (s0, s0);
-
- /* 2^p g = s0 u + t0 v. Eliminate one factor of two at a time. To
- adjust cofactors, we need u / g and v / g */
-
- mpz_divexact (s1, v, tv);
- mpz_abs (s1, s1);
- mpz_divexact (t1, u, tv);
- mpz_abs (t1, t1);
-
- while (power-- > 0)
- {
- /* s0 u + t0 v = (s0 - v/g) u - (t0 + u/g) v */
- if (mpz_odd_p (s0) || mpz_odd_p (t0))
- {
- mpz_sub (s0, s0, s1);
- mpz_add (t0, t0, t1);
- }
- mpz_divexact_ui (s0, s0, 2);
- mpz_divexact_ui (t0, t0, 2);
- }
-
- /* Arrange so that |s| < |u| / 2g */
- mpz_add (s1, s0, s1);
- if (mpz_cmpabs (s0, s1) > 0)
- {
- mpz_swap (s0, s1);
- mpz_sub (t0, t0, t1);
- }
- if (u->_mp_size < 0)
- mpz_neg (s0, s0);
- if (v->_mp_size < 0)
- mpz_neg (t0, t0);
-
- mpz_swap (g, tv);
- if (s)
- mpz_swap (s, s0);
- if (t)
- mpz_swap (t, t0);
-
- mpz_clear (tu);
- mpz_clear (tv);
- mpz_clear (s0);
- mpz_clear (s1);
- mpz_clear (t0);
- mpz_clear (t1);
-}
-
-void
-mpz_lcm (mpz_t r, const mpz_t u, const mpz_t v)
-{
- mpz_t g;
-
- if (u->_mp_size == 0 || v->_mp_size == 0)
- {
- r->_mp_size = 0;
- return;
- }
-
- mpz_init (g);
-
- mpz_gcd (g, u, v);
- mpz_divexact (g, u, g);
- mpz_mul (r, g, v);
-
- mpz_clear (g);
- mpz_abs (r, r);
-}
-
-void
-mpz_lcm_ui (mpz_t r, const mpz_t u, unsigned long v)
-{
- if (v == 0 || u->_mp_size == 0)
- {
- r->_mp_size = 0;
- return;
- }
-
- v /= mpz_gcd_ui (NULL, u, v);
- mpz_mul_ui (r, u, v);
-
- mpz_abs (r, r);
-}
-
-int
-mpz_invert (mpz_t r, const mpz_t u, const mpz_t m)
-{
- mpz_t g, tr;
- int invertible;
-
- if (u->_mp_size == 0 || mpz_cmpabs_ui (m, 1) <= 0)
- return 0;
-
- mpz_init (g);
- mpz_init (tr);
-
- mpz_gcdext (g, tr, NULL, u, m);
- invertible = (mpz_cmp_ui (g, 1) == 0);
-
- if (invertible)
- {
- if (tr->_mp_size < 0)
- {
- if (m->_mp_size >= 0)
- mpz_add (tr, tr, m);
- else
- mpz_sub (tr, tr, m);
- }
- mpz_swap (r, tr);
- }
-
- mpz_clear (g);
- mpz_clear (tr);
- return invertible;
-}
-
-
-/* Higher level operations (sqrt, pow and root) */
-
-void
-mpz_pow_ui (mpz_t r, const mpz_t b, unsigned long e)
-{
- unsigned long bit;
- mpz_t tr;
- mpz_init_set_ui (tr, 1);
-
- for (bit = GMP_ULONG_HIGHBIT; bit > 0; bit >>= 1)
- {
- mpz_mul (tr, tr, tr);
- if (e & bit)
- mpz_mul (tr, tr, b);
- }
- mpz_swap (r, tr);
- mpz_clear (tr);
-}
-
-void
-mpz_ui_pow_ui (mpz_t r, unsigned long blimb, unsigned long e)
-{
- mpz_t b;
- mpz_init_set_ui (b, blimb);
- mpz_pow_ui (r, b, e);
- mpz_clear (b);
-}
-
-void
-mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m)
-{
- mpz_t tr;
- mpz_t base;
- mp_size_t en, mn;
- mp_srcptr mp;
- struct gmp_div_inverse minv;
- unsigned shift;
- mp_ptr tp = NULL;
-
- en = GMP_ABS (e->_mp_size);
- mn = GMP_ABS (m->_mp_size);
- if (mn == 0)
- gmp_die ("mpz_powm: Zero modulo.");
-
- if (en == 0)
- {
- mpz_set_ui (r, 1);
- return;
- }
-
- mp = m->_mp_d;
- mpn_div_qr_invert (&minv, mp, mn);
- shift = minv.shift;
-
- if (shift > 0)
- {
- /* To avoid shifts, we do all our reductions, except the final
- one, using a *normalized* m. */
- minv.shift = 0;
-
- tp = gmp_xalloc_limbs (mn);
- gmp_assert_nocarry (mpn_lshift (tp, mp, mn, shift));
- mp = tp;
- }
-
- mpz_init (base);
-
- if (e->_mp_size < 0)
- {
- if (!mpz_invert (base, b, m))
- gmp_die ("mpz_powm: Negative exponent and non-invertibe base.");
- }
- else
- {
- mp_size_t bn;
- mpz_abs (base, b);
-
- bn = base->_mp_size;
- if (bn >= mn)
- {
- mpn_div_qr_preinv (NULL, base->_mp_d, base->_mp_size, mp, mn, &minv);
- bn = mn;
- }
-
- /* We have reduced the absolute value. Now take care of the
- sign. Note that we get zero represented non-canonically as
- m. */
- if (b->_mp_size < 0)
- {
- mp_ptr bp = MPZ_REALLOC (base, mn);
- gmp_assert_nocarry (mpn_sub (bp, mp, mn, bp, bn));
- bn = mn;
- }
- base->_mp_size = mpn_normalized_size (base->_mp_d, bn);
- }
- mpz_init_set_ui (tr, 1);
-
- while (en-- > 0)
- {
- mp_limb_t w = e->_mp_d[en];
- mp_limb_t bit;
-
- for (bit = GMP_LIMB_HIGHBIT; bit > 0; bit >>= 1)
- {
- mpz_mul (tr, tr, tr);
- if (w & bit)
- mpz_mul (tr, tr, base);
- if (tr->_mp_size > mn)
- {
- mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv);
- tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn);
- }
- }
- }
-
- /* Final reduction */
- if (tr->_mp_size >= mn)
- {
- minv.shift = shift;
- mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv);
- tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn);
- }
- if (tp)
- gmp_free (tp);
-
- mpz_swap (r, tr);
- mpz_clear (tr);
- mpz_clear (base);
-}
-
-void
-mpz_powm_ui (mpz_t r, const mpz_t b, unsigned long elimb, const mpz_t m)
-{
- mpz_t e;
- mpz_init_set_ui (e, elimb);
- mpz_powm (r, b, e, m);
- mpz_clear (e);
-}
-
-/* x=trunc(y^(1/z)), r=y-x^z */
-void
-mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z)
-{
- int sgn;
- mpz_t t, u;
-
- sgn = y->_mp_size < 0;
- if (sgn && (z & 1) == 0)
- gmp_die ("mpz_rootrem: Negative argument, with even root.");
- if (z == 0)
- gmp_die ("mpz_rootrem: Zeroth root.");
-
- if (mpz_cmpabs_ui (y, 1) <= 0) {
- mpz_set (x, y);
- if (r)
- r->_mp_size = 0;
- return;
- }
-
- mpz_init (t);
- mpz_init (u);
- mpz_setbit (t, mpz_sizeinbase (y, 2) / z + 1);
-
- if (z == 2) /* simplify sqrt loop: z-1 == 1 */
- do {
- mpz_swap (u, t); /* u = x */
- mpz_tdiv_q (t, y, u); /* t = y/x */
- mpz_add (t, t, u); /* t = y/x + x */
- mpz_tdiv_q_2exp (t, t, 1); /* x'= (y/x + x)/2 */
- } while (mpz_cmpabs (t, u) < 0); /* |x'| < |x| */
- else /* z != 2 */ {
- mpz_t v;
-
- mpz_init (v);
- if (sgn)
- mpz_neg (t, t);
-
- do {
- mpz_swap (u, t); /* u = x */
- mpz_pow_ui (t, u, z - 1); /* t = x^(z-1) */
- mpz_tdiv_q (t, y, t); /* t = y/x^(z-1) */
- mpz_mul_ui (v, u, z - 1); /* v = x*(z-1) */
- mpz_add (t, t, v); /* t = y/x^(z-1) + x*(z-1) */
- mpz_tdiv_q_ui (t, t, z); /* x'=(y/x^(z-1) + x*(z-1))/z */
- } while (mpz_cmpabs (t, u) < 0); /* |x'| < |x| */
-
- mpz_clear (v);
- }
-
- if (r) {
- mpz_pow_ui (t, u, z);
- mpz_sub (r, y, t);
- }
- mpz_swap (x, u);
- mpz_clear (u);
- mpz_clear (t);
-}
-
-int
-mpz_root (mpz_t x, const mpz_t y, unsigned long z)
-{
- int res;
- mpz_t r;
-
- mpz_init (r);
- mpz_rootrem (x, r, y, z);
- res = r->_mp_size == 0;
- mpz_clear (r);
-
- return res;
-}
-
-/* Compute s = floor(sqrt(u)) and r = u - s^2. Allows r == NULL */
-void
-mpz_sqrtrem (mpz_t s, mpz_t r, const mpz_t u)
-{
- mpz_rootrem (s, r, u, 2);
-}
-
-void
-mpz_sqrt (mpz_t s, const mpz_t u)
-{
- mpz_rootrem (s, NULL, u, 2);
-}
-
-
-/* Combinatorics */
-
-void
-mpz_fac_ui (mpz_t x, unsigned long n)
-{
- if (n < 2) {
- mpz_set_ui (x, 1);
- return;
- }
- mpz_set_ui (x, n);
- for (;--n > 1;)
- mpz_mul_ui (x, x, n);
-}
-
-void
-mpz_bin_uiui (mpz_t r, unsigned long n, unsigned long k)
-{
- mpz_t t;
-
- if (k > n) {
- r->_mp_size = 0;
- return;
- }
- mpz_fac_ui (r, n);
- mpz_init (t);
- mpz_fac_ui (t, k);
- mpz_divexact (r, r, t);
- mpz_fac_ui (t, n - k);
- mpz_divexact (r, r, t);
- mpz_clear (t);
-}
-
-
-/* Logical operations and bit manipulation. */
-
-/* Numbers are treated as if represented in two's complement (and
- infinitely sign extended). For a negative values we get the two's
- complement from -x = ~x + 1, where ~ is bitwise complementt.
- Negation transforms
-
- xxxx10...0
-
- into
-
- yyyy10...0
-
- where yyyy is the bitwise complement of xxxx. So least significant
- bits, up to and including the first one bit, are unchanged, and
- the more significant bits are all complemented.
-
- To change a bit from zero to one in a negative number, subtract the
- corresponding power of two from the absolute value. This can never
- underflow. To change a bit from one to zero, add the corresponding
- power of two, and this might overflow. E.g., if x = -001111, the
- two's complement is 110001. Clearing the least significant bit, we
- get two's complement 110000, and -010000. */
-
-int
-mpz_tstbit (const mpz_t d, mp_bitcnt_t bit_index)
-{
- mp_size_t limb_index;
- unsigned shift;
- mp_size_t ds;
- mp_size_t dn;
- mp_limb_t w;
- int bit;
-
- ds = d->_mp_size;
- dn = GMP_ABS (ds);
- limb_index = bit_index / GMP_LIMB_BITS;
- if (limb_index >= dn)
- return ds < 0;
-
- shift = bit_index % GMP_LIMB_BITS;
- w = d->_mp_d[limb_index];
- bit = (w >> shift) & 1;
-
- if (ds < 0)
- {
- /* d < 0. Check if any of the bits below is set: If so, our bit
- must be complemented. */
- if (shift > 0 && (w << (GMP_LIMB_BITS - shift)) > 0)
- return bit ^ 1;
- while (limb_index-- > 0)
- if (d->_mp_d[limb_index] > 0)
- return bit ^ 1;
- }
- return bit;
-}
-
-static void
-mpz_abs_add_bit (mpz_t d, mp_bitcnt_t bit_index)
-{
- mp_size_t dn, limb_index;
- mp_limb_t bit;
- mp_ptr dp;
-
- dn = GMP_ABS (d->_mp_size);
-
- limb_index = bit_index / GMP_LIMB_BITS;
- bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS);
-
- if (limb_index >= dn)
- {
- mp_size_t i;
- /* The bit should be set outside of the end of the number.
- We have to increase the size of the number. */
- dp = MPZ_REALLOC (d, limb_index + 1);
-
- dp[limb_index] = bit;
- for (i = dn; i < limb_index; i++)
- dp[i] = 0;
- dn = limb_index + 1;
- }
- else
- {
- mp_limb_t cy;
-
- dp = d->_mp_d;
-
- cy = mpn_add_1 (dp + limb_index, dp + limb_index, dn - limb_index, bit);
- if (cy > 0)
- {
- dp = MPZ_REALLOC (d, dn + 1);
- dp[dn++] = cy;
- }
- }
-
- d->_mp_size = (d->_mp_size < 0) ? - dn : dn;
-}
-
-static void
-mpz_abs_sub_bit (mpz_t d, mp_bitcnt_t bit_index)
-{
- mp_size_t dn, limb_index;
- mp_ptr dp;
- mp_limb_t bit;
-
- dn = GMP_ABS (d->_mp_size);
- dp = d->_mp_d;
-
- limb_index = bit_index / GMP_LIMB_BITS;
- bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS);
-
- assert (limb_index < dn);
-
- gmp_assert_nocarry (mpn_sub_1 (dp + limb_index, dp + limb_index,
- dn - limb_index, bit));
- dn -= (dp[dn-1] == 0);
- d->_mp_size = (d->_mp_size < 0) ? - dn : dn;
-}
-
-void
-mpz_setbit (mpz_t d, mp_bitcnt_t bit_index)
-{
- if (!mpz_tstbit (d, bit_index))
- {
- if (d->_mp_size >= 0)
- mpz_abs_add_bit (d, bit_index);
- else
- mpz_abs_sub_bit (d, bit_index);
- }
-}
-
-void
-mpz_clrbit (mpz_t d, mp_bitcnt_t bit_index)
-{
- if (mpz_tstbit (d, bit_index))
- {
- if (d->_mp_size >= 0)
- mpz_abs_sub_bit (d, bit_index);
- else
- mpz_abs_add_bit (d, bit_index);
- }
-}
-
-void
-mpz_combit (mpz_t d, mp_bitcnt_t bit_index)
-{
- if (mpz_tstbit (d, bit_index) ^ (d->_mp_size < 0))
- mpz_abs_sub_bit (d, bit_index);
- else
- mpz_abs_add_bit (d, bit_index);
-}
-
-void
-mpz_com (mpz_t r, const mpz_t u)
-{
- mpz_neg (r, u);
- mpz_sub_ui (r, r, 1);
-}
-
-void
-mpz_and (mpz_t r, const mpz_t u, const mpz_t v)
-{
- mp_size_t un, vn, rn, i;
- mp_ptr up, vp, rp;
-
- mp_limb_t ux, vx, rx;
- mp_limb_t uc, vc, rc;
- mp_limb_t ul, vl, rl;
-
- un = GMP_ABS (u->_mp_size);
- vn = GMP_ABS (v->_mp_size);
- if (un < vn)
- {
- MPZ_SRCPTR_SWAP (u, v);
- MP_SIZE_T_SWAP (un, vn);
- }
- if (vn == 0)
- {
- r->_mp_size = 0;
- return;
- }
-
- uc = u->_mp_size < 0;
- vc = v->_mp_size < 0;
- rc = uc & vc;
-
- ux = -uc;
- vx = -vc;
- rx = -rc;
-
- /* If the smaller input is positive, higher limbs don't matter. */
- rn = vx ? un : vn;
-
- rp = MPZ_REALLOC (r, rn + rc);
-
- up = u->_mp_d;
- vp = v->_mp_d;
-
- for (i = 0; i < vn; i++)
- {
- ul = (up[i] ^ ux) + uc;
- uc = ul < uc;
-
- vl = (vp[i] ^ vx) + vc;
- vc = vl < vc;
-
- rl = ( (ul & vl) ^ rx) + rc;
- rc = rl < rc;
- rp[i] = rl;
- }
- assert (vc == 0);
-
- for (; i < rn; i++)
- {
- ul = (up[i] ^ ux) + uc;
- uc = ul < uc;
-
- rl = ( (ul & vx) ^ rx) + rc;
- rc = rl < rc;
- rp[i] = rl;
- }
- if (rc)
- rp[rn++] = rc;
- else
- rn = mpn_normalized_size (rp, rn);
-
- r->_mp_size = rx ? -rn : rn;
-}
-
-void
-mpz_ior (mpz_t r, const mpz_t u, const mpz_t v)
-{
- mp_size_t un, vn, rn, i;
- mp_ptr up, vp, rp;
-
- mp_limb_t ux, vx, rx;
- mp_limb_t uc, vc, rc;
- mp_limb_t ul, vl, rl;
-
- un = GMP_ABS (u->_mp_size);
- vn = GMP_ABS (v->_mp_size);
- if (un < vn)
- {
- MPZ_SRCPTR_SWAP (u, v);
- MP_SIZE_T_SWAP (un, vn);
- }
- if (vn == 0)
- {
- mpz_set (r, u);
- return;
- }
-
- uc = u->_mp_size < 0;
- vc = v->_mp_size < 0;
- rc = uc | vc;
-
- ux = -uc;
- vx = -vc;
- rx = -rc;
-
- /* If the smaller input is negative, by sign extension higher limbs
- don't matter. */
- rn = vx ? vn : un;
-
- rp = MPZ_REALLOC (r, rn + rc);
-
- up = u->_mp_d;
- vp = v->_mp_d;
-
- for (i = 0; i < vn; i++)
- {
- ul = (up[i] ^ ux) + uc;
- uc = ul < uc;
-
- vl = (vp[i] ^ vx) + vc;
- vc = vl < vc;
-
- rl = ( (ul | vl) ^ rx) + rc;
- rc = rl < rc;
- rp[i] = rl;
- }
- assert (vc == 0);
-
- for (; i < rn; i++)
- {
- ul = (up[i] ^ ux) + uc;
- uc = ul < uc;
-
- rl = ( (ul | vx) ^ rx) + rc;
- rc = rl < rc;
- rp[i] = rl;
- }
- if (rc)
- rp[rn++] = rc;
- else
- rn = mpn_normalized_size (rp, rn);
-
- r->_mp_size = rx ? -rn : rn;
-}
-
-void
-mpz_xor (mpz_t r, const mpz_t u, const mpz_t v)
-{
- mp_size_t un, vn, i;
- mp_ptr up, vp, rp;
-
- mp_limb_t ux, vx, rx;
- mp_limb_t uc, vc, rc;
- mp_limb_t ul, vl, rl;
-
- un = GMP_ABS (u->_mp_size);
- vn = GMP_ABS (v->_mp_size);
- if (un < vn)
- {
- MPZ_SRCPTR_SWAP (u, v);
- MP_SIZE_T_SWAP (un, vn);
- }
- if (vn == 0)
- {
- mpz_set (r, u);
- return;
- }
-
- uc = u->_mp_size < 0;
- vc = v->_mp_size < 0;
- rc = uc ^ vc;
-
- ux = -uc;
- vx = -vc;
- rx = -rc;
-
- rp = MPZ_REALLOC (r, un + rc);
-
- up = u->_mp_d;
- vp = v->_mp_d;
-
- for (i = 0; i < vn; i++)
- {
- ul = (up[i] ^ ux) + uc;
- uc = ul < uc;
-
- vl = (vp[i] ^ vx) + vc;
- vc = vl < vc;
-
- rl = (ul ^ vl ^ rx) + rc;
- rc = rl < rc;
- rp[i] = rl;
- }
- assert (vc == 0);
-
- for (; i < un; i++)
- {
- ul = (up[i] ^ ux) + uc;
- uc = ul < uc;
-
- rl = (ul ^ ux) + rc;
- rc = rl < rc;
- rp[i] = rl;
- }
- if (rc)
- rp[un++] = rc;
- else
- un = mpn_normalized_size (rp, un);
-
- r->_mp_size = rx ? -un : un;
-}
-
-static unsigned
-gmp_popcount_limb (mp_limb_t x)
-{
- unsigned c;
-
- /* Do 16 bits at a time, to avoid limb-sized constants. */
- for (c = 0; x > 0; x >>= 16)
- {
- unsigned w = ((x >> 1) & 0x5555) + (x & 0x5555);
- w = ((w >> 2) & 0x3333) + (w & 0x3333);
- w = ((w >> 4) & 0x0f0f) + (w & 0x0f0f);
- w = (w >> 8) + (w & 0x00ff);
- c += w;
- }
- return c;
-}
-
-mp_bitcnt_t
-mpz_popcount (const mpz_t u)
-{
- mp_size_t un, i;
- mp_bitcnt_t c;
-
- un = u->_mp_size;
-
- if (un < 0)
- return ~(mp_bitcnt_t) 0;
-
- for (c = 0, i = 0; i < un; i++)
- c += gmp_popcount_limb (u->_mp_d[i]);
-
- return c;
-}
-
-mp_bitcnt_t
-mpz_hamdist (const mpz_t u, const mpz_t v)
-{
- mp_size_t un, vn, i;
- mp_limb_t uc, vc, ul, vl, comp;
- mp_srcptr up, vp;
- mp_bitcnt_t c;
-
- un = u->_mp_size;
- vn = v->_mp_size;
-
- if ( (un ^ vn) < 0)
- return ~(mp_bitcnt_t) 0;
-
- if (un < 0)
- {
- assert (vn < 0);
- un = -un;
- vn = -vn;
- uc = vc = 1;
- comp = - (mp_limb_t) 1;
- }
- else
- uc = vc = comp = 0;
-
- up = u->_mp_d;
- vp = v->_mp_d;
-
- if (un < vn)
- MPN_SRCPTR_SWAP (up, un, vp, vn);
-
- for (i = 0, c = 0; i < vn; i++)
- {
- ul = (up[i] ^ comp) + uc;
- uc = ul < uc;
-
- vl = (vp[i] ^ comp) + vc;
- vc = vl < vc;
-
- c += gmp_popcount_limb (ul ^ vl);
- }
- assert (vc == 0);
-
- for (; i < un; i++)
- {
- ul = (up[i] ^ comp) + uc;
- uc = ul < uc;
-
- c += gmp_popcount_limb (ul ^ comp);
- }
-
- return c;
-}
-
-mp_bitcnt_t
-mpz_scan1 (const mpz_t u, mp_bitcnt_t starting_bit)
-{
- mp_ptr up;
- mp_size_t us, un, i;
- mp_limb_t limb, ux, uc;
- unsigned cnt;
-
- up = u->_mp_d;
- us = u->_mp_size;
- un = GMP_ABS (us);
- i = starting_bit / GMP_LIMB_BITS;
-
- /* Past the end there's no 1 bits for u>=0, or an immediate 1 bit
- for u<0. Notice this test picks up any u==0 too. */
- if (i >= un)
- return (us >= 0 ? ~(mp_bitcnt_t) 0 : starting_bit);
-
- if (us < 0)
- {
- ux = GMP_LIMB_MAX;
- uc = mpn_zero_p (up, i);
- }
- else
- ux = uc = 0;
-
- limb = (ux ^ up[i]) + uc;
- uc = limb < uc;
-
- /* Mask to 0 all bits before starting_bit, thus ignoring them. */
- limb &= (GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS));
-
- while (limb == 0)
- {
- i++;
- if (i == un)
- {
- assert (uc == 0);
- /* For the u > 0 case, this can happen only for the first
- masked limb. For the u < 0 case, it happens when the
- highest limbs of the absolute value are all ones. */
- return (us >= 0 ? ~(mp_bitcnt_t) 0 : un * GMP_LIMB_BITS);
- }
- limb = (ux ^ up[i]) + uc;
- uc = limb < uc;
- }
- gmp_ctz (cnt, limb);
- return (mp_bitcnt_t) i * GMP_LIMB_BITS + cnt;
-}
-
-mp_bitcnt_t
-mpz_scan0 (const mpz_t u, mp_bitcnt_t starting_bit)
-{
- mp_ptr up;
- mp_size_t us, un, i;
- mp_limb_t limb, ux, uc;
- unsigned cnt;
-
- up = u->_mp_d;
- us = u->_mp_size;
- un = GMP_ABS (us);
- i = starting_bit / GMP_LIMB_BITS;
-
- /* When past end, there's an immediate 0 bit for u>=0, or no 0 bits for
- u<0. Notice this test picks up all cases of u==0 too. */
- if (i >= un)
- return (us >= 0 ? starting_bit : ~(mp_bitcnt_t) 0);
-
- if (us < 0)
- {
- ux = GMP_LIMB_MAX;
- uc = mpn_zero_p (up, i);
- }
- else
- ux = uc = 0;
-
- limb = (ux ^ up[i]) + uc;
- uc = limb < uc;
-
- /* Mask to 1 all bits before starting_bit, thus ignoring them. */
- limb |= ((mp_limb_t) 1 << (starting_bit % GMP_LIMB_BITS)) - 1;
-
- while (limb == GMP_LIMB_MAX)
- {
- i++;
- if (i == un)
- {
- assert (uc == 0);
- return (us >= 0 ? un * GMP_LIMB_BITS : ~(mp_bitcnt_t) 0);
- }
- limb = (ux ^ up[i]) + uc;
- uc = limb < uc;
- }
- gmp_ctz (cnt, ~limb);
- return (mp_bitcnt_t) i * GMP_LIMB_BITS + cnt;
-}
-
-
-/* MPZ base conversion. */
-
-size_t
-mpz_sizeinbase (const mpz_t u, int base)
-{
- mp_size_t un;
- mp_srcptr up;
- mp_ptr tp;
- mp_bitcnt_t bits;
- struct gmp_div_inverse bi;
- size_t ndigits;
-
- assert (base >= 2);
- assert (base <= 36);
-
- un = GMP_ABS (u->_mp_size);
- if (un == 0)
- return 1;
-
- up = u->_mp_d;
-
- bits = (un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1]);
- switch (base)
- {
- case 2:
- return bits;
- case 4:
- return (bits + 1) / 2;
- case 8:
- return (bits + 2) / 3;
- case 16:
- return (bits + 3) / 4;
- case 32:
- return (bits + 4) / 5;
- /* FIXME: Do something more clever for the common case of base
- 10. */
- }
-
- tp = gmp_xalloc_limbs (un);
- mpn_copyi (tp, up, un);
- mpn_div_qr_1_invert (&bi, base);
-
- for (ndigits = 0; un > 0; ndigits++)
- {
- mpn_div_qr_1_preinv (tp, tp, un, &bi);
- un -= (tp[un-1] == 0);
- }
- gmp_free (tp);
- return ndigits;
-}
-
-char *
-mpz_get_str (char *sp, int base, const mpz_t u)
-{
- unsigned bits;
- const char *digits;
- mp_size_t un;
- size_t i, sn;
-
- if (base >= 0)
- {
- digits = "0123456789abcdefghijklmnopqrstuvwxyz";
- }
- else
- {
- base = -base;
- digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- }
- if (base <= 1)
- base = 10;
- if (base > 36)
- return NULL;
-
- sn = 1 + mpz_sizeinbase (u, base);
- if (!sp)
- sp = gmp_xalloc (1 + sn);
-
- un = GMP_ABS (u->_mp_size);
-
- if (un == 0)
- {
- sp[0] = '0';
- sp[1] = '\0';
- return sp;
- }
-
- i = 0;
-
- if (u->_mp_size < 0)
- sp[i++] = '-';
-
- bits = mpn_base_power_of_two_p (base);
-
- if (bits)
- /* Not modified in this case. */
- sn = i + mpn_get_str_bits ((unsigned char *) sp + i, bits, u->_mp_d, un);
- else
- {
- struct mpn_base_info info;
- mp_ptr tp;
-
- mpn_get_base_info (&info, base);
- tp = gmp_xalloc_limbs (un);
- mpn_copyi (tp, u->_mp_d, un);
-
- sn = i + mpn_get_str_other ((unsigned char *) sp + i, base, &info, tp, un);
- gmp_free (tp);
- }
-
- for (; i < sn; i++)
- sp[i] = digits[(unsigned char) sp[i]];
-
- sp[sn] = '\0';
- return sp;
-}
-
-int
-mpz_set_str (mpz_t r, const char *sp, int base)
-{
- unsigned bits;
- mp_size_t rn, alloc;
- mp_ptr rp;
- size_t sn;
- size_t dn;
- int sign;
- unsigned char *dp;
-
- assert (base == 0 || (base >= 2 && base <= 36));
-
- while (isspace( (unsigned char) *sp))
- sp++;
-
- if (*sp == '-')
- {
- sign = 1;
- sp++;
- }
- else
- sign = 0;
-
- if (base == 0)
- {
- if (*sp == '0')
- {
- sp++;
- if (*sp == 'x' || *sp == 'X')
- {
- base = 16;
- sp++;
- }
- else if (*sp == 'b' || *sp == 'B')
- {
- base = 2;
- sp++;
- }
- else
- base = 8;
- }
- else
- base = 10;
- }
-
- sn = strlen (sp);
- dp = gmp_xalloc (sn + (sn == 0));
-
- for (dn = 0; *sp; sp++)
- {
- unsigned digit;
-
- if (isspace ((unsigned char) *sp))
- continue;
- if (*sp >= '0' && *sp <= '9')
- digit = *sp - '0';
- else if (*sp >= 'a' && *sp <= 'z')
- digit = *sp - 'a' + 10;
- else if (*sp >= 'A' && *sp <= 'Z')
- digit = *sp - 'A' + 10;
- else
- digit = base; /* fail */
-
- if (digit >= base)
- {
- gmp_free (dp);
- r->_mp_size = 0;
- return -1;
- }
-
- dp[dn++] = digit;
- }
-
- bits = mpn_base_power_of_two_p (base);
-
- if (bits > 0)
- {
- alloc = (sn * bits + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
- rp = MPZ_REALLOC (r, alloc);
- rn = mpn_set_str_bits (rp, dp, dn, bits);
- }
- else
- {
- struct mpn_base_info info;
- mpn_get_base_info (&info, base);
- alloc = (sn + info.exp - 1) / info.exp;
- rp = MPZ_REALLOC (r, alloc);
- rn = mpn_set_str_other (rp, dp, dn, base, &info);
- }
- assert (rn <= alloc);
- gmp_free (dp);
-
- r->_mp_size = sign ? - rn : rn;
-
- return 0;
-}
-
-int
-mpz_init_set_str (mpz_t r, const char *sp, int base)
-{
- mpz_init (r);
- return mpz_set_str (r, sp, base);
-}
-
-size_t
-mpz_out_str (FILE *stream, int base, const mpz_t x)
-{
- char *str;
- size_t len;
-
- str = mpz_get_str (NULL, base, x);
- len = strlen (str);
- len = fwrite (str, 1, len, stream);
- gmp_free (str);
- return len;
-}
-
-
-static int
-gmp_detect_endian (void)
-{
- static const int i = 1;
- const unsigned char *p = (const unsigned char *) &i;
- if (*p == 1)
- /* Little endian */
- return -1;
- else
- /* Big endian */
- return 1;
-}
-
-/* Import and export. Does not support nails. */
-void
-mpz_import (mpz_t r, size_t count, int order, size_t size, int endian,
- size_t nails, const void *src)
-{
- const unsigned char *p;
- ptrdiff_t word_step;
- mp_ptr rp;
- mp_size_t rn;
-
- /* The current (partial) limb. */
- mp_limb_t limb;
- /* The number of bytes already copied to this limb (starting from
- the low end). */
- size_t bytes;
- /* The index where the limb should be stored, when completed. */
- mp_size_t i;
-
- if (nails != 0)
- gmp_die ("mpz_import: Nails not supported.");
-
- assert (order == 1 || order == -1);
- assert (endian >= -1 && endian <= 1);
-
- if (endian == 0)
- endian = gmp_detect_endian ();
-
- p = (unsigned char *) src;
-
- word_step = (order != endian) ? 2 * size : 0;
-
- /* Process bytes from the least significant end, so point p at the
- least significant word. */
- if (order == 1)
- {
- p += size * (count - 1);
- word_step = - word_step;
- }
-
- /* And at least significant byte of that word. */
- if (endian == 1)
- p += (size - 1);
-
- rn = (size * count + sizeof(mp_limb_t) - 1) / sizeof(mp_limb_t);
- rp = MPZ_REALLOC (r, rn);
-
- for (limb = 0, bytes = 0, i = 0; count > 0; count--, p += word_step)
- {
- size_t j;
- for (j = 0; j < size; j++, p -= (ptrdiff_t) endian)
- {
- limb |= (mp_limb_t) *p << (bytes++ * CHAR_BIT);
- if (bytes == sizeof(mp_limb_t))
- {
- rp[i++] = limb;
- bytes = 0;
- limb = 0;
- }
- }
- }
- if (bytes > 0)
- rp[i++] = limb;
- assert (i == rn);
-
- r->_mp_size = mpn_normalized_size (rp, i);
-}
-
-void *
-mpz_export (void *r, size_t *countp, int order, size_t size, int endian,
- size_t nails, const mpz_t u)
-{
- unsigned char *p;
- ptrdiff_t word_step;
- size_t count, k;
- mp_size_t un;
-
- /* The current (partial) limb. */
- mp_limb_t limb;
- /* The number of bytes left to to in this limb. */
- size_t bytes;
- /* The index where the limb was read. */
- mp_size_t i;
-
- if (nails != 0)
- gmp_die ("mpz_import: Nails not supported.");
-
- assert (order == 1 || order == -1);
- assert (endian >= -1 && endian <= 1);
- assert (size > 0 || u->_mp_size == 0);
-
- un = GMP_ABS (u->_mp_size);
- if (un == 0)
- {
- if (countp)
- *countp = 0;
- return r;
- }
-
- /* Count bytes in top limb. */
- for (limb = u->_mp_d[un-1], k = 0; limb > 0; k++, limb >>= CHAR_BIT)
- ;
-
- assert (k > 0);
-
- count = (k + (un-1) * sizeof (mp_limb_t) + size - 1) / size;
-
- if (!r)
- r = gmp_xalloc (count * size);
-
- if (endian == 0)
- endian = gmp_detect_endian ();
-
- p = (unsigned char *) r;
-
- word_step = (order != endian) ? 2 * size : 0;
-
- /* Process bytes from the least significant end, so point p at the
- least significant word. */
- if (order == 1)
- {
- p += size * (count - 1);
- word_step = - word_step;
- }
-
- /* And at least significant byte of that word. */
- if (endian == 1)
- p += (size - 1);
-
- for (bytes = 0, i = 0, k = 0; k < count; k++, p += word_step)
- {
- size_t j;
- for (j = 0; j < size; j++, p -= (ptrdiff_t) endian)
- {
- if (bytes == 0)
- {
- if (i < un)
- limb = u->_mp_d[i++];
- bytes = sizeof (mp_limb_t);
- }
- *p = limb;
- limb >>= CHAR_BIT;
- bytes--;
- }
- }
- assert (i == un);
- assert (k == count);
-
- if (countp)
- *countp = count;
-
- return r;
-}
diff --git a/src/gmp/mini-gmp.h b/src/gmp/mini-gmp.h
deleted file mode 100644
index 8c94ca2ed..000000000
--- a/src/gmp/mini-gmp.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
-
-Copyright 2011, 2012, 2013 Free Software Foundation, Inc.
-
-This file is part of the GNU MP Library.
-
-The GNU MP Library is free software; you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 3 of the License, or (at your
-option) any later version.
-
-The GNU MP Library 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 Lesser General Public
-License for more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
-
-/* About mini-gmp: This is a minimal implementation of a subset of the
- GMP interface. It is intended for inclusion into applications which
- have modest bignums needs, as a fallback when the real GMP library
- is not installed.
-
- This file defines the public interface. */
-
-#ifndef __MINI_GMP_H__
-#define __MINI_GMP_H__
-
-/* For size_t */
-#include <stddef.h>
-
-#if defined (__cplusplus)
-extern "C" {
-#endif
-
-void mp_set_memory_functions (void *(*) (size_t),
- void *(*) (void *, size_t, size_t),
- void (*) (void *, size_t));
-
-void mp_get_memory_functions (void *(**) (size_t),
- void *(**) (void *, size_t, size_t),
- void (**) (void *, size_t));
-
-typedef unsigned long mp_limb_t;
-typedef long mp_size_t;
-typedef unsigned long mp_bitcnt_t;
-
-typedef mp_limb_t *mp_ptr;
-typedef const mp_limb_t *mp_srcptr;
-
-typedef struct
-{
- int _mp_alloc; /* Number of *limbs* allocated and pointed
- to by the _mp_d field. */
- int _mp_size; /* abs(_mp_size) is the number of limbs the
- last field points to. If _mp_size is
- negative this is a negative number. */
- mp_limb_t *_mp_d; /* Pointer to the limbs. */
-} __mpz_struct;
-
-typedef __mpz_struct mpz_t[1];
-
-typedef __mpz_struct *mpz_ptr;
-typedef const __mpz_struct *mpz_srcptr;
-
-void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
-void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
-
-int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t);
-
-mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
-mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
-mp_limb_t mpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
-
-mp_limb_t mpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
-mp_limb_t mpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
-mp_limb_t mpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
-
-mp_limb_t mpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
-mp_limb_t mpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
-mp_limb_t mpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
-
-mp_limb_t mpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
-void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
-void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t);
-
-mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
-mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
-
-mp_limb_t mpn_invert_3by2 (mp_limb_t, mp_limb_t);
-#define mpn_invert_limb(x) mpn_invert_3by2 ((x), 0)
-
-size_t mpn_get_str (unsigned char *, int, mp_ptr, mp_size_t);
-mp_size_t mpn_set_str (mp_ptr, const unsigned char *, size_t, int);
-
-void mpz_init (mpz_t);
-void mpz_init2 (mpz_t, mp_bitcnt_t);
-void mpz_clear (mpz_t);
-
-#define mpz_odd_p(z) (((z)->_mp_size != 0) & (int) (z)->_mp_d[0])
-#define mpz_even_p(z) (! mpz_odd_p (z))
-
-int mpz_sgn (const mpz_t);
-int mpz_cmp_si (const mpz_t, long);
-int mpz_cmp_ui (const mpz_t, unsigned long);
-int mpz_cmp (const mpz_t, const mpz_t);
-int mpz_cmpabs_ui (const mpz_t, unsigned long);
-int mpz_cmpabs (const mpz_t, const mpz_t);
-int mpz_cmp_d (const mpz_t, double);
-int mpz_cmpabs_d (const mpz_t, double);
-
-void mpz_abs (mpz_t, const mpz_t);
-void mpz_neg (mpz_t, const mpz_t);
-void mpz_swap (mpz_t, mpz_t);
-
-void mpz_add_ui (mpz_t, const mpz_t, unsigned long);
-void mpz_add (mpz_t, const mpz_t, const mpz_t);
-void mpz_sub_ui (mpz_t, const mpz_t, unsigned long);
-void mpz_ui_sub (mpz_t, unsigned long, const mpz_t);
-void mpz_sub (mpz_t, const mpz_t, const mpz_t);
-
-void mpz_mul_si (mpz_t, const mpz_t, long int);
-void mpz_mul_ui (mpz_t, const mpz_t, unsigned long int);
-void mpz_mul (mpz_t, const mpz_t, const mpz_t);
-void mpz_mul_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
-
-void mpz_cdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
-void mpz_fdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
-void mpz_tdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
-void mpz_cdiv_q (mpz_t, const mpz_t, const mpz_t);
-void mpz_fdiv_q (mpz_t, const mpz_t, const mpz_t);
-void mpz_tdiv_q (mpz_t, const mpz_t, const mpz_t);
-void mpz_cdiv_r (mpz_t, const mpz_t, const mpz_t);
-void mpz_fdiv_r (mpz_t, const mpz_t, const mpz_t);
-void mpz_tdiv_r (mpz_t, const mpz_t, const mpz_t);
-
-void mpz_cdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
-void mpz_fdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
-void mpz_tdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
-void mpz_cdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
-void mpz_fdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
-void mpz_tdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
-
-void mpz_mod (mpz_t, const mpz_t, const mpz_t);
-
-void mpz_divexact (mpz_t, const mpz_t, const mpz_t);
-
-int mpz_divisible_p (const mpz_t, const mpz_t);
-
-unsigned long mpz_cdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
-unsigned long mpz_fdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
-unsigned long mpz_tdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
-unsigned long mpz_cdiv_q_ui (mpz_t, const mpz_t, unsigned long);
-unsigned long mpz_fdiv_q_ui (mpz_t, const mpz_t, unsigned long);
-unsigned long mpz_tdiv_q_ui (mpz_t, const mpz_t, unsigned long);
-unsigned long mpz_cdiv_r_ui (mpz_t, const mpz_t, unsigned long);
-unsigned long mpz_fdiv_r_ui (mpz_t, const mpz_t, unsigned long);
-unsigned long mpz_tdiv_r_ui (mpz_t, const mpz_t, unsigned long);
-unsigned long mpz_cdiv_ui (const mpz_t, unsigned long);
-unsigned long mpz_fdiv_ui (const mpz_t, unsigned long);
-unsigned long mpz_tdiv_ui (const mpz_t, unsigned long);
-
-unsigned long mpz_mod_ui (mpz_t, const mpz_t, unsigned long);
-
-void mpz_divexact_ui (mpz_t, const mpz_t, unsigned long);
-
-int mpz_divisible_ui_p (const mpz_t, unsigned long);
-
-unsigned long mpz_gcd_ui (mpz_t, const mpz_t, unsigned long);
-void mpz_gcd (mpz_t, const mpz_t, const mpz_t);
-void mpz_gcdext (mpz_t, mpz_t, mpz_t, const mpz_t, const mpz_t);
-void mpz_lcm_ui (mpz_t, const mpz_t, unsigned long);
-void mpz_lcm (mpz_t, const mpz_t, const mpz_t);
-int mpz_invert (mpz_t, const mpz_t, const mpz_t);
-
-void mpz_sqrtrem (mpz_t, mpz_t, const mpz_t);
-void mpz_sqrt (mpz_t, const mpz_t);
-
-void mpz_pow_ui (mpz_t, const mpz_t, unsigned long);
-void mpz_ui_pow_ui (mpz_t, unsigned long, unsigned long);
-void mpz_powm (mpz_t, const mpz_t, const mpz_t, const mpz_t);
-void mpz_powm_ui (mpz_t, const mpz_t, unsigned long, const mpz_t);
-
-void mpz_rootrem (mpz_t, mpz_t, const mpz_t, unsigned long);
-int mpz_root (mpz_t, const mpz_t, unsigned long);
-
-void mpz_fac_ui (mpz_t, unsigned long);
-void mpz_bin_uiui (mpz_t, unsigned long, unsigned long);
-
-int mpz_tstbit (const mpz_t, mp_bitcnt_t);
-void mpz_setbit (mpz_t, mp_bitcnt_t);
-void mpz_clrbit (mpz_t, mp_bitcnt_t);
-void mpz_combit (mpz_t, mp_bitcnt_t);
-
-void mpz_com (mpz_t, const mpz_t);
-void mpz_and (mpz_t, const mpz_t, const mpz_t);
-void mpz_ior (mpz_t, const mpz_t, const mpz_t);
-void mpz_xor (mpz_t, const mpz_t, const mpz_t);
-
-mp_bitcnt_t mpz_popcount (const mpz_t);
-mp_bitcnt_t mpz_hamdist (const mpz_t, const mpz_t);
-mp_bitcnt_t mpz_scan0 (const mpz_t, mp_bitcnt_t);
-mp_bitcnt_t mpz_scan1 (const mpz_t, mp_bitcnt_t);
-
-int mpz_fits_slong_p (const mpz_t);
-int mpz_fits_ulong_p (const mpz_t);
-long int mpz_get_si (const mpz_t);
-unsigned long int mpz_get_ui (const mpz_t);
-double mpz_get_d (const mpz_t);
-size_t mpz_size (const mpz_t);
-mp_limb_t mpz_getlimbn (const mpz_t, mp_size_t);
-
-void mpz_set_si (mpz_t, signed long int);
-void mpz_set_ui (mpz_t, unsigned long int);
-void mpz_set (mpz_t, const mpz_t);
-void mpz_set_d (mpz_t, double);
-
-void mpz_init_set_si (mpz_t, signed long int);
-void mpz_init_set_ui (mpz_t, unsigned long int);
-void mpz_init_set (mpz_t, const mpz_t);
-void mpz_init_set_d (mpz_t, double);
-
-size_t mpz_sizeinbase (const mpz_t, int);
-char *mpz_get_str (char *, int, const mpz_t);
-int mpz_set_str (mpz_t, const char *, int);
-int mpz_init_set_str (mpz_t, const char *, int);
-
-/* This long list taken from gmp.h. */
-/* For reference, "defined(EOF)" cannot be used here. In g++ 2.95.4,
- <iostream> defines EOF but not FILE. */
-#if defined (FILE) \
- || defined (H_STDIO) \
- || defined (_H_STDIO) /* AIX */ \
- || defined (_STDIO_H) /* glibc, Sun, SCO */ \
- || defined (_STDIO_H_) /* BSD, OSF */ \
- || defined (__STDIO_H) /* Borland */ \
- || defined (__STDIO_H__) /* IRIX */ \
- || defined (_STDIO_INCLUDED) /* HPUX */ \
- || defined (__dj_include_stdio_h_) /* DJGPP */ \
- || defined (_FILE_DEFINED) /* Microsoft */ \
- || defined (__STDIO__) /* Apple MPW MrC */ \
- || defined (_MSL_STDIO_H) /* Metrowerks */ \
- || defined (_STDIO_H_INCLUDED) /* QNX4 */ \
- || defined (_ISO_STDIO_ISO_H) /* Sun C++ */ \
- || defined (__STDIO_LOADED) /* VMS */
-size_t mpz_out_str (FILE *, int, const mpz_t);
-#endif
-
-void mpz_import (mpz_t, size_t, int, size_t, int, size_t, const void *);
-void *mpz_export (void *, size_t *, int, size_t, int, size_t, const mpz_t);
-
-#if defined (__cplusplus)
-}
-#endif
-#endif /* __MINI_GMP_H__ */
diff --git a/src/guiChatConsole.cpp b/src/guiChatConsole.cpp
index 8dd5ab032..5bb80bbbe 100644
--- a/src/guiChatConsole.cpp
+++ b/src/guiChatConsole.cpp
@@ -55,7 +55,7 @@ GUIChatConsole::GUIChatConsole(
m_client(client),
m_menumgr(menumgr),
m_screensize(v2u32(0,0)),
- m_animate_time_old(0),
+ m_animate_time_old(porting::getTimeMs()),
m_open(false),
m_close_on_enter(false),
m_height(0),
@@ -71,8 +71,6 @@ GUIChatConsole::GUIChatConsole(
m_font(NULL),
m_fontsize(0, 0)
{
- m_animate_time_old = getTimeMs();
-
// load background settings
s32 console_alpha = g_settings->getS32("console_alpha");
m_background_color.setAlpha(clamp_u8(console_alpha));
@@ -116,13 +114,15 @@ GUIChatConsole::~GUIChatConsole()
m_font->drop();
}
-void GUIChatConsole::openConsole(f32 height)
+void GUIChatConsole::openConsole(f32 scale)
{
+ assert(scale > 0.0f && scale <= 1.0f);
+
m_open = true;
- m_desired_height_fraction = height;
- m_desired_height = height * m_screensize.Y;
+ m_desired_height_fraction = scale;
+ m_desired_height = scale * m_screensize.Y;
reformatConsole();
- m_animate_time_old = getTimeMs();
+ m_animate_time_old = porting::getTimeMs();
IGUIElement::setVisible(true);
Environment->setFocus(this);
m_menumgr->createdMenu(this);
@@ -210,7 +210,7 @@ void GUIChatConsole::draw()
}
// Animation
- u32 now = getTimeMs();
+ u64 now = porting::getTimeMs();
animate(now - m_animate_time_old);
m_animate_time_old = now;
@@ -627,10 +627,8 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
bool backwards = event.KeyInput.Shift;
prompt.nickCompletion(names, backwards);
return true;
- }
- else if(event.KeyInput.Char != 0 && !event.KeyInput.Control)
- {
- #if (defined(__linux__))
+ } else if (!iswcntrl(event.KeyInput.Char) && !event.KeyInput.Control) {
+ #if defined(__linux__) && (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9)
wchar_t wc = L'_';
mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) );
prompt.input(wc);
diff --git a/src/guiChatConsole.h b/src/guiChatConsole.h
index 3013a1d31..0332678c7 100644
--- a/src/guiChatConsole.h
+++ b/src/guiChatConsole.h
@@ -41,7 +41,7 @@ public:
// Open the console (height = desired fraction of screen size)
// This doesn't open immediately but initiates an animation.
// You should call isOpenInhibited() before this.
- void openConsole(f32 height);
+ void openConsole(f32 scale);
bool isOpen() const;
@@ -98,7 +98,7 @@ private:
v2u32 m_screensize;
// used to compute how much time passed since last animate()
- u32 m_animate_time_old;
+ u64 m_animate_time_old;
// should the console be opened or closed?
bool m_open;
diff --git a/src/guiEngine.cpp b/src/guiEngine.cpp
index a3c35f68d..2d1bd6d44 100644
--- a/src/guiEngine.cpp
+++ b/src/guiEngine.cpp
@@ -60,7 +60,7 @@ void TextDestGuiEngine::gotText(const StringMap &fields)
}
/******************************************************************************/
-void TextDestGuiEngine::gotText(std::wstring text)
+void TextDestGuiEngine::gotText(const std::wstring &text)
{
m_engine->getScriptIface()->handleMainMenuEvent(wide_to_utf8(text));
}
@@ -194,11 +194,9 @@ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev,
-1,
m_menumanager,
NULL /* &client */,
- NULL /* gamedef */,
m_texture_source,
m_formspecgui,
m_buttonhandler,
- NULL,
false);
m_menu->allowClose(false);
@@ -215,13 +213,13 @@ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev,
m_data->script_data.errormessage = "";
if (!loadMainMenuScript()) {
- errorstream << "No future without mainmenu" << std::endl;
+ errorstream << "No future without main menu!" << std::endl;
abort();
}
run();
} catch (LuaError &e) {
- errorstream << "MAINMENU ERROR: " << e.what() << std::endl;
+ errorstream << "Main menu error: " << e.what() << std::endl;
m_data->script_data.errormessage = e.what();
}
@@ -233,13 +231,13 @@ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev,
/******************************************************************************/
bool GUIEngine::loadMainMenuScript()
{
- // Try custom menu script (main_menu_path)
-
+ // Set main menu path (for core.get_mainmenu_path())
m_scriptdir = g_settings->get("main_menu_path");
if (m_scriptdir.empty()) {
- m_scriptdir = porting::path_share + DIR_DELIM "builtin" + DIR_DELIM "mainmenu";
+ m_scriptdir = porting::path_share + DIR_DELIM + "builtin" + DIR_DELIM + "mainmenu";
}
+ // Load builtin (which will load the main menu script)
std::string script = porting::path_share + DIR_DELIM "builtin" + DIR_DELIM "init.lua";
try {
m_script->loadScript(script);
@@ -264,8 +262,24 @@ void GUIEngine::run()
unsigned int text_height = g_fontengine->getTextHeight();
- while(m_device->run() && (!m_startgame) && (!m_kill))
- {
+ irr::core::dimension2d<u32> previous_screen_size(g_settings->getU16("screenW"),
+ g_settings->getU16("screenH"));
+
+ while (m_device->run() && (!m_startgame) && (!m_kill)) {
+
+ const irr::core::dimension2d<u32> &current_screen_size =
+ m_device->getVideoDriver()->getScreenSize();
+ // Verify if window size has changed and save it if it's the case
+ // Ensure evaluating settings->getBool after verifying screensize
+ // First condition is cheaper
+ if (previous_screen_size != current_screen_size &&
+ current_screen_size != irr::core::dimension2d<u32>(0,0) &&
+ g_settings->getBool("autosave_screensize")) {
+ g_settings->setU16("screenW", current_screen_size.Width);
+ g_settings->setU16("screenH", current_screen_size.Height);
+ previous_screen_size = current_screen_size;
+ }
+
//check if we need to update the "upper left corner"-text
if (text_height != g_fontengine->getTextHeight()) {
updateTopLeftTextSize();
@@ -542,7 +556,7 @@ bool GUIEngine::setTexture(texture_layer layer, std::string texturepath,
}
/******************************************************************************/
-bool GUIEngine::downloadFile(std::string url, std::string target)
+bool GUIEngine::downloadFile(const std::string &url, const std::string &target)
{
#if USE_CURL
std::ofstream target_file(target.c_str(), std::ios::out | std::ios::binary);
@@ -604,8 +618,8 @@ void GUIEngine::stopSound(s32 handle)
}
/******************************************************************************/
-unsigned int GUIEngine::queueAsync(std::string serialized_func,
- std::string serialized_params)
+unsigned int GUIEngine::queueAsync(const std::string &serialized_func,
+ const std::string &serialized_params)
{
return m_script->queueAsync(serialized_func, serialized_params);
}
diff --git a/src/guiEngine.h b/src/guiEngine.h
index 897244808..e7e5ca05d 100644
--- a/src/guiEngine.h
+++ b/src/guiEngine.h
@@ -80,7 +80,7 @@ public:
* receive text/events transmitted by guiFormSpecMenu
* @param text textual representation of event
*/
- void gotText(std::wstring text);
+ void gotText(const std::wstring &text);
private:
/** target to transmit data to */
@@ -139,6 +139,7 @@ private:
class GUIEngine {
/** grant ModApiMainMenu access to private members */
friend class ModApiMainMenu;
+ friend class ModApiSound;
public:
/**
@@ -177,7 +178,8 @@ public:
}
/** pass async callback to scriptengine **/
- unsigned int queueAsync(std::string serialized_fct,std::string serialized_params);
+ unsigned int queueAsync(const std::string &serialized_fct,
+ const std::string &serialized_params);
private:
@@ -187,9 +189,6 @@ private:
/** run main menu loop */
void run();
- /** handler to limit frame rate within main menu */
- void limitFrameRate();
-
/** update size of topleftext element */
void updateTopLeftTextSize();
@@ -261,14 +260,11 @@ private:
* @param url url to download
* @param target file to store to
*/
- static bool downloadFile(std::string url,std::string target);
+ static bool downloadFile(const std::string &url, const std::string &target);
/** array containing pointers to current specified texture layers */
image_definition m_textures[TEX_LAYER_MAX];
- /** draw version string in topleft corner */
- void drawVersion();
-
/**
* specify text to appear as top left string
* @param text to set
diff --git a/src/guiFileSelectMenu.cpp b/src/guiFileSelectMenu.cpp
index 0bb02f8a6..65a07be39 100644
--- a/src/guiFileSelectMenu.cpp
+++ b/src/guiFileSelectMenu.cpp
@@ -18,19 +18,16 @@
*/
#include "guiFileSelectMenu.h"
-#include "util/string.h"
-#include <locale.h>
GUIFileSelectMenu::GUIFileSelectMenu(gui::IGUIEnvironment* env,
- gui::IGUIElement* parent, s32 id, IMenuManager *menumgr,
- std::string title, std::string formname) :
-GUIModalMenu(env, parent, id, menumgr)
+ gui::IGUIElement* parent, s32 id, IMenuManager *menumgr,
+ const std::string &title, const std::string &formname) :
+ GUIModalMenu(env, parent, id, menumgr),
+ m_title(utf8_to_wide(title)),
+ m_accepted(false),
+ m_text_dst(NULL),
+ m_formname(formname)
{
- m_title = utf8_to_wide(title);
- m_parent = parent;
- m_formname = formname;
- m_text_dst = 0;
- m_accepted = false;
}
GUIFileSelectMenu::~GUIFileSelectMenu()
@@ -107,16 +104,12 @@ bool GUIFileSelectMenu::OnEvent(const SEvent& event)
acceptInput();
quitMenu();
return true;
- break;
-
case gui::EGET_DIRECTORY_SELECTED:
case gui::EGET_FILE_SELECTED:
m_accepted=true;
acceptInput();
quitMenu();
return true;
- break;
-
default:
//ignore this event
break;
diff --git a/src/guiFileSelectMenu.h b/src/guiFileSelectMenu.h
index e37d3d8df..034823740 100644
--- a/src/guiFileSelectMenu.h
+++ b/src/guiFileSelectMenu.h
@@ -26,14 +26,12 @@
#include "IGUIFileOpenDialog.h"
#include "guiFormSpecMenu.h" //required because of TextDest only !!!
-
-class GUIFileSelectMenu: public GUIModalMenu
+class GUIFileSelectMenu : public GUIModalMenu
{
public:
- GUIFileSelectMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent,
- s32 id, IMenuManager *menumgr,
- std::string title,
- std::string formid);
+ GUIFileSelectMenu(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
+ IMenuManager *menumgr, const std::string &title,
+ const std::string &formid);
~GUIFileSelectMenu();
void removeChildren();
@@ -45,34 +43,21 @@ public:
void drawMenu();
- bool OnEvent(const SEvent& event);
-
- bool isRunning() {
- return m_running;
- }
+ bool OnEvent(const SEvent &event);
- void setTextDest(TextDest * dest) {
- m_text_dst = dest;
- }
+ void setTextDest(TextDest *dest) { m_text_dst = dest; }
private:
void acceptInput();
std::wstring m_title;
bool m_accepted;
- gui::IGUIElement* m_parent;
-
- std::string m_selectedPath;
- gui::IGUIFileOpenDialog* m_fileOpenDialog;
-
- bool m_running;
+ gui::IGUIFileOpenDialog *m_fileOpenDialog;
TextDest *m_text_dst;
std::string m_formname;
};
-
-
#endif /* GUIFILESELECTMENU_H_ */
diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp
index bfc7a9b79..19fd9f1f0 100644
--- a/src/guiFormSpecMenu.cpp
+++ b/src/guiFormSpecMenu.cpp
@@ -42,7 +42,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "filesys.h"
#include "gettime.h"
#include "gettext.h"
-#include "scripting_game.h"
+#include "scripting_server.h"
#include "porting.h"
#include "settings.h"
#include "client.h"
@@ -81,13 +81,12 @@ static unsigned int font_line_height(gui::IGUIFont *font)
GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev,
JoystickController *joystick,
gui::IGUIElement* parent, s32 id, IMenuManager *menumgr,
- InventoryManager *invmgr, IGameDef *gamedef,
+ Client *client,
ISimpleTextureSource *tsrc, IFormSource* fsrc, TextDest* tdst,
- Client* client, bool remap_dbl_click) :
+ bool remap_dbl_click) :
GUIModalMenu(dev->getGUIEnvironment(), parent, id, menumgr),
m_device(dev),
- m_invmgr(invmgr),
- m_gamedef(gamedef),
+ m_invmgr(client),
m_tsrc(tsrc),
m_client(client),
m_selected_item(NULL),
@@ -253,7 +252,7 @@ std::vector<std::string>* GUIFormSpecMenu::getDropDownValues(const std::string &
return NULL;
}
-void GUIFormSpecMenu::parseSize(parserData* data,std::string element)
+void GUIFormSpecMenu::parseSize(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,',');
@@ -279,7 +278,7 @@ void GUIFormSpecMenu::parseSize(parserData* data,std::string element)
errorstream<< "Invalid size element (" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseContainer(parserData* data, std::string element)
+void GUIFormSpecMenu::parseContainer(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element, ',');
@@ -305,10 +304,10 @@ void GUIFormSpecMenu::parseContainerEnd(parserData* data)
}
}
-void GUIFormSpecMenu::parseList(parserData* data,std::string element)
+void GUIFormSpecMenu::parseList(parserData* data, const std::string &element)
{
- if (m_gamedef == 0) {
- warningstream<<"invalid use of 'list' with m_gamedef==0"<<std::endl;
+ if (m_client == 0) {
+ warningstream<<"invalid use of 'list' with m_client==0"<<std::endl;
return;
}
@@ -360,10 +359,10 @@ void GUIFormSpecMenu::parseList(parserData* data,std::string element)
errorstream<< "Invalid list element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseListRing(parserData* data, std::string element)
+void GUIFormSpecMenu::parseListRing(parserData* data, const std::string &element)
{
- if (m_gamedef == 0) {
- errorstream << "WARNING: invalid use of 'listring' with m_gamedef==0" << std::endl;
+ if (m_client == 0) {
+ errorstream << "WARNING: invalid use of 'listring' with m_client==0" << std::endl;
return;
}
@@ -395,7 +394,7 @@ void GUIFormSpecMenu::parseListRing(parserData* data, std::string element)
<< m_inventorylists.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseCheckbox(parserData* data,std::string element)
+void GUIFormSpecMenu::parseCheckbox(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -451,7 +450,7 @@ void GUIFormSpecMenu::parseCheckbox(parserData* data,std::string element)
errorstream<< "Invalid checkbox element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseScrollBar(parserData* data, std::string element)
+void GUIFormSpecMenu::parseScrollBar(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -510,7 +509,7 @@ void GUIFormSpecMenu::parseScrollBar(parserData* data, std::string element)
errorstream<< "Invalid scrollbar element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseImage(parserData* data,std::string element)
+void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -554,7 +553,7 @@ void GUIFormSpecMenu::parseImage(parserData* data,std::string element)
errorstream<< "Invalid image element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseItemImage(parserData* data,std::string element)
+void GUIFormSpecMenu::parseItemImage(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -584,8 +583,8 @@ void GUIFormSpecMenu::parseItemImage(parserData* data,std::string element)
errorstream<< "Invalid ItemImage element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseButton(parserData* data,std::string element,
- std::string type)
+void GUIFormSpecMenu::parseButton(parserData* data, const std::string &element,
+ const std::string &type)
{
std::vector<std::string> parts = split(element,';');
@@ -639,7 +638,7 @@ void GUIFormSpecMenu::parseButton(parserData* data,std::string element,
errorstream<< "Invalid button element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseBackground(parserData* data,std::string element)
+void GUIFormSpecMenu::parseBackground(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -677,7 +676,7 @@ void GUIFormSpecMenu::parseBackground(parserData* data,std::string element)
errorstream<< "Invalid background element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseTableOptions(parserData* data,std::string element)
+void GUIFormSpecMenu::parseTableOptions(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -689,7 +688,7 @@ void GUIFormSpecMenu::parseTableOptions(parserData* data,std::string element)
}
}
-void GUIFormSpecMenu::parseTableColumns(parserData* data,std::string element)
+void GUIFormSpecMenu::parseTableColumns(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -709,7 +708,7 @@ void GUIFormSpecMenu::parseTableColumns(parserData* data,std::string element)
}
}
-void GUIFormSpecMenu::parseTable(parserData* data,std::string element)
+void GUIFormSpecMenu::parseTable(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -777,7 +776,7 @@ void GUIFormSpecMenu::parseTable(parserData* data,std::string element)
errorstream<< "Invalid table element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseTextList(parserData* data,std::string element)
+void GUIFormSpecMenu::parseTextList(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -850,7 +849,7 @@ void GUIFormSpecMenu::parseTextList(parserData* data,std::string element)
}
-void GUIFormSpecMenu::parseDropDown(parserData* data,std::string element)
+void GUIFormSpecMenu::parseDropDown(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -914,8 +913,7 @@ void GUIFormSpecMenu::parseDropDown(parserData* data,std::string element)
<< element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseFieldCloseOnEnter(parserData *data,
- const std::string &element)
+void GUIFormSpecMenu::parseFieldCloseOnEnter(parserData *data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
if (parts.size() == 2 ||
@@ -924,7 +922,7 @@ void GUIFormSpecMenu::parseFieldCloseOnEnter(parserData *data,
}
}
-void GUIFormSpecMenu::parsePwdField(parserData* data,std::string element)
+void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -1085,8 +1083,8 @@ void GUIFormSpecMenu::parseSimpleField(parserData* data,
m_fields.push_back(spec);
}
-void GUIFormSpecMenu::parseTextArea(parserData* data,
- std::vector<std::string>& parts,std::string type)
+void GUIFormSpecMenu::parseTextArea(parserData* data, std::vector<std::string>& parts,
+ const std::string &type)
{
std::vector<std::string> v_pos = split(parts[0],',');
@@ -1197,8 +1195,8 @@ void GUIFormSpecMenu::parseTextArea(parserData* data,
m_fields.push_back(spec);
}
-void GUIFormSpecMenu::parseField(parserData* data,std::string element,
- std::string type)
+void GUIFormSpecMenu::parseField(parserData* data, const std::string &element,
+ const std::string &type)
{
std::vector<std::string> parts = split(element,';');
@@ -1216,7 +1214,7 @@ void GUIFormSpecMenu::parseField(parserData* data,std::string element,
errorstream<< "Invalid field element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseLabel(parserData* data,std::string element)
+void GUIFormSpecMenu::parseLabel(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -1272,7 +1270,7 @@ void GUIFormSpecMenu::parseLabel(parserData* data,std::string element)
errorstream<< "Invalid label element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseVertLabel(parserData* data,std::string element)
+void GUIFormSpecMenu::parseVertLabel(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -1322,8 +1320,8 @@ void GUIFormSpecMenu::parseVertLabel(parserData* data,std::string element)
errorstream<< "Invalid vertlabel element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseImageButton(parserData* data,std::string element,
- std::string type)
+void GUIFormSpecMenu::parseImageButton(parserData* data, const std::string &element,
+ const std::string &type)
{
std::vector<std::string> parts = split(element,';');
@@ -1411,7 +1409,7 @@ void GUIFormSpecMenu::parseImageButton(parserData* data,std::string element,
errorstream<< "Invalid imagebutton element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseTabHeader(parserData* data,std::string element)
+void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -1483,11 +1481,11 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data,std::string element)
<< element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element)
+void GUIFormSpecMenu::parseItemImageButton(parserData* data, const std::string &element)
{
- if (m_gamedef == 0) {
- warningstream << "invalid use of item_image_button with m_gamedef==0"
+ if (m_client == 0) {
+ warningstream << "invalid use of item_image_button with m_client==0"
<< std::endl;
return;
}
@@ -1521,7 +1519,7 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element)
if(!data->explicit_size)
warningstream<<"invalid use of item_image_button without a size[] element"<<std::endl;
- IItemDefManager *idef = m_gamedef->idef();
+ IItemDefManager *idef = m_client->idef();
ItemStack item;
item.deSerialize(item_name, idef);
@@ -1557,7 +1555,7 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element)
errorstream<< "Invalid ItemImagebutton element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseBox(parserData* data,std::string element)
+void GUIFormSpecMenu::parseBox(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -1593,7 +1591,7 @@ void GUIFormSpecMenu::parseBox(parserData* data,std::string element)
errorstream<< "Invalid Box element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseBackgroundColor(parserData* data,std::string element)
+void GUIFormSpecMenu::parseBackgroundColor(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -1611,7 +1609,7 @@ void GUIFormSpecMenu::parseBackgroundColor(parserData* data,std::string element)
errorstream<< "Invalid bgcolor element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseListColors(parserData* data,std::string element)
+void GUIFormSpecMenu::parseListColors(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@@ -1639,7 +1637,7 @@ void GUIFormSpecMenu::parseListColors(parserData* data,std::string element)
errorstream<< "Invalid listcolors element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-void GUIFormSpecMenu::parseTooltip(parserData* data, std::string element)
+void GUIFormSpecMenu::parseTooltip(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
if (parts.size() == 2) {
@@ -1659,7 +1657,7 @@ void GUIFormSpecMenu::parseTooltip(parserData* data, std::string element)
errorstream<< "Invalid tooltip element(" << parts.size() << "): '" << element << "'" << std::endl;
}
-bool GUIFormSpecMenu::parseVersionDirect(std::string data)
+bool GUIFormSpecMenu::parseVersionDirect(const std::string &data)
{
//some prechecks
if (data == "")
@@ -1683,7 +1681,7 @@ bool GUIFormSpecMenu::parseVersionDirect(std::string data)
return false;
}
-bool GUIFormSpecMenu::parseSizeDirect(parserData* data, std::string element)
+bool GUIFormSpecMenu::parseSizeDirect(parserData* data, const std::string &element)
{
if (element == "")
return false;
@@ -1707,7 +1705,76 @@ bool GUIFormSpecMenu::parseSizeDirect(parserData* data, std::string element)
return true;
}
-void GUIFormSpecMenu::parseElement(parserData* data, std::string element)
+bool GUIFormSpecMenu::parsePositionDirect(parserData *data, const std::string &element)
+{
+ if (element.empty())
+ return false;
+
+ std::vector<std::string> parts = split(element, '[');
+
+ if (parts.size() != 2)
+ return false;
+
+ std::string type = trim(parts[0]);
+ std::string description = trim(parts[1]);
+
+ if (type != "position")
+ return false;
+
+ parsePosition(data, description);
+
+ return true;
+}
+
+void GUIFormSpecMenu::parsePosition(parserData *data, const std::string &element)
+{
+ std::vector<std::string> parts = split(element, ',');
+
+ if (parts.size() == 2) {
+ data->offset.X = stof(parts[0]);
+ data->offset.Y = stof(parts[1]);
+ return;
+ }
+
+ errorstream << "Invalid position element (" << parts.size() << "): '" << element << "'" << std::endl;
+}
+
+bool GUIFormSpecMenu::parseAnchorDirect(parserData *data, const std::string &element)
+{
+ if (element.empty())
+ return false;
+
+ std::vector<std::string> parts = split(element, '[');
+
+ if (parts.size() != 2)
+ return false;
+
+ std::string type = trim(parts[0]);
+ std::string description = trim(parts[1]);
+
+ if (type != "anchor")
+ return false;
+
+ parseAnchor(data, description);
+
+ return true;
+}
+
+void GUIFormSpecMenu::parseAnchor(parserData *data, const std::string &element)
+{
+ std::vector<std::string> parts = split(element, ',');
+
+ if (parts.size() == 2) {
+ data->anchor.X = stof(parts[0]);
+ data->anchor.Y = stof(parts[1]);
+ return;
+ }
+
+ errorstream << "Invalid anchor element (" << parts.size() << "): '" << element
+ << "'" << std::endl;
+}
+
+void GUIFormSpecMenu::parseElement(parserData* data, const std::string &element)
{
//some prechecks
if (element == "")
@@ -1918,6 +1985,8 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
mydata.size= v2s32(100,100);
mydata.screensize = screensize;
+ mydata.offset = v2f32(0.5f, 0.5f);
+ mydata.anchor = v2f32(0.5f, 0.5f);
// Base position of contents of form
mydata.basepos = getBasePos();
@@ -1936,6 +2005,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
m_tooltips.clear();
m_inventory_rings.clear();
m_static_texts.clear();
+ m_dropdowns.clear();
// Set default values (fits old formspec values)
m_bgcolor = video::SColor(140,0,0,0);
@@ -1984,6 +2054,21 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
}
}
+ /* "position" element is always after "size" element if it used */
+ for (; i< elements.size(); i++) {
+ if (!parsePositionDirect(&mydata, elements[i])) {
+ break;
+ }
+ }
+
+ /* "anchor" element is always after "position" (or "size" element) if it used */
+ for (; i< elements.size(); i++) {
+ if (!parseAnchorDirect(&mydata, elements[i])) {
+ break;
+ }
+ }
+
+
if (mydata.explicit_size) {
// compute scaling for specified form size
if (m_lock) {
@@ -2067,10 +2152,10 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
padding.Y*2+spacing.Y*(mydata.invsize.Y-1.0)+imgsize.Y + m_btn_height*2.0/3.0
);
DesiredRect = mydata.rect = core::rect<s32>(
- mydata.screensize.X/2 - mydata.size.X/2 + offset.X,
- mydata.screensize.Y/2 - mydata.size.Y/2 + offset.Y,
- mydata.screensize.X/2 + mydata.size.X/2 + offset.X,
- mydata.screensize.Y/2 + mydata.size.Y/2 + offset.Y
+ (s32)((f32)mydata.screensize.X * mydata.offset.X) - (s32)(mydata.anchor.X * (f32)mydata.size.X) + offset.X,
+ (s32)((f32)mydata.screensize.Y * mydata.offset.Y) - (s32)(mydata.anchor.Y * (f32)mydata.size.Y) + offset.Y,
+ (s32)((f32)mydata.screensize.X * mydata.offset.X) + (s32)((1.0 - mydata.anchor.X) * (f32)mydata.size.X) + offset.X,
+ (s32)((f32)mydata.screensize.Y * mydata.offset.Y) + (s32)((1.0 - mydata.anchor.Y) * (f32)mydata.size.Y) + offset.Y
);
} else {
// Non-size[] form must consist only of text fields and
@@ -2079,10 +2164,10 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
m_font = g_fontengine->getFont();
m_btn_height = font_line_height(m_font) * 0.875;
DesiredRect = core::rect<s32>(
- mydata.screensize.X/2 - 580/2,
- mydata.screensize.Y/2 - 300/2,
- mydata.screensize.X/2 + 580/2,
- mydata.screensize.Y/2 + 300/2
+ (s32)((f32)mydata.screensize.X * mydata.offset.X) - (s32)(mydata.anchor.X * 580.0),
+ (s32)((f32)mydata.screensize.Y * mydata.offset.Y) - (s32)(mydata.anchor.Y * 300.0),
+ (s32)((f32)mydata.screensize.X * mydata.offset.X) + (s32)((1.0 - mydata.anchor.X) * 580.0),
+ (s32)((f32)mydata.screensize.Y * mydata.offset.Y) + (s32)((1.0 - mydata.anchor.Y) * 300.0)
);
}
recalculateAbsolutePosition(false);
@@ -2297,46 +2382,26 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase,
if(!item.empty())
{
drawItemStack(driver, m_font, item,
- rect, &AbsoluteClippingRect, m_gamedef,
+ rect, &AbsoluteClippingRect, m_client,
rotation_kind);
}
// Draw tooltip
std::wstring tooltip_text = L"";
if (hovering && !m_selected_item) {
- tooltip_text = utf8_to_wide(item.getDefinition(m_gamedef->idef()).description);
+ const std::string &desc = item.metadata.getString("description");
+ if (desc.empty())
+ tooltip_text =
+ utf8_to_wide(item.getDefinition(m_client->idef()).description);
+ else
+ tooltip_text = utf8_to_wide(desc);
+ // Show itemstring as fallback for easier debugging
+ if (!item.name.empty() && tooltip_text.empty())
+ tooltip_text = utf8_to_wide(item.name);
}
- if (tooltip_text != L"") {
- std::vector<std::wstring> tt_rows = str_split(tooltip_text, L'\n');
- m_tooltip_element->setBackgroundColor(m_default_tooltip_bgcolor);
- m_tooltip_element->setOverrideColor(m_default_tooltip_color);
- m_tooltip_element->setVisible(true);
- this->bringToFront(m_tooltip_element);
- setStaticText(m_tooltip_element, tooltip_text.c_str());
- s32 tooltip_width = m_tooltip_element->getTextWidth() + m_btn_height;
-#if (IRRLICHT_VERSION_MAJOR <= 1 && IRRLICHT_VERSION_MINOR <= 8 && IRRLICHT_VERSION_REVISION < 2) || USE_FREETYPE == 1
- s32 tooltip_height = m_tooltip_element->getTextHeight() * tt_rows.size() + 5;
-#else
- s32 tooltip_height = m_tooltip_element->getTextHeight() + 5;
-#endif
- v2u32 screenSize = driver->getScreenSize();
- int tooltip_offset_x = m_btn_height;
- int tooltip_offset_y = m_btn_height;
-#ifdef __ANDROID__
- tooltip_offset_x *= 3;
- tooltip_offset_y = 0;
- if (m_pointer.X > (s32)screenSize.X / 2)
- tooltip_offset_x = (tooltip_offset_x + tooltip_width) * -1;
-#endif
- s32 tooltip_x = m_pointer.X + tooltip_offset_x;
- s32 tooltip_y = m_pointer.Y + tooltip_offset_y;
- if (tooltip_x + tooltip_width > (s32)screenSize.X)
- tooltip_x = (s32)screenSize.X - tooltip_width - m_btn_height;
- if (tooltip_y + tooltip_height > (s32)screenSize.Y)
- tooltip_y = (s32)screenSize.Y - tooltip_height - m_btn_height;
- m_tooltip_element->setRelativePosition(core::rect<s32>(
- core::position2d<s32>(tooltip_x, tooltip_y),
- core::dimension2d<s32>(tooltip_width, tooltip_height)));
+ if (!tooltip_text.empty()) {
+ showTooltip(tooltip_text, m_default_tooltip_color,
+ m_default_tooltip_bgcolor);
}
}
}
@@ -2349,7 +2414,7 @@ void GUIFormSpecMenu::drawSelectedItem()
if (!m_selected_item) {
drawItemStack(driver, m_font, ItemStack(),
core::rect<s32>(v2s32(0, 0), v2s32(0, 0)),
- NULL, m_gamedef, IT_ROT_DRAGGED);
+ NULL, m_client, IT_ROT_DRAGGED);
return;
}
@@ -2363,7 +2428,7 @@ void GUIFormSpecMenu::drawSelectedItem()
core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
core::rect<s32> rect = imgrect + (m_pointer - imgrect.getCenter());
rect.constrainTo(driver->getViewPort());
- drawItemStack(driver, m_font, stack, rect, NULL, m_gamedef, IT_ROT_DRAGGED);
+ drawItemStack(driver, m_font, stack, rect, NULL, m_client, IT_ROT_DRAGGED);
}
void GUIFormSpecMenu::drawMenu()
@@ -2488,11 +2553,11 @@ void GUIFormSpecMenu::drawMenu()
*/
for(u32 i=0; i<m_itemimages.size(); i++)
{
- if (m_gamedef == 0)
+ if (m_client == 0)
break;
const ImageDrawSpec &spec = m_itemimages[i];
- IItemDefManager *idef = m_gamedef->idef();
+ IItemDefManager *idef = m_client->idef();
ItemStack item;
item.deSerialize(spec.item_name, idef);
core::rect<s32> imgrect(0, 0, spec.geom.X, spec.geom.Y);
@@ -2509,7 +2574,7 @@ void GUIFormSpecMenu::drawMenu()
#endif
}
drawItemStack(driver, m_font, item, rect, &AbsoluteClippingRect,
- m_gamedef, IT_ROT_NONE);
+ m_client, IT_ROT_NONE);
}
/*
@@ -2527,7 +2592,7 @@ void GUIFormSpecMenu::drawMenu()
if (!item_hovered) {
drawItemStack(driver, m_font, ItemStack(),
core::rect<s32>(v2s32(0, 0), v2s32(0, 0)),
- NULL, m_gamedef, IT_ROT_HOVERED);
+ NULL, m_client, IT_ROT_HOVERED);
}
/* TODO find way to show tooltips on touchscreen */
@@ -2566,53 +2631,33 @@ void GUIFormSpecMenu::drawMenu()
if (hovered != NULL) {
s32 id = hovered->getID();
- u32 delta = 0;
+ u64 delta = 0;
if (id == -1) {
m_old_tooltip_id = id;
m_old_tooltip = L"";
} else {
if (id == m_old_tooltip_id) {
- delta = porting::getDeltaMs(m_hovered_time, getTimeMs());
+ delta = porting::getDeltaMs(m_hovered_time, porting::getTimeMs());
} else {
- m_hovered_time = getTimeMs();
+ m_hovered_time = porting::getTimeMs();
m_old_tooltip_id = id;
}
}
+ // Find and update the current tooltip
if (id != -1 && delta >= m_tooltip_show_delay) {
- for(std::vector<FieldSpec>::iterator iter = m_fields.begin();
+ for (std::vector<FieldSpec>::iterator iter = m_fields.begin();
iter != m_fields.end(); ++iter) {
- if (iter->fid == id && m_tooltips[iter->fname].tooltip != L"") {
- if (m_old_tooltip != m_tooltips[iter->fname].tooltip) {
- m_tooltip_element->setBackgroundColor(m_tooltips[iter->fname].bgcolor);
- m_tooltip_element->setOverrideColor(m_tooltips[iter->fname].color);
- m_old_tooltip = m_tooltips[iter->fname].tooltip;
- setStaticText(m_tooltip_element, m_tooltips[iter->fname].tooltip.c_str());
- std::vector<std::wstring> tt_rows = str_split(m_tooltips[iter->fname].tooltip, L'\n');
- s32 tooltip_width = m_tooltip_element->getTextWidth() + m_btn_height;
- s32 tooltip_height = m_tooltip_element->getTextHeight() * tt_rows.size() + 5;
- int tooltip_offset_x = m_btn_height;
- int tooltip_offset_y = m_btn_height;
-#ifdef __ANDROID__
- tooltip_offset_x *= 3;
- tooltip_offset_y = 0;
- if (m_pointer.X > (s32)screenSize.X / 2)
- tooltip_offset_x = (tooltip_offset_x + tooltip_width) * -1;
-#endif
- s32 tooltip_x = m_pointer.X + tooltip_offset_x;
- s32 tooltip_y = m_pointer.Y + tooltip_offset_y;
- if (tooltip_x + tooltip_width > (s32)screenSize.X)
- tooltip_x = (s32)screenSize.X - tooltip_width - m_btn_height;
- if (tooltip_y + tooltip_height > (s32)screenSize.Y)
- tooltip_y = (s32)screenSize.Y - tooltip_height - m_btn_height;
- m_tooltip_element->setRelativePosition(core::rect<s32>(
- core::position2d<s32>(tooltip_x, tooltip_y),
- core::dimension2d<s32>(tooltip_width, tooltip_height)));
- }
- m_tooltip_element->setVisible(true);
- this->bringToFront(m_tooltip_element);
- break;
- }
+
+ if (iter->fid != id)
+ continue;
+
+ const std::wstring &text = m_tooltips[iter->fname].tooltip;
+ if (!text.empty())
+ showTooltip(text, m_tooltips[iter->fname].color,
+ m_tooltips[iter->fname].bgcolor);
+
+ break;
}
}
}
@@ -2627,6 +2672,53 @@ void GUIFormSpecMenu::drawMenu()
skin->setFont(old_font);
}
+
+void GUIFormSpecMenu::showTooltip(const std::wstring &text,
+ const irr::video::SColor &color, const irr::video::SColor &bgcolor)
+{
+ m_tooltip_element->setOverrideColor(color);
+ m_tooltip_element->setBackgroundColor(bgcolor);
+ m_old_tooltip = text;
+ setStaticText(m_tooltip_element, text.c_str());
+
+ // Tooltip size and offset
+ s32 tooltip_width = m_tooltip_element->getTextWidth() + m_btn_height;
+#if (IRRLICHT_VERSION_MAJOR <= 1 && IRRLICHT_VERSION_MINOR <= 8 && IRRLICHT_VERSION_REVISION < 2) || USE_FREETYPE == 1
+ std::vector<std::wstring> text_rows = str_split(text, L'\n');
+ s32 tooltip_height = m_tooltip_element->getTextHeight() * text_rows.size() + 5;
+#else
+ s32 tooltip_height = m_tooltip_element->getTextHeight() + 5;
+#endif
+ v2u32 screenSize = Environment->getVideoDriver()->getScreenSize();
+ int tooltip_offset_x = m_btn_height;
+ int tooltip_offset_y = m_btn_height;
+#ifdef __ANDROID__
+ tooltip_offset_x *= 3;
+ tooltip_offset_y = 0;
+ if (m_pointer.X > (s32)screenSize.X / 2)
+ tooltip_offset_x = -(tooltip_offset_x + tooltip_width);
+#endif
+
+ // Calculate and set the tooltip position
+ s32 tooltip_x = m_pointer.X + tooltip_offset_x;
+ s32 tooltip_y = m_pointer.Y + tooltip_offset_y;
+ if (tooltip_x + tooltip_width > (s32)screenSize.X)
+ tooltip_x = (s32)screenSize.X - tooltip_width - m_btn_height;
+ if (tooltip_y + tooltip_height > (s32)screenSize.Y)
+ tooltip_y = (s32)screenSize.Y - tooltip_height - m_btn_height;
+
+ m_tooltip_element->setRelativePosition(
+ core::rect<s32>(
+ core::position2d<s32>(tooltip_x, tooltip_y),
+ core::dimension2d<s32>(tooltip_width, tooltip_height)
+ )
+ );
+
+ // Display the tooltip
+ m_tooltip_element->setVisible(true);
+ bringToFront(m_tooltip_element);
+}
+
void GUIFormSpecMenu::updateSelectedItem()
{
// If the selected stack has become empty for some reason, deselect it.
@@ -3152,10 +3244,10 @@ bool GUIFormSpecMenu::DoubleClickDetection(const SEvent event)
m_doubleclickdetect[0].time = m_doubleclickdetect[1].time;
m_doubleclickdetect[1].pos = m_pointer;
- m_doubleclickdetect[1].time = getTimeMs();
+ m_doubleclickdetect[1].time = porting::getTimeMs();
}
else if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) {
- u32 delta = porting::getDeltaMs(m_doubleclickdetect[0].time, getTimeMs());
+ u64 delta = porting::getDeltaMs(m_doubleclickdetect[0].time, porting::getTimeMs());
if (delta > 400) {
return false;
}
@@ -3204,8 +3296,9 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
{
if (event.EventType==EET_KEY_INPUT_EVENT) {
KeyPress kp(event.KeyInput);
- if (event.KeyInput.PressedDown && ( (kp == EscapeKey) ||
- (kp == getKeySetting("keymap_inventory")) || (kp == CancelKey))) {
+ if (event.KeyInput.PressedDown && (
+ (kp == EscapeKey) || (kp == CancelKey) ||
+ ((m_client != NULL) && (kp == getKeySetting("keymap_inventory"))))) {
tryClose();
return true;
} else if (m_client != NULL && event.KeyInput.PressedDown &&
@@ -3470,7 +3563,7 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
// Check how many items can be moved
move_amount = stack_from.count = MYMIN(move_amount, stack_from.count);
- ItemStack leftover = stack_to.addItem(stack_from, m_gamedef->idef());
+ ItemStack leftover = stack_to.addItem(stack_from, m_client->idef());
// If source stack cannot be added to destination stack at all,
// they are swapped
if ((leftover.count == stack_from.count) &&
diff --git a/src/guiFormSpecMenu.h b/src/guiFormSpecMenu.h
index 95df11e6a..9eaf60ac6 100644
--- a/src/guiFormSpecMenu.h
+++ b/src/guiFormSpecMenu.h
@@ -25,7 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <stack>
#include "irrlichttypes_extrabloated.h"
-#include "inventory.h"
#include "inventorymanager.h"
#include "modalMenu.h"
#include "guiTable.h"
@@ -34,7 +33,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h"
#include "util/enriched_string.h"
-class IGameDef;
class InventoryManager;
class ISimpleTextureSource;
class Client;
@@ -57,12 +55,10 @@ typedef enum {
struct TextDest
{
- virtual ~TextDest() {};
+ virtual ~TextDest() {}
// This is deprecated I guess? -celeron55
- virtual void gotText(std::wstring text){}
+ virtual void gotText(const std::wstring &text) {}
virtual void gotText(const StringMap &fields) = 0;
- virtual void setFormName(std::string formname)
- { m_formname = formname;};
std::string m_formname;
};
@@ -73,30 +69,29 @@ public:
virtual ~IFormSource(){}
virtual std::string getForm() = 0;
// Fill in variables in field text
- virtual std::string resolveText(std::string str){ return str; }
+ virtual std::string resolveText(const std::string &str) { return str; }
};
class GUIFormSpecMenu : public GUIModalMenu
{
struct ItemSpec
{
- ItemSpec()
+ ItemSpec() :
+ i(-1)
{
- i = -1;
}
+
ItemSpec(const InventoryLocation &a_inventoryloc,
const std::string &a_listname,
- s32 a_i)
- {
- inventoryloc = a_inventoryloc;
- listname = a_listname;
- i = a_i;
- }
- bool isValid() const
+ s32 a_i) :
+ inventoryloc(a_inventoryloc),
+ listname(a_listname),
+ i(a_i)
{
- return i != -1;
}
+ bool isValid() const { return i != -1; }
+
InventoryLocation inventoryloc;
std::string listname;
s32 i;
@@ -146,7 +141,8 @@ class GUIFormSpecMenu : public GUIModalMenu
ImageDrawSpec():
parent_button(NULL),
clip(false)
- {}
+ {
+ }
ImageDrawSpec(const std::string &a_name,
const std::string &a_item_name,
@@ -159,7 +155,8 @@ class GUIFormSpecMenu : public GUIModalMenu
geom(a_geom),
scale(true),
clip(false)
- {}
+ {
+ }
ImageDrawSpec(const std::string &a_name,
const std::string &a_item_name,
@@ -171,7 +168,8 @@ class GUIFormSpecMenu : public GUIModalMenu
geom(a_geom),
scale(true),
clip(false)
- {}
+ {
+ }
ImageDrawSpec(const std::string &a_name,
const v2s32 &a_pos, const v2s32 &a_geom, bool clip=false):
@@ -181,7 +179,8 @@ class GUIFormSpecMenu : public GUIModalMenu
geom(a_geom),
scale(true),
clip(clip)
- {}
+ {
+ }
ImageDrawSpec(const std::string &a_name,
const v2s32 &a_pos):
@@ -190,7 +189,8 @@ class GUIFormSpecMenu : public GUIModalMenu
pos(a_pos),
scale(false),
clip(false)
- {}
+ {
+ }
std::string name;
std::string item_name;
@@ -210,14 +210,14 @@ class GUIFormSpecMenu : public GUIModalMenu
const std::wstring &default_text, int id) :
fname(name),
flabel(label),
+ fdefault(unescape_enriched(default_text)),
fid(id),
send(false),
ftype(f_Unknown),
is_exit(false)
{
- //flabel = unescape_enriched(label);
- fdefault = unescape_enriched(default_text);
}
+
std::string fname;
std::wstring flabel;
std::wstring fdefault;
@@ -228,7 +228,8 @@ class GUIFormSpecMenu : public GUIModalMenu
core::rect<s32> rect;
};
- struct BoxDrawSpec {
+ struct BoxDrawSpec
+ {
BoxDrawSpec(v2s32 a_pos, v2s32 a_geom,irr::video::SColor a_color):
pos(a_pos),
geom(a_geom),
@@ -240,45 +241,46 @@ class GUIFormSpecMenu : public GUIModalMenu
irr::video::SColor color;
};
- struct TooltipSpec {
- TooltipSpec()
- {
- }
- TooltipSpec(std::string a_tooltip, irr::video::SColor a_bgcolor,
+ struct TooltipSpec
+ {
+ TooltipSpec() {}
+ TooltipSpec(const std::string &a_tooltip, irr::video::SColor a_bgcolor,
irr::video::SColor a_color):
+ tooltip(utf8_to_wide(a_tooltip)),
bgcolor(a_bgcolor),
color(a_color)
{
- //tooltip = unescape_enriched(utf8_to_wide(a_tooltip));
- tooltip = utf8_to_wide(a_tooltip);
}
+
std::wstring tooltip;
irr::video::SColor bgcolor;
irr::video::SColor color;
};
- struct StaticTextSpec {
+ struct StaticTextSpec
+ {
StaticTextSpec():
parent_button(NULL)
{
}
+
StaticTextSpec(const std::wstring &a_text,
const core::rect<s32> &a_rect):
+ text(a_text),
rect(a_rect),
parent_button(NULL)
{
- //text = unescape_enriched(a_text);
- text = a_text;
}
+
StaticTextSpec(const std::wstring &a_text,
const core::rect<s32> &a_rect,
gui::IGUIButton *a_parent_button):
+ text(a_text),
rect(a_rect),
parent_button(a_parent_button)
{
- //text = unescape_enriched(a_text);
- text = a_text;
}
+
std::wstring text;
core::rect<s32> rect;
gui::IGUIButton *parent_button;
@@ -289,18 +291,16 @@ public:
JoystickController *joystick,
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr,
- InventoryManager *invmgr,
- IGameDef *gamedef,
+ Client *client,
ISimpleTextureSource *tsrc,
IFormSource* fs_src,
TextDest* txt_dst,
- Client* client,
bool remap_dbl_click = true);
~GUIFormSpecMenu();
void setFormSpec(const std::string &formspec_string,
- InventoryLocation current_inventory_location)
+ const InventoryLocation &current_inventory_location)
{
m_formspec_string = formspec_string;
m_current_inventory_location = current_inventory_location;
@@ -339,7 +339,7 @@ public:
void removeChildren();
void setInitialFocus();
- void setFocus(std::string &elementname)
+ void setFocus(const std::string &elementname)
{
m_focused_element = elementname;
}
@@ -384,7 +384,6 @@ protected:
irr::IrrlichtDevice* m_device;
InventoryManager *m_invmgr;
- IGameDef *m_gamedef;
ISimpleTextureSource *m_tsrc;
Client *m_client;
@@ -421,8 +420,8 @@ protected:
v2s32 m_old_pointer; // Mouse position after previous mouse event
gui::IGUIStaticText *m_tooltip_element;
- u32 m_tooltip_show_delay;
- s32 m_hovered_time;
+ u64 m_tooltip_show_delay;
+ u64 m_hovered_time;
s32 m_old_tooltip_id;
std::wstring m_old_tooltip;
@@ -452,6 +451,8 @@ private:
bool explicit_size;
v2f invsize;
v2s32 size;
+ v2f32 offset;
+ v2f32 anchor;
core::rect<s32> rect;
v2s32 basepos;
v2u32 screensize;
@@ -472,44 +473,53 @@ private:
fs_key_pendig current_keys_pending;
std::string current_field_enter_pending;
- void parseElement(parserData* data, std::string element);
+ void parseElement(parserData* data, const std::string &element);
- void parseSize(parserData* data, std::string element);
- void parseContainer(parserData* data, std::string element);
+ void parseSize(parserData* data, const std::string &element);
+ void parseContainer(parserData* data, const std::string &element);
void parseContainerEnd(parserData* data);
- void parseList(parserData* data, std::string element);
- void parseListRing(parserData* data, std::string element);
- void parseCheckbox(parserData* data, std::string element);
- void parseImage(parserData* data, std::string element);
- void parseItemImage(parserData* data,std::string element);
- void parseButton(parserData* data,std::string element,std::string typ);
- void parseBackground(parserData* data,std::string element);
- void parseTableOptions(parserData* data,std::string element);
- void parseTableColumns(parserData* data,std::string element);
- void parseTable(parserData* data,std::string element);
- void parseTextList(parserData* data,std::string element);
- void parseDropDown(parserData* data,std::string element);
+ void parseList(parserData* data, const std::string &element);
+ void parseListRing(parserData* data, const std::string &element);
+ void parseCheckbox(parserData* data, const std::string &element);
+ void parseImage(parserData* data, const std::string &element);
+ void parseItemImage(parserData* data, const std::string &element);
+ void parseButton(parserData* data, const std::string &element,
+ const std::string &typ);
+ void parseBackground(parserData* data, const std::string &element);
+ void parseTableOptions(parserData* data, const std::string &element);
+ void parseTableColumns(parserData* data, const std::string &element);
+ void parseTable(parserData* data, const std::string &element);
+ void parseTextList(parserData* data, const std::string &element);
+ void parseDropDown(parserData* data, const std::string &element);
void parseFieldCloseOnEnter(parserData *data, const std::string &element);
- void parsePwdField(parserData* data,std::string element);
- void parseField(parserData* data,std::string element,std::string type);
+ void parsePwdField(parserData* data, const std::string &element);
+ void parseField(parserData* data, const std::string &element, const std::string &type);
void parseSimpleField(parserData* data,std::vector<std::string> &parts);
void parseTextArea(parserData* data,std::vector<std::string>& parts,
- std::string type);
- void parseLabel(parserData* data,std::string element);
- void parseVertLabel(parserData* data,std::string element);
- void parseImageButton(parserData* data,std::string element,std::string type);
- void parseItemImageButton(parserData* data,std::string element);
- void parseTabHeader(parserData* data,std::string element);
- void parseBox(parserData* data,std::string element);
- void parseBackgroundColor(parserData* data,std::string element);
- void parseListColors(parserData* data,std::string element);
- void parseTooltip(parserData* data,std::string element);
- bool parseVersionDirect(std::string data);
- bool parseSizeDirect(parserData* data, std::string element);
- void parseScrollBar(parserData* data, std::string element);
+ const std::string &type);
+ void parseLabel(parserData* data, const std::string &element);
+ void parseVertLabel(parserData* data, const std::string &element);
+ void parseImageButton(parserData* data, const std::string &element,
+ const std::string &type);
+ void parseItemImageButton(parserData* data, const std::string &element);
+ void parseTabHeader(parserData* data, const std::string &element);
+ void parseBox(parserData* data, const std::string &element);
+ void parseBackgroundColor(parserData* data, const std::string &element);
+ void parseListColors(parserData* data, const std::string &element);
+ void parseTooltip(parserData* data, const std::string &element);
+ bool parseVersionDirect(const std::string &data);
+ bool parseSizeDirect(parserData* data, const std::string &element);
+ void parseScrollBar(parserData* data, const std::string &element);
+ bool parsePositionDirect(parserData *data, const std::string &element);
+ void parsePosition(parserData *data, const std::string &element);
+ bool parseAnchorDirect(parserData *data, const std::string &element);
+ void parseAnchor(parserData *data, const std::string &element);
void tryClose();
+ void showTooltip(const std::wstring &text, const irr::video::SColor &color,
+ const irr::video::SColor &bgcolor);
+
/**
* check if event is part of a double click
* @param event event to evaluate
@@ -520,7 +530,7 @@ private:
struct clickpos
{
v2s32 pos;
- s32 time;
+ s64 time;
};
clickpos m_doubleclickdetect[2];
@@ -547,23 +557,22 @@ private:
class FormspecFormSource: public IFormSource
{
public:
- FormspecFormSource(std::string formspec)
+ FormspecFormSource(const std::string &formspec):
+ m_formspec(formspec)
{
- m_formspec = formspec;
}
~FormspecFormSource()
- {}
-
- void setForm(std::string formspec) {
- m_formspec = FORMSPEC_VERSION_STRING + formspec;
+ {
}
- std::string getForm()
+ void setForm(const std::string &formspec)
{
- return m_formspec;
+ m_formspec = FORMSPEC_VERSION_STRING + formspec;
}
+ std::string getForm() { return m_formspec; }
+
std::string m_formspec;
};
diff --git a/src/guiKeyChangeMenu.cpp b/src/guiKeyChangeMenu.cpp
index 07137d1bc..ae53c56f9 100644
--- a/src/guiKeyChangeMenu.cpp
+++ b/src/guiKeyChangeMenu.cpp
@@ -53,10 +53,16 @@ enum
GUI_ID_KEY_CINEMATIC_BUTTON,
GUI_ID_KEY_CHAT_BUTTON,
GUI_ID_KEY_CMD_BUTTON,
+ GUI_ID_KEY_CMD_LOCAL_BUTTON,
GUI_ID_KEY_CONSOLE_BUTTON,
GUI_ID_KEY_SNEAK_BUTTON,
GUI_ID_KEY_DROP_BUTTON,
GUI_ID_KEY_INVENTORY_BUTTON,
+ GUI_ID_KEY_HOTBAR_PREV_BUTTON,
+ GUI_ID_KEY_HOTBAR_NEXT_BUTTON,
+ GUI_ID_KEY_MUTE_BUTTON,
+ GUI_ID_KEY_DEC_VOLUME_BUTTON,
+ GUI_ID_KEY_INC_VOLUME_BUTTON,
GUI_ID_KEY_DUMP_BUTTON,
GUI_ID_KEY_RANGE_BUTTON,
GUI_ID_KEY_ZOOM_BUTTON,
@@ -108,7 +114,7 @@ void GUIKeyChangeMenu::removeChildren()
void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
{
removeChildren();
- v2s32 size(620, 430);
+ v2s32 size(745, 430);
core::rect < s32 > rect(screensize.X / 2 - size.X / 2,
screensize.Y / 2 - size.Y / 2, screensize.X / 2 + size.X / 2,
@@ -145,15 +151,17 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
{
core::rect < s32 > rect(0, 0, 100, 30);
- rect += topleft + v2s32(offset.X + 115, offset.Y - 5);
+ rect += topleft + v2s32(offset.X + 120, offset.Y - 5);
const wchar_t *text = wgettext(k->key.name());
k->button = Environment->addButton(rect, this, k->id, text);
delete[] text;
}
- if(i + 1 == KMaxButtonPerColumns)
- offset = v2s32(260, 60);
- else
+ if ((i + 1) % KMaxButtonPerColumns == 0) {
+ offset.X += 230;
+ offset.Y = 60;
+ } else {
offset += v2s32(0, 25);
+ }
}
{
@@ -214,7 +222,7 @@ void GUIKeyChangeMenu::drawMenu()
video::SColor bgcolor(140, 0, 0, 0);
{
- core::rect < s32 > rect(0, 0, 620, 620);
+ core::rect < s32 > rect(0, 0, 745, 620);
rect += AbsoluteRect.UpperLeftCorner;
driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
}
@@ -406,8 +414,14 @@ void GUIKeyChangeMenu::init_keys()
this->add_key(GUI_ID_KEY_SNEAK_BUTTON, wgettext("Sneak"), "keymap_sneak");
this->add_key(GUI_ID_KEY_DROP_BUTTON, wgettext("Drop"), "keymap_drop");
this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"), "keymap_inventory");
+ this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON,wgettext("Prev. item"), "keymap_hotbar_previous");
+ this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON,wgettext("Next item"), "keymap_hotbar_next");
+ this->add_key(GUI_ID_KEY_MUTE_BUTTON, wgettext("Mute"), "keymap_mute");
+ this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON,wgettext("Dec. volume"), "keymap_decrease_volume");
+ this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON,wgettext("Inc. volume"), "keymap_increase_volume");
this->add_key(GUI_ID_KEY_CHAT_BUTTON, wgettext("Chat"), "keymap_chat");
this->add_key(GUI_ID_KEY_CMD_BUTTON, wgettext("Command"), "keymap_cmd");
+ this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON, wgettext("Local command"), "keymap_cmd_local");
this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, wgettext("Console"), "keymap_console");
this->add_key(GUI_ID_KEY_FLY_BUTTON, wgettext("Toggle fly"), "keymap_freemove");
this->add_key(GUI_ID_KEY_FAST_BUTTON, wgettext("Toggle fast"), "keymap_fastmove");
diff --git a/src/guiKeyChangeMenu.h b/src/guiKeyChangeMenu.h
index 19a07620d..1aa400632 100644
--- a/src/guiKeyChangeMenu.h
+++ b/src/guiKeyChangeMenu.h
@@ -30,7 +30,8 @@
#include <string>
#include <vector>
-struct key_setting {
+struct key_setting
+{
int id;
const wchar_t *button_name;
KeyPress key;
@@ -38,12 +39,11 @@ struct key_setting {
gui::IGUIButton *button;
};
-
-class GUIKeyChangeMenu: public GUIModalMenu
+class GUIKeyChangeMenu : public GUIModalMenu
{
public:
- GUIKeyChangeMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent,
- s32 id, IMenuManager *menumgr);
+ GUIKeyChangeMenu(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
+ IMenuManager *menumgr);
~GUIKeyChangeMenu();
void removeChildren();
@@ -56,10 +56,9 @@ public:
bool acceptInput();
- bool OnEvent(const SEvent& event);
+ bool OnEvent(const SEvent &event);
private:
-
void init_keys();
bool resetMenu();
@@ -67,13 +66,12 @@ private:
void add_key(int id, const wchar_t *button_name, const std::string &setting_name);
bool shift_down;
-
+
s32 activeKey;
-
+
std::vector<KeyPress> key_used;
gui::IGUIStaticText *key_used_text;
std::vector<key_setting *> key_settings;
};
#endif
-
diff --git a/src/guiPasswordChange.cpp b/src/guiPasswordChange.cpp
index e2f9994be..c8eb36e5f 100644
--- a/src/guiPasswordChange.cpp
+++ b/src/guiPasswordChange.cpp
@@ -33,6 +33,7 @@ const int ID_newPassword1 = 257;
const int ID_newPassword2 = 258;
const int ID_change = 259;
const int ID_message = 260;
+const int ID_cancel = 261;
GUIPasswordChange::GUIPasswordChange(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
@@ -40,7 +41,10 @@ GUIPasswordChange::GUIPasswordChange(gui::IGUIEnvironment* env,
Client* client
):
GUIModalMenu(env, parent, id, menumgr),
- m_client(client)
+ m_client(client),
+ m_oldpass(L""),
+ m_newpass(L""),
+ m_newpass_confirm(L"")
{
}
@@ -51,31 +55,25 @@ GUIPasswordChange::~GUIPasswordChange()
void GUIPasswordChange::removeChildren()
{
- {
- gui::IGUIElement *e = getElementFromId(ID_oldPassword);
- if(e != NULL)
- e->remove();
- }
- {
- gui::IGUIElement *e = getElementFromId(ID_newPassword1);
- if(e != NULL)
- e->remove();
+ 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);
}
- {
- gui::IGUIElement *e = getElementFromId(ID_newPassword2);
- if(e != NULL)
- e->remove();
- }
- {
- gui::IGUIElement *e = getElementFromId(ID_change);
- if(e != NULL)
- e->remove();
+ for (core::list<gui::IGUIElement *>::Iterator i = children_copy.begin();
+ i != children_copy.end(); i++) {
+ (*i)->remove();
}
}
-
void GUIPasswordChange::regenerateGui(v2u32 screensize)
{
/*
+ save current input
+ */
+ acceptInput();
+
+ /*
Remove stuff
*/
removeChildren();
@@ -104,7 +102,7 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
s32 ypos = 50;
{
core::rect<s32> rect(0, 0, 150, 20);
- rect += topleft_client + v2s32(25, ypos+6);
+ rect += topleft_client + v2s32(25, ypos + 6);
text = wgettext("Old Password");
Environment->addStaticText(text, rect, false, true, this, -1);
delete[] text;
@@ -112,15 +110,15 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
{
core::rect<s32> rect(0, 0, 230, 30);
rect += topleft_client + v2s32(160, ypos);
- gui::IGUIEditBox *e =
- Environment->addEditBox(L"", rect, true, this, ID_oldPassword);
+ gui::IGUIEditBox *e = Environment->addEditBox(
+ m_oldpass.c_str(), rect, true, this, ID_oldPassword);
Environment->setFocus(e);
e->setPasswordBox(true);
}
ypos += 50;
{
core::rect<s32> rect(0, 0, 150, 20);
- rect += topleft_client + v2s32(25, ypos+6);
+ rect += topleft_client + v2s32(25, ypos + 6);
text = wgettext("New Password");
Environment->addStaticText(text, rect, false, true, this, -1);
delete[] text;
@@ -128,14 +126,14 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
{
core::rect<s32> rect(0, 0, 230, 30);
rect += topleft_client + v2s32(160, ypos);
- gui::IGUIEditBox *e =
- Environment->addEditBox(L"", rect, true, this, ID_newPassword1);
+ gui::IGUIEditBox *e = Environment->addEditBox(
+ m_newpass.c_str(), rect, true, this, ID_newPassword1);
e->setPasswordBox(true);
}
ypos += 50;
{
core::rect<s32> rect(0, 0, 150, 20);
- rect += topleft_client + v2s32(25, ypos+6);
+ rect += topleft_client + v2s32(25, ypos + 6);
text = wgettext("Confirm Password");
Environment->addStaticText(text, rect, false, true, this, -1);
delete[] text;
@@ -143,19 +141,26 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
{
core::rect<s32> rect(0, 0, 230, 30);
rect += topleft_client + v2s32(160, ypos);
- gui::IGUIEditBox *e =
- Environment->addEditBox(L"", rect, true, this, ID_newPassword2);
+ gui::IGUIEditBox *e = Environment->addEditBox(
+ m_newpass_confirm.c_str(), rect, true, this, ID_newPassword2);
e->setPasswordBox(true);
}
ypos += 50;
{
- core::rect<s32> rect(0, 0, 140, 30);
- rect = rect + v2s32(size.X/2-140/2, ypos);
+ core::rect<s32> rect(0, 0, 100, 30);
+ rect = rect + v2s32(size.X / 4 + 56, ypos);
text = wgettext("Change");
Environment->addButton(rect, this, ID_change, text);
delete[] text;
}
+ {
+ core::rect<s32> rect(0, 0, 100, 30);
+ rect = rect + v2s32(size.X / 4 + 185, ypos);
+ text = wgettext("Cancel");
+ Environment->addButton(rect, this, ID_cancel, text);
+ delete[] text;
+ }
ypos += 50;
{
@@ -163,9 +168,8 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
rect += topleft_client + v2s32(35, ypos);
text = wgettext("Passwords do not match!");
IGUIElement *e =
- Environment->addStaticText(
- text,
- rect, false, true, this, ID_message);
+ Environment->addStaticText(
+ text, rect, false, true, this, ID_message);
e->setVisible(false);
delete[] text;
}
@@ -173,88 +177,86 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
void GUIPasswordChange::drawMenu()
{
- gui::IGUISkin* skin = Environment->getSkin();
+ gui::IGUISkin *skin = Environment->getSkin();
if (!skin)
return;
- video::IVideoDriver* driver = Environment->getVideoDriver();
+ video::IVideoDriver *driver = Environment->getVideoDriver();
- video::SColor bgcolor(140,0,0,0);
+ video::SColor bgcolor(140, 0, 0, 0);
driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
gui::IGUIElement::draw();
}
-bool GUIPasswordChange::acceptInput()
+void GUIPasswordChange::acceptInput()
{
- std::wstring oldpass;
- std::wstring newpass;
- gui::IGUIElement *e;
- e = getElementFromId(ID_oldPassword);
- if(e != NULL)
- oldpass = e->getText();
- e = getElementFromId(ID_newPassword1);
- if(e != NULL)
- newpass = e->getText();
- e = getElementFromId(ID_newPassword2);
- if(e != NULL && newpass != e->getText())
- {
- e = getElementFromId(ID_message);
- if(e != NULL)
- e->setVisible(true);
- return false;
- }
- m_client->sendChangePassword(wide_to_utf8(oldpass),
- wide_to_utf8(newpass));
- return true;
+ gui::IGUIElement *e;
+ e = getElementFromId(ID_oldPassword);
+ if (e != NULL)
+ m_oldpass = e->getText();
+ e = getElementFromId(ID_newPassword1);
+ if (e != NULL)
+ m_newpass = e->getText();
+ e = getElementFromId(ID_newPassword2);
+ if (e != NULL)
+ m_newpass_confirm = e->getText();
}
-bool GUIPasswordChange::OnEvent(const SEvent& event)
+bool GUIPasswordChange::processInput()
{
- if(event.EventType==EET_KEY_INPUT_EVENT)
- {
- if(event.KeyInput.Key==KEY_ESCAPE && event.KeyInput.PressedDown)
- {
+ if (m_newpass != m_newpass_confirm) {
+ gui::IGUIElement *e = getElementFromId(ID_message);
+ if (e != NULL)
+ e->setVisible(true);
+ return false;
+ }
+ m_client->sendChangePassword(wide_to_utf8(m_oldpass), wide_to_utf8(m_newpass));
+ return true;
+}
+
+bool GUIPasswordChange::OnEvent(const SEvent &event)
+{
+ if (event.EventType == EET_KEY_INPUT_EVENT) {
+ if (event.KeyInput.Key == KEY_ESCAPE && event.KeyInput.PressedDown) {
quitMenu();
return true;
}
- if(event.KeyInput.Key==KEY_RETURN && event.KeyInput.PressedDown)
- {
- if(acceptInput())
+ if (event.KeyInput.Key == KEY_RETURN && event.KeyInput.PressedDown) {
+ acceptInput();
+ if (processInput())
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<<"GUIPasswordChange: Not allowing focus change."
- <<std::endl;
+ if (event.EventType == EET_GUI_EVENT) {
+ if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST &&
+ isVisible()) {
+ if (!canTakeFocus(event.GUIEvent.Element)) {
+ dstream << "GUIPasswordChange: 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())
- {
+ if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED) {
+ switch (event.GUIEvent.Caller->getID()) {
case ID_change:
- if(acceptInput())
+ acceptInput();
+ if (processInput())
quitMenu();
return true;
+ case ID_cancel:
+ quitMenu();
+ return true;
}
}
- if(event.GUIEvent.EventType==gui::EGET_EDITBOX_ENTER)
- {
- switch(event.GUIEvent.Caller->getID())
- {
+ if (event.GUIEvent.EventType == gui::EGET_EDITBOX_ENTER) {
+ switch (event.GUIEvent.Caller->getID()) {
case ID_oldPassword:
case ID_newPassword1:
case ID_newPassword2:
- if(acceptInput())
+ acceptInput();
+ if (processInput())
quitMenu();
return true;
}
@@ -263,4 +265,3 @@ bool GUIPasswordChange::OnEvent(const SEvent& event)
return Parent ? Parent->OnEvent(event) : false;
}
-
diff --git a/src/guiPasswordChange.h b/src/guiPasswordChange.h
index aecc7076f..9680ef13d 100644
--- a/src/guiPasswordChange.h
+++ b/src/guiPasswordChange.h
@@ -27,12 +27,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
class GUIPasswordChange : public GUIModalMenu
{
public:
- GUIPasswordChange(gui::IGUIEnvironment* env,
- gui::IGUIElement* parent, s32 id,
- IMenuManager *menumgr,
- Client* client);
+ GUIPasswordChange(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
+ IMenuManager *menumgr, Client *client);
~GUIPasswordChange();
-
+
void removeChildren();
/*
Remove and re-add (or reposition) stuff
@@ -41,14 +39,17 @@ public:
void drawMenu();
- bool acceptInput();
+ void acceptInput();
- bool OnEvent(const SEvent& event);
-
-private:
- Client* m_client;
+ bool processInput();
+
+ bool OnEvent(const SEvent &event);
+private:
+ Client *m_client;
+ std::wstring m_oldpass;
+ std::wstring m_newpass;
+ std::wstring m_newpass_confirm;
};
#endif
-
diff --git a/src/guiTable.cpp b/src/guiTable.cpp
index 6b33b8266..d223e3069 100644
--- a/src/guiTable.cpp
+++ b/src/guiTable.cpp
@@ -828,7 +828,7 @@ bool GUITable::OnEvent(const SEvent &event)
}
else if (event.KeyInput.PressedDown && event.KeyInput.Char) {
// change selection based on text as it is typed
- s32 now = getTimeMs();
+ u64 now = porting::getTimeMs();
if (now - m_keynav_time >= 500)
m_keynav_buffer = L"";
m_keynav_time = now;
diff --git a/src/guiTable.h b/src/guiTable.h
index 4d5b39166..02e8af00b 100644
--- a/src/guiTable.h
+++ b/src/guiTable.h
@@ -74,11 +74,10 @@ public:
std::string name;
std::string value;
- Option(const std::string &name_, const std::string &value_)
- {
- name = name_;
- value = value_;
- }
+ Option(const std::string &name_, const std::string &value_) :
+ name(name_),
+ value(value_)
+ {}
};
/*
@@ -197,7 +196,7 @@ protected:
bool m_sel_doubleclick;
// Keyboard navigation stuff
- s32 m_keynav_time;
+ u64 m_keynav_time;
core::stringw m_keynav_buffer;
// Drawing and geometry information
diff --git a/src/guiVolumeChange.cpp b/src/guiVolumeChange.cpp
index 8425bc04f..c7868ad35 100644
--- a/src/guiVolumeChange.cpp
+++ b/src/guiVolumeChange.cpp
@@ -30,10 +30,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "gettext.h"
-const int ID_soundText1 = 263;
-const int ID_soundText2 = 264;
-const int ID_soundExitButton = 265;
-const int ID_soundSlider = 266;
+const int ID_soundText = 263;
+const int ID_soundExitButton = 264;
+const int ID_soundSlider = 265;
GUIVolumeChange::GUIVolumeChange(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
@@ -50,10 +49,7 @@ GUIVolumeChange::~GUIVolumeChange()
void GUIVolumeChange::removeChildren()
{
- if (gui::IGUIElement *e = getElementFromId(ID_soundText1))
- e->remove();
-
- if (gui::IGUIElement *e = getElementFromId(ID_soundText2))
+ if (gui::IGUIElement *e = getElementFromId(ID_soundText))
e->remove();
if (gui::IGUIElement *e = getElementFromId(ID_soundExitButton))
@@ -69,39 +65,35 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize)
Remove stuff
*/
removeChildren();
-
+
/*
Calculate new sizes and positions
*/
- core::rect<s32> rect(
- screensize.X/2 - 380/2,
- screensize.Y/2 - 200/2,
- screensize.X/2 + 380/2,
- screensize.Y/2 + 200/2
+ DesiredRect = core::rect<s32>(
+ screensize.X/2 - 380/2,
+ screensize.Y/2 - 200/2,
+ screensize.X/2 + 380/2,
+ screensize.Y/2 + 200/2
);
-
- DesiredRect = rect;
recalculateAbsolutePosition(false);
- v2s32 size = rect.getSize();
- v2s32 topleft_client(40, 0);
- int volume = (int)(g_settings->getFloat("sound_volume")*100);
+ v2s32 size = DesiredRect.getSize();
+ int volume = (int)(g_settings->getFloat("sound_volume") * 100);
+
/*
Add stuff
*/
{
- core::rect<s32> rect(0, 0, 120, 20);
- rect = rect + v2s32(size.X/2-60, size.Y/2-35);
+ core::rect<s32> rect(0, 0, 160, 20);
+ rect = rect + v2s32(size.X / 2 - 80, size.Y / 2 - 35);
+
const wchar_t *text = wgettext("Sound Volume: ");
- Environment->addStaticText(text, rect, false,
- true, this, ID_soundText1);
- delete[] text;
- }
- {
- core::rect<s32> rect(0, 0, 30, 20);
- rect = rect + v2s32(size.X/2+40, size.Y/2-35);
- Environment->addStaticText(core::stringw(volume).c_str(), rect, false,
- true, this, ID_soundText2);
+ core::stringw volume_text = text;
+ delete [] text;
+
+ volume_text += core::stringw(volume) + core::stringw("%");
+ Environment->addStaticText(volume_text.c_str(), rect, false,
+ true, this, ID_soundText);
}
{
core::rect<s32> rect(0, 0, 80, 30);
@@ -156,10 +148,15 @@ bool GUIVolumeChange::OnEvent(const SEvent& event)
if (event.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED) {
if (event.GUIEvent.Caller->getID() == ID_soundSlider) {
s32 pos = ((gui::IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
- g_settings->setFloat("sound_volume", (float)pos/100);
+ g_settings->setFloat("sound_volume", (float) pos / 100);
+
+ gui::IGUIElement *e = getElementFromId(ID_soundText);
+ const wchar_t *text = wgettext("Sound Volume: ");
+ core::stringw volume_text = text;
+ delete [] text;
- gui::IGUIElement *e = getElementFromId(ID_soundText2);
- e->setText(core::stringw(pos).c_str());
+ volume_text += core::stringw(pos) + core::stringw("%");
+ e->setText(volume_text.c_str());
return true;
}
}
diff --git a/src/httpfetch.cpp b/src/httpfetch.cpp
index f64c9f717..3b3f5d331 100644
--- a/src/httpfetch.cpp
+++ b/src/httpfetch.cpp
@@ -40,16 +40,15 @@ Mutex g_httpfetch_mutex;
std::map<unsigned long, std::queue<HTTPFetchResult> > g_httpfetch_results;
PcgRandom g_callerid_randomness;
-HTTPFetchRequest::HTTPFetchRequest()
+HTTPFetchRequest::HTTPFetchRequest() :
+ url(""),
+ caller(HTTPFETCH_DISCARD),
+ request_id(0),
+ timeout(g_settings->getS32("curl_timeout")),
+ connect_timeout(timeout),
+ multipart(false),
+ useragent(std::string(PROJECT_NAME_C "/") + g_version_hash + " (" + porting::get_sysinfo() + ")")
{
- url = "";
- caller = HTTPFETCH_DISCARD;
- request_id = 0;
- timeout = g_settings->getS32("curl_timeout");
- connect_timeout = timeout;
- multipart = false;
-
- useragent = std::string(PROJECT_NAME_C "/") + g_version_hash + " (" + porting::get_sysinfo() + ")";
}
@@ -207,7 +206,7 @@ public:
class HTTPFetchOngoing
{
public:
- HTTPFetchOngoing(HTTPFetchRequest request, CurlHandlePool *pool);
+ HTTPFetchOngoing(const HTTPFetchRequest &request, CurlHandlePool *pool);
~HTTPFetchOngoing();
CURLcode start(CURLM *multi);
@@ -228,7 +227,8 @@ private:
};
-HTTPFetchOngoing::HTTPFetchOngoing(HTTPFetchRequest request_, CurlHandlePool *pool_):
+HTTPFetchOngoing::HTTPFetchOngoing(const HTTPFetchRequest &request_,
+ CurlHandlePool *pool_):
pool(pool_),
curl(NULL),
multi(NULL),
diff --git a/src/httpfetch.h b/src/httpfetch.h
index f57ed8789..29fb540d0 100644
--- a/src/httpfetch.h
+++ b/src/httpfetch.h
@@ -61,7 +61,7 @@ struct HTTPFetchRequest
// If not empty, should contain entries such as "Accept: text/html"
std::vector<std::string> extra_headers;
- //useragent to use
+ // useragent to use
std::string useragent;
HTTPFetchRequest();
@@ -78,25 +78,16 @@ struct HTTPFetchResult
unsigned long request_id;
HTTPFetchResult()
+ : succeeded(false), timeout(false), response_code(0), data(""),
+ caller(HTTPFETCH_DISCARD), request_id(0)
{
- succeeded = false;
- timeout = false;
- response_code = 0;
- data = "";
- caller = HTTPFETCH_DISCARD;
- request_id = 0;
}
HTTPFetchResult(const HTTPFetchRequest &fetch_request)
+ : succeeded(false), timeout(false), response_code(0), data(""),
+ caller(fetch_request.caller), request_id(fetch_request.request_id)
{
- succeeded = false;
- timeout = false;
- response_code = 0;
- data = "";
- caller = fetch_request.caller;
- request_id = fetch_request.request_id;
}
-
};
// Initializes the httpfetch module
@@ -126,8 +117,6 @@ void httpfetch_caller_free(unsigned long caller);
// Performs a synchronous HTTP request. This blocks and therefore should
// only be used from background threads.
-void httpfetch_sync(const HTTPFetchRequest &fetch_request,
- HTTPFetchResult &fetch_result);
-
+void httpfetch_sync(const HTTPFetchRequest &fetch_request, HTTPFetchResult &fetch_result);
#endif // !HTTPFETCH_HEADER
diff --git a/src/hud.cpp b/src/hud.cpp
index 43d957380..a2f031b4c 100644
--- a/src/hud.cpp
+++ b/src/hud.cpp
@@ -22,10 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "hud.h"
#include "settings.h"
#include "util/numeric.h"
-#include "util/string.h"
#include "log.h"
-#include "gamedef.h"
-#include "itemdef.h"
+#include "client.h"
#include "inventory.h"
#include "client/tile.h"
#include "localplayer.h"
@@ -34,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "fontengine.h"
#include "guiscalingfilter.h"
#include "mesh.h"
+#include "wieldmesh.h"
#include <IGUIStaticText.h>
#ifdef HAVE_TOUCHSCREENGUI
@@ -41,13 +40,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#endif
Hud::Hud(video::IVideoDriver *driver, scene::ISceneManager* smgr,
- gui::IGUIEnvironment* guienv, IGameDef *gamedef, LocalPlayer *player,
+ gui::IGUIEnvironment* guienv, Client *client, LocalPlayer *player,
Inventory *inventory)
{
this->driver = driver;
this->smgr = smgr;
this->guienv = guienv;
- this->gamedef = gamedef;
+ this->client = client;
this->player = player;
this->inventory = inventory;
@@ -61,7 +60,7 @@ Hud::Hud(video::IVideoDriver *driver, scene::ISceneManager* smgr,
for (unsigned int i = 0; i < 4; i++)
hbar_colors[i] = video::SColor(255, 255, 255, 255);
- tsrc = gamedef->getTextureSource();
+ tsrc = client->getTextureSource();
v3f crosshair_color = g_settings->getV3F("crosshair_color");
u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255);
@@ -88,24 +87,31 @@ Hud::Hud(video::IVideoDriver *driver, scene::ISceneManager* smgr,
m_halo_boxes.clear();
m_selection_pos = v3f(0.0, 0.0, 0.0);
- std::string mode = g_settings->get("node_highlighting");
+ std::string mode_setting = g_settings->get("node_highlighting");
+
+ if (mode_setting == "halo") {
+ m_mode = HIGHLIGHT_HALO;
+ } else if (mode_setting == "none") {
+ m_mode = HIGHLIGHT_NONE;
+ } else {
+ m_mode = HIGHLIGHT_BOX;
+ }
+
m_selection_material.Lighting = false;
if (g_settings->getBool("enable_shaders")) {
- IShaderSource *shdrsrc = gamedef->getShaderSource();
+ IShaderSource *shdrsrc = client->getShaderSource();
u16 shader_id = shdrsrc->getShader(
- mode == "halo" ? "selection_shader" : "default_shader", 1, 1);
+ m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", 1, 1);
m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material;
} else {
m_selection_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
}
- if (mode == "box") {
- m_use_selection_mesh = false;
+ if (m_mode == HIGHLIGHT_BOX) {
m_selection_material.Thickness =
rangelim(g_settings->getS16("selectionbox_width"), 1, 5);
- } else if (mode == "halo") {
- m_use_selection_mesh = true;
+ } else if (m_mode == HIGHLIGHT_HALO) {
m_selection_material.setTexture(0, tsrc->getTextureForMesh("halo.png"));
m_selection_material.setFlag(video::EMF_BACK_FACE_CULLING, true);
} else {
@@ -193,7 +199,7 @@ void Hud::drawItem(const ItemStack &item, const core::rect<s32>& rect,
if (!use_hotbar_image)
driver->draw2DRectangle(bgcolor2, rect, NULL);
drawItemStack(driver, g_fontengine->getFont(), item, rect, NULL,
- gamedef, selected ? IT_ROT_SELECTED : IT_ROT_NONE);
+ client, selected ? IT_ROT_SELECTED : IT_ROT_NONE);
}
//NOTE: selectitem = 0 -> no selected; selectitem 1-based
@@ -519,7 +525,7 @@ void Hud::setSelectionPos(const v3f &pos, const v3s16 &camera_offset)
void Hud::drawSelectionMesh()
{
- if (!m_use_selection_mesh) {
+ if (m_mode == HIGHLIGHT_BOX) {
// Draw 3D selection boxes
video::SMaterial oldmaterial = driver->getMaterial2D();
driver->setMaterial(m_selection_material);
@@ -539,7 +545,7 @@ void Hud::drawSelectionMesh()
driver->draw3DBox(box, video::SColor(255, r, g, b));
}
driver->setMaterial(oldmaterial);
- } else if (m_selection_mesh) {
+ } else if (m_mode == HIGHLIGHT_HALO && m_selection_mesh) {
// Draw selection mesh
video::SMaterial oldmaterial = driver->getMaterial2D();
driver->setMaterial(m_selection_material);
@@ -565,7 +571,7 @@ void Hud::drawSelectionMesh()
void Hud::updateSelectionMesh(const v3s16 &camera_offset)
{
m_camera_offset = camera_offset;
- if (!m_use_selection_mesh)
+ if (m_mode != HIGHLIGHT_HALO)
return;
if (m_selection_mesh) {
@@ -620,7 +626,7 @@ void Hud::resizeHotbar() {
}
struct MeshTimeInfo {
- s32 time;
+ u64 time;
scene::IMesh *mesh;
};
@@ -629,7 +635,7 @@ void drawItemStack(video::IVideoDriver *driver,
const ItemStack &item,
const core::rect<s32> &rect,
const core::rect<s32> *clip,
- IGameDef *gamedef,
+ Client *client,
ItemRotationKind rotation_kind)
{
static MeshTimeInfo rotation_time_infos[IT_ROT_NONE];
@@ -643,19 +649,20 @@ void drawItemStack(video::IVideoDriver *driver,
return;
}
- const ItemDefinition &def = item.getDefinition(gamedef->idef());
- scene::IMesh* mesh = gamedef->idef()->getWieldMesh(def.name, gamedef);
+ const ItemDefinition &def = item.getDefinition(client->idef());
+ ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client);
- if (mesh) {
+ if (imesh && imesh->mesh) {
+ scene::IMesh *mesh = imesh->mesh;
driver->clearZBuffer();
s32 delta = 0;
if (rotation_kind < IT_ROT_NONE) {
MeshTimeInfo &ti = rotation_time_infos[rotation_kind];
if (mesh != ti.mesh) {
ti.mesh = mesh;
- ti.time = getTimeMs();
+ ti.time = porting::getTimeMs();
} else {
- delta = porting::getDeltaMs(ti.time, getTimeMs()) % 100000;
+ delta = porting::getDeltaMs(ti.time, porting::getTimeMs()) % 100000;
}
}
core::rect<s32> oldViewPort = driver->getViewPort();
@@ -669,16 +676,32 @@ void drawItemStack(video::IVideoDriver *driver,
matrix.makeIdentity();
if (enable_animations) {
- float timer_f = (float)delta / 5000.0;
+ float timer_f = (float) delta / 5000.0;
matrix.setRotationDegrees(core::vector3df(0, 360 * timer_f, 0));
}
driver->setTransform(video::ETS_WORLD, matrix);
driver->setViewPort(rect);
+ video::SColor basecolor =
+ client->idef()->getItemstackColor(item, client);
+
u32 mc = mesh->getMeshBufferCount();
for (u32 j = 0; j < mc; ++j) {
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+ // we can modify vertices relatively fast,
+ // because these meshes are not buffered.
+ assert(buf->getHardwareMappingHint_Vertex() == scene::EHM_NEVER);
+ video::SColor c = basecolor;
+ if (imesh->buffer_colors.size() > j) {
+ ItemPartColor *p = &imesh->buffer_colors[j];
+ if (p->override_base)
+ c = p->color;
+ }
+ if (imesh->needs_shading)
+ colorizeMeshBuffer(buf, &c);
+ else
+ setMeshBufferColor(buf, c);
video::SMaterial &material = buf->getMaterial();
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
material.Lighting = false;
diff --git a/src/hud.h b/src/hud.h
index a4d7990e9..15c115d89 100644
--- a/src/hud.h
+++ b/src/hud.h
@@ -95,7 +95,7 @@ struct HudElement {
#include <IGUIFont.h>
#include "irr_aabb3d.h"
-class IGameDef;
+class Client;
class ITextureSource;
class Inventory;
class InventoryList;
@@ -107,7 +107,7 @@ public:
video::IVideoDriver *driver;
scene::ISceneManager* smgr;
gui::IGUIEnvironment *guienv;
- IGameDef *gamedef;
+ Client *client;
LocalPlayer *player;
Inventory *inventory;
ITextureSource *tsrc;
@@ -121,7 +121,7 @@ public:
bool use_hotbar_selected_image;
Hud(video::IVideoDriver *driver,scene::ISceneManager* smgr,
- gui::IGUIEnvironment* guienv, IGameDef *gamedef, LocalPlayer *player,
+ gui::IGUIEnvironment* guienv, Client *client, LocalPlayer *player,
Inventory *inventory);
~Hud();
@@ -175,7 +175,11 @@ private:
v3f m_selected_face_normal;
video::SMaterial m_selection_material;
- bool m_use_selection_mesh;
+
+ enum {
+ HIGHLIGHT_BOX,
+ HIGHLIGHT_HALO,
+ HIGHLIGHT_NONE } m_mode;
};
enum ItemRotationKind {
@@ -190,7 +194,7 @@ void drawItemStack(video::IVideoDriver *driver,
const ItemStack &item,
const core::rect<s32> &rect,
const core::rect<s32> *clip,
- IGameDef *gamedef,
+ Client *client,
ItemRotationKind rotation_kind);
#endif
diff --git a/src/intlGUIEditBox.cpp b/src/intlGUIEditBox.cpp
index 29f828076..37687e1e4 100644
--- a/src/intlGUIEditBox.cpp
+++ b/src/intlGUIEditBox.cpp
@@ -29,6 +29,7 @@
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
+#include <util/numeric.h>
#include "intlGUIEditBox.h"
#if defined(_IRR_COMPILE_WITH_GUI_) && IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9
@@ -1096,39 +1097,39 @@ s32 intlGUIEditBox::getCursorPos(s32 x, s32 y)
const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1;
- core::stringw *txtLine=0;
- s32 startPos=0;
- x+=3;
+ core::stringw *txtLine = NULL;
+ s32 startPos = 0;
+ u32 curr_line_idx = 0;
+ x += 3;
- for (u32 i=0; i < lineCount; ++i)
- {
- setTextRect(i);
- if (i == 0 && y < CurrentTextRect.UpperLeftCorner.Y)
+ for (; curr_line_idx < lineCount; ++curr_line_idx) {
+ setTextRect(curr_line_idx);
+ if (curr_line_idx == 0 && y < CurrentTextRect.UpperLeftCorner.Y)
y = CurrentTextRect.UpperLeftCorner.Y;
- if (i == lineCount - 1 && y > CurrentTextRect.LowerRightCorner.Y )
+ if (curr_line_idx == lineCount - 1 && y > CurrentTextRect.LowerRightCorner.Y)
y = CurrentTextRect.LowerRightCorner.Y;
// is it inside this region?
- if (y >= CurrentTextRect.UpperLeftCorner.Y && y <= CurrentTextRect.LowerRightCorner.Y)
- {
+ if (y >= CurrentTextRect.UpperLeftCorner.Y && y <= CurrentTextRect.LowerRightCorner.Y) {
// we've found the clicked line
- txtLine = (WordWrap || MultiLine) ? &BrokenText[i] : &Text;
- startPos = (WordWrap || MultiLine) ? BrokenTextPositions[i] : 0;
+ txtLine = (WordWrap || MultiLine) ? &BrokenText[curr_line_idx] : &Text;
+ startPos = (WordWrap || MultiLine) ? BrokenTextPositions[curr_line_idx] : 0;
break;
}
}
if (x < CurrentTextRect.UpperLeftCorner.X)
x = CurrentTextRect.UpperLeftCorner.X;
+ else if (x > CurrentTextRect.LowerRightCorner.X)
+ x = CurrentTextRect.LowerRightCorner.X;
- s32 idx = font->getCharacterFromPos(Text.c_str(), x - CurrentTextRect.UpperLeftCorner.X);
-
- // click was on or left of the line
- if (idx != -1)
- return idx + startPos;
+ s32 idx = font->getCharacterFromPos(txtLine->c_str(), x - CurrentTextRect.UpperLeftCorner.X);
+ // Special handling for last line, if we are on limits, add 1 extra shift because idx
+ // will be the last char, not null char of the wstring
+ if (curr_line_idx == lineCount - 1 && x == CurrentTextRect.LowerRightCorner.X)
+ idx++;
- // click was off the right edge of the line, go to end.
- return txtLine->size() + startPos;
+ return rangelim(idx + startPos, 0, S32_MAX);
}
diff --git a/src/intlGUIEditBox.h b/src/intlGUIEditBox.h
index e3ee15a30..bb617476c 100644
--- a/src/intlGUIEditBox.h
+++ b/src/intlGUIEditBox.h
@@ -155,7 +155,7 @@ namespace gui
gui::IGUIFont *OverrideFont, *LastBreakFont;
IOSOperator* Operator;
- u32 BlinkStartTime;
+ u64 BlinkStartTime;
s32 CursorPos;
s32 HScrollPos, VScrollPos; // scroll position in characters
u32 Max;
diff --git a/src/inventory.cpp b/src/inventory.cpp
index cb8faecbc..8617f7263 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -45,82 +45,15 @@ static content_t content_translate_from_19_to_internal(content_t c_from)
return c_from;
}
-// If the string contains spaces, quotes or control characters, encodes as JSON.
-// Else returns the string unmodified.
-static std::string serializeJsonStringIfNeeded(const std::string &s)
+ItemStack::ItemStack(const std::string &name_, u16 count_,
+ u16 wear_, IItemDefManager *itemdef) :
+ name(itemdef->getAlias(name_)),
+ count(count_),
+ wear(wear_)
{
- for(size_t i = 0; i < s.size(); ++i)
- {
- if(s[i] <= 0x1f || s[i] >= 0x7f || s[i] == ' ' || s[i] == '\"')
- return serializeJsonString(s);
- }
- return s;
-}
-
-// Parses a string serialized by serializeJsonStringIfNeeded.
-static std::string deSerializeJsonStringIfNeeded(std::istream &is)
-{
- std::ostringstream tmp_os;
- bool expect_initial_quote = true;
- bool is_json = false;
- bool was_backslash = false;
- for(;;)
- {
- char c = is.get();
- if(is.eof())
- break;
- if(expect_initial_quote && c == '"')
- {
- tmp_os << c;
- is_json = true;
- }
- else if(is_json)
- {
- tmp_os << c;
- if(was_backslash)
- was_backslash = false;
- else if(c == '\\')
- was_backslash = true;
- else if(c == '"')
- break; // Found end of string
- }
- else
- {
- if(c == ' ')
- {
- // Found end of word
- is.unget();
- break;
- }
- else
- {
- tmp_os << c;
- }
- }
- expect_initial_quote = false;
- }
- if(is_json)
- {
- std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
- return deSerializeJsonString(tmp_is);
- }
- else
- return tmp_os.str();
-}
-
-
-ItemStack::ItemStack(std::string name_, u16 count_,
- u16 wear_, std::string metadata_,
- IItemDefManager *itemdef)
-{
- name = itemdef->getAlias(name_);
- count = count_;
- wear = wear_;
- metadata = metadata_;
-
- if(name.empty() || count == 0)
+ if (name.empty() || count == 0)
clear();
- else if(itemdef->get(name).type == ITEM_TOOL)
+ else if (itemdef->get(name).type == ITEM_TOOL)
count = 1;
}
@@ -137,7 +70,7 @@ void ItemStack::serialize(std::ostream &os) const
parts = 2;
if(wear != 0)
parts = 3;
- if(metadata != "")
+ if (!metadata.empty())
parts = 4;
os<<serializeJsonStringIfNeeded(name);
@@ -145,8 +78,10 @@ void ItemStack::serialize(std::ostream &os) const
os<<" "<<count;
if(parts >= 3)
os<<" "<<wear;
- if(parts >= 4)
- os<<" "<<serializeJsonStringIfNeeded(metadata);
+ if (parts >= 4) {
+ os << " ";
+ metadata.serialize(os);
+ }
}
void ItemStack::deSerialize(std::istream &is, IItemDefManager *itemdef)
@@ -289,7 +224,7 @@ void ItemStack::deSerialize(std::istream &is, IItemDefManager *itemdef)
wear = stoi(wear_str);
// Read metadata
- metadata = deSerializeJsonStringIfNeeded(is);
+ metadata.deSerialize(is);
// In case fields are added after metadata, skip space here:
//std::getline(is, tmp, ' ');
@@ -335,7 +270,7 @@ ItemStack ItemStack::addItem(const ItemStack &newitem_,
*this = newitem;
newitem.clear();
}
- // If item name or metadata differs, bail out
+ // If item name or metadata differs, bail out
else if (name != newitem.name
|| metadata != newitem.metadata)
{
@@ -375,7 +310,7 @@ bool ItemStack::itemFits(const ItemStack &newitem_,
{
newitem.clear();
}
- // If item name or metadata differs, bail out
+ // If item name or metadata differs, bail out
else if (name != newitem.name
|| metadata != newitem.metadata)
{
@@ -434,14 +369,13 @@ ItemStack ItemStack::peekItem(u32 peekcount) const
Inventory
*/
-InventoryList::InventoryList(std::string name, u32 size, IItemDefManager *itemdef)
+InventoryList::InventoryList(const std::string &name, u32 size, IItemDefManager *itemdef):
+ m_name(name),
+ m_size(size),
+ m_width(0),
+ m_itemdef(itemdef)
{
- m_name = name;
- m_size = size;
- m_width = 0;
- m_itemdef = itemdef;
clearItems();
- //m_dirty = false;
}
InventoryList::~InventoryList()
@@ -776,14 +710,6 @@ ItemStack InventoryList::takeItem(u32 i, u32 takecount)
return taken;
}
-ItemStack InventoryList::peekItem(u32 i, u32 peekcount) const
-{
- if(i >= m_items.size())
- return ItemStack();
-
- return m_items[i].peekItem(peekcount);
-}
-
void InventoryList::moveItemSomewhere(u32 i, InventoryList *dest, u32 count)
{
// Take item from source list
diff --git a/src/inventory.h b/src/inventory.h
index 7d7e58d61..a9fef3b05 100644
--- a/src/inventory.h
+++ b/src/inventory.h
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "debug.h"
#include "itemdef.h"
#include "irrlichttypes.h"
+#include "itemstackmetadata.h"
#include <istream>
#include <ostream>
#include <string>
@@ -32,10 +33,10 @@ struct ToolCapabilities;
struct ItemStack
{
- ItemStack(): name(""), count(0), wear(0), metadata("") {}
- ItemStack(std::string name_, u16 count_,
- u16 wear, std::string metadata_,
- IItemDefManager *itemdef);
+ ItemStack(): name(""), count(0), wear(0) {}
+ ItemStack(const std::string &name_, u16 count_,
+ u16 wear, IItemDefManager *itemdef);
+
~ItemStack() {}
// Serialization
@@ -61,7 +62,7 @@ struct ItemStack
name = "";
count = 0;
wear = 0;
- metadata = "";
+ metadata.clear();
}
void add(u16 n)
@@ -166,13 +167,13 @@ struct ItemStack
std::string name;
u16 count;
u16 wear;
- std::string metadata;
+ ItemStackMetadata metadata;
};
class InventoryList
{
public:
- InventoryList(std::string name, u32 size, IItemDefManager *itemdef);
+ InventoryList(const std::string &name, u32 size, IItemDefManager *itemdef);
~InventoryList();
void clearItems();
void setSize(u32 newsize);
@@ -238,9 +239,6 @@ public:
// Returns empty item if couldn't take any.
ItemStack takeItem(u32 i, u32 takecount);
- // Similar to takeItem, but keeps the slot intact.
- ItemStack peekItem(u32 i, u32 peekcount) const;
-
// Move an item to a different list (or a different stack in the same list)
// count is the maximum number of items to move (0 for everything)
// returns number of moved items
@@ -253,8 +251,8 @@ public:
private:
std::vector<ItemStack> m_items;
- u32 m_size, m_width;
std::string m_name;
+ u32 m_size, m_width;
IItemDefManager *m_itemdef;
};
@@ -313,4 +311,3 @@ private:
};
#endif
-
diff --git a/src/inventorymanager.cpp b/src/inventorymanager.cpp
index 3d8513492..c976bd037 100644
--- a/src/inventorymanager.cpp
+++ b/src/inventorymanager.cpp
@@ -19,15 +19,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "inventorymanager.h"
#include "log.h"
-#include "environment.h"
-#include "scripting_game.h"
+#include "serverenvironment.h"
+#include "scripting_server.h"
#include "serverobject.h"
#include "settings.h"
#include "craftdef.h"
#include "rollback_interface.h"
#include "util/strfnd.h"
-
-#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
+#include "util/basic_macros.h"
#define PLAYER_TO_SA(p) p->getEnv()->getScriptIface()
diff --git a/src/irr_aabb3d.h b/src/irr_aabb3d.h
index 7ac401837..4c6b3f5e6 100644
--- a/src/irr_aabb3d.h
+++ b/src/irr_aabb3d.h
@@ -27,4 +27,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
typedef core::aabbox3d<f32> aabb3f;
#endif
-
diff --git a/src/irr_v2d.h b/src/irr_v2d.h
index 5c0d65a30..617491cf0 100644
--- a/src/irr_v2d.h
+++ b/src/irr_v2d.h
@@ -31,4 +31,3 @@ typedef core::vector2d<u32> v2u32;
typedef core::vector2d<f32> v2f32;
#endif
-
diff --git a/src/irr_v3d.h b/src/irr_v3d.h
index f74d601e8..fa6af3661 100644
--- a/src/irr_v3d.h
+++ b/src/irr_v3d.h
@@ -30,4 +30,3 @@ typedef core::vector3d<u16> v3u16;
typedef core::vector3d<s32> v3s32;
#endif
-
diff --git a/src/irrlicht_changes/static_text.cpp b/src/irrlicht_changes/static_text.cpp
index 703287eb3..50c6c6a68 100644
--- a/src/irrlicht_changes/static_text.cpp
+++ b/src/irrlicht_changes/static_text.cpp
@@ -20,6 +20,10 @@
#if USE_FREETYPE
#include "cguittfont/xCGUITTFont.h"
#endif
+#ifndef _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX
+ // newer Irrlicht versions no longer have this
+ #define _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX
+#endif
#include "util/string.h"
diff --git a/src/irrlichttypes_bloated.h b/src/irrlichttypes_bloated.h
index 77aba350c..2caca6fc4 100644
--- a/src/irrlichttypes_bloated.h
+++ b/src/irrlichttypes_bloated.h
@@ -29,4 +29,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <SColor.h>
#endif
-
diff --git a/src/irrlichttypes_extrabloated.h b/src/irrlichttypes_extrabloated.h
index cd6cb1d2c..464ee7904 100644
--- a/src/irrlichttypes_extrabloated.h
+++ b/src/irrlichttypes_extrabloated.h
@@ -36,4 +36,3 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#endif
#endif
-
diff --git a/src/itemdef.cpp b/src/itemdef.cpp
index 1aa6331dc..51d8f1d5d 100644
--- a/src/itemdef.cpp
+++ b/src/itemdef.cpp
@@ -20,7 +20,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "itemdef.h"
-#include "gamedef.h"
#include "nodedef.h"
#include "tool.h"
#include "inventory.h"
@@ -29,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mesh.h"
#include "wieldmesh.h"
#include "client/tile.h"
+#include "client.h"
#endif
#include "log.h"
#include "settings.h"
@@ -82,6 +82,8 @@ ItemDefinition& ItemDefinition::operator=(const ItemDefinition &def)
sound_place = def.sound_place;
sound_place_failed = def.sound_place_failed;
range = def.range;
+ palette_image = def.palette_image;
+ color = def.color;
return *this;
}
@@ -104,6 +106,8 @@ void ItemDefinition::reset()
description = "";
inventory_image = "";
wield_image = "";
+ palette_image = "";
+ color = video::SColor(0xFFFFFFFF);
wield_scale = v3f(1.0, 1.0, 1.0);
stack_max = 99;
usable = false;
@@ -123,17 +127,13 @@ void ItemDefinition::reset()
void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
{
- if(protocol_version <= 17)
- writeU8(os, 1); // version
- else if(protocol_version <= 20)
- writeU8(os, 2); // version
- else
- writeU8(os, 3); // version
+
+ writeU8(os, 3); // version (proto > 20)
writeU8(os, type);
- os<<serializeString(name);
- os<<serializeString(description);
- os<<serializeString(inventory_image);
- os<<serializeString(wield_image);
+ os << serializeString(name);
+ os << serializeString(description);
+ os << serializeString(inventory_image);
+ os << serializeString(wield_image);
writeV3F1000(os, wield_scale);
writeS16(os, stack_max);
writeU8(os, usable);
@@ -144,24 +144,21 @@ void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
tool_capabilities->serialize(tmp_os, protocol_version);
tool_capabilities_s = tmp_os.str();
}
- os<<serializeString(tool_capabilities_s);
+ os << serializeString(tool_capabilities_s);
writeU16(os, groups.size());
for (ItemGroupList::const_iterator
i = groups.begin(); i != groups.end(); ++i){
os << serializeString(i->first);
writeS16(os, i->second);
}
- os<<serializeString(node_placement_prediction);
- if(protocol_version > 17){
- //serializeSimpleSoundSpec(sound_place, os);
- os<<serializeString(sound_place.name);
- writeF1000(os, sound_place.gain);
- }
- if (protocol_version > 20) {
- writeF1000(os, range);
- os << serializeString(sound_place_failed.name);
- writeF1000(os, sound_place_failed.gain);
- }
+ os << serializeString(node_placement_prediction);
+ os << serializeString(sound_place.name);
+ writeF1000(os, sound_place.gain);
+ writeF1000(os, range);
+ os << serializeString(sound_place_failed.name);
+ writeF1000(os, sound_place_failed.gain);
+ os << serializeString(palette_image);
+ writeU32(os, color.color);
}
void ItemDefinition::deSerialize(std::istream &is)
@@ -218,6 +215,8 @@ void ItemDefinition::deSerialize(std::istream &is)
try {
sound_place_failed.name = deSerializeString(is);
sound_place_failed.gain = readF1000(is);
+ palette_image = deSerializeString(is);
+ color.set(readU32(is));
} catch(SerializationError &e) {};
}
@@ -233,11 +232,13 @@ class CItemDefManager: public IWritableItemDefManager
struct ClientCached
{
video::ITexture *inventory_texture;
- scene::IMesh *wield_mesh;
+ ItemMesh wield_mesh;
+ Palette *palette;
ClientCached():
inventory_texture(NULL),
- wield_mesh(NULL)
+ wield_mesh(),
+ palette(NULL)
{}
};
#endif
@@ -259,8 +260,8 @@ public:
i = values.begin(); i != values.end(); ++i)
{
ClientCached *cc = *i;
- if (cc->wield_mesh)
- cc->wield_mesh->drop();
+ if (cc->wield_mesh.mesh)
+ cc->wield_mesh.mesh->drop();
delete cc;
}
@@ -284,16 +285,16 @@ public:
assert(i != m_item_definitions.end());
return *(i->second);
}
- virtual std::string getAlias(const std::string &name) const
+ virtual const std::string &getAlias(const std::string &name) const
{
StringMap::const_iterator it = m_aliases.find(name);
if (it != m_aliases.end())
return it->second;
return name;
}
- virtual std::set<std::string> getAll() const
+ virtual void getAll(std::set<std::string> &result) const
{
- std::set<std::string> result;
+ result.clear();
for(std::map<std::string, ItemDefinition *>::const_iterator
it = m_item_definitions.begin();
it != m_item_definitions.end(); ++it) {
@@ -304,7 +305,6 @@ public:
it != m_aliases.end(); ++it) {
result.insert(it->first);
}
- return result;
}
virtual bool isKnown(const std::string &name_) const
{
@@ -317,7 +317,7 @@ public:
#ifndef SERVER
public:
ClientCached* createClientCachedDirect(const std::string &name,
- IGameDef *gamedef) const
+ Client *client) const
{
infostream<<"Lazily creating item texture and mesh for \""
<<name<<"\""<<std::endl;
@@ -331,7 +331,7 @@ public:
if(cc)
return cc;
- ITextureSource *tsrc = gamedef->getTextureSource();
+ ITextureSource *tsrc = client->getTextureSource();
const ItemDefinition &def = get(name);
// Create new ClientCached
@@ -345,8 +345,9 @@ public:
ItemStack item = ItemStack();
item.name = def.name;
- scene::IMesh *mesh = getItemMesh(gamedef, item);
- cc->wield_mesh = mesh;
+ getItemMesh(client, item, &(cc->wield_mesh));
+
+ cc->palette = tsrc->getPalette(def.palette_image);
// Put in cache
m_clientcached.set(name, cc);
@@ -354,7 +355,7 @@ public:
return cc;
}
ClientCached* getClientCached(const std::string &name,
- IGameDef *gamedef) const
+ Client *client) const
{
ClientCached *cc = NULL;
m_clientcached.get(name, &cc);
@@ -363,7 +364,7 @@ public:
if(thr_is_current_thread(m_main_thread))
{
- return createClientCachedDirect(name, gamedef);
+ return createClientCachedDirect(name, client);
}
else
{
@@ -392,21 +393,49 @@ public:
}
// Get item inventory texture
virtual video::ITexture* getInventoryTexture(const std::string &name,
- IGameDef *gamedef) const
+ Client *client) const
{
- ClientCached *cc = getClientCached(name, gamedef);
+ ClientCached *cc = getClientCached(name, client);
if(!cc)
return NULL;
return cc->inventory_texture;
}
// Get item wield mesh
- virtual scene::IMesh* getWieldMesh(const std::string &name,
- IGameDef *gamedef) const
+ virtual ItemMesh* getWieldMesh(const std::string &name,
+ Client *client) const
+ {
+ ClientCached *cc = getClientCached(name, client);
+ if(!cc)
+ return NULL;
+ return &(cc->wield_mesh);
+ }
+
+ // Get item palette
+ virtual Palette* getPalette(const std::string &name,
+ Client *client) const
{
- ClientCached *cc = getClientCached(name, gamedef);
+ ClientCached *cc = getClientCached(name, client);
if(!cc)
return NULL;
- return cc->wield_mesh;
+ return cc->palette;
+ }
+
+ virtual video::SColor getItemstackColor(const ItemStack &stack,
+ Client *client) const
+ {
+ // Look for direct color definition
+ const std::string &colorstring = stack.metadata.getString("color", 0);
+ video::SColor directcolor;
+ if ((colorstring != "")
+ && parseColorString(colorstring, directcolor, true))
+ return directcolor;
+ // See if there is a palette
+ Palette *palette = getPalette(stack.name, client);
+ const std::string &index = stack.metadata.getString("palette_index", 0);
+ if ((palette != NULL) && (index != ""))
+ return (*palette)[mystoi(index, 0, 255)];
+ // Fallback color
+ return get(stack.name).color;
}
#endif
void clear()
@@ -543,7 +572,7 @@ public:
request = m_get_clientcached_queue.pop();
m_get_clientcached_queue.pushResult(request,
- createClientCachedDirect(request.key, gamedef));
+ createClientCachedDirect(request.key, (Client *)gamedef));
}
#endif
}
diff --git a/src/itemdef.h b/src/itemdef.h
index dcb98e8a9..2d7ff570d 100644
--- a/src/itemdef.h
+++ b/src/itemdef.h
@@ -28,7 +28,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "itemgroup.h"
#include "sound.h"
class IGameDef;
+class Client;
struct ToolCapabilities;
+#ifndef SERVER
+#include "client/tile.h"
+struct ItemMesh;
+struct ItemStack;
+#endif
/*
Base item definition
@@ -56,6 +62,8 @@ struct ItemDefinition
*/
std::string inventory_image; // Optional for nodes, mandatory for tools/craftitems
std::string wield_image; // If empty, inventory_image or mesh (only nodes) is used
+ std::string palette_image; // If specified, the item will be colorized based on this
+ video::SColor color; // The fallback color of the node.
v3f wield_scale;
/*
@@ -99,18 +107,25 @@ public:
// Get item definition
virtual const ItemDefinition& get(const std::string &name) const=0;
// Get alias definition
- virtual std::string getAlias(const std::string &name) const=0;
+ virtual const std::string &getAlias(const std::string &name) const=0;
// Get set of all defined item names and aliases
- virtual std::set<std::string> getAll() const=0;
+ virtual void getAll(std::set<std::string> &result) const=0;
// Check if item is known
virtual bool isKnown(const std::string &name) const=0;
#ifndef SERVER
// Get item inventory texture
virtual video::ITexture* getInventoryTexture(const std::string &name,
- IGameDef *gamedef) const=0;
+ Client *client) const=0;
// Get item wield mesh
- virtual scene::IMesh* getWieldMesh(const std::string &name,
- IGameDef *gamedef) const=0;
+ virtual ItemMesh* getWieldMesh(const std::string &name,
+ Client *client) const=0;
+ // Get item palette
+ virtual Palette* getPalette(const std::string &name,
+ Client *client) const = 0;
+ // Returns the base color of an item stack: the color of all
+ // tiles that do not define their own color.
+ virtual video::SColor getItemstackColor(const ItemStack &stack,
+ Client *client) const = 0;
#endif
virtual void serialize(std::ostream &os, u16 protocol_version)=0;
@@ -125,18 +140,18 @@ public:
// Get item definition
virtual const ItemDefinition& get(const std::string &name) const=0;
// Get alias definition
- virtual std::string getAlias(const std::string &name) const=0;
+ virtual const std::string &getAlias(const std::string &name) const=0;
// Get set of all defined item names and aliases
- virtual std::set<std::string> getAll() const=0;
+ virtual void getAll(std::set<std::string> &result) const=0;
// Check if item is known
virtual bool isKnown(const std::string &name) const=0;
#ifndef SERVER
// Get item inventory texture
virtual video::ITexture* getInventoryTexture(const std::string &name,
- IGameDef *gamedef) const=0;
+ Client *client) const=0;
// Get item wield mesh
- virtual scene::IMesh* getWieldMesh(const std::string &name,
- IGameDef *gamedef) const=0;
+ virtual ItemMesh* getWieldMesh(const std::string &name,
+ Client *client) const=0;
#endif
// Remove all registered item and node definitions and aliases
diff --git a/src/itemgroup.h b/src/itemgroup.h
index f91ccc221..2206857fd 100644
--- a/src/itemgroup.h
+++ b/src/itemgroup.h
@@ -25,14 +25,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
typedef UNORDERED_MAP<std::string, int> ItemGroupList;
-static inline int itemgroup_get(const ItemGroupList &groups,
- const std::string &name)
+static inline int itemgroup_get(const ItemGroupList &groups, const std::string &name)
{
ItemGroupList::const_iterator i = groups.find(name);
- if(i == groups.end())
+ if (i == groups.end())
return 0;
return i->second;
}
#endif
-
diff --git a/src/itemstackmetadata.cpp b/src/itemstackmetadata.cpp
new file mode 100644
index 000000000..c3d602245
--- /dev/null
+++ b/src/itemstackmetadata.cpp
@@ -0,0 +1,43 @@
+#include "itemstackmetadata.h"
+#include "util/serialize.h"
+#include "util/strfnd.h"
+
+#define DESERIALIZE_START '\x01'
+#define DESERIALIZE_KV_DELIM '\x02'
+#define DESERIALIZE_PAIR_DELIM '\x03'
+#define DESERIALIZE_START_STR "\x01"
+#define DESERIALIZE_KV_DELIM_STR "\x02"
+#define DESERIALIZE_PAIR_DELIM_STR "\x03"
+
+void ItemStackMetadata::serialize(std::ostream &os) const
+{
+ std::ostringstream os2;
+ os2 << DESERIALIZE_START;
+ for (StringMap::const_iterator
+ it = m_stringvars.begin();
+ it != m_stringvars.end(); ++it) {
+ os2 << it->first << DESERIALIZE_KV_DELIM
+ << it->second << DESERIALIZE_PAIR_DELIM;
+ }
+ os << serializeJsonStringIfNeeded(os2.str());
+}
+
+void ItemStackMetadata::deSerialize(std::istream &is)
+{
+ std::string in = deSerializeJsonStringIfNeeded(is);
+
+ m_stringvars.clear();
+
+ if (!in.empty() && in[0] == DESERIALIZE_START) {
+ Strfnd fnd(in);
+ fnd.to(1);
+ while (!fnd.at_end()) {
+ std::string name = fnd.next(DESERIALIZE_KV_DELIM_STR);
+ std::string var = fnd.next(DESERIALIZE_PAIR_DELIM_STR);
+ m_stringvars[name] = var;
+ }
+ } else {
+ // BACKWARDS COMPATIBILITY
+ m_stringvars[""] = in;
+ }
+}
diff --git a/src/itemstackmetadata.h b/src/itemstackmetadata.h
new file mode 100644
index 000000000..c56c58fd2
--- /dev/null
+++ b/src/itemstackmetadata.h
@@ -0,0 +1,35 @@
+/*
+Minetest
+Copyright (C) 2010-2013 rubenwardy <rubenwardy@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 ITEMSTACKMETADATA_HEADER
+#define ITEMSTACKMETADATA_HEADER
+
+#include "metadata.h"
+
+class Inventory;
+class IItemDefManager;
+
+class ItemStackMetadata : public Metadata
+{
+public:
+ void serialize(std::ostream &os) const;
+ void deSerialize(std::istream &is);
+};
+
+#endif
diff --git a/src/jsoncpp/json/CMakeLists.txt b/src/jsoncpp/json/CMakeLists.txt
deleted file mode 100644
index 9056e4b6d..000000000
--- a/src/jsoncpp/json/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-if(MSVC)
- set(CMAKE_CXX_FLAGS_RELEASE "/MT /O2 /Ob2 /D NDEBUG")
-endif()
-
-add_library(jsoncpp jsoncpp.cpp)
-target_link_libraries(jsoncpp)
-
diff --git a/src/jsoncpp/json/UPDATING b/src/jsoncpp/json/UPDATING
deleted file mode 100644
index d00076601..000000000
--- a/src/jsoncpp/json/UPDATING
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-cd ..
-svn co https://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/trunk/jsoncpp jsoncpp
-svn up jsoncpp
-cd jsoncpp
-python amalgamate.py
-cp -R dist/json ..
-cp dist/jsoncpp.cpp ../json
-
-# maybe you need to patch:
-# src/json/jsoncpp.cpp:
-# -#include <json/json.h>
-# +#include "json/json.h"
-
-#svn export --force https://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/trunk/jsoncpp/src/lib_json json
-#svn export --force https://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/trunk/jsoncpp/include/json json
diff --git a/src/jsoncpp/json/json.h b/src/jsoncpp/json/json.h
deleted file mode 100644
index 396aafa82..000000000
--- a/src/jsoncpp/json/json.h
+++ /dev/null
@@ -1,1914 +0,0 @@
-/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/).
-/// It is intented to be used with #include <json/json.h>
-
-// //////////////////////////////////////////////////////////////////////
-// Beginning of content of file: LICENSE
-// //////////////////////////////////////////////////////////////////////
-
-/*
-The JsonCpp library's source code, including accompanying documentation,
-tests and demonstration applications, are licensed under the following
-conditions...
-
-The author (Baptiste Lepilleur) explicitly disclaims copyright in all
-jurisdictions which recognize such a disclaimer. In such jurisdictions,
-this software is released into the Public Domain.
-
-In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
-2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
-released under the terms of the MIT License (see below).
-
-In jurisdictions which recognize Public Domain property, the user of this
-software may choose to accept it either as 1) Public Domain, 2) under the
-conditions of the MIT License (see below), or 3) under the terms of dual
-Public Domain/MIT License conditions described here, as they choose.
-
-The MIT License is about as close to Public Domain as a license can get, and is
-described in clear, concise terms at:
-
- http://en.wikipedia.org/wiki/MIT_License
-
-The full text of the MIT License follows:
-
-========================================================================
-Copyright (c) 2007-2010 Baptiste Lepilleur
-
-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.
-========================================================================
-(END LICENSE TEXT)
-
-The MIT license is compatible with both the GPL and commercial
-software, affording one all of the rights of Public Domain with the
-minor nuisance of being required to keep the above copyright notice
-and license text in the source code. Note also that by accepting the
-Public Domain "license" you can re-license your copy using whatever
-license you like.
-
-*/
-
-// //////////////////////////////////////////////////////////////////////
-// End of content of file: LICENSE
-// //////////////////////////////////////////////////////////////////////
-
-
-
-
-
-#ifndef JSON_AMALGATED_H_INCLUDED
-# define JSON_AMALGATED_H_INCLUDED
-/// If defined, indicates that the source file is amalgated
-/// to prevent private header inclusion.
-#define JSON_IS_AMALGAMATION
-
-// //////////////////////////////////////////////////////////////////////
-// Beginning of content of file: include/json/config.h
-// //////////////////////////////////////////////////////////////////////
-
-// Copyright 2007-2010 Baptiste Lepilleur
-// Distributed under MIT license, or public domain if desired and
-// recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-
-#ifndef JSON_CONFIG_H_INCLUDED
-# define JSON_CONFIG_H_INCLUDED
-
-/// If defined, indicates that json library is embedded in CppTL library.
-//# define JSON_IN_CPPTL 1
-
-/// If defined, indicates that json may leverage CppTL library
-//# define JSON_USE_CPPTL 1
-/// If defined, indicates that cpptl vector based map should be used instead of std::map
-/// as Value container.
-//# define JSON_USE_CPPTL_SMALLMAP 1
-/// If defined, indicates that Json specific container should be used
-/// (hash table & simple deque container with customizable allocator).
-/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332
-//# define JSON_VALUE_USE_INTERNAL_MAP 1
-/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
-/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
-/// as if it was a POD) that may cause some validation tool to report errors.
-/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
-//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
-
-// If non-zero, the library uses exceptions to report bad input instead of C
-// assertion macros. The default is to use exceptions.
-# ifndef JSON_USE_EXCEPTION
-# define JSON_USE_EXCEPTION 1
-# endif
-
-/// If defined, indicates that the source file is amalgated
-/// to prevent private header inclusion.
-/// Remarks: it is automatically defined in the generated amalgated header.
-// #define JSON_IS_AMALGAMATION
-
-
-# ifdef JSON_IN_CPPTL
-# include <cpptl/config.h>
-# ifndef JSON_USE_CPPTL
-# define JSON_USE_CPPTL 1
-# endif
-# endif
-
-# ifdef JSON_IN_CPPTL
-# define JSON_API CPPTL_API
-# elif defined(JSON_DLL_BUILD)
-# define JSON_API __declspec(dllexport)
-# elif defined(JSON_DLL)
-# define JSON_API __declspec(dllimport)
-# else
-# define JSON_API
-# endif
-
-// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer
-// Storages, and 64 bits integer support is disabled.
-// #define JSON_NO_INT64 1
-
-#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6
-// Microsoft Visual Studio 6 only support conversion from __int64 to double
-// (no conversion from unsigned __int64).
-#define JSON_USE_INT64_DOUBLE_CONVERSION 1
-#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6
-
-#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008
-/// Indicates that the following function is deprecated.
-# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
-#endif
-
-#if !defined(JSONCPP_DEPRECATED)
-# define JSONCPP_DEPRECATED(message)
-#endif // if !defined(JSONCPP_DEPRECATED)
-
-namespace Json {
- typedef int Int;
- typedef unsigned int UInt;
-# if defined(JSON_NO_INT64)
- typedef int LargestInt;
- typedef unsigned int LargestUInt;
-# undef JSON_HAS_INT64
-# else // if defined(JSON_NO_INT64)
- // For Microsoft Visual use specific types as long long is not supported
-# if defined(_MSC_VER) // Microsoft Visual Studio
- typedef __int64 Int64;
- typedef unsigned __int64 UInt64;
-# else // if defined(_MSC_VER) // Other platforms, use long long
- typedef long long int Int64;
- typedef unsigned long long int UInt64;
-# endif // if defined(_MSC_VER)
- typedef Int64 LargestInt;
- typedef UInt64 LargestUInt;
-# define JSON_HAS_INT64
-# endif // if defined(JSON_NO_INT64)
-} // end namespace Json
-
-
-#endif // JSON_CONFIG_H_INCLUDED
-
-// //////////////////////////////////////////////////////////////////////
-// End of content of file: include/json/config.h
-// //////////////////////////////////////////////////////////////////////
-
-
-
-
-
-
-// //////////////////////////////////////////////////////////////////////
-// Beginning of content of file: include/json/forwards.h
-// //////////////////////////////////////////////////////////////////////
-
-// Copyright 2007-2010 Baptiste Lepilleur
-// Distributed under MIT license, or public domain if desired and
-// recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-
-#ifndef JSON_FORWARDS_H_INCLUDED
-# define JSON_FORWARDS_H_INCLUDED
-
-#if !defined(JSON_IS_AMALGAMATION)
-# include "config.h"
-#endif // if !defined(JSON_IS_AMALGAMATION)
-
-namespace Json {
-
- // writer.h
- class FastWriter;
- class StyledWriter;
-
- // reader.h
- class Reader;
-
- // features.h
- class Features;
-
- // value.h
- typedef unsigned int ArrayIndex;
- class StaticString;
- class Path;
- class PathArgument;
- class Value;
- class ValueIteratorBase;
- class ValueIterator;
- class ValueConstIterator;
-#ifdef JSON_VALUE_USE_INTERNAL_MAP
- class ValueMapAllocator;
- class ValueInternalLink;
- class ValueInternalArray;
- class ValueInternalMap;
-#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
-
-} // namespace Json
-
-
-#endif // JSON_FORWARDS_H_INCLUDED
-
-// //////////////////////////////////////////////////////////////////////
-// End of content of file: include/json/forwards.h
-// //////////////////////////////////////////////////////////////////////
-
-
-
-
-
-
-// //////////////////////////////////////////////////////////////////////
-// Beginning of content of file: include/json/features.h
-// //////////////////////////////////////////////////////////////////////
-
-// Copyright 2007-2010 Baptiste Lepilleur
-// Distributed under MIT license, or public domain if desired and
-// recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-
-#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
-# define CPPTL_JSON_FEATURES_H_INCLUDED
-
-#if !defined(JSON_IS_AMALGAMATION)
-# include "forwards.h"
-#endif // if !defined(JSON_IS_AMALGAMATION)
-
-namespace Json {
-
- /** \brief Configuration passed to reader and writer.
- * This configuration object can be used to force the Reader or Writer
- * to behave in a standard conforming way.
- */
- class JSON_API Features
- {
- public:
- /** \brief A configuration that allows all features and assumes all strings are UTF-8.
- * - C & C++ comments are allowed
- * - Root object can be any JSON value
- * - Assumes Value strings are encoded in UTF-8
- */
- static Features all();
-
- /** \brief A configuration that is strictly compatible with the JSON specification.
- * - Comments are forbidden.
- * - Root object must be either an array or an object value.
- * - Assumes Value strings are encoded in UTF-8
- */
- static Features strictMode();
-
- /** \brief Initialize the configuration like JsonConfig::allFeatures;
- */
- Features();
-
- /// \c true if comments are allowed. Default: \c true.
- bool allowComments_;
-
- /// \c true if root must be either an array or an object value. Default: \c false.
- bool strictRoot_;
- };
-
-} // namespace Json
-
-#endif // CPPTL_JSON_FEATURES_H_INCLUDED
-
-// //////////////////////////////////////////////////////////////////////
-// End of content of file: include/json/features.h
-// //////////////////////////////////////////////////////////////////////
-
-
-
-
-
-
-// //////////////////////////////////////////////////////////////////////
-// Beginning of content of file: include/json/value.h
-// //////////////////////////////////////////////////////////////////////
-
-// Copyright 2007-2010 Baptiste Lepilleur
-// Distributed under MIT license, or public domain if desired and
-// recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-
-#ifndef CPPTL_JSON_H_INCLUDED
-# define CPPTL_JSON_H_INCLUDED
-
-#if !defined(JSON_IS_AMALGAMATION)
-# include "forwards.h"
-#endif // if !defined(JSON_IS_AMALGAMATION)
-# include <string>
-# include <vector>
-
-# ifndef JSON_USE_CPPTL_SMALLMAP
-# include <map>
-# else
-# include <cpptl/smallmap.h>
-# endif
-# ifdef JSON_USE_CPPTL
-# include <cpptl/forwards.h>
-# endif
-
-/** \brief JSON (JavaScript Object Notation).
- */
-namespace Json {
-
- /** \brief Type of the value held by a Value object.
- */
- enum ValueType
- {
- nullValue = 0, ///< 'null' value
- intValue, ///< signed integer value
- uintValue, ///< unsigned integer value
- realValue, ///< double value
- stringValue, ///< UTF-8 string value
- booleanValue, ///< bool value
- arrayValue, ///< array value (ordered list)
- objectValue ///< object value (collection of name/value pairs).
- };
-
- enum CommentPlacement
- {
- commentBefore = 0, ///< a comment placed on the line before a value
- commentAfterOnSameLine, ///< a comment just after a value on the same line
- commentAfter, ///< a comment on the line after a value (only make sense for root value)
- numberOfCommentPlacement
- };
-
-//# ifdef JSON_USE_CPPTL
-// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
-// typedef CppTL::AnyEnumerator<const Value &> EnumValues;
-//# endif
-
- /** \brief Lightweight wrapper to tag static string.
- *
- * Value constructor and objectValue member assignement takes advantage of the
- * StaticString and avoid the cost of string duplication when storing the
- * string or the member name.
- *
- * Example of usage:
- * \code
- * Json::Value aValue( StaticString("some text") );
- * Json::Value object;
- * static const StaticString code("code");
- * object[code] = 1234;
- * \endcode
- */
- class JSON_API StaticString
- {
- public:
- explicit StaticString( const char *czstring )
- : str_( czstring )
- {
- }
-
- operator const char *() const
- {
- return str_;
- }
-
- const char *c_str() const
- {
- return str_;
- }
-
- private:
- const char *str_;
- };
-
- /** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
- *
- * This class is a discriminated union wrapper that can represents a:
- * - signed integer [range: Value::minInt - Value::maxInt]
- * - unsigned integer (range: 0 - Value::maxUInt)
- * - double
- * - UTF-8 string
- * - boolean
- * - 'null'
- * - an ordered list of Value
- * - collection of name/value pairs (javascript object)
- *
- * The type of the held value is represented by a #ValueType and
- * can be obtained using type().
- *
- * values of an #objectValue or #arrayValue can be accessed using operator[]() methods.
- * Non const methods will automatically create the a #nullValue element
- * if it does not exist.
- * The sequence of an #arrayValue will be automatically resize and initialized
- * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
- *
- * The get() methods can be used to obtanis default value in the case the required element
- * does not exist.
- *
- * It is possible to iterate over the list of a #objectValue values using
- * the getMemberNames() method.
- */
- class JSON_API Value
- {
- friend class ValueIteratorBase;
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- friend class ValueInternalLink;
- friend class ValueInternalMap;
-# endif
- public:
- typedef std::vector<std::string> Members;
- typedef ValueIterator iterator;
- typedef ValueConstIterator const_iterator;
- typedef Json::UInt UInt;
- typedef Json::Int Int;
-# if defined(JSON_HAS_INT64)
- typedef Json::UInt64 UInt64;
- typedef Json::Int64 Int64;
-#endif // defined(JSON_HAS_INT64)
- typedef Json::LargestInt LargestInt;
- typedef Json::LargestUInt LargestUInt;
- typedef Json::ArrayIndex ArrayIndex;
-
- static const Value null;
- /// Minimum signed integer value that can be stored in a Json::Value.
- static const LargestInt minLargestInt;
- /// Maximum signed integer value that can be stored in a Json::Value.
- static const LargestInt maxLargestInt;
- /// Maximum unsigned integer value that can be stored in a Json::Value.
- static const LargestUInt maxLargestUInt;
-
- /// Minimum signed int value that can be stored in a Json::Value.
- static const Int minInt;
- /// Maximum signed int value that can be stored in a Json::Value.
- static const Int maxInt;
- /// Maximum unsigned int value that can be stored in a Json::Value.
- static const UInt maxUInt;
-
-# if defined(JSON_HAS_INT64)
- /// Minimum signed 64 bits int value that can be stored in a Json::Value.
- static const Int64 minInt64;
- /// Maximum signed 64 bits int value that can be stored in a Json::Value.
- static const Int64 maxInt64;
- /// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
- static const UInt64 maxUInt64;
-#endif // defined(JSON_HAS_INT64)
-
- private:
-#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
-# ifndef JSON_VALUE_USE_INTERNAL_MAP
- class CZString
- {
- public:
- enum DuplicationPolicy
- {
- noDuplication = 0,
- duplicate,
- duplicateOnCopy
- };
- CZString( ArrayIndex index );
- CZString( const char *cstr, DuplicationPolicy allocate );
- CZString( const CZString &other );
- ~CZString();
- CZString &operator =( const CZString &other );
- bool operator<( const CZString &other ) const;
- bool operator==( const CZString &other ) const;
- ArrayIndex index() const;
- const char *c_str() const;
- bool isStaticString() const;
- private:
- void swap( CZString &other );
- const char *cstr_;
- ArrayIndex index_;
- };
-
- public:
-# ifndef JSON_USE_CPPTL_SMALLMAP
- typedef std::map<CZString, Value> ObjectValues;
-# else
- typedef CppTL::SmallMap<CZString, Value> ObjectValues;
-# endif // ifndef JSON_USE_CPPTL_SMALLMAP
-# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
-#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
-
- public:
- /** \brief Create a default Value of the given type.
-
- This is a very useful constructor.
- To create an empty array, pass arrayValue.
- To create an empty object, pass objectValue.
- Another Value can then be set to this one by assignment.
- This is useful since clear() and resize() will not alter types.
-
- Examples:
- \code
- Json::Value null_value; // null
- Json::Value arr_value(Json::arrayValue); // []
- Json::Value obj_value(Json::objectValue); // {}
- \endcode
- */
- Value( ValueType type = nullValue );
- Value( Int value );
- Value( UInt value );
-#if defined(JSON_HAS_INT64)
- Value( Int64 value );
- Value( UInt64 value );
-#endif // if defined(JSON_HAS_INT64)
- Value( double value );
- Value( const char *value );
- Value( const char *beginValue, const char *endValue );
- /** \brief Constructs a value from a static string.
-
- * Like other value string constructor but do not duplicate the string for
- * internal storage. The given string must remain alive after the call to this
- * constructor.
- * Example of usage:
- * \code
- * Json::Value aValue( StaticString("some text") );
- * \endcode
- */
- Value( const StaticString &value );
- Value( const std::string &value );
-# ifdef JSON_USE_CPPTL
- Value( const CppTL::ConstString &value );
-# endif
- Value( bool value );
- Value( const Value &other );
- ~Value();
-
- Value &operator=( const Value &other );
- /// Swap values.
- /// \note Currently, comments are intentionally not swapped, for
- /// both logic and efficiency.
- void swap( Value &other );
-
- ValueType type() const;
-
- bool operator <( const Value &other ) const;
- bool operator <=( const Value &other ) const;
- bool operator >=( const Value &other ) const;
- bool operator >( const Value &other ) const;
-
- bool operator ==( const Value &other ) const;
- bool operator !=( const Value &other ) const;
-
- int compare( const Value &other ) const;
-
- const char *asCString() const;
- std::string asString() const;
-# ifdef JSON_USE_CPPTL
- CppTL::ConstString asConstString() const;
-# endif
- Int asInt() const;
- UInt asUInt() const;
-#if defined(JSON_HAS_INT64)
- Int64 asInt64() const;
- UInt64 asUInt64() const;
-#endif // if defined(JSON_HAS_INT64)
- LargestInt asLargestInt() const;
- LargestUInt asLargestUInt() const;
- float asFloat() const;
- double asDouble() const;
- bool asBool() const;
-
- bool isNull() const;
- bool isBool() const;
- bool isInt() const;
- bool isInt64() const;
- bool isUInt() const;
- bool isUInt64() const;
- bool isIntegral() const;
- bool isDouble() const;
- bool isNumeric() const;
- bool isString() const;
- bool isArray() const;
- bool isObject() const;
-
- bool isConvertibleTo( ValueType other ) const;
-
- /// Number of values in array or object
- ArrayIndex size() const;
-
- /// \brief Return true if empty array, empty object, or null;
- /// otherwise, false.
- bool empty() const;
-
- /// Return isNull()
- bool operator!() const;
-
- /// Remove all object members and array elements.
- /// \pre type() is arrayValue, objectValue, or nullValue
- /// \post type() is unchanged
- void clear();
-
- /// Resize the array to size elements.
- /// New elements are initialized to null.
- /// May only be called on nullValue or arrayValue.
- /// \pre type() is arrayValue or nullValue
- /// \post type() is arrayValue
- void resize( ArrayIndex size );
-
- /// Access an array element (zero based index ).
- /// If the array contains less than index element, then null value are inserted
- /// in the array so that its size is index+1.
- /// (You may need to say 'value[0u]' to get your compiler to distinguish
- /// this from the operator[] which takes a string.)
- Value &operator[]( ArrayIndex index );
-
- /// Access an array element (zero based index ).
- /// If the array contains less than index element, then null value are inserted
- /// in the array so that its size is index+1.
- /// (You may need to say 'value[0u]' to get your compiler to distinguish
- /// this from the operator[] which takes a string.)
- Value &operator[]( int index );
-
- /// Access an array element (zero based index )
- /// (You may need to say 'value[0u]' to get your compiler to distinguish
- /// this from the operator[] which takes a string.)
- const Value &operator[]( ArrayIndex index ) const;
-
- /// Access an array element (zero based index )
- /// (You may need to say 'value[0u]' to get your compiler to distinguish
- /// this from the operator[] which takes a string.)
- const Value &operator[]( int index ) const;
-
- /// If the array contains at least index+1 elements, returns the element value,
- /// otherwise returns defaultValue.
- Value get( ArrayIndex index,
- const Value &defaultValue ) const;
- /// Return true if index < size().
- bool isValidIndex( ArrayIndex index ) const;
- /// \brief Append value to array at the end.
- ///
- /// Equivalent to jsonvalue[jsonvalue.size()] = value;
- Value &append( const Value &value );
-
- /// Access an object value by name, create a null member if it does not exist.
- Value &operator[]( const char *key );
- /// Access an object value by name, returns null if there is no member with that name.
- const Value &operator[]( const char *key ) const;
- /// Access an object value by name, create a null member if it does not exist.
- Value &operator[]( const std::string &key );
- /// Access an object value by name, returns null if there is no member with that name.
- const Value &operator[]( const std::string &key ) const;
- /** \brief Access an object value by name, create a null member if it does not exist.
-
- * If the object as no entry for that name, then the member name used to store
- * the new entry is not duplicated.
- * Example of use:
- * \code
- * Json::Value object;
- * static const StaticString code("code");
- * object[code] = 1234;
- * \endcode
- */
- Value &operator[]( const StaticString &key );
-# ifdef JSON_USE_CPPTL
- /// Access an object value by name, create a null member if it does not exist.
- Value &operator[]( const CppTL::ConstString &key );
- /// Access an object value by name, returns null if there is no member with that name.
- const Value &operator[]( const CppTL::ConstString &key ) const;
-# endif
- /// Return the member named key if it exist, defaultValue otherwise.
- Value get( const char *key,
- const Value &defaultValue ) const;
- /// Return the member named key if it exist, defaultValue otherwise.
- Value get( const std::string &key,
- const Value &defaultValue ) const;
-# ifdef JSON_USE_CPPTL
- /// Return the member named key if it exist, defaultValue otherwise.
- Value get( const CppTL::ConstString &key,
- const Value &defaultValue ) const;
-# endif
- /// \brief Remove and return the named member.
- ///
- /// Do nothing if it did not exist.
- /// \return the removed Value, or null.
- /// \pre type() is objectValue or nullValue
- /// \post type() is unchanged
- Value removeMember( const char* key );
- /// Same as removeMember(const char*)
- Value removeMember( const std::string &key );
-
- /// Return true if the object has a member named key.
- bool isMember( const char *key ) const;
- /// Return true if the object has a member named key.
- bool isMember( const std::string &key ) const;
-# ifdef JSON_USE_CPPTL
- /// Return true if the object has a member named key.
- bool isMember( const CppTL::ConstString &key ) const;
-# endif
-
- /// \brief Return a list of the member names.
- ///
- /// If null, return an empty list.
- /// \pre type() is objectValue or nullValue
- /// \post if type() was nullValue, it remains nullValue
- Members getMemberNames() const;
-
-//# ifdef JSON_USE_CPPTL
-// EnumMemberNames enumMemberNames() const;
-// EnumValues enumValues() const;
-//# endif
-
- /// Comments must be //... or /* ... */
- void setComment( const char *comment,
- CommentPlacement placement );
- /// Comments must be //... or /* ... */
- void setComment( const std::string &comment,
- CommentPlacement placement );
- bool hasComment( CommentPlacement placement ) const;
- /// Include delimiters and embedded newlines.
- std::string getComment( CommentPlacement placement ) const;
-
- std::string toStyledString() const;
-
- const_iterator begin() const;
- const_iterator end() const;
-
- iterator begin();
- iterator end();
-
- private:
- Value &resolveReference( const char *key,
- bool isStatic );
-
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- inline bool isItemAvailable() const
- {
- return itemIsUsed_ == 0;
- }
-
- inline void setItemUsed( bool isUsed = true )
- {
- itemIsUsed_ = isUsed ? 1 : 0;
- }
-
- inline bool isMemberNameStatic() const
- {
- return memberNameIsStatic_ == 0;
- }
-
- inline void setMemberNameIsStatic( bool isStatic )
- {
- memberNameIsStatic_ = isStatic ? 1 : 0;
- }
-# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP
-
- private:
- struct CommentInfo
- {
- CommentInfo();
- ~CommentInfo();
-
- void setComment( const char *text );
-
- char *comment_;
- };
-
- //struct MemberNamesTransform
- //{
- // typedef const char *result_type;
- // const char *operator()( const CZString &name ) const
- // {
- // return name.c_str();
- // }
- //};
-
- union ValueHolder
- {
- LargestInt int_;
- LargestUInt uint_;
- double real_;
- bool bool_;
- char *string_;
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- ValueInternalArray *array_;
- ValueInternalMap *map_;
-#else
- ObjectValues *map_;
-# endif
- } value_;
- ValueType type_ : 8;
- int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container.
- int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
-# endif
- CommentInfo *comments_;
- };
-
-
- /** \brief Experimental and untested: represents an element of the "path" to access a node.
- */
- class PathArgument
- {
- public:
- friend class Path;
-
- PathArgument();
- PathArgument( ArrayIndex index );
- PathArgument( const char *key );
- PathArgument( const std::string &key );
-
- private:
- enum Kind
- {
- kindNone = 0,
- kindIndex,
- kindKey
- };
- std::string key_;
- ArrayIndex index_;
- Kind kind_;
- };
-
- /** \brief Experimental and untested: represents a "path" to access a node.
- *
- * Syntax:
- * - "." => root node
- * - ".[n]" => elements at index 'n' of root node (an array value)
- * - ".name" => member named 'name' of root node (an object value)
- * - ".name1.name2.name3"
- * - ".[0][1][2].name1[3]"
- * - ".%" => member name is provided as parameter
- * - ".[%]" => index is provied as parameter
- */
- class Path
- {
- public:
- Path( const std::string &path,
- const PathArgument &a1 = PathArgument(),
- const PathArgument &a2 = PathArgument(),
- const PathArgument &a3 = PathArgument(),
- const PathArgument &a4 = PathArgument(),
- const PathArgument &a5 = PathArgument() );
-
- const Value &resolve( const Value &root ) const;
- Value resolve( const Value &root,
- const Value &defaultValue ) const;
- /// Creates the "path" to access the specified node and returns a reference on the node.
- Value &make( Value &root ) const;
-
- private:
- typedef std::vector<const PathArgument *> InArgs;
- typedef std::vector<PathArgument> Args;
-
- void makePath( const std::string &path,
- const InArgs &in );
- void addPathInArg( const std::string &path,
- const InArgs &in,
- InArgs::const_iterator &itInArg,
- PathArgument::Kind kind );
- void invalidPath( const std::string &path,
- int location );
-
- Args args_;
- };
-
-
-
-#ifdef JSON_VALUE_USE_INTERNAL_MAP
- /** \brief Allocator to customize Value internal map.
- * Below is an example of a simple implementation (default implementation actually
- * use memory pool for speed).
- * \code
- class DefaultValueMapAllocator : public ValueMapAllocator
- {
- public: // overridden from ValueMapAllocator
- virtual ValueInternalMap *newMap()
- {
- return new ValueInternalMap();
- }
-
- virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
- {
- return new ValueInternalMap( other );
- }
-
- virtual void destructMap( ValueInternalMap *map )
- {
- delete map;
- }
-
- virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
- {
- return new ValueInternalLink[size];
- }
-
- virtual void releaseMapBuckets( ValueInternalLink *links )
- {
- delete [] links;
- }
-
- virtual ValueInternalLink *allocateMapLink()
- {
- return new ValueInternalLink();
- }
-
- virtual void releaseMapLink( ValueInternalLink *link )
- {
- delete link;
- }
- };
- * \endcode
- */
- class JSON_API ValueMapAllocator
- {
- public:
- virtual ~ValueMapAllocator();
- virtual ValueInternalMap *newMap() = 0;
- virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0;
- virtual void destructMap( ValueInternalMap *map ) = 0;
- virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0;
- virtual void releaseMapBuckets( ValueInternalLink *links ) = 0;
- virtual ValueInternalLink *allocateMapLink() = 0;
- virtual void releaseMapLink( ValueInternalLink *link ) = 0;
- };
-
- /** \brief ValueInternalMap hash-map bucket chain link (for internal use only).
- * \internal previous_ & next_ allows for bidirectional traversal.
- */
- class JSON_API ValueInternalLink
- {
- public:
- enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture.
- enum InternalFlags {
- flagAvailable = 0,
- flagUsed = 1
- };
-
- ValueInternalLink();
-
- ~ValueInternalLink();
-
- Value items_[itemPerLink];
- char *keys_[itemPerLink];
- ValueInternalLink *previous_;
- ValueInternalLink *next_;
- };
-
-
- /** \brief A linked page based hash-table implementation used internally by Value.
- * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked
- * list in each bucket to handle collision. There is an addional twist in that
- * each node of the collision linked list is a page containing a fixed amount of
- * value. This provides a better compromise between memory usage and speed.
- *
- * Each bucket is made up of a chained list of ValueInternalLink. The last
- * link of a given bucket can be found in the 'previous_' field of the following bucket.
- * The last link of the last bucket is stored in tailLink_ as it has no following bucket.
- * Only the last link of a bucket may contains 'available' item. The last link always
- * contains at least one element unless is it the bucket one very first link.
- */
- class JSON_API ValueInternalMap
- {
- friend class ValueIteratorBase;
- friend class Value;
- public:
- typedef unsigned int HashKey;
- typedef unsigned int BucketIndex;
-
-# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
- struct IteratorState
- {
- IteratorState()
- : map_(0)
- , link_(0)
- , itemIndex_(0)
- , bucketIndex_(0)
- {
- }
- ValueInternalMap *map_;
- ValueInternalLink *link_;
- BucketIndex itemIndex_;
- BucketIndex bucketIndex_;
- };
-# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
-
- ValueInternalMap();
- ValueInternalMap( const ValueInternalMap &other );
- ValueInternalMap &operator =( const ValueInternalMap &other );
- ~ValueInternalMap();
-
- void swap( ValueInternalMap &other );
-
- BucketIndex size() const;
-
- void clear();
-
- bool reserveDelta( BucketIndex growth );
-
- bool reserve( BucketIndex newItemCount );
-
- const Value *find( const char *key ) const;
-
- Value *find( const char *key );
-
- Value &resolveReference( const char *key,
- bool isStatic );
-
- void remove( const char *key );
-
- void doActualRemove( ValueInternalLink *link,
- BucketIndex index,
- BucketIndex bucketIndex );
-
- ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex );
-
- Value &setNewItem( const char *key,
- bool isStatic,
- ValueInternalLink *link,
- BucketIndex index );
-
- Value &unsafeAdd( const char *key,
- bool isStatic,
- HashKey hashedKey );
-
- HashKey hash( const char *key ) const;
-
- int compare( const ValueInternalMap &other ) const;
-
- private:
- void makeBeginIterator( IteratorState &it ) const;
- void makeEndIterator( IteratorState &it ) const;
- static bool equals( const IteratorState &x, const IteratorState &other );
- static void increment( IteratorState &iterator );
- static void incrementBucket( IteratorState &iterator );
- static void decrement( IteratorState &iterator );
- static const char *key( const IteratorState &iterator );
- static const char *key( const IteratorState &iterator, bool &isStatic );
- static Value &value( const IteratorState &iterator );
- static int distance( const IteratorState &x, const IteratorState &y );
-
- private:
- ValueInternalLink *buckets_;
- ValueInternalLink *tailLink_;
- BucketIndex bucketsSize_;
- BucketIndex itemCount_;
- };
-
- /** \brief A simplified deque implementation used internally by Value.
- * \internal
- * It is based on a list of fixed "page", each page contains a fixed number of items.
- * Instead of using a linked-list, a array of pointer is used for fast item look-up.
- * Look-up for an element is as follow:
- * - compute page index: pageIndex = itemIndex / itemsPerPage
- * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage]
- *
- * Insertion is amortized constant time (only the array containing the index of pointers
- * need to be reallocated when items are appended).
- */
- class JSON_API ValueInternalArray
- {
- friend class Value;
- friend class ValueIteratorBase;
- public:
- enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo.
- typedef Value::ArrayIndex ArrayIndex;
- typedef unsigned int PageIndex;
-
-# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
- struct IteratorState // Must be a POD
- {
- IteratorState()
- : array_(0)
- , currentPageIndex_(0)
- , currentItemIndex_(0)
- {
- }
- ValueInternalArray *array_;
- Value **currentPageIndex_;
- unsigned int currentItemIndex_;
- };
-# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
-
- ValueInternalArray();
- ValueInternalArray( const ValueInternalArray &other );
- ValueInternalArray &operator =( const ValueInternalArray &other );
- ~ValueInternalArray();
- void swap( ValueInternalArray &other );
-
- void clear();
- void resize( ArrayIndex newSize );
-
- Value &resolveReference( ArrayIndex index );
-
- Value *find( ArrayIndex index ) const;
-
- ArrayIndex size() const;
-
- int compare( const ValueInternalArray &other ) const;
-
- private:
- static bool equals( const IteratorState &x, const IteratorState &other );
- static void increment( IteratorState &iterator );
- static void decrement( IteratorState &iterator );
- static Value &dereference( const IteratorState &iterator );
- static Value &unsafeDereference( const IteratorState &iterator );
- static int distance( const IteratorState &x, const IteratorState &y );
- static ArrayIndex indexOf( const IteratorState &iterator );
- void makeBeginIterator( IteratorState &it ) const;
- void makeEndIterator( IteratorState &it ) const;
- void makeIterator( IteratorState &it, ArrayIndex index ) const;
-
- void makeIndexValid( ArrayIndex index );
-
- Value **pages_;
- ArrayIndex size_;
- PageIndex pageCount_;
- };
-
- /** \brief Experimental: do not use. Allocator to customize Value internal array.
- * Below is an example of a simple implementation (actual implementation use
- * memory pool).
- \code
-class DefaultValueArrayAllocator : public ValueArrayAllocator
-{
-public: // overridden from ValueArrayAllocator
- virtual ~DefaultValueArrayAllocator()
- {
- }
-
- virtual ValueInternalArray *newArray()
- {
- return new ValueInternalArray();
- }
-
- virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
- {
- return new ValueInternalArray( other );
- }
-
- virtual void destruct( ValueInternalArray *array )
- {
- delete array;
- }
-
- virtual void reallocateArrayPageIndex( Value **&indexes,
- ValueInternalArray::PageIndex &indexCount,
- ValueInternalArray::PageIndex minNewIndexCount )
- {
- ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
- if ( minNewIndexCount > newIndexCount )
- newIndexCount = minNewIndexCount;
- void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
- if ( !newIndexes )
- throw std::bad_alloc();
- indexCount = newIndexCount;
- indexes = static_cast<Value **>( newIndexes );
- }
- virtual void releaseArrayPageIndex( Value **indexes,
- ValueInternalArray::PageIndex indexCount )
- {
- if ( indexes )
- free( indexes );
- }
-
- virtual Value *allocateArrayPage()
- {
- return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
- }
-
- virtual void releaseArrayPage( Value *value )
- {
- if ( value )
- free( value );
- }
-};
- \endcode
- */
- class JSON_API ValueArrayAllocator
- {
- public:
- virtual ~ValueArrayAllocator();
- virtual ValueInternalArray *newArray() = 0;
- virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0;
- virtual void destructArray( ValueInternalArray *array ) = 0;
- /** \brief Reallocate array page index.
- * Reallocates an array of pointer on each page.
- * \param indexes [input] pointer on the current index. May be \c NULL.
- * [output] pointer on the new index of at least
- * \a minNewIndexCount pages.
- * \param indexCount [input] current number of pages in the index.
- * [output] number of page the reallocated index can handle.
- * \b MUST be >= \a minNewIndexCount.
- * \param minNewIndexCount Minimum number of page the new index must be able to
- * handle.
- */
- virtual void reallocateArrayPageIndex( Value **&indexes,
- ValueInternalArray::PageIndex &indexCount,
- ValueInternalArray::PageIndex minNewIndexCount ) = 0;
- virtual void releaseArrayPageIndex( Value **indexes,
- ValueInternalArray::PageIndex indexCount ) = 0;
- virtual Value *allocateArrayPage() = 0;
- virtual void releaseArrayPage( Value *value ) = 0;
- };
-#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
-
-
- /** \brief base class for Value iterators.
- *
- */
- class ValueIteratorBase
- {
- public:
- typedef unsigned int size_t;
- typedef int difference_type;
- typedef ValueIteratorBase SelfType;
-
- ValueIteratorBase();
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- explicit ValueIteratorBase( const Value::ObjectValues::iterator &current );
-#else
- ValueIteratorBase( const ValueInternalArray::IteratorState &state );
- ValueIteratorBase( const ValueInternalMap::IteratorState &state );
-#endif
-
- bool operator ==( const SelfType &other ) const
- {
- return isEqual( other );
- }
-
- bool operator !=( const SelfType &other ) const
- {
- return !isEqual( other );
- }
-
- difference_type operator -( const SelfType &other ) const
- {
- return computeDistance( other );
- }
-
- /// Return either the index or the member name of the referenced value as a Value.
- Value key() const;
-
- /// Return the index of the referenced Value. -1 if it is not an arrayValue.
- UInt index() const;
-
- /// Return the member name of the referenced Value. "" if it is not an objectValue.
- const char *memberName() const;
-
- protected:
- Value &deref() const;
-
- void increment();
-
- void decrement();
-
- difference_type computeDistance( const SelfType &other ) const;
-
- bool isEqual( const SelfType &other ) const;
-
- void copy( const SelfType &other );
-
- private:
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- Value::ObjectValues::iterator current_;
- // Indicates that iterator is for a null value.
- bool isNull_;
-#else
- union
- {
- ValueInternalArray::IteratorState array_;
- ValueInternalMap::IteratorState map_;
- } iterator_;
- bool isArray_;
-#endif
- };
-
- /** \brief const iterator for object and array value.
- *
- */
- class ValueConstIterator : public ValueIteratorBase
- {
- friend class Value;
- public:
- typedef unsigned int size_t;
- typedef int difference_type;
- typedef const Value &reference;
- typedef const Value *pointer;
- typedef ValueConstIterator SelfType;
-
- ValueConstIterator();
- private:
- /*! \internal Use by Value to create an iterator.
- */
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- explicit ValueConstIterator( const Value::ObjectValues::iterator &current );
-#else
- ValueConstIterator( const ValueInternalArray::IteratorState &state );
- ValueConstIterator( const ValueInternalMap::IteratorState &state );
-#endif
- public:
- SelfType &operator =( const ValueIteratorBase &other );
-
- SelfType operator++( int )
- {
- SelfType temp( *this );
- ++*this;
- return temp;
- }
-
- SelfType operator--( int )
- {
- SelfType temp( *this );
- --*this;
- return temp;
- }
-
- SelfType &operator--()
- {
- decrement();
- return *this;
- }
-
- SelfType &operator++()
- {
- increment();
- return *this;
- }
-
- reference operator *() const
- {
- return deref();
- }
- };
-
-
- /** \brief Iterator for object and array value.
- */
- class ValueIterator : public ValueIteratorBase
- {
- friend class Value;
- public:
- typedef unsigned int size_t;
- typedef int difference_type;
- typedef Value &reference;
- typedef Value *pointer;
- typedef ValueIterator SelfType;
-
- ValueIterator();
- ValueIterator( const ValueConstIterator &other );
- ValueIterator( const ValueIterator &other );
- private:
- /*! \internal Use by Value to create an iterator.
- */
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- explicit ValueIterator( const Value::ObjectValues::iterator &current );
-#else
- ValueIterator( const ValueInternalArray::IteratorState &state );
- ValueIterator( const ValueInternalMap::IteratorState &state );
-#endif
- public:
-
- SelfType &operator =( const SelfType &other );
-
- SelfType operator++( int )
- {
- SelfType temp( *this );
- ++*this;
- return temp;
- }
-
- SelfType operator--( int )
- {
- SelfType temp( *this );
- --*this;
- return temp;
- }
-
- SelfType &operator--()
- {
- decrement();
- return *this;
- }
-
- SelfType &operator++()
- {
- increment();
- return *this;
- }
-
- reference operator *() const
- {
- return deref();
- }
- };
-
-
-} // namespace Json
-
-
-#endif // CPPTL_JSON_H_INCLUDED
-
-// //////////////////////////////////////////////////////////////////////
-// End of content of file: include/json/value.h
-// //////////////////////////////////////////////////////////////////////
-
-
-
-
-
-
-// //////////////////////////////////////////////////////////////////////
-// Beginning of content of file: include/json/reader.h
-// //////////////////////////////////////////////////////////////////////
-
-// Copyright 2007-2010 Baptiste Lepilleur
-// Distributed under MIT license, or public domain if desired and
-// recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-
-#ifndef CPPTL_JSON_READER_H_INCLUDED
-# define CPPTL_JSON_READER_H_INCLUDED
-
-#if !defined(JSON_IS_AMALGAMATION)
-# include "features.h"
-# include "value.h"
-#endif // if !defined(JSON_IS_AMALGAMATION)
-# include <deque>
-# include <stack>
-# include <string>
-
-namespace Json {
-
- /** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
- *
- */
- class JSON_API Reader
- {
- public:
- typedef char Char;
- typedef const Char *Location;
-
- /** \brief Constructs a Reader allowing all features
- * for parsing.
- */
- Reader();
-
- /** \brief Constructs a Reader allowing the specified feature set
- * for parsing.
- */
- Reader( const Features &features );
-
- /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
- * \param document UTF-8 encoded string containing the document to read.
- * \param root [out] Contains the root value of the document if it was
- * successfully parsed.
- * \param collectComments \c true to collect comment and allow writing them back during
- * serialization, \c false to discard comments.
- * This parameter is ignored if Features::allowComments_
- * is \c false.
- * \return \c true if the document was successfully parsed, \c false if an error occurred.
- */
- bool parse( const std::string &document,
- Value &root,
- bool collectComments = true );
-
- /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
- * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the document to read.
- * \param endDoc Pointer on the end of the UTF-8 encoded string of the document to read.
- \ Must be >= beginDoc.
- * \param root [out] Contains the root value of the document if it was
- * successfully parsed.
- * \param collectComments \c true to collect comment and allow writing them back during
- * serialization, \c false to discard comments.
- * This parameter is ignored if Features::allowComments_
- * is \c false.
- * \return \c true if the document was successfully parsed, \c false if an error occurred.
- */
- bool parse( const char *beginDoc, const char *endDoc,
- Value &root,
- bool collectComments = true );
-
- /// \brief Parse from input stream.
- /// \see Json::operator>>(std::istream&, Json::Value&).
- bool parse( std::istream &is,
- Value &root,
- bool collectComments = true );
-
- /** \brief Returns a user friendly string that list errors in the parsed document.
- * \return Formatted error message with the list of errors with their location in
- * the parsed document. An empty string is returned if no error occurred
- * during parsing.
- * \deprecated Use getFormattedErrorMessages() instead (typo fix).
- */
- JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead")
- std::string getFormatedErrorMessages() const;
-
- /** \brief Returns a user friendly string that list errors in the parsed document.
- * \return Formatted error message with the list of errors with their location in
- * the parsed document. An empty string is returned if no error occurred
- * during parsing.
- */
- std::string getFormattedErrorMessages() const;
-
- private:
- enum TokenType
- {
- tokenEndOfStream = 0,
- tokenObjectBegin,
- tokenObjectEnd,
- tokenArrayBegin,
- tokenArrayEnd,
- tokenString,
- tokenNumber,
- tokenTrue,
- tokenFalse,
- tokenNull,
- tokenArraySeparator,
- tokenMemberSeparator,
- tokenComment,
- tokenError
- };
-
- class Token
- {
- public:
- TokenType type_;
- Location start_;
- Location end_;
- };
-
- class ErrorInfo
- {
- public:
- Token token_;
- std::string message_;
- Location extra_;
- };
-
- typedef std::deque<ErrorInfo> Errors;
-
- bool expectToken( TokenType type, Token &token, const char *message );
- bool readToken( Token &token );
- void skipSpaces();
- bool match( Location pattern,
- int patternLength );
- bool readComment();
- bool readCStyleComment();
- bool readCppStyleComment();
- bool readString();
- void readNumber();
- bool readValue();
- bool readObject( Token &token );
- bool readArray( Token &token );
- bool decodeNumber( Token &token );
- bool decodeString( Token &token );
- bool decodeString( Token &token, std::string &decoded );
- bool decodeDouble( Token &token );
- bool decodeUnicodeCodePoint( Token &token,
- Location &current,
- Location end,
- unsigned int &unicode );
- bool decodeUnicodeEscapeSequence( Token &token,
- Location &current,
- Location end,
- unsigned int &unicode );
- bool addError( const std::string &message,
- Token &token,
- Location extra = 0 );
- bool recoverFromError( TokenType skipUntilToken );
- bool addErrorAndRecover( const std::string &message,
- Token &token,
- TokenType skipUntilToken );
- void skipUntilSpace();
- Value &currentValue();
- Char getNextChar();
- void getLocationLineAndColumn( Location location,
- int &line,
- int &column ) const;
- std::string getLocationLineAndColumn( Location location ) const;
- void addComment( Location begin,
- Location end,
- CommentPlacement placement );
- void skipCommentTokens( Token &token );
-
- typedef std::stack<Value *> Nodes;
- Nodes nodes_;
- Errors errors_;
- std::string document_;
- Location begin_;
- Location end_;
- Location current_;
- Location lastValueEnd_;
- Value *lastValue_;
- std::string commentsBefore_;
- Features features_;
- bool collectComments_;
- };
-
- /** \brief Read from 'sin' into 'root'.
-
- Always keep comments from the input JSON.
-
- This can be used to read a file into a particular sub-object.
- For example:
- \code
- Json::Value root;
- cin >> root["dir"]["file"];
- cout << root;
- \endcode
- Result:
- \verbatim
- {
- "dir": {
- "file": {
- // The input stream JSON would be nested here.
- }
- }
- }
- \endverbatim
- \throw std::exception on parse error.
- \see Json::operator<<()
- */
- std::istream& operator>>( std::istream&, Value& );
-
-} // namespace Json
-
-#endif // CPPTL_JSON_READER_H_INCLUDED
-
-// //////////////////////////////////////////////////////////////////////
-// End of content of file: include/json/reader.h
-// //////////////////////////////////////////////////////////////////////
-
-
-
-
-
-
-// //////////////////////////////////////////////////////////////////////
-// Beginning of content of file: include/json/writer.h
-// //////////////////////////////////////////////////////////////////////
-
-// Copyright 2007-2010 Baptiste Lepilleur
-// Distributed under MIT license, or public domain if desired and
-// recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-
-#ifndef JSON_WRITER_H_INCLUDED
-# define JSON_WRITER_H_INCLUDED
-
-#if !defined(JSON_IS_AMALGAMATION)
-# include "value.h"
-#endif // if !defined(JSON_IS_AMALGAMATION)
-# include <vector>
-# include <string>
-
-namespace Json {
-
- class Value;
-
- /** \brief Abstract class for writers.
- */
- class JSON_API Writer
- {
- public:
- virtual ~Writer();
-
- virtual std::string write( const Value &root ) = 0;
- };
-
- /** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly).
- *
- * The JSON document is written in a single line. It is not intended for 'human' consumption,
- * but may be usefull to support feature such as RPC where bandwith is limited.
- * \sa Reader, Value
- */
- class JSON_API FastWriter : public Writer
- {
- public:
- FastWriter();
- virtual ~FastWriter(){}
-
- void enableYAMLCompatibility();
-
- /** \brief Drop the "null" string from the writer's output for nullValues.
- * Strictly speaking, this is not valid JSON. But when the output is being
- * fed to a browser's Javascript, it makes for smaller output and the
- * browser can handle the output just fine.
- */
- void dropNullPlaceholders();
-
- public: // overridden from Writer
- virtual std::string write( const Value &root );
-
- private:
- void writeValue( const Value &value );
-
- std::string document_;
- bool yamlCompatiblityEnabled_;
- bool dropNullPlaceholders_;
- };
-
- /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
- *
- * The rules for line break and indent are as follow:
- * - Object value:
- * - if empty then print {} without indent and line break
- * - if not empty the print '{', line break & indent, print one value per line
- * and then unindent and line break and print '}'.
- * - Array value:
- * - if empty then print [] without indent and line break
- * - if the array contains no object value, empty array or some other value types,
- * and all the values fit on one lines, then print the array on a single line.
- * - otherwise, it the values do not fit on one line, or the array contains
- * object or non empty array, then print one value per line.
- *
- * If the Value have comments then they are outputed according to their #CommentPlacement.
- *
- * \sa Reader, Value, Value::setComment()
- */
- class JSON_API StyledWriter: public Writer
- {
- public:
- StyledWriter();
- virtual ~StyledWriter(){}
-
- public: // overridden from Writer
- /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
- * \param root Value to serialize.
- * \return String containing the JSON document that represents the root value.
- */
- virtual std::string write( const Value &root );
-
- private:
- void writeValue( const Value &value );
- void writeArrayValue( const Value &value );
- bool isMultineArray( const Value &value );
- void pushValue( const std::string &value );
- void writeIndent();
- void writeWithIndent( const std::string &value );
- void indent();
- void unindent();
- void writeCommentBeforeValue( const Value &root );
- void writeCommentAfterValueOnSameLine( const Value &root );
- bool hasCommentForValue( const Value &value );
- static std::string normalizeEOL( const std::string &text );
-
- typedef std::vector<std::string> ChildValues;
-
- ChildValues childValues_;
- std::string document_;
- std::string indentString_;
- int rightMargin_;
- int indentSize_;
- bool addChildValues_;
- };
-
- /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way,
- to a stream rather than to a string.
- *
- * The rules for line break and indent are as follow:
- * - Object value:
- * - if empty then print {} without indent and line break
- * - if not empty the print '{', line break & indent, print one value per line
- * and then unindent and line break and print '}'.
- * - Array value:
- * - if empty then print [] without indent and line break
- * - if the array contains no object value, empty array or some other value types,
- * and all the values fit on one lines, then print the array on a single line.
- * - otherwise, it the values do not fit on one line, or the array contains
- * object or non empty array, then print one value per line.
- *
- * If the Value have comments then they are outputed according to their #CommentPlacement.
- *
- * \param indentation Each level will be indented by this amount extra.
- * \sa Reader, Value, Value::setComment()
- */
- class JSON_API StyledStreamWriter
- {
- public:
- StyledStreamWriter( std::string indentation="\t" );
- ~StyledStreamWriter(){}
-
- public:
- /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
- * \param out Stream to write to. (Can be ostringstream, e.g.)
- * \param root Value to serialize.
- * \note There is no point in deriving from Writer, since write() should not return a value.
- */
- void write( std::ostream &out, const Value &root );
-
- private:
- void writeValue( const Value &value );
- void writeArrayValue( const Value &value );
- bool isMultineArray( const Value &value );
- void pushValue( const std::string &value );
- void writeIndent();
- void writeWithIndent( const std::string &value );
- void indent();
- void unindent();
- void writeCommentBeforeValue( const Value &root );
- void writeCommentAfterValueOnSameLine( const Value &root );
- bool hasCommentForValue( const Value &value );
- static std::string normalizeEOL( const std::string &text );
-
- typedef std::vector<std::string> ChildValues;
-
- ChildValues childValues_;
- std::ostream* document_;
- std::string indentString_;
- int rightMargin_;
- std::string indentation_;
- bool addChildValues_;
- };
-
-# if defined(JSON_HAS_INT64)
- std::string JSON_API valueToString( Int value );
- std::string JSON_API valueToString( UInt value );
-# endif // if defined(JSON_HAS_INT64)
- std::string JSON_API valueToString( LargestInt value );
- std::string JSON_API valueToString( LargestUInt value );
- std::string JSON_API valueToString( double value );
- std::string JSON_API valueToString( bool value );
- std::string JSON_API valueToQuotedString( const char *value );
-
- /// \brief Output using the StyledStreamWriter.
- /// \see Json::operator>>()
- std::ostream& operator<<( std::ostream&, const Value &root );
-
-} // namespace Json
-
-
-
-#endif // JSON_WRITER_H_INCLUDED
-
-// //////////////////////////////////////////////////////////////////////
-// End of content of file: include/json/writer.h
-// //////////////////////////////////////////////////////////////////////
-
-
-
-
-
-
-// //////////////////////////////////////////////////////////////////////
-// Beginning of content of file: include/json/assertions.h
-// //////////////////////////////////////////////////////////////////////
-
-// Copyright 2007-2010 Baptiste Lepilleur
-// Distributed under MIT license, or public domain if desired and
-// recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-
-#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED
-# define CPPTL_JSON_ASSERTIONS_H_INCLUDED
-
-#include <stdlib.h>
-
-#if !defined(JSON_IS_AMALGAMATION)
-# include <json/config.h>
-#endif // if !defined(JSON_IS_AMALGAMATION)
-
-#if JSON_USE_EXCEPTION
-#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw
-#define JSON_FAIL_MESSAGE( message ) throw std::runtime_error( message );
-#else // JSON_USE_EXCEPTION
-#define JSON_ASSERT( condition ) assert( condition );
-
-// The call to assert() will show the failure message in debug builds. In
-// release bugs we write to invalid memory in order to crash hard, so that a
-// debugger or crash reporter gets the chance to take over. We still call exit()
-// afterward in order to tell the compiler that this macro doesn't return.
-#define JSON_FAIL_MESSAGE( message ) { assert(false && message); strcpy(reinterpret_cast<char*>(666), message); exit(123); }
-
-#endif
-
-#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) { JSON_FAIL_MESSAGE( message ) }
-
-#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED
-
-// //////////////////////////////////////////////////////////////////////
-// End of content of file: include/json/assertions.h
-// //////////////////////////////////////////////////////////////////////
-
-
-
-
-
-#endif //ifndef JSON_AMALGATED_H_INCLUDED
diff --git a/src/jsoncpp/json/jsoncpp.cpp b/src/jsoncpp/json/jsoncpp.cpp
deleted file mode 100644
index 7a04736de..000000000
--- a/src/jsoncpp/json/jsoncpp.cpp
+++ /dev/null
@@ -1,4367 +0,0 @@
-/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/).
-/// It is intented to be used with #include <json/json.h>
-
-// //////////////////////////////////////////////////////////////////////
-// Beginning of content of file: LICENSE
-// //////////////////////////////////////////////////////////////////////
-
-/*
-The JsonCpp library's source code, including accompanying documentation,
-tests and demonstration applications, are licensed under the following
-conditions...
-
-The author (Baptiste Lepilleur) explicitly disclaims copyright in all
-jurisdictions which recognize such a disclaimer. In such jurisdictions,
-this software is released into the Public Domain.
-
-In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
-2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
-released under the terms of the MIT License (see below).
-
-In jurisdictions which recognize Public Domain property, the user of this
-software may choose to accept it either as 1) Public Domain, 2) under the
-conditions of the MIT License (see below), or 3) under the terms of dual
-Public Domain/MIT License conditions described here, as they choose.
-
-The MIT License is about as close to Public Domain as a license can get, and is
-described in clear, concise terms at:
-
- http://en.wikipedia.org/wiki/MIT_License
-
-The full text of the MIT License follows:
-
-========================================================================
-Copyright (c) 2007-2010 Baptiste Lepilleur
-
-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.
-========================================================================
-(END LICENSE TEXT)
-
-The MIT license is compatible with both the GPL and commercial
-software, affording one all of the rights of Public Domain with the
-minor nuisance of being required to keep the above copyright notice
-and license text in the source code. Note also that by accepting the
-Public Domain "license" you can re-license your copy using whatever
-license you like.
-
-*/
-
-// //////////////////////////////////////////////////////////////////////
-// End of content of file: LICENSE
-// //////////////////////////////////////////////////////////////////////
-
-
-
-
-
-
-#include "json.h"
-
-
-// //////////////////////////////////////////////////////////////////////
-// Beginning of content of file: src/lib_json/json_tool.h
-// //////////////////////////////////////////////////////////////////////
-
-// Copyright 2007-2010 Baptiste Lepilleur
-// Distributed under MIT license, or public domain if desired and
-// recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-
-#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
-# define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
-
-/* This header provides common string manipulation support, such as UTF-8,
- * portable conversion from/to string...
- *
- * It is an internal header that must not be exposed.
- */
-
-namespace Json {
-
-/// Converts a unicode code-point to UTF-8.
-static inline std::string
-codePointToUTF8(unsigned int cp)
-{
- std::string result;
-
- // based on description from http://en.wikipedia.org/wiki/UTF-8
-
- if (cp <= 0x7f)
- {
- result.resize(1);
- result[0] = static_cast<char>(cp);
- }
- else if (cp <= 0x7FF)
- {
- result.resize(2);
- result[1] = static_cast<char>(0x80 | (0x3f & cp));
- result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
- }
- else if (cp <= 0xFFFF)
- {
- result.resize(3);
- result[2] = static_cast<char>(0x80 | (0x3f & cp));
- result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
- result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
- }
- else if (cp <= 0x10FFFF)
- {
- result.resize(4);
- result[3] = static_cast<char>(0x80 | (0x3f & cp));
- result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
- result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
- result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
- }
-
- return result;
-}
-
-
-/// Returns true if ch is a control character (in range [0,32[).
-static inline bool
-isControlCharacter(char ch)
-{
- return ch > 0 && ch <= 0x1F;
-}
-
-
-enum {
- /// Constant that specify the size of the buffer that must be passed to uintToString.
- uintToStringBufferSize = 3*sizeof(LargestUInt)+1
-};
-
-// Defines a char buffer for use with uintToString().
-typedef char UIntToStringBuffer[uintToStringBufferSize];
-
-
-/** Converts an unsigned integer to string.
- * @param value Unsigned interger to convert to string
- * @param current Input/Output string buffer.
- * Must have at least uintToStringBufferSize chars free.
- */
-static inline void
-uintToString( LargestUInt value,
- char *&current )
-{
- *--current = 0;
- do
- {
- *--current = char(value % 10) + '0';
- value /= 10;
- }
- while ( value != 0 );
-}
-
-} // namespace Json {
-
-#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
-
-// //////////////////////////////////////////////////////////////////////
-// End of content of file: src/lib_json/json_tool.h
-// //////////////////////////////////////////////////////////////////////
-
-
-
-
-
-
-// //////////////////////////////////////////////////////////////////////
-// Beginning of content of file: src/lib_json/json_reader.cpp
-// //////////////////////////////////////////////////////////////////////
-
-// Copyright 2007-2011 Baptiste Lepilleur
-// Distributed under MIT license, or public domain if desired and
-// recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-
-#if !defined(JSON_IS_AMALGAMATION)
-# include <json/assertions.h>
-# include <json/reader.h>
-# include <json/value.h>
-# include "json_tool.h"
-#endif // if !defined(JSON_IS_AMALGAMATION)
-#include <utility>
-#include <cstdio>
-#include <cassert>
-#include <cstring>
-#include <stdexcept>
-
-#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
-#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
-#endif
-
-namespace Json {
-
-// Implementation of class Features
-// ////////////////////////////////
-
-Features::Features()
- : allowComments_( true )
- , strictRoot_( false )
-{
-}
-
-
-Features
-Features::all()
-{
- return Features();
-}
-
-
-Features
-Features::strictMode()
-{
- Features features;
- features.allowComments_ = false;
- features.strictRoot_ = true;
- return features;
-}
-
-// Implementation of class Reader
-// ////////////////////////////////
-
-
-static inline bool
-in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
-{
- return c == c1 || c == c2 || c == c3 || c == c4;
-}
-
-static inline bool
-in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )
-{
- return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
-}
-
-
-static bool
-containsNewLine( Reader::Location begin,
- Reader::Location end )
-{
- for ( ;begin < end; ++begin )
- if ( *begin == '\n' || *begin == '\r' )
- return true;
- return false;
-}
-
-
-// Class Reader
-// //////////////////////////////////////////////////////////////////
-
-Reader::Reader()
- : errors_(),
- document_(),
- begin_(),
- end_(),
- current_(),
- lastValueEnd_(),
- lastValue_(),
- commentsBefore_(),
- features_( Features::all() ),
- collectComments_()
-{
-}
-
-
-Reader::Reader( const Features &features )
- : errors_(),
- document_(),
- begin_(),
- end_(),
- current_(),
- lastValueEnd_(),
- lastValue_(),
- commentsBefore_(),
- features_( features ),
- collectComments_()
-{
-}
-
-
-bool
-Reader::parse( const std::string &document,
- Value &root,
- bool collectComments )
-{
- document_ = document;
- const char *begin = document_.c_str();
- const char *end = begin + document_.length();
- return parse( begin, end, root, collectComments );
-}
-
-
-bool
-Reader::parse( std::istream& sin,
- Value &root,
- bool collectComments )
-{
- //std::istream_iterator<char> begin(sin);
- //std::istream_iterator<char> end;
- // Those would allow streamed input from a file, if parse() were a
- // template function.
-
- // Since std::string is reference-counted, this at least does not
- // create an extra copy.
- std::string doc;
- std::getline(sin, doc, (char)EOF);
- return parse( doc, root, collectComments );
-}
-
-bool
-Reader::parse( const char *beginDoc, const char *endDoc,
- Value &root,
- bool collectComments )
-{
- if ( !features_.allowComments_ )
- {
- collectComments = false;
- }
-
- begin_ = beginDoc;
- end_ = endDoc;
- collectComments_ = collectComments;
- current_ = begin_;
- lastValueEnd_ = 0;
- lastValue_ = 0;
- commentsBefore_ = "";
- errors_.clear();
- while ( !nodes_.empty() )
- nodes_.pop();
- nodes_.push( &root );
-
- bool successful = readValue();
- Token token;
- skipCommentTokens( token );
- if ( collectComments_ && !commentsBefore_.empty() )
- root.setComment( commentsBefore_, commentAfter );
- if ( features_.strictRoot_ )
- {
- if ( !root.isArray() && !root.isObject() )
- {
- // Set error location to start of doc, ideally should be first token found in doc
- token.type_ = tokenError;
- token.start_ = beginDoc;
- token.end_ = endDoc;
- addError( "A valid JSON document must be either an array or an object value.",
- token );
- return false;
- }
- }
- return successful;
-}
-
-
-bool
-Reader::readValue()
-{
- Token token;
- skipCommentTokens( token );
- bool successful = true;
-
- if ( collectComments_ && !commentsBefore_.empty() )
- {
- currentValue().setComment( commentsBefore_, commentBefore );
- commentsBefore_ = "";
- }
-
-
- switch ( token.type_ )
- {
- case tokenObjectBegin:
- successful = readObject( token );
- break;
- case tokenArrayBegin:
- successful = readArray( token );
- break;
- case tokenNumber:
- successful = decodeNumber( token );
- break;
- case tokenString:
- successful = decodeString( token );
- break;
- case tokenTrue:
- currentValue() = true;
- break;
- case tokenFalse:
- currentValue() = false;
- break;
- case tokenNull:
- currentValue() = Value();
- break;
- default:
- return addError( "Syntax error: value, object or array expected.", token );
- }
-
- if ( collectComments_ )
- {
- lastValueEnd_ = current_;
- lastValue_ = &currentValue();
- }
-
- return successful;
-}
-
-
-void
-Reader::skipCommentTokens( Token &token )
-{
- if ( features_.allowComments_ )
- {
- do
- {
- readToken( token );
- }
- while ( token.type_ == tokenComment );
- }
- else
- {
- readToken( token );
- }
-}
-
-
-bool
-Reader::expectToken( TokenType type, Token &token, const char *message )
-{
- readToken( token );
- if ( token.type_ != type )
- return addError( message, token );
- return true;
-}
-
-
-bool
-Reader::readToken( Token &token )
-{
- skipSpaces();
- token.start_ = current_;
- Char c = getNextChar();
- bool ok = true;
- switch ( c )
- {
- case '{':
- token.type_ = tokenObjectBegin;
- break;
- case '}':
- token.type_ = tokenObjectEnd;
- break;
- case '[':
- token.type_ = tokenArrayBegin;
- break;
- case ']':
- token.type_ = tokenArrayEnd;
- break;
- case '"':
- token.type_ = tokenString;
- ok = readString();
- break;
- case '/':
- token.type_ = tokenComment;
- ok = readComment();
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '-':
- token.type_ = tokenNumber;
- readNumber();
- break;
- case 't':
- token.type_ = tokenTrue;
- ok = match( "rue", 3 );
- break;
- case 'f':
- token.type_ = tokenFalse;
- ok = match( "alse", 4 );
- break;
- case 'n':
- token.type_ = tokenNull;
- ok = match( "ull", 3 );
- break;
- case ',':
- token.type_ = tokenArraySeparator;
- break;
- case ':':
- token.type_ = tokenMemberSeparator;
- break;
- case 0:
- token.type_ = tokenEndOfStream;
- break;
- default:
- ok = false;
- break;
- }
- if ( !ok )
- token.type_ = tokenError;
- token.end_ = current_;
- return true;
-}
-
-
-void
-Reader::skipSpaces()
-{
- while ( current_ != end_ )
- {
- Char c = *current_;
- if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' )
- ++current_;
- else
- break;
- }
-}
-
-
-bool
-Reader::match( Location pattern,
- int patternLength )
-{
- if ( end_ - current_ < patternLength )
- return false;
- int index = patternLength;
- while ( index-- )
- if ( current_[index] != pattern[index] )
- return false;
- current_ += patternLength;
- return true;
-}
-
-
-bool
-Reader::readComment()
-{
- Location commentBegin = current_ - 1;
- Char c = getNextChar();
- bool successful = false;
- if ( c == '*' )
- successful = readCStyleComment();
- else if ( c == '/' )
- successful = readCppStyleComment();
- if ( !successful )
- return false;
-
- if ( collectComments_ )
- {
- CommentPlacement placement = commentBefore;
- if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) )
- {
- if ( c != '*' || !containsNewLine( commentBegin, current_ ) )
- placement = commentAfterOnSameLine;
- }
-
- addComment( commentBegin, current_, placement );
- }
- return true;
-}
-
-
-void
-Reader::addComment( Location begin,
- Location end,
- CommentPlacement placement )
-{
- assert( collectComments_ );
- if ( placement == commentAfterOnSameLine )
- {
- assert( lastValue_ != 0 );
- lastValue_->setComment( std::string( begin, end ), placement );
- }
- else
- {
- if ( !commentsBefore_.empty() )
- commentsBefore_ += "\n";
- commentsBefore_ += std::string( begin, end );
- }
-}
-
-
-bool
-Reader::readCStyleComment()
-{
- while ( current_ != end_ )
- {
- Char c = getNextChar();
- if ( c == '*' && *current_ == '/' )
- break;
- }
- return getNextChar() == '/';
-}
-
-
-bool
-Reader::readCppStyleComment()
-{
- while ( current_ != end_ )
- {
- Char c = getNextChar();
- if ( c == '\r' || c == '\n' )
- break;
- }
- return true;
-}
-
-
-void
-Reader::readNumber()
-{
- while ( current_ != end_ )
- {
- if ( !(*current_ >= '0' && *current_ <= '9') &&
- !in( *current_, '.', 'e', 'E', '+', '-' ) )
- break;
- ++current_;
- }
-}
-
-bool
-Reader::readString()
-{
- Char c = 0;
- while ( current_ != end_ )
- {
- c = getNextChar();
- if ( c == '\\' )
- getNextChar();
- else if ( c == '"' )
- break;
- }
- return c == '"';
-}
-
-
-bool
-Reader::readObject( Token &/*tokenStart*/ )
-{
- Token tokenName;
- std::string name;
- currentValue() = Value( objectValue );
- while ( readToken( tokenName ) )
- {
- bool initialTokenOk = true;
- while ( tokenName.type_ == tokenComment && initialTokenOk )
- initialTokenOk = readToken( tokenName );
- if ( !initialTokenOk )
- break;
- if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object
- return true;
- if ( tokenName.type_ != tokenString )
- break;
-
- name = "";
- if ( !decodeString( tokenName, name ) )
- return recoverFromError( tokenObjectEnd );
-
- Token colon;
- if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator )
- {
- return addErrorAndRecover( "Missing ':' after object member name",
- colon,
- tokenObjectEnd );
- }
- Value &value = currentValue()[ name ];
- nodes_.push( &value );
- bool ok = readValue();
- nodes_.pop();
- if ( !ok ) // error already set
- return recoverFromError( tokenObjectEnd );
-
- Token comma;
- if ( !readToken( comma )
- || ( comma.type_ != tokenObjectEnd &&
- comma.type_ != tokenArraySeparator &&
- comma.type_ != tokenComment ) )
- {
- return addErrorAndRecover( "Missing ',' or '}' in object declaration",
- comma,
- tokenObjectEnd );
- }
- bool finalizeTokenOk = true;
- while ( comma.type_ == tokenComment &&
- finalizeTokenOk )
- finalizeTokenOk = readToken( comma );
- if ( comma.type_ == tokenObjectEnd )
- return true;
- }
- return addErrorAndRecover( "Missing '}' or object member name",
- tokenName,
- tokenObjectEnd );
-}
-
-
-bool
-Reader::readArray( Token &/*tokenStart*/ )
-{
- currentValue() = Value( arrayValue );
- skipSpaces();
- if ( *current_ == ']' ) // empty array
- {
- Token endArray;
- readToken( endArray );
- return true;
- }
- int index = 0;
- for (;;)
- {
- Value &value = currentValue()[ index++ ];
- nodes_.push( &value );
- bool ok = readValue();
- nodes_.pop();
- if ( !ok ) // error already set
- return recoverFromError( tokenArrayEnd );
-
- Token token;
- // Accept Comment after last item in the array.
- ok = readToken( token );
- while ( token.type_ == tokenComment && ok )
- {
- ok = readToken( token );
- }
- bool badTokenType = ( token.type_ != tokenArraySeparator &&
- token.type_ != tokenArrayEnd );
- if ( !ok || badTokenType )
- {
- return addErrorAndRecover( "Missing ',' or ']' in array declaration",
- token,
- tokenArrayEnd );
- }
- if ( token.type_ == tokenArrayEnd )
- break;
- }
- return true;
-}
-
-
-bool
-Reader::decodeNumber( Token &token )
-{
- bool isDouble = false;
- for ( Location inspect = token.start_; inspect != token.end_; ++inspect )
- {
- isDouble = isDouble
- || in( *inspect, '.', 'e', 'E', '+' )
- || ( *inspect == '-' && inspect != token.start_ );
- }
- if ( isDouble )
- return decodeDouble( token );
- // Attempts to parse the number as an integer. If the number is
- // larger than the maximum supported value of an integer then
- // we decode the number as a double.
- Location current = token.start_;
- bool isNegative = *current == '-';
- if ( isNegative )
- ++current;
- Value::LargestUInt maxIntegerValue = isNegative ? Value::LargestUInt(-Value::minLargestInt)
- : Value::maxLargestUInt;
- Value::LargestUInt threshold = maxIntegerValue / 10;
- Value::LargestUInt value = 0;
- while ( current < token.end_ )
- {
- Char c = *current++;
- if ( c < '0' || c > '9' )
- return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
- Value::UInt digit(c - '0');
- if ( value >= threshold )
- {
- // We've hit or exceeded the max value divided by 10 (rounded down). If
- // a) we've only just touched the limit, b) this is the last digit, and
- // c) it's small enough to fit in that rounding delta, we're okay.
- // Otherwise treat this number as a double to avoid overflow.
- if (value > threshold ||
- current != token.end_ ||
- digit > maxIntegerValue % 10)
- {
- return decodeDouble( token );
- }
- }
- value = value * 10 + digit;
- }
- if ( isNegative )
- currentValue() = -Value::LargestInt( value );
- else if ( value <= Value::LargestUInt(Value::maxInt) )
- currentValue() = Value::LargestInt( value );
- else
- currentValue() = value;
- return true;
-}
-
-
-bool
-Reader::decodeDouble( Token &token )
-{
- double value = 0;
- const int bufferSize = 32;
- int count;
- int length = int(token.end_ - token.start_);
-
- // Sanity check to avoid buffer overflow exploits.
- if (length < 0) {
- return addError( "Unable to parse token length", token );
- }
-
- // Avoid using a string constant for the format control string given to
- // sscanf, as this can cause hard to debug crashes on OS X. See here for more
- // info:
- //
- // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
- char format[] = "%lf";
-
- if ( length <= bufferSize )
- {
- Char buffer[bufferSize+1];
- memcpy( buffer, token.start_, length );
- buffer[length] = 0;
- count = sscanf( buffer, format, &value );
- }
- else
- {
- std::string buffer( token.start_, token.end_ );
- count = sscanf( buffer.c_str(), format, &value );
- }
-
- if ( count != 1 )
- return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
- currentValue() = value;
- return true;
-}
-
-
-bool
-Reader::decodeString( Token &token )
-{
- std::string decoded;
- if ( !decodeString( token, decoded ) )
- return false;
- currentValue() = decoded;
- return true;
-}
-
-
-bool
-Reader::decodeString( Token &token, std::string &decoded )
-{
- decoded.reserve( token.end_ - token.start_ - 2 );
- Location current = token.start_ + 1; // skip '"'
- Location end = token.end_ - 1; // do not include '"'
- while ( current != end )
- {
- Char c = *current++;
- if ( c == '"' )
- break;
- else if ( c == '\\' )
- {
- if ( current == end )
- return addError( "Empty escape sequence in string", token, current );
- Char escape = *current++;
- switch ( escape )
- {
- case '"': decoded += '"'; break;
- case '/': decoded += '/'; break;
- case '\\': decoded += '\\'; break;
- case 'b': decoded += '\b'; break;
- case 'f': decoded += '\f'; break;
- case 'n': decoded += '\n'; break;
- case 'r': decoded += '\r'; break;
- case 't': decoded += '\t'; break;
- case 'u':
- {
- unsigned int unicode;
- if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )
- return false;
- decoded += codePointToUTF8(unicode);
- }
- break;
- default:
- return addError( "Bad escape sequence in string", token, current );
- }
- }
- else
- {
- decoded += c;
- }
- }
- return true;
-}
-
-bool
-Reader::decodeUnicodeCodePoint( Token &token,
- Location &current,
- Location end,
- unsigned int &unicode )
-{
-
- if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )
- return false;
- if (unicode >= 0xD800 && unicode <= 0xDBFF)
- {
- // surrogate pairs
- if (end - current < 6)
- return addError( "additional six characters expected to parse unicode surrogate pair.", token, current );
- unsigned int surrogatePair;
- if (*(current++) == '\\' && *(current++)== 'u')
- {
- if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))
- {
- unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
- }
- else
- return false;
- }
- else
- return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current );
- }
- return true;
-}
-
-bool
-Reader::decodeUnicodeEscapeSequence( Token &token,
- Location &current,
- Location end,
- unsigned int &unicode )
-{
- if ( end - current < 4 )
- return addError( "Bad unicode escape sequence in string: four digits expected.", token, current );
- unicode = 0;
- for ( int index =0; index < 4; ++index )
- {
- Char c = *current++;
- unicode *= 16;
- if ( c >= '0' && c <= '9' )
- unicode += c - '0';
- else if ( c >= 'a' && c <= 'f' )
- unicode += c - 'a' + 10;
- else if ( c >= 'A' && c <= 'F' )
- unicode += c - 'A' + 10;
- else
- return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current );
- }
- return true;
-}
-
-
-bool
-Reader::addError( const std::string &message,
- Token &token,
- Location extra )
-{
- ErrorInfo info;
- info.token_ = token;
- info.message_ = message;
- info.extra_ = extra;
- errors_.push_back( info );
- return false;
-}
-
-
-bool
-Reader::recoverFromError( TokenType skipUntilToken )
-{
- int errorCount = int(errors_.size());
- Token skip;
- for (;;)
- {
- if ( !readToken(skip) )
- errors_.resize( errorCount ); // discard errors caused by recovery
- if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream )
- break;
- }
- errors_.resize( errorCount );
- return false;
-}
-
-
-bool
-Reader::addErrorAndRecover( const std::string &message,
- Token &token,
- TokenType skipUntilToken )
-{
- addError( message, token );
- return recoverFromError( skipUntilToken );
-}
-
-
-Value &
-Reader::currentValue()
-{
- return *(nodes_.top());
-}
-
-
-Reader::Char
-Reader::getNextChar()
-{
- if ( current_ == end_ )
- return 0;
- return *current_++;
-}
-
-
-void
-Reader::getLocationLineAndColumn( Location location,
- int &line,
- int &column ) const
-{
- Location current = begin_;
- Location lastLineStart = current;
- line = 0;
- while ( current < location && current != end_ )
- {
- Char c = *current++;
- if ( c == '\r' )
- {
- if ( *current == '\n' )
- ++current;
- lastLineStart = current;
- ++line;
- }
- else if ( c == '\n' )
- {
- lastLineStart = current;
- ++line;
- }
- }
- // column & line start at 1
- column = int(location - lastLineStart) + 1;
- ++line;
-}
-
-
-std::string
-Reader::getLocationLineAndColumn( Location location ) const
-{
- int line, column;
- getLocationLineAndColumn( location, line, column );
- char buffer[18+16+16+1];
- sprintf( buffer, "Line %d, Column %d", line, column );
- return buffer;
-}
-
-
-// Deprecated. Preserved for backward compatibility
-std::string
-Reader::getFormatedErrorMessages() const
-{
- return getFormattedErrorMessages();
-}
-
-
-std::string
-Reader::getFormattedErrorMessages() const
-{
- std::string formattedMessage;
- for ( Errors::const_iterator itError = errors_.begin();
- itError != errors_.end();
- ++itError )
- {
- const ErrorInfo &error = *itError;
- formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n";
- formattedMessage += " " + error.message_ + "\n";
- if ( error.extra_ )
- formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n";
- }
- return formattedMessage;
-}
-
-
-std::istream& operator>>( std::istream &sin, Value &root )
-{
- Json::Reader reader;
- bool ok = reader.parse(sin, root, true);
- if (!ok) {
- fprintf(
- stderr,
- "Error from reader: %s",
- reader.getFormattedErrorMessages().c_str());
-
- JSON_FAIL_MESSAGE("reader error");
- }
- return sin;
-}
-
-
-} // namespace Json
-
-// //////////////////////////////////////////////////////////////////////
-// End of content of file: src/lib_json/json_reader.cpp
-// //////////////////////////////////////////////////////////////////////
-
-
-
-
-
-
-// //////////////////////////////////////////////////////////////////////
-// Beginning of content of file: src/lib_json/json_batchallocator.h
-// //////////////////////////////////////////////////////////////////////
-
-// Copyright 2007-2010 Baptiste Lepilleur
-// Distributed under MIT license, or public domain if desired and
-// recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-
-#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
-# define JSONCPP_BATCHALLOCATOR_H_INCLUDED
-
-# include <stdlib.h>
-# include <assert.h>
-
-# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
-
-namespace Json {
-
-/* Fast memory allocator.
- *
- * This memory allocator allocates memory for a batch of object (specified by
- * the page size, the number of object in each page).
- *
- * It does not allow the destruction of a single object. All the allocated objects
- * can be destroyed at once. The memory can be either released or reused for future
- * allocation.
- *
- * The in-place new operator must be used to construct the object using the pointer
- * returned by allocate.
- */
-template<typename AllocatedType
- ,const unsigned int objectPerAllocation>
-class BatchAllocator
-{
-public:
- BatchAllocator( unsigned int objectsPerPage = 255 )
- : freeHead_( 0 )
- , objectsPerPage_( objectsPerPage )
- {
-// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
- assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.
- assert( objectsPerPage >= 16 );
- batches_ = allocateBatch( 0 ); // allocated a dummy page
- currentBatch_ = batches_;
- }
-
- ~BatchAllocator()
- {
- for ( BatchInfo *batch = batches_; batch; )
- {
- BatchInfo *nextBatch = batch->next_;
- free( batch );
- batch = nextBatch;
- }
- }
-
- /// allocate space for an array of objectPerAllocation object.
- /// @warning it is the responsability of the caller to call objects constructors.
- AllocatedType *allocate()
- {
- if ( freeHead_ ) // returns node from free list.
- {
- AllocatedType *object = freeHead_;
- freeHead_ = *(AllocatedType **)object;
- return object;
- }
- if ( currentBatch_->used_ == currentBatch_->end_ )
- {
- currentBatch_ = currentBatch_->next_;
- while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ )
- currentBatch_ = currentBatch_->next_;
-
- if ( !currentBatch_ ) // no free batch found, allocate a new one
- {
- currentBatch_ = allocateBatch( objectsPerPage_ );
- currentBatch_->next_ = batches_; // insert at the head of the list
- batches_ = currentBatch_;
- }
- }
- AllocatedType *allocated = currentBatch_->used_;
- currentBatch_->used_ += objectPerAllocation;
- return allocated;
- }
-
- /// Release the object.
- /// @warning it is the responsability of the caller to actually destruct the object.
- void release( AllocatedType *object )
- {
- assert( object != 0 );
- *(AllocatedType **)object = freeHead_;
- freeHead_ = object;
- }
-
-private:
- struct BatchInfo
- {
- BatchInfo *next_;
- AllocatedType *used_;
- AllocatedType *end_;
- AllocatedType buffer_[objectPerAllocation];
- };
-
- // disabled copy constructor and assignement operator.
- BatchAllocator( const BatchAllocator & );
- void operator =( const BatchAllocator &);
-
- static BatchInfo *allocateBatch( unsigned int objectsPerPage )
- {
- const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation
- + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
- BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) );
- batch->next_ = 0;
- batch->used_ = batch->buffer_;
- batch->end_ = batch->buffer_ + objectsPerPage;
- return batch;
- }
-
- BatchInfo *batches_;
- BatchInfo *currentBatch_;
- /// Head of a single linked list within the allocated space of freeed object
- AllocatedType *freeHead_;
- unsigned int objectsPerPage_;
-};
-
-
-} // namespace Json
-
-# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
-
-#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
-
-// //////////////////////////////////////////////////////////////////////
-// End of content of file: src/lib_json/json_batchallocator.h
-// //////////////////////////////////////////////////////////////////////
-
-
-
-
-
-
-// //////////////////////////////////////////////////////////////////////
-// Beginning of content of file: src/lib_json/json_valueiterator.inl
-// //////////////////////////////////////////////////////////////////////
-
-// Copyright 2007-2010 Baptiste Lepilleur
-// Distributed under MIT license, or public domain if desired and
-// recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-
-// included by json_value.cpp
-
-namespace Json {
-
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// class ValueIteratorBase
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-
-ValueIteratorBase::ValueIteratorBase()
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- : current_()
- , isNull_( true )
-{
-}
-#else
- : isArray_( true )
- , isNull_( true )
-{
- iterator_.array_ = ValueInternalArray::IteratorState();
-}
-#endif
-
-
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
-ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator &current )
- : current_( current )
- , isNull_( false )
-{
-}
-#else
-ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state )
- : isArray_( true )
-{
- iterator_.array_ = state;
-}
-
-
-ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state )
- : isArray_( false )
-{
- iterator_.map_ = state;
-}
-#endif
-
-Value &
-ValueIteratorBase::deref() const
-{
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- return current_->second;
-#else
- if ( isArray_ )
- return ValueInternalArray::dereference( iterator_.array_ );
- return ValueInternalMap::value( iterator_.map_ );
-#endif
-}
-
-
-void
-ValueIteratorBase::increment()
-{
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- ++current_;
-#else
- if ( isArray_ )
- ValueInternalArray::increment( iterator_.array_ );
- ValueInternalMap::increment( iterator_.map_ );
-#endif
-}
-
-
-void
-ValueIteratorBase::decrement()
-{
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- --current_;
-#else
- if ( isArray_ )
- ValueInternalArray::decrement( iterator_.array_ );
- ValueInternalMap::decrement( iterator_.map_ );
-#endif
-}
-
-
-ValueIteratorBase::difference_type
-ValueIteratorBase::computeDistance( const SelfType &other ) const
-{
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
-# ifdef JSON_USE_CPPTL_SMALLMAP
- return current_ - other.current_;
-# else
- // Iterator for null value are initialized using the default
- // constructor, which initialize current_ to the default
- // std::map::iterator. As begin() and end() are two instance
- // of the default std::map::iterator, they can not be compared.
- // To allow this, we handle this comparison specifically.
- if ( isNull_ && other.isNull_ )
- {
- return 0;
- }
-
-
- // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL,
- // which is the one used by default).
- // Using a portable hand-made version for non random iterator instead:
- // return difference_type( std::distance( current_, other.current_ ) );
- difference_type myDistance = 0;
- for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it )
- {
- ++myDistance;
- }
- return myDistance;
-# endif
-#else
- if ( isArray_ )
- return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ );
- return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ );
-#endif
-}
-
-
-bool
-ValueIteratorBase::isEqual( const SelfType &other ) const
-{
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- if ( isNull_ )
- {
- return other.isNull_;
- }
- return current_ == other.current_;
-#else
- if ( isArray_ )
- return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ );
- return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ );
-#endif
-}
-
-
-void
-ValueIteratorBase::copy( const SelfType &other )
-{
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- current_ = other.current_;
-#else
- if ( isArray_ )
- iterator_.array_ = other.iterator_.array_;
- iterator_.map_ = other.iterator_.map_;
-#endif
-}
-
-
-Value
-ValueIteratorBase::key() const
-{
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- const Value::CZString czstring = (*current_).first;
- if ( czstring.c_str() )
- {
- if ( czstring.isStaticString() )
- return Value( StaticString( czstring.c_str() ) );
- return Value( czstring.c_str() );
- }
- return Value( czstring.index() );
-#else
- if ( isArray_ )
- return Value( ValueInternalArray::indexOf( iterator_.array_ ) );
- bool isStatic;
- const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic );
- if ( isStatic )
- return Value( StaticString( memberName ) );
- return Value( memberName );
-#endif
-}
-
-
-UInt
-ValueIteratorBase::index() const
-{
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- const Value::CZString czstring = (*current_).first;
- if ( !czstring.c_str() )
- return czstring.index();
- return Value::UInt( -1 );
-#else
- if ( isArray_ )
- return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) );
- return Value::UInt( -1 );
-#endif
-}
-
-
-const char *
-ValueIteratorBase::memberName() const
-{
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- const char *name = (*current_).first.c_str();
- return name ? name : "";
-#else
- if ( !isArray_ )
- return ValueInternalMap::key( iterator_.map_ );
- return "";
-#endif
-}
-
-
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// class ValueConstIterator
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-
-ValueConstIterator::ValueConstIterator()
-{
-}
-
-
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
-ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator &current )
- : ValueIteratorBase( current )
-{
-}
-#else
-ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state )
- : ValueIteratorBase( state )
-{
-}
-
-ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state )
- : ValueIteratorBase( state )
-{
-}
-#endif
-
-ValueConstIterator &
-ValueConstIterator::operator =( const ValueIteratorBase &other )
-{
- copy( other );
- return *this;
-}
-
-
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// class ValueIterator
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-
-ValueIterator::ValueIterator()
-{
-}
-
-
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
-ValueIterator::ValueIterator( const Value::ObjectValues::iterator &current )
- : ValueIteratorBase( current )
-{
-}
-#else
-ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state )
- : ValueIteratorBase( state )
-{
-}
-
-ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state )
- : ValueIteratorBase( state )
-{
-}
-#endif
-
-ValueIterator::ValueIterator( const ValueConstIterator &other )
- : ValueIteratorBase( other )
-{
-}
-
-ValueIterator::ValueIterator( const ValueIterator &other )
- : ValueIteratorBase( other )
-{
-}
-
-ValueIterator &
-ValueIterator::operator =( const SelfType &other )
-{
- copy( other );
- return *this;
-}
-
-} // namespace Json
-
-// //////////////////////////////////////////////////////////////////////
-// End of content of file: src/lib_json/json_valueiterator.inl
-// //////////////////////////////////////////////////////////////////////
-
-
-
-
-
-
-// //////////////////////////////////////////////////////////////////////
-// Beginning of content of file: src/lib_json/json_value.cpp
-// //////////////////////////////////////////////////////////////////////
-
-// Copyright 2011 Baptiste Lepilleur
-// Distributed under MIT license, or public domain if desired and
-// recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-
-#if !defined(JSON_IS_AMALGAMATION)
-# include <json/assertions.h>
-# include <json/value.h>
-# include <json/writer.h>
-# ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
-# include "json_batchallocator.h"
-# endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
-#endif // if !defined(JSON_IS_AMALGAMATION)
-#include <math.h>
-#include <sstream>
-#include <utility>
-#include <stdexcept>
-#include <cstring>
-#include <cassert>
-#ifdef JSON_USE_CPPTL
-# include <cpptl/conststring.h>
-#endif
-#include <cstddef> // size_t
-
-#define JSON_ASSERT_UNREACHABLE assert( false )
-
-namespace Json {
-
-const Value Value::null;
-const Int Value::minInt = Int( ~(UInt(-1)/2) );
-const Int Value::maxInt = Int( UInt(-1)/2 );
-const UInt Value::maxUInt = UInt(-1);
-# if defined(JSON_HAS_INT64)
-const Int64 Value::minInt64 = Int64( ~(UInt64(-1)/2) );
-const Int64 Value::maxInt64 = Int64( UInt64(-1)/2 );
-const UInt64 Value::maxUInt64 = UInt64(-1);
-// The constant is hard-coded because some compiler have trouble
-// converting Value::maxUInt64 to a double correctly (AIX/xlC).
-// Assumes that UInt64 is a 64 bits integer.
-static const double maxUInt64AsDouble = 18446744073709551615.0;
-#endif // defined(JSON_HAS_INT64)
-const LargestInt Value::minLargestInt = LargestInt( ~(LargestUInt(-1)/2) );
-const LargestInt Value::maxLargestInt = LargestInt( LargestUInt(-1)/2 );
-const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
-
-
-/// Unknown size marker
-static const unsigned int unknown = (unsigned)-1;
-
-#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
-template <typename T, typename U>
-static inline bool InRange(double d, T min, U max) {
- return d >= min && d <= max;
-}
-#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
-static inline double integerToDouble( Json::UInt64 value )
-{
- return static_cast<double>( Int64(value/2) ) * 2.0 + Int64(value & 1);
-}
-
-template<typename T>
-static inline double integerToDouble( T value )
-{
- return static_cast<double>( value );
-}
-
-template <typename T, typename U>
-static inline bool InRange(double d, T min, U max) {
- return d >= integerToDouble(min) && d <= integerToDouble(max);
-}
-#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
-
-
-/** Duplicates the specified string value.
- * @param value Pointer to the string to duplicate. Must be zero-terminated if
- * length is "unknown".
- * @param length Length of the value. if equals to unknown, then it will be
- * computed using strlen(value).
- * @return Pointer on the duplicate instance of string.
- */
-static inline char *
-duplicateStringValue( const char *value,
- unsigned int length = unknown )
-{
- if ( length == unknown )
- length = (unsigned int)strlen(value);
-
- // Avoid an integer overflow in the call to malloc below by limiting length
- // to a sane value.
- if (length >= (unsigned)Value::maxInt)
- length = Value::maxInt - 1;
-
- char *newString = static_cast<char *>( malloc( length + 1 ) );
- JSON_ASSERT_MESSAGE( newString != 0, "Failed to allocate string value buffer" );
- memcpy( newString, value, length );
- newString[length] = 0;
- return newString;
-}
-
-
-/** Free the string duplicated by duplicateStringValue().
- */
-static inline void
-releaseStringValue( char *value )
-{
- if ( value )
- free( value );
-}
-
-} // namespace Json
-
-
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// ValueInternals...
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-#if !defined(JSON_IS_AMALGAMATION)
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
-# include "json_internalarray.inl"
-# include "json_internalmap.inl"
-# endif // JSON_VALUE_USE_INTERNAL_MAP
-
-# include "json_valueiterator.inl"
-#endif // if !defined(JSON_IS_AMALGAMATION)
-
-namespace Json {
-
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// class Value::CommentInfo
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-
-
-Value::CommentInfo::CommentInfo()
- : comment_( 0 )
-{
-}
-
-Value::CommentInfo::~CommentInfo()
-{
- if ( comment_ )
- releaseStringValue( comment_ );
-}
-
-
-void
-Value::CommentInfo::setComment( const char *text )
-{
- if ( comment_ )
- releaseStringValue( comment_ );
- JSON_ASSERT( text != 0 );
- JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /");
- // It seems that /**/ style comments are acceptable as well.
- comment_ = duplicateStringValue( text );
-}
-
-
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// class Value::CZString
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-# ifndef JSON_VALUE_USE_INTERNAL_MAP
-
-// Notes: index_ indicates if the string was allocated when
-// a string is stored.
-
-Value::CZString::CZString( ArrayIndex index )
- : cstr_( 0 )
- , index_( index )
-{
-}
-
-Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate )
- : cstr_( allocate == duplicate ? duplicateStringValue(cstr)
- : cstr )
- , index_( allocate )
-{
-}
-
-Value::CZString::CZString( const CZString &other )
-: cstr_( other.index_ != noDuplication && other.cstr_ != 0
- ? duplicateStringValue( other.cstr_ )
- : other.cstr_ )
- , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate)
- : other.index_ )
-{
-}
-
-Value::CZString::~CZString()
-{
- if ( cstr_ && index_ == duplicate )
- releaseStringValue( const_cast<char *>( cstr_ ) );
-}
-
-void
-Value::CZString::swap( CZString &other )
-{
- std::swap( cstr_, other.cstr_ );
- std::swap( index_, other.index_ );
-}
-
-Value::CZString &
-Value::CZString::operator =( const CZString &other )
-{
- CZString temp( other );
- swap( temp );
- return *this;
-}
-
-bool
-Value::CZString::operator<( const CZString &other ) const
-{
- if ( cstr_ )
- return strcmp( cstr_, other.cstr_ ) < 0;
- return index_ < other.index_;
-}
-
-bool
-Value::CZString::operator==( const CZString &other ) const
-{
- if ( cstr_ )
- return strcmp( cstr_, other.cstr_ ) == 0;
- return index_ == other.index_;
-}
-
-
-ArrayIndex
-Value::CZString::index() const
-{
- return index_;
-}
-
-
-const char *
-Value::CZString::c_str() const
-{
- return cstr_;
-}
-
-bool
-Value::CZString::isStaticString() const
-{
- return index_ == noDuplication;
-}
-
-#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
-
-
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// class Value::Value
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-
-/*! \internal Default constructor initialization must be equivalent to:
- * memset( this, 0, sizeof(Value) )
- * This optimization is used in ValueInternalMap fast allocator.
- */
-Value::Value( ValueType type )
- : type_( type )
- , allocated_( false )
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- , itemIsUsed_( 0 )
-#endif
- , comments_( 0 )
-{
- switch ( type )
- {
- case nullValue:
- break;
- case intValue:
- case uintValue:
- value_.int_ = 0;
- break;
- case realValue:
- value_.real_ = 0.0;
- break;
- case stringValue:
- value_.string_ = 0;
- break;
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- case arrayValue:
- case objectValue:
- value_.map_ = new ObjectValues();
- break;
-#else
- case arrayValue:
- value_.array_ = arrayAllocator()->newArray();
- break;
- case objectValue:
- value_.map_ = mapAllocator()->newMap();
- break;
-#endif
- case booleanValue:
- value_.bool_ = false;
- break;
- default:
- JSON_ASSERT_UNREACHABLE;
- }
-}
-
-
-Value::Value( UInt value )
- : type_( uintValue )
- , allocated_( false )
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- , itemIsUsed_( 0 )
-#endif
- , comments_( 0 )
-{
- value_.uint_ = value;
-}
-
-Value::Value( Int value )
- : type_( intValue )
- , allocated_( false )
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- , itemIsUsed_( 0 )
-#endif
- , comments_( 0 )
-{
- value_.int_ = value;
-}
-
-
-# if defined(JSON_HAS_INT64)
-Value::Value( Int64 value )
- : type_( intValue )
- , allocated_( false )
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- , itemIsUsed_( 0 )
-#endif
- , comments_( 0 )
-{
- value_.int_ = value;
-}
-
-
-Value::Value( UInt64 value )
- : type_( uintValue )
- , allocated_( false )
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- , itemIsUsed_( 0 )
-#endif
- , comments_( 0 )
-{
- value_.uint_ = value;
-}
-#endif // defined(JSON_HAS_INT64)
-
-Value::Value( double value )
- : type_( realValue )
- , allocated_( false )
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- , itemIsUsed_( 0 )
-#endif
- , comments_( 0 )
-{
- value_.real_ = value;
-}
-
-Value::Value( const char *value )
- : type_( stringValue )
- , allocated_( true )
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- , itemIsUsed_( 0 )
-#endif
- , comments_( 0 )
-{
- value_.string_ = duplicateStringValue( value );
-}
-
-
-Value::Value( const char *beginValue,
- const char *endValue )
- : type_( stringValue )
- , allocated_( true )
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- , itemIsUsed_( 0 )
-#endif
- , comments_( 0 )
-{
- value_.string_ = duplicateStringValue( beginValue,
- (unsigned int)(endValue - beginValue) );
-}
-
-
-Value::Value( const std::string &value )
- : type_( stringValue )
- , allocated_( true )
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- , itemIsUsed_( 0 )
-#endif
- , comments_( 0 )
-{
- value_.string_ = duplicateStringValue( value.c_str(),
- (unsigned int)value.length() );
-
-}
-
-Value::Value( const StaticString &value )
- : type_( stringValue )
- , allocated_( false )
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- , itemIsUsed_( 0 )
-#endif
- , comments_( 0 )
-{
- value_.string_ = const_cast<char *>( value.c_str() );
-}
-
-
-# ifdef JSON_USE_CPPTL
-Value::Value( const CppTL::ConstString &value )
- : type_( stringValue )
- , allocated_( true )
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- , itemIsUsed_( 0 )
-#endif
- , comments_( 0 )
-{
- value_.string_ = duplicateStringValue( value, value.length() );
-}
-# endif
-
-Value::Value( bool value )
- : type_( booleanValue )
- , allocated_( false )
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- , itemIsUsed_( 0 )
-#endif
- , comments_( 0 )
-{
- value_.bool_ = value;
-}
-
-
-Value::Value( const Value &other )
- : type_( other.type_ )
- , allocated_( false )
-# ifdef JSON_VALUE_USE_INTERNAL_MAP
- , itemIsUsed_( 0 )
-#endif
- , comments_( 0 )
-{
- switch ( type_ )
- {
- case nullValue:
- case intValue:
- case uintValue:
- case realValue:
- case booleanValue:
- value_ = other.value_;
- break;
- case stringValue:
- if ( other.value_.string_ )
- {
- value_.string_ = duplicateStringValue( other.value_.string_ );
- allocated_ = true;
- }
- else
- value_.string_ = 0;
- break;
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- case arrayValue:
- case objectValue:
- value_.map_ = new ObjectValues( *other.value_.map_ );
- break;
-#else
- case arrayValue:
- value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ );
- break;
- case objectValue:
- value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ );
- break;
-#endif
- default:
- JSON_ASSERT_UNREACHABLE;
- }
- if ( other.comments_ )
- {
- comments_ = new CommentInfo[numberOfCommentPlacement];
- for ( int comment =0; comment < numberOfCommentPlacement; ++comment )
- {
- const CommentInfo &otherComment = other.comments_[comment];
- if ( otherComment.comment_ )
- comments_[comment].setComment( otherComment.comment_ );
- }
- }
-}
-
-
-Value::~Value()
-{
- switch ( type_ )
- {
- case nullValue:
- case intValue:
- case uintValue:
- case realValue:
- case booleanValue:
- break;
- case stringValue:
- if ( allocated_ )
- releaseStringValue( value_.string_ );
- break;
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- case arrayValue:
- case objectValue:
- delete value_.map_;
- break;
-#else
- case arrayValue:
- arrayAllocator()->destructArray( value_.array_ );
- break;
- case objectValue:
- mapAllocator()->destructMap( value_.map_ );
- break;
-#endif
- default:
- JSON_ASSERT_UNREACHABLE;
- }
-
- if ( comments_ )
- delete[] comments_;
-}
-
-Value &
-Value::operator=( const Value &other )
-{
- Value temp( other );
- swap( temp );
- return *this;
-}
-
-void
-Value::swap( Value &other )
-{
- ValueType temp = type_;
- type_ = other.type_;
- other.type_ = temp;
- std::swap( value_, other.value_ );
- int temp2 = allocated_;
- allocated_ = other.allocated_;
- other.allocated_ = temp2;
-}
-
-ValueType
-Value::type() const
-{
- return type_;
-}
-
-
-int
-Value::compare( const Value &other ) const
-{
- if ( *this < other )
- return -1;
- if ( *this > other )
- return 1;
- return 0;
-}
-
-
-bool
-Value::operator <( const Value &other ) const
-{
- int typeDelta = type_ - other.type_;
- if ( typeDelta )
- return typeDelta < 0 ? true : false;
- switch ( type_ )
- {
- case nullValue:
- return false;
- case intValue:
- return value_.int_ < other.value_.int_;
- case uintValue:
- return value_.uint_ < other.value_.uint_;
- case realValue:
- return value_.real_ < other.value_.real_;
- case booleanValue:
- return value_.bool_ < other.value_.bool_;
- case stringValue:
- return ( value_.string_ == 0 && other.value_.string_ )
- || ( other.value_.string_
- && value_.string_
- && strcmp( value_.string_, other.value_.string_ ) < 0 );
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- case arrayValue:
- case objectValue:
- {
- int delta = int( value_.map_->size() - other.value_.map_->size() );
- if ( delta )
- return delta < 0;
- return (*value_.map_) < (*other.value_.map_);
- }
-#else
- case arrayValue:
- return value_.array_->compare( *(other.value_.array_) ) < 0;
- case objectValue:
- return value_.map_->compare( *(other.value_.map_) ) < 0;
-#endif
- default:
- JSON_ASSERT_UNREACHABLE;
- }
- return false; // unreachable
-}
-
-bool
-Value::operator <=( const Value &other ) const
-{
- return !(other < *this);
-}
-
-bool
-Value::operator >=( const Value &other ) const
-{
- return !(*this < other);
-}
-
-bool
-Value::operator >( const Value &other ) const
-{
- return other < *this;
-}
-
-bool
-Value::operator ==( const Value &other ) const
-{
- //if ( type_ != other.type_ )
- // GCC 2.95.3 says:
- // attempt to take address of bit-field structure member `Json::Value::type_'
- // Beats me, but a temp solves the problem.
- int temp = other.type_;
- if ( type_ != temp )
- return false;
- switch ( type_ )
- {
- case nullValue:
- return true;
- case intValue:
- return value_.int_ == other.value_.int_;
- case uintValue:
- return value_.uint_ == other.value_.uint_;
- case realValue:
- return value_.real_ == other.value_.real_;
- case booleanValue:
- return value_.bool_ == other.value_.bool_;
- case stringValue:
- return ( value_.string_ == other.value_.string_ )
- || ( other.value_.string_
- && value_.string_
- && strcmp( value_.string_, other.value_.string_ ) == 0 );
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- case arrayValue:
- case objectValue:
- return value_.map_->size() == other.value_.map_->size()
- && (*value_.map_) == (*other.value_.map_);
-#else
- case arrayValue:
- return value_.array_->compare( *(other.value_.array_) ) == 0;
- case objectValue:
- return value_.map_->compare( *(other.value_.map_) ) == 0;
-#endif
- default:
- JSON_ASSERT_UNREACHABLE;
- }
- return false; // unreachable
-}
-
-bool
-Value::operator !=( const Value &other ) const
-{
- return !( *this == other );
-}
-
-const char *
-Value::asCString() const
-{
- JSON_ASSERT( type_ == stringValue );
- return value_.string_;
-}
-
-
-std::string
-Value::asString() const
-{
- switch ( type_ )
- {
- case nullValue:
- return "";
- case stringValue:
- return value_.string_ ? value_.string_ : "";
- case booleanValue:
- return value_.bool_ ? "true" : "false";
- case intValue:
- return valueToString( value_.int_ );
- case uintValue:
- return valueToString( value_.uint_ );
- case realValue:
- return valueToString( value_.real_ );
- default:
- JSON_FAIL_MESSAGE( "Type is not convertible to string" );
- }
-}
-
-# ifdef JSON_USE_CPPTL
-CppTL::ConstString
-Value::asConstString() const
-{
- return CppTL::ConstString( asString().c_str() );
-}
-# endif
-
-
-Value::Int
-Value::asInt() const
-{
- switch ( type_ )
- {
- case intValue:
- JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
- return Int(value_.int_);
- case uintValue:
- JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
- return Int(value_.uint_);
- case realValue:
- JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), "double out of Int range");
- return Int(value_.real_);
- case nullValue:
- return 0;
- case booleanValue:
- return value_.bool_ ? 1 : 0;
- default:
- break;
- }
- JSON_FAIL_MESSAGE("Value is not convertible to Int.");
-}
-
-
-Value::UInt
-Value::asUInt() const
-{
- switch ( type_ )
- {
- case intValue:
- JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
- return UInt(value_.int_);
- case uintValue:
- JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
- return UInt(value_.uint_);
- case realValue:
- JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), "double out of UInt range");
- return UInt( value_.real_ );
- case nullValue:
- return 0;
- case booleanValue:
- return value_.bool_ ? 1 : 0;
- default:
- break;
- }
- JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
-}
-
-
-# if defined(JSON_HAS_INT64)
-
-Value::Int64
-Value::asInt64() const
-{
- switch ( type_ )
- {
- case intValue:
- return Int64(value_.int_);
- case uintValue:
- JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
- return Int64(value_.uint_);
- case realValue:
- JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), "double out of Int64 range");
- return Int64(value_.real_);
- case nullValue:
- return 0;
- case booleanValue:
- return value_.bool_ ? 1 : 0;
- default:
- break;
- }
- JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
-}
-
-
-Value::UInt64
-Value::asUInt64() const
-{
- switch ( type_ )
- {
- case intValue:
- JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
- return UInt64(value_.int_);
- case uintValue:
- return UInt64(value_.uint_);
- case realValue:
- JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), "double out of UInt64 range");
- return UInt64( value_.real_ );
- case nullValue:
- return 0;
- case booleanValue:
- return value_.bool_ ? 1 : 0;
- default:
- break;
- }
- JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
-}
-# endif // if defined(JSON_HAS_INT64)
-
-
-LargestInt
-Value::asLargestInt() const
-{
-#if defined(JSON_NO_INT64)
- return asInt();
-#else
- return asInt64();
-#endif
-}
-
-
-LargestUInt
-Value::asLargestUInt() const
-{
-#if defined(JSON_NO_INT64)
- return asUInt();
-#else
- return asUInt64();
-#endif
-}
-
-
-double
-Value::asDouble() const
-{
- switch ( type_ )
- {
- case intValue:
- return static_cast<double>( value_.int_ );
- case uintValue:
-#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
- return static_cast<double>( value_.uint_ );
-#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
- return integerToDouble( value_.uint_ );
-#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
- case realValue:
- return value_.real_;
- case nullValue:
- return 0.0;
- case booleanValue:
- return value_.bool_ ? 1.0 : 0.0;
- default:
- break;
- }
- JSON_FAIL_MESSAGE("Value is not convertible to double.");
-}
-
-float
-Value::asFloat() const
-{
- switch ( type_ )
- {
- case intValue:
- return static_cast<float>( value_.int_ );
- case uintValue:
-#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
- return static_cast<float>( value_.uint_ );
-#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
- return integerToDouble( value_.uint_ );
-#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
- case realValue:
- return static_cast<float>( value_.real_ );
- case nullValue:
- return 0.0;
- case booleanValue:
- return value_.bool_ ? 1.0f : 0.0f;
- default:
- break;
- }
- JSON_FAIL_MESSAGE("Value is not convertible to float.");
-}
-
-bool
-Value::asBool() const
-{
- switch ( type_ )
- {
- case booleanValue:
- return value_.bool_;
- case nullValue:
- return false;
- case intValue:
- return value_.int_ ? true : false;
- case uintValue:
- return value_.uint_ ? true : false;
- case realValue:
- return value_.real_ ? true : false;
- default:
- break;
- }
- JSON_FAIL_MESSAGE("Value is not convertible to bool.");
-}
-
-
-bool
-Value::isConvertibleTo( ValueType other ) const
-{
- switch ( other )
- {
- case nullValue:
- return ( isNumeric() && asDouble() == 0.0 )
- || ( type_ == booleanValue && value_.bool_ == false )
- || ( type_ == stringValue && asString() == "" )
- || ( type_ == arrayValue && value_.map_->size() == 0 )
- || ( type_ == objectValue && value_.map_->size() == 0 )
- || type_ == nullValue;
- case intValue:
- return isInt()
- || (type_ == realValue && InRange(value_.real_, minInt, maxInt))
- || type_ == booleanValue
- || type_ == nullValue;
- case uintValue:
- return isUInt()
- || (type_ == realValue && InRange(value_.real_, 0, maxUInt))
- || type_ == booleanValue
- || type_ == nullValue;
- case realValue:
- return isNumeric()
- || type_ == booleanValue
- || type_ == nullValue;
- case booleanValue:
- return isNumeric()
- || type_ == booleanValue
- || type_ == nullValue;
- case stringValue:
- return isNumeric()
- || type_ == booleanValue
- || type_ == stringValue
- || type_ == nullValue;
- case arrayValue:
- return type_ == arrayValue
- || type_ == nullValue;
- case objectValue:
- return type_ == objectValue
- || type_ == nullValue;
- }
- JSON_ASSERT_UNREACHABLE;
- return false;
-}
-
-
-/// Number of values in array or object
-ArrayIndex
-Value::size() const
-{
- switch ( type_ )
- {
- case nullValue:
- case intValue:
- case uintValue:
- case realValue:
- case booleanValue:
- case stringValue:
- return 0;
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- case arrayValue: // size of the array is highest index + 1
- if ( !value_.map_->empty() )
- {
- ObjectValues::const_iterator itLast = value_.map_->end();
- --itLast;
- return (*itLast).first.index()+1;
- }
- return 0;
- case objectValue:
- return ArrayIndex( value_.map_->size() );
-#else
- case arrayValue:
- return Int( value_.array_->size() );
- case objectValue:
- return Int( value_.map_->size() );
-#endif
- }
- JSON_ASSERT_UNREACHABLE;
- return 0; // unreachable;
-}
-
-
-bool
-Value::empty() const
-{
- if ( isNull() || isArray() || isObject() )
- return size() == 0u;
- else
- return false;
-}
-
-
-bool
-Value::operator!() const
-{
- return isNull();
-}
-
-
-void
-Value::clear()
-{
- JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue );
-
- switch ( type_ )
- {
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- case arrayValue:
- case objectValue:
- value_.map_->clear();
- break;
-#else
- case arrayValue:
- value_.array_->clear();
- break;
- case objectValue:
- value_.map_->clear();
- break;
-#endif
- default:
- break;
- }
-}
-
-void
-Value::resize( ArrayIndex newSize )
-{
- JSON_ASSERT( type_ == nullValue || type_ == arrayValue );
- if ( type_ == nullValue )
- *this = Value( arrayValue );
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- ArrayIndex oldSize = size();
- if ( newSize == 0 )
- clear();
- else if ( newSize > oldSize )
- (*this)[ newSize - 1 ];
- else
- {
- for ( ArrayIndex index = newSize; index < oldSize; ++index )
- {
- value_.map_->erase( index );
- }
- assert( size() == newSize );
- }
-#else
- value_.array_->resize( newSize );
-#endif
-}
-
-
-Value &
-Value::operator[]( ArrayIndex index )
-{
- JSON_ASSERT( type_ == nullValue || type_ == arrayValue );
- if ( type_ == nullValue )
- *this = Value( arrayValue );
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- CZString key( index );
- ObjectValues::iterator it = value_.map_->lower_bound( key );
- if ( it != value_.map_->end() && (*it).first == key )
- return (*it).second;
-
- ObjectValues::value_type defaultValue( key, null );
- it = value_.map_->insert( it, defaultValue );
- return (*it).second;
-#else
- return value_.array_->resolveReference( index );
-#endif
-}
-
-
-Value &
-Value::operator[]( int index )
-{
- JSON_ASSERT( index >= 0 );
- return (*this)[ ArrayIndex(index) ];
-}
-
-
-const Value &
-Value::operator[]( ArrayIndex index ) const
-{
- JSON_ASSERT( type_ == nullValue || type_ == arrayValue );
- if ( type_ == nullValue )
- return null;
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- CZString key( index );
- ObjectValues::const_iterator it = value_.map_->find( key );
- if ( it == value_.map_->end() )
- return null;
- return (*it).second;
-#else
- Value *value = value_.array_->find( index );
- return value ? *value : null;
-#endif
-}
-
-
-const Value &
-Value::operator[]( int index ) const
-{
- JSON_ASSERT( index >= 0 );
- return (*this)[ ArrayIndex(index) ];
-}
-
-
-Value &
-Value::operator[]( const char *key )
-{
- return resolveReference( key, false );
-}
-
-
-Value &
-Value::resolveReference( const char *key,
- bool isStatic )
-{
- JSON_ASSERT( type_ == nullValue || type_ == objectValue );
- if ( type_ == nullValue )
- *this = Value( objectValue );
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- CZString actualKey( key, isStatic ? CZString::noDuplication
- : CZString::duplicateOnCopy );
- ObjectValues::iterator it = value_.map_->lower_bound( actualKey );
- if ( it != value_.map_->end() && (*it).first == actualKey )
- return (*it).second;
-
- ObjectValues::value_type defaultValue( actualKey, null );
- it = value_.map_->insert( it, defaultValue );
- Value &value = (*it).second;
- return value;
-#else
- return value_.map_->resolveReference( key, isStatic );
-#endif
-}
-
-
-Value
-Value::get( ArrayIndex index,
- const Value &defaultValue ) const
-{
- const Value *value = &((*this)[index]);
- return value == &null ? defaultValue : *value;
-}
-
-
-bool
-Value::isValidIndex( ArrayIndex index ) const
-{
- return index < size();
-}
-
-
-
-const Value &
-Value::operator[]( const char *key ) const
-{
- JSON_ASSERT( type_ == nullValue || type_ == objectValue );
- if ( type_ == nullValue )
- return null;
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- CZString actualKey( key, CZString::noDuplication );
- ObjectValues::const_iterator it = value_.map_->find( actualKey );
- if ( it == value_.map_->end() )
- return null;
- return (*it).second;
-#else
- const Value *value = value_.map_->find( key );
- return value ? *value : null;
-#endif
-}
-
-
-Value &
-Value::operator[]( const std::string &key )
-{
- return (*this)[ key.c_str() ];
-}
-
-
-const Value &
-Value::operator[]( const std::string &key ) const
-{
- return (*this)[ key.c_str() ];
-}
-
-Value &
-Value::operator[]( const StaticString &key )
-{
- return resolveReference( key, true );
-}
-
-
-# ifdef JSON_USE_CPPTL
-Value &
-Value::operator[]( const CppTL::ConstString &key )
-{
- return (*this)[ key.c_str() ];
-}
-
-
-const Value &
-Value::operator[]( const CppTL::ConstString &key ) const
-{
- return (*this)[ key.c_str() ];
-}
-# endif
-
-
-Value &
-Value::append( const Value &value )
-{
- return (*this)[size()] = value;
-}
-
-
-Value
-Value::get( const char *key,
- const Value &defaultValue ) const
-{
- const Value *value = &((*this)[key]);
- return value == &null ? defaultValue : *value;
-}
-
-
-Value
-Value::get( const std::string &key,
- const Value &defaultValue ) const
-{
- return get( key.c_str(), defaultValue );
-}
-
-Value
-Value::removeMember( const char* key )
-{
- JSON_ASSERT( type_ == nullValue || type_ == objectValue );
- if ( type_ == nullValue )
- return null;
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- CZString actualKey( key, CZString::noDuplication );
- ObjectValues::iterator it = value_.map_->find( actualKey );
- if ( it == value_.map_->end() )
- return null;
- Value old(it->second);
- value_.map_->erase(it);
- return old;
-#else
- Value *value = value_.map_->find( key );
- if (value){
- Value old(*value);
- value_.map_.remove( key );
- return old;
- } else {
- return null;
- }
-#endif
-}
-
-Value
-Value::removeMember( const std::string &key )
-{
- return removeMember( key.c_str() );
-}
-
-# ifdef JSON_USE_CPPTL
-Value
-Value::get( const CppTL::ConstString &key,
- const Value &defaultValue ) const
-{
- return get( key.c_str(), defaultValue );
-}
-# endif
-
-bool
-Value::isMember( const char *key ) const
-{
- const Value *value = &((*this)[key]);
- return value != &null;
-}
-
-
-bool
-Value::isMember( const std::string &key ) const
-{
- return isMember( key.c_str() );
-}
-
-
-# ifdef JSON_USE_CPPTL
-bool
-Value::isMember( const CppTL::ConstString &key ) const
-{
- return isMember( key.c_str() );
-}
-#endif
-
-Value::Members
-Value::getMemberNames() const
-{
- JSON_ASSERT( type_ == nullValue || type_ == objectValue );
- if ( type_ == nullValue )
- return Value::Members();
- Members members;
- members.reserve( value_.map_->size() );
-#ifndef JSON_VALUE_USE_INTERNAL_MAP
- ObjectValues::const_iterator it = value_.map_->begin();
- ObjectValues::const_iterator itEnd = value_.map_->end();
- for ( ; it != itEnd; ++it )
- members.push_back( std::string( (*it).first.c_str() ) );
-#else
- ValueInternalMap::IteratorState it;
- ValueInternalMap::IteratorState itEnd;
- value_.map_->makeBeginIterator( it );
- value_.map_->makeEndIterator( itEnd );
- for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) )
- members.push_back( std::string( ValueInternalMap::key( it ) ) );
-#endif
- return members;
-}
-//
-//# ifdef JSON_USE_CPPTL
-//EnumMemberNames
-//Value::enumMemberNames() const
-//{
-// if ( type_ == objectValue )
-// {
-// return CppTL::Enum::any( CppTL::Enum::transform(
-// CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
-// MemberNamesTransform() ) );
-// }
-// return EnumMemberNames();
-//}
-//
-//
-//EnumValues
-//Value::enumValues() const
-//{
-// if ( type_ == objectValue || type_ == arrayValue )
-// return CppTL::Enum::anyValues( *(value_.map_),
-// CppTL::Type<const Value &>() );
-// return EnumValues();
-//}
-//
-//# endif
-
-static bool IsIntegral(double d) {
- double integral_part;
- return modf(d, &integral_part) == 0.0;
-}
-
-
-bool
-Value::isNull() const
-{
- return type_ == nullValue;
-}
-
-
-bool
-Value::isBool() const
-{
- return type_ == booleanValue;
-}
-
-
-bool
-Value::isInt() const
-{
- switch ( type_ )
- {
- case intValue:
- return value_.int_ >= minInt && value_.int_ <= maxInt;
- case uintValue:
- return value_.uint_ <= UInt(maxInt);
- case realValue:
- return value_.real_ >= minInt &&
- value_.real_ <= maxInt &&
- IsIntegral(value_.real_);
- default:
- break;
- }
- return false;
-}
-
-
-bool
-Value::isUInt() const
-{
- switch ( type_ )
- {
- case intValue:
- return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
- case uintValue:
- return value_.uint_ <= maxUInt;
- case realValue:
- return value_.real_ >= 0 &&
- value_.real_ <= maxUInt &&
- IsIntegral(value_.real_);
- default:
- break;
- }
- return false;
-}
-
-bool
-Value::isInt64() const
-{
-# if defined(JSON_HAS_INT64)
- switch ( type_ )
- {
- case intValue:
- return true;
- case uintValue:
- return value_.uint_ <= UInt64(maxInt64);
- case realValue:
- // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
- // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
- // require the value to be strictly less than the limit.
- return value_.real_ >= double(minInt64) &&
- value_.real_ < double(maxInt64) &&
- IsIntegral(value_.real_);
- default:
- break;
- }
-# endif // JSON_HAS_INT64
- return false;
-}
-
-bool
-Value::isUInt64() const
-{
-# if defined(JSON_HAS_INT64)
- switch ( type_ )
- {
- case intValue:
- return value_.int_ >= 0;
- case uintValue:
- return true;
- case realValue:
- // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
- // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
- // require the value to be strictly less than the limit.
- return value_.real_ >= 0 &&
- value_.real_ < maxUInt64AsDouble &&
- IsIntegral(value_.real_);
- default:
- break;
- }
-# endif // JSON_HAS_INT64
- return false;
-}
-
-
-bool
-Value::isIntegral() const
-{
-#if defined(JSON_HAS_INT64)
- return isInt64() || isUInt64();
-#else
- return isInt() || isUInt();
-#endif
-}
-
-
-bool
-Value::isDouble() const
-{
- return type_ == realValue || isIntegral();
-}
-
-
-bool
-Value::isNumeric() const
-{
- return isIntegral() || isDouble();
-}
-
-
-bool
-Value::isString() const
-{
- return type_ == stringValue;
-}
-
-
-bool
-Value::isArray() const
-{
- return type_ == arrayValue;
-}
-
-
-bool
-Value::isObject() const
-{
- return type_ == objectValue;
-}
-
-
-void
-Value::setComment( const char *comment,
- CommentPlacement placement )
-{
- if ( !comments_ )
- comments_ = new CommentInfo[numberOfCommentPlacement];
- comments_[placement].setComment( comment );
-}
-
-
-void
-Value::setComment( const std::string &comment,
- CommentPlacement placement )
-{
- setComment( comment.c_str(), placement );
-}
-
-
-bool
-Value::hasComment( CommentPlacement placement ) const
-{
- return comments_ != 0 && comments_[placement].comment_ != 0;
-}
-
-std::string
-Value::getComment( CommentPlacement placement ) const
-{
- if ( hasComment(placement) )
- return comments_[placement].comment_;
- return "";
-}
-
-
-std::string
-Value::toStyledString() const
-{
- StyledWriter writer;
- return writer.write( *this );
-}
-
-
-Value::const_iterator
-Value::begin() const
-{
- switch ( type_ )
- {
-#ifdef JSON_VALUE_USE_INTERNAL_MAP
- case arrayValue:
- if ( value_.array_ )
- {
- ValueInternalArray::IteratorState it;
- value_.array_->makeBeginIterator( it );
- return const_iterator( it );
- }
- break;
- case objectValue:
- if ( value_.map_ )
- {
- ValueInternalMap::IteratorState it;
- value_.map_->makeBeginIterator( it );
- return const_iterator( it );
- }
- break;
-#else
- case arrayValue:
- case objectValue:
- if ( value_.map_ )
- return const_iterator( value_.map_->begin() );
- break;
-#endif
- default:
- break;
- }
- return const_iterator();
-}
-
-Value::const_iterator
-Value::end() const
-{
- switch ( type_ )
- {
-#ifdef JSON_VALUE_USE_INTERNAL_MAP
- case arrayValue:
- if ( value_.array_ )
- {
- ValueInternalArray::IteratorState it;
- value_.array_->makeEndIterator( it );
- return const_iterator( it );
- }
- break;
- case objectValue:
- if ( value_.map_ )
- {
- ValueInternalMap::IteratorState it;
- value_.map_->makeEndIterator( it );
- return const_iterator( it );
- }
- break;
-#else
- case arrayValue:
- case objectValue:
- if ( value_.map_ )
- return const_iterator( value_.map_->end() );
- break;
-#endif
- default:
- break;
- }
- return const_iterator();
-}
-
-
-Value::iterator
-Value::begin()
-{
- switch ( type_ )
- {
-#ifdef JSON_VALUE_USE_INTERNAL_MAP
- case arrayValue:
- if ( value_.array_ )
- {
- ValueInternalArray::IteratorState it;
- value_.array_->makeBeginIterator( it );
- return iterator( it );
- }
- break;
- case objectValue:
- if ( value_.map_ )
- {
- ValueInternalMap::IteratorState it;
- value_.map_->makeBeginIterator( it );
- return iterator( it );
- }
- break;
-#else
- case arrayValue:
- case objectValue:
- if ( value_.map_ )
- return iterator( value_.map_->begin() );
- break;
-#endif
- default:
- break;
- }
- return iterator();
-}
-
-Value::iterator
-Value::end()
-{
- switch ( type_ )
- {
-#ifdef JSON_VALUE_USE_INTERNAL_MAP
- case arrayValue:
- if ( value_.array_ )
- {
- ValueInternalArray::IteratorState it;
- value_.array_->makeEndIterator( it );
- return iterator( it );
- }
- break;
- case objectValue:
- if ( value_.map_ )
- {
- ValueInternalMap::IteratorState it;
- value_.map_->makeEndIterator( it );
- return iterator( it );
- }
- break;
-#else
- case arrayValue:
- case objectValue:
- if ( value_.map_ )
- return iterator( value_.map_->end() );
- break;
-#endif
- default:
- break;
- }
- return iterator();
-}
-
-
-// class PathArgument
-// //////////////////////////////////////////////////////////////////
-
-PathArgument::PathArgument()
- : key_()
- , index_()
- , kind_( kindNone )
-{
-}
-
-
-PathArgument::PathArgument( ArrayIndex index )
- : key_()
- , index_( index )
- , kind_( kindIndex )
-{
-}
-
-
-PathArgument::PathArgument( const char *key )
- : key_( key )
- , index_()
- , kind_( kindKey )
-{
-}
-
-
-PathArgument::PathArgument( const std::string &key )
- : key_( key.c_str() )
- , index_()
- , kind_( kindKey )
-{
-}
-
-// class Path
-// //////////////////////////////////////////////////////////////////
-
-Path::Path( const std::string &path,
- const PathArgument &a1,
- const PathArgument &a2,
- const PathArgument &a3,
- const PathArgument &a4,
- const PathArgument &a5 )
-{
- InArgs in;
- in.push_back( &a1 );
- in.push_back( &a2 );
- in.push_back( &a3 );
- in.push_back( &a4 );
- in.push_back( &a5 );
- makePath( path, in );
-}
-
-
-void
-Path::makePath( const std::string &path,
- const InArgs &in )
-{
- const char *current = path.c_str();
- const char *end = current + path.length();
- InArgs::const_iterator itInArg = in.begin();
- while ( current != end )
- {
- if ( *current == '[' )
- {
- ++current;
- if ( *current == '%' )
- addPathInArg( path, in, itInArg, PathArgument::kindIndex );
- else
- {
- ArrayIndex index = 0;
- for ( ; current != end && *current >= '0' && *current <= '9'; ++current )
- index = index * 10 + ArrayIndex(*current - '0');
- args_.push_back( index );
- }
- if ( current == end || *current++ != ']' )
- invalidPath( path, int(current - path.c_str()) );
- }
- else if ( *current == '%' )
- {
- addPathInArg( path, in, itInArg, PathArgument::kindKey );
- ++current;
- }
- else if ( *current == '.' )
- {
- ++current;
- }
- else
- {
- const char *beginName = current;
- while ( current != end && !strchr( "[.", *current ) )
- ++current;
- args_.push_back( std::string( beginName, current ) );
- }
- }
-}
-
-
-void
-Path::addPathInArg( const std::string &path,
- const InArgs &in,
- InArgs::const_iterator &itInArg,
- PathArgument::Kind kind )
-{
- if ( itInArg == in.end() )
- {
- // Error: missing argument %d
- }
- else if ( (*itInArg)->kind_ != kind )
- {
- // Error: bad argument type
- }
- else
- {
- args_.push_back( **itInArg );
- }
-}
-
-
-void
-Path::invalidPath( const std::string &path,
- int location )
-{
- // Error: invalid path.
-}
-
-
-const Value &
-Path::resolve( const Value &root ) const
-{
- const Value *node = &root;
- for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )
- {
- const PathArgument &arg = *it;
- if ( arg.kind_ == PathArgument::kindIndex )
- {
- if ( !node->isArray() || !node->isValidIndex( arg.index_ ) )
- {
- // Error: unable to resolve path (array value expected at position...
- }
- node = &((*node)[arg.index_]);
- }
- else if ( arg.kind_ == PathArgument::kindKey )
- {
- if ( !node->isObject() )
- {
- // Error: unable to resolve path (object value expected at position...)
- }
- node = &((*node)[arg.key_]);
- if ( node == &Value::null )
- {
- // Error: unable to resolve path (object has no member named '' at position...)
- }
- }
- }
- return *node;
-}
-
-
-Value
-Path::resolve( const Value &root,
- const Value &defaultValue ) const
-{
- const Value *node = &root;
- for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )
- {
- const PathArgument &arg = *it;
- if ( arg.kind_ == PathArgument::kindIndex )
- {
- if ( !node->isArray() || !node->isValidIndex( arg.index_ ) )
- return defaultValue;
- node = &((*node)[arg.index_]);
- }
- else if ( arg.kind_ == PathArgument::kindKey )
- {
- if ( !node->isObject() )
- return defaultValue;
- node = &((*node)[arg.key_]);
- if ( node == &Value::null )
- return defaultValue;
- }
- }
- return *node;
-}
-
-
-Value &
-Path::make( Value &root ) const
-{
- Value *node = &root;
- for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )
- {
- const PathArgument &arg = *it;
- if ( arg.kind_ == PathArgument::kindIndex )
- {
- if ( !node->isArray() )
- {
- // Error: node is not an array at position ...
- }
- node = &((*node)[arg.index_]);
- }
- else if ( arg.kind_ == PathArgument::kindKey )
- {
- if ( !node->isObject() )
- {
- // Error: node is not an object at position...
- }
- node = &((*node)[arg.key_]);
- }
- }
- return *node;
-}
-
-
-} // namespace Json
-
-// //////////////////////////////////////////////////////////////////////
-// End of content of file: src/lib_json/json_value.cpp
-// //////////////////////////////////////////////////////////////////////
-
-
-
-
-
-
-// //////////////////////////////////////////////////////////////////////
-// Beginning of content of file: src/lib_json/json_writer.cpp
-// //////////////////////////////////////////////////////////////////////
-
-// Copyright 2011 Baptiste Lepilleur
-// Distributed under MIT license, or public domain if desired and
-// recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-
-#if !defined(JSON_IS_AMALGAMATION)
-# include <json/writer.h>
-# include "json_tool.h"
-#endif // if !defined(JSON_IS_AMALGAMATION)
-#include <utility>
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#include <sstream>
-#include <iomanip>
-
-#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
-#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
-#endif
-
-namespace Json {
-
-static bool containsControlCharacter( const char* str )
-{
- while ( *str )
- {
- if ( isControlCharacter( *(str++) ) )
- return true;
- }
- return false;
-}
-
-
-std::string valueToString( LargestInt value )
-{
- UIntToStringBuffer buffer;
- char *current = buffer + sizeof(buffer);
- bool isNegative = value < 0;
- if ( isNegative )
- value = -value;
- uintToString( LargestUInt(value), current );
- if ( isNegative )
- *--current = '-';
- assert( current >= buffer );
- return current;
-}
-
-
-std::string valueToString( LargestUInt value )
-{
- UIntToStringBuffer buffer;
- char *current = buffer + sizeof(buffer);
- uintToString( value, current );
- assert( current >= buffer );
- return current;
-}
-
-#if defined(JSON_HAS_INT64)
-
-std::string valueToString( Int value )
-{
- return valueToString( LargestInt(value) );
-}
-
-
-std::string valueToString( UInt value )
-{
- return valueToString( LargestUInt(value) );
-}
-
-#endif // # if defined(JSON_HAS_INT64)
-
-
-std::string valueToString( double value )
-{
- char buffer[32];
-#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning.
- sprintf_s(buffer, sizeof(buffer), "%#.16g", value);
-#else
- sprintf(buffer, "%#.16g", value);
-#endif
- char* ch = buffer + strlen(buffer) - 1;
- if (*ch != '0') return buffer; // nothing to truncate, so save time
- while(ch > buffer && *ch == '0'){
- --ch;
- }
- char* last_nonzero = ch;
- while(ch >= buffer){
- switch(*ch){
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- --ch;
- continue;
- case '.':
- // Truncate zeroes to save bytes in output, but keep one.
- *(last_nonzero+2) = '\0';
- return buffer;
- default:
- return buffer;
- }
- }
- return buffer;
-}
-
-
-std::string valueToString( bool value )
-{
- return value ? "true" : "false";
-}
-
-std::string valueToQuotedString( const char *value )
-{
- if (value == NULL)
- return "";
- // Not sure how to handle unicode...
- if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value ))
- return std::string("\"") + value + "\"";
- // We have to walk value and escape any special characters.
- // Appending to std::string is not efficient, but this should be rare.
- // (Note: forward slashes are *not* rare, but I am not escaping them.)
- std::string::size_type maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL
- std::string result;
- result.reserve(maxsize); // to avoid lots of mallocs
- result += "\"";
- for (const char* c=value; *c != 0; ++c)
- {
- switch(*c)
- {
- case '\"':
- result += "\\\"";
- break;
- case '\\':
- result += "\\\\";
- break;
- case '\b':
- result += "\\b";
- break;
- case '\f':
- result += "\\f";
- break;
- case '\n':
- result += "\\n";
- break;
- case '\r':
- result += "\\r";
- break;
- case '\t':
- result += "\\t";
- break;
- //case '/':
- // Even though \/ is considered a legal escape in JSON, a bare
- // slash is also legal, so I see no reason to escape it.
- // (I hope I am not misunderstanding something.
- // blep notes: actually escaping \/ may be useful in javascript to avoid </
- // sequence.
- // Should add a flag to allow this compatibility mode and prevent this
- // sequence from occurring.
- default:
- if ( isControlCharacter( *c ) )
- {
- std::ostringstream oss;
- oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);
- result += oss.str();
- }
- else
- {
- result += *c;
- }
- break;
- }
- }
- result += "\"";
- return result;
-}
-
-// Class Writer
-// //////////////////////////////////////////////////////////////////
-Writer::~Writer()
-{
-}
-
-
-// Class FastWriter
-// //////////////////////////////////////////////////////////////////
-
-FastWriter::FastWriter()
- : yamlCompatiblityEnabled_( false ),
- dropNullPlaceholders_( false )
-{
-}
-
-
-void
-FastWriter::enableYAMLCompatibility()
-{
- yamlCompatiblityEnabled_ = true;
-}
-
-
-void
-FastWriter::dropNullPlaceholders()
-{
- dropNullPlaceholders_ = true;
-}
-
-
-std::string
-FastWriter::write( const Value &root )
-{
- document_ = "";
- writeValue( root );
- document_ += "\n";
- return document_;
-}
-
-
-void
-FastWriter::writeValue( const Value &value )
-{
- switch ( value.type() )
- {
- case nullValue:
- if (!dropNullPlaceholders_) document_ += "null";
- break;
- case intValue:
- document_ += valueToString( value.asLargestInt() );
- break;
- case uintValue:
- document_ += valueToString( value.asLargestUInt() );
- break;
- case realValue:
- document_ += valueToString( value.asDouble() );
- break;
- case stringValue:
- document_ += valueToQuotedString( value.asCString() );
- break;
- case booleanValue:
- document_ += valueToString( value.asBool() );
- break;
- case arrayValue:
- {
- document_ += "[";
- int size = value.size();
- for ( int index =0; index < size; ++index )
- {
- if ( index > 0 )
- document_ += ",";
- writeValue( value[index] );
- }
- document_ += "]";
- }
- break;
- case objectValue:
- {
- Value::Members members( value.getMemberNames() );
- document_ += "{";
- for ( Value::Members::iterator it = members.begin();
- it != members.end();
- ++it )
- {
- const std::string &name = *it;
- if ( it != members.begin() )
- document_ += ",";
- document_ += valueToQuotedString( name.c_str() );
- document_ += yamlCompatiblityEnabled_ ? ": "
- : ":";
- writeValue( value[name] );
- }
- document_ += "}";
- }
- break;
- }
-}
-
-
-// Class StyledWriter
-// //////////////////////////////////////////////////////////////////
-
-StyledWriter::StyledWriter()
- : rightMargin_( 74 )
- , indentSize_( 3 )
- , addChildValues_()
-{
-}
-
-
-std::string
-StyledWriter::write( const Value &root )
-{
- document_ = "";
- addChildValues_ = false;
- indentString_ = "";
- writeCommentBeforeValue( root );
- writeValue( root );
- writeCommentAfterValueOnSameLine( root );
- document_ += "\n";
- return document_;
-}
-
-
-void
-StyledWriter::writeValue( const Value &value )
-{
- switch ( value.type() )
- {
- case nullValue:
- pushValue( "null" );
- break;
- case intValue:
- pushValue( valueToString( value.asLargestInt() ) );
- break;
- case uintValue:
- pushValue( valueToString( value.asLargestUInt() ) );
- break;
- case realValue:
- pushValue( valueToString( value.asDouble() ) );
- break;
- case stringValue:
- pushValue( valueToQuotedString( value.asCString() ) );
- break;
- case booleanValue:
- pushValue( valueToString( value.asBool() ) );
- break;
- case arrayValue:
- writeArrayValue( value);
- break;
- case objectValue:
- {
- Value::Members members( value.getMemberNames() );
- if ( members.empty() )
- pushValue( "{}" );
- else
- {
- writeWithIndent( "{" );
- indent();
- Value::Members::iterator it = members.begin();
- for (;;)
- {
- const std::string &name = *it;
- const Value &childValue = value[name];
- writeCommentBeforeValue( childValue );
- writeWithIndent( valueToQuotedString( name.c_str() ) );
- document_ += " : ";
- writeValue( childValue );
- if ( ++it == members.end() )
- {
- writeCommentAfterValueOnSameLine( childValue );
- break;
- }
- document_ += ",";
- writeCommentAfterValueOnSameLine( childValue );
- }
- unindent();
- writeWithIndent( "}" );
- }
- }
- break;
- }
-}
-
-
-void
-StyledWriter::writeArrayValue( const Value &value )
-{
- unsigned size = value.size();
- if ( size == 0 )
- pushValue( "[]" );
- else
- {
- bool isArrayMultiLine = isMultineArray( value );
- if ( isArrayMultiLine )
- {
- writeWithIndent( "[" );
- indent();
- bool hasChildValue = !childValues_.empty();
- unsigned index =0;
- for (;;)
- {
- const Value &childValue = value[index];
- writeCommentBeforeValue( childValue );
- if ( hasChildValue )
- writeWithIndent( childValues_[index] );
- else
- {
- writeIndent();
- writeValue( childValue );
- }
- if ( ++index == size )
- {
- writeCommentAfterValueOnSameLine( childValue );
- break;
- }
- document_ += ",";
- writeCommentAfterValueOnSameLine( childValue );
- }
- unindent();
- writeWithIndent( "]" );
- }
- else // output on a single line
- {
- assert( childValues_.size() == size );
- document_ += "[ ";
- for ( unsigned index =0; index < size; ++index )
- {
- if ( index > 0 )
- document_ += ", ";
- document_ += childValues_[index];
- }
- document_ += " ]";
- }
- }
-}
-
-
-bool
-StyledWriter::isMultineArray( const Value &value )
-{
- int size = value.size();
- bool isMultiLine = size*3 >= rightMargin_ ;
- childValues_.clear();
- for ( int index =0; index < size && !isMultiLine; ++index )
- {
- const Value &childValue = value[index];
- isMultiLine = isMultiLine ||
- ( (childValue.isArray() || childValue.isObject()) &&
- childValue.size() > 0 );
- }
- if ( !isMultiLine ) // check if line length > max line length
- {
- childValues_.reserve( size );
- addChildValues_ = true;
- int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
- for ( int index =0; index < size && !isMultiLine; ++index )
- {
- writeValue( value[index] );
- lineLength += int( childValues_[index].length() );
- isMultiLine = isMultiLine && hasCommentForValue( value[index] );
- }
- addChildValues_ = false;
- isMultiLine = isMultiLine || lineLength >= rightMargin_;
- }
- return isMultiLine;
-}
-
-
-void
-StyledWriter::pushValue( const std::string &value )
-{
- if ( addChildValues_ )
- childValues_.push_back( value );
- else
- document_ += value;
-}
-
-
-void
-StyledWriter::writeIndent()
-{
- if ( !document_.empty() )
- {
- char last = document_[document_.length()-1];
- if ( last == ' ' ) // already indented
- return;
- if ( last != '\n' ) // Comments may add new-line
- document_ += '\n';
- }
- document_ += indentString_;
-}
-
-
-void
-StyledWriter::writeWithIndent( const std::string &value )
-{
- writeIndent();
- document_ += value;
-}
-
-
-void
-StyledWriter::indent()
-{
- indentString_ += std::string( indentSize_, ' ' );
-}
-
-
-void
-StyledWriter::unindent()
-{
- assert( int(indentString_.size()) >= indentSize_ );
- indentString_.resize( indentString_.size() - indentSize_ );
-}
-
-
-void
-StyledWriter::writeCommentBeforeValue( const Value &root )
-{
- if ( !root.hasComment( commentBefore ) )
- return;
- document_ += normalizeEOL( root.getComment( commentBefore ) );
- document_ += "\n";
-}
-
-
-void
-StyledWriter::writeCommentAfterValueOnSameLine( const Value &root )
-{
- if ( root.hasComment( commentAfterOnSameLine ) )
- document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
-
- if ( root.hasComment( commentAfter ) )
- {
- document_ += "\n";
- document_ += normalizeEOL( root.getComment( commentAfter ) );
- document_ += "\n";
- }
-}
-
-
-bool
-StyledWriter::hasCommentForValue( const Value &value )
-{
- return value.hasComment( commentBefore )
- || value.hasComment( commentAfterOnSameLine )
- || value.hasComment( commentAfter );
-}
-
-
-std::string
-StyledWriter::normalizeEOL( const std::string &text )
-{
- std::string normalized;
- normalized.reserve( text.length() );
- const char *begin = text.c_str();
- const char *end = begin + text.length();
- const char *current = begin;
- while ( current != end )
- {
- char c = *current++;
- if ( c == '\r' ) // mac or dos EOL
- {
- if ( *current == '\n' ) // convert dos EOL
- ++current;
- normalized += '\n';
- }
- else // handle unix EOL & other char
- normalized += c;
- }
- return normalized;
-}
-
-
-// Class StyledStreamWriter
-// //////////////////////////////////////////////////////////////////
-
-StyledStreamWriter::StyledStreamWriter( std::string indentation )
- : document_(NULL)
- , rightMargin_( 74 )
- , indentation_( indentation )
- , addChildValues_()
-{
-}
-
-
-void
-StyledStreamWriter::write( std::ostream &out, const Value &root )
-{
- document_ = &out;
- addChildValues_ = false;
- indentString_ = "";
- writeCommentBeforeValue( root );
- writeValue( root );
- writeCommentAfterValueOnSameLine( root );
- *document_ << "\n";
- document_ = NULL; // Forget the stream, for safety.
-}
-
-
-void
-StyledStreamWriter::writeValue( const Value &value )
-{
- switch ( value.type() )
- {
- case nullValue:
- pushValue( "null" );
- break;
- case intValue:
- pushValue( valueToString( value.asLargestInt() ) );
- break;
- case uintValue:
- pushValue( valueToString( value.asLargestUInt() ) );
- break;
- case realValue:
- pushValue( valueToString( value.asDouble() ) );
- break;
- case stringValue:
- pushValue( valueToQuotedString( value.asCString() ) );
- break;
- case booleanValue:
- pushValue( valueToString( value.asBool() ) );
- break;
- case arrayValue:
- writeArrayValue( value);
- break;
- case objectValue:
- {
- Value::Members members( value.getMemberNames() );
- if ( members.empty() )
- pushValue( "{}" );
- else
- {
- writeWithIndent( "{" );
- indent();
- Value::Members::iterator it = members.begin();
- for (;;)
- {
- const std::string &name = *it;
- const Value &childValue = value[name];
- writeCommentBeforeValue( childValue );
- writeWithIndent( valueToQuotedString( name.c_str() ) );
- *document_ << " : ";
- writeValue( childValue );
- if ( ++it == members.end() )
- {
- writeCommentAfterValueOnSameLine( childValue );
- break;
- }
- *document_ << ",";
- writeCommentAfterValueOnSameLine( childValue );
- }
- unindent();
- writeWithIndent( "}" );
- }
- }
- break;
- }
-}
-
-
-void
-StyledStreamWriter::writeArrayValue( const Value &value )
-{
- unsigned size = value.size();
- if ( size == 0 )
- pushValue( "[]" );
- else
- {
- bool isArrayMultiLine = isMultineArray( value );
- if ( isArrayMultiLine )
- {
- writeWithIndent( "[" );
- indent();
- bool hasChildValue = !childValues_.empty();
- unsigned index =0;
- for (;;)
- {
- const Value &childValue = value[index];
- writeCommentBeforeValue( childValue );
- if ( hasChildValue )
- writeWithIndent( childValues_[index] );
- else
- {
- writeIndent();
- writeValue( childValue );
- }
- if ( ++index == size )
- {
- writeCommentAfterValueOnSameLine( childValue );
- break;
- }
- *document_ << ",";
- writeCommentAfterValueOnSameLine( childValue );
- }
- unindent();
- writeWithIndent( "]" );
- }
- else // output on a single line
- {
- assert( childValues_.size() == size );
- *document_ << "[ ";
- for ( unsigned index =0; index < size; ++index )
- {
- if ( index > 0 )
- *document_ << ", ";
- *document_ << childValues_[index];
- }
- *document_ << " ]";
- }
- }
-}
-
-
-bool
-StyledStreamWriter::isMultineArray( const Value &value )
-{
- int size = value.size();
- bool isMultiLine = size*3 >= rightMargin_ ;
- childValues_.clear();
- for ( int index =0; index < size && !isMultiLine; ++index )
- {
- const Value &childValue = value[index];
- isMultiLine = isMultiLine ||
- ( (childValue.isArray() || childValue.isObject()) &&
- childValue.size() > 0 );
- }
- if ( !isMultiLine ) // check if line length > max line length
- {
- childValues_.reserve( size );
- addChildValues_ = true;
- int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
- for ( int index =0; index < size && !isMultiLine; ++index )
- {
- writeValue( value[index] );
- lineLength += int( childValues_[index].length() );
- isMultiLine = isMultiLine && hasCommentForValue( value[index] );
- }
- addChildValues_ = false;
- isMultiLine = isMultiLine || lineLength >= rightMargin_;
- }
- return isMultiLine;
-}
-
-
-void
-StyledStreamWriter::pushValue( const std::string &value )
-{
- if ( addChildValues_ )
- childValues_.push_back( value );
- else
- *document_ << value;
-}
-
-
-void
-StyledStreamWriter::writeIndent()
-{
- /*
- Some comments in this method would have been nice. ;-)
-
- if ( !document_.empty() )
- {
- char last = document_[document_.length()-1];
- if ( last == ' ' ) // already indented
- return;
- if ( last != '\n' ) // Comments may add new-line
- *document_ << '\n';
- }
- */
- *document_ << '\n' << indentString_;
-}
-
-
-void
-StyledStreamWriter::writeWithIndent( const std::string &value )
-{
- writeIndent();
- *document_ << value;
-}
-
-
-void
-StyledStreamWriter::indent()
-{
- indentString_ += indentation_;
-}
-
-
-void
-StyledStreamWriter::unindent()
-{
- assert( indentString_.size() >= indentation_.size() );
- indentString_.resize( indentString_.size() - indentation_.size() );
-}
-
-
-void
-StyledStreamWriter::writeCommentBeforeValue( const Value &root )
-{
- if ( !root.hasComment( commentBefore ) )
- return;
- *document_ << normalizeEOL( root.getComment( commentBefore ) );
- *document_ << "\n";
-}
-
-
-void
-StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )
-{
- if ( root.hasComment( commentAfterOnSameLine ) )
- *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
-
- if ( root.hasComment( commentAfter ) )
- {
- *document_ << "\n";
- *document_ << normalizeEOL( root.getComment( commentAfter ) );
- *document_ << "\n";
- }
-}
-
-
-bool
-StyledStreamWriter::hasCommentForValue( const Value &value )
-{
- return value.hasComment( commentBefore )
- || value.hasComment( commentAfterOnSameLine )
- || value.hasComment( commentAfter );
-}
-
-
-std::string
-StyledStreamWriter::normalizeEOL( const std::string &text )
-{
- std::string normalized;
- normalized.reserve( text.length() );
- const char *begin = text.c_str();
- const char *end = begin + text.length();
- const char *current = begin;
- while ( current != end )
- {
- char c = *current++;
- if ( c == '\r' ) // mac or dos EOL
- {
- if ( *current == '\n' ) // convert dos EOL
- ++current;
- normalized += '\n';
- }
- else // handle unix EOL & other char
- normalized += c;
- }
- return normalized;
-}
-
-
-std::ostream& operator<<( std::ostream &sout, const Value &root )
-{
- Json::StyledStreamWriter writer;
- writer.write(sout, root);
- return sout;
-}
-
-
-} // namespace Json
-
-// //////////////////////////////////////////////////////////////////////
-// End of content of file: src/lib_json/json_writer.cpp
-// //////////////////////////////////////////////////////////////////////
-
-
-
-
-
diff --git a/src/keycode.cpp b/src/keycode.cpp
index 2e211ad59..66708fb19 100644
--- a/src/keycode.cpp
+++ b/src/keycode.cpp
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "debug.h"
#include "util/hex.h"
#include "util/string.h"
+#include "util/basic_macros.h"
class UnknownKeycode : public BaseException
{
@@ -242,11 +243,10 @@ static const struct table_key table[] = {
#undef N_
-#define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
struct table_key lookup_keyname(const char *name)
{
- for (u16 i = 0; i < ARRAYSIZE(table); i++) {
+ for (u16 i = 0; i < ARRLEN(table); i++) {
if (strcmp(table[i].Name, name) == 0)
return table[i];
}
@@ -256,7 +256,7 @@ struct table_key lookup_keyname(const char *name)
struct table_key lookup_keykey(irr::EKEY_CODE key)
{
- for (u16 i = 0; i < ARRAYSIZE(table); i++) {
+ for (u16 i = 0; i < ARRLEN(table); i++) {
if (table[i].Key == key)
return table[i];
}
@@ -268,7 +268,7 @@ struct table_key lookup_keykey(irr::EKEY_CODE key)
struct table_key lookup_keychar(wchar_t Char)
{
- for (u16 i = 0; i < ARRAYSIZE(table); i++) {
+ for (u16 i = 0; i < ARRLEN(table); i++) {
if (table[i].Char == Char)
return table[i];
}
diff --git a/src/keycode.h b/src/keycode.h
index 4d66cf7b5..4cd0b707e 100644
--- a/src/keycode.h
+++ b/src/keycode.h
@@ -34,16 +34,16 @@ public:
KeyPress();
KeyPress(const char *name);
- KeyPress(const irr::SEvent::SKeyInput &in, bool prefer_character=false);
+ KeyPress(const irr::SEvent::SKeyInput &in, bool prefer_character = false);
bool operator==(const KeyPress &o) const
{
- return (Char > 0 && Char == o.Char) ||
- (valid_kcode(Key) && Key == o.Key);
+ return (Char > 0 && Char == o.Char) || (valid_kcode(Key) && Key == o.Key);
}
const char *sym() const;
const char *name() const;
+
protected:
static bool valid_kcode(irr::EKEY_CODE k)
{
@@ -68,4 +68,3 @@ void clearKeyCache();
irr::EKEY_CODE keyname_to_keycode(const char *name);
#endif
-
diff --git a/src/light.cpp b/src/light.cpp
index 5dc01fcf0..4a3ca5a60 100644
--- a/src/light.cpp
+++ b/src/light.cpp
@@ -26,29 +26,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// Length of LIGHT_MAX+1 means LIGHT_MAX is the last value.
// LIGHT_SUN is read as LIGHT_MAX from here.
-u8 light_LUT[LIGHT_MAX+1] =
-{
- /* Middle-raised variation of a_n+1 = a_n * 0.786
- * Length of LIGHT_MAX+1 means LIGHT_MAX is the last value.
- * LIGHT_SUN is read as LIGHT_MAX from here.
- */
- 8,
- 11+2,
- 14+7,
- 18+10,
- 22+15,
- 29+20,
- 37+20,
- 47+15,
- 60+10,
- 76+7,
- 97+5,
- 123+2,
- 157,
- 200,
- 255,
-};
+u8 light_LUT[LIGHT_MAX+1];
+// the const ref to light_LUT is what is actually used in the code.
const u8 *light_decode_table = light_LUT;
/** Initialize or update the light value tables using the specified \p gamma.
@@ -65,26 +45,26 @@ void set_light_table(float gamma)
{
static const float brightness_step = 255.0f / (LIGHT_MAX + 1);
- /* These are adjustment values that are added to the calculated light value
- * after gamma is applied. Currently they are used so that given a gamma
- * of 1.8 the light values set by this function are the same as those
- * hardcoded in the initalizer list for the declaration of light_LUT.
- */
+ // this table is pure arbitrary values, made so that
+ // at gamma 2.2 the game looks not too dark at light=1,
+ // and mostly linear for the rest of the scale.
+ // we could try to inverse the gamma power function, but this
+ // is simpler and quicker.
static const int adjustments[LIGHT_MAX + 1] = {
- 7,
- 7,
- 7,
- 5,
- 2,
- 0,
- -7,
- -20,
- -31,
- -39,
- -43,
- -45,
- -40,
- -25,
+ -67,
+ -91,
+ -125,
+ -115,
+ -104,
+ -85,
+ -70,
+ -63,
+ -56,
+ -49,
+ -42,
+ -35,
+ -28,
+ -22,
0
};
@@ -93,296 +73,13 @@ void set_light_table(float gamma)
float brightness = brightness_step;
for (size_t i = 0; i < LIGHT_MAX; i++) {
- light_LUT[i] = (u8)(255 * powf(brightness / 255.0f, gamma));
+ light_LUT[i] = (u8)(255 * powf(brightness / 255.0f, 1.0 / gamma));
light_LUT[i] = rangelim(light_LUT[i] + adjustments[i], 0, 255);
- if (i > 1 && light_LUT[i] < light_LUT[i-1])
- light_LUT[i] = light_LUT[i-1] + 1;
+ if (i > 1 && light_LUT[i] < light_LUT[i - 1])
+ light_LUT[i] = light_LUT[i - 1] + 1;
brightness += brightness_step;
}
light_LUT[LIGHT_MAX] = 255;
}
#endif
-
-
-#if 0
-/*
-Made using this and:
-- adding 220 as the second last one
-- replacing the third last one (212) with 195
-
-#!/usr/bin/python
-
-from math import *
-from sys import stdout
-
-# We want 0 at light=0 and 255 at light=LIGHT_MAX
-LIGHT_MAX = 14
-#FACTOR = 0.69
-#FACTOR = 0.75
-FACTOR = 0.83
-START_FROM_ZERO = False
-
-L = []
-if START_FROM_ZERO:
- for i in range(1,LIGHT_MAX+1):
- L.append(int(round(255.0 * FACTOR ** (i-1))))
- L.append(0)
-else:
- for i in range(1,LIGHT_MAX+1):
- L.append(int(round(255.0 * FACTOR ** (i-1))))
- L.append(255)
-
-L.reverse()
-for i in L:
- stdout.write(str(i)+",\n")
-*/
-u8 light_decode_table[LIGHT_MAX+1] =
-{
-23,
-27,
-33,
-40,
-48,
-57,
-69,
-83,
-100,
-121,
-146,
-176,
-195,
-220,
-255,
-};
-#endif
-
-#if 0
-// This is good
-// a_n+1 = a_n * 0.786
-// Length of LIGHT_MAX+1 means LIGHT_MAX is the last value.
-// LIGHT_SUN is read as LIGHT_MAX from here.
-u8 light_decode_table[LIGHT_MAX+1] =
-{
-8,
-11,
-14,
-18,
-22,
-29,
-37,
-47,
-60,
-76,
-97,
-123,
-157,
-200,
-255,
-};
-#endif
-
-#if 0
-// Use for debugging in dark
-u8 light_decode_table[LIGHT_MAX+1] =
-{
-58,
-64,
-72,
-80,
-88,
-98,
-109,
-121,
-135,
-150,
-167,
-185,
-206,
-229,
-255,
-};
-#endif
-
-// This is reasonable with classic lighting with a light source
-/*u8 light_decode_table[LIGHT_MAX+1] =
-{
-2,
-3,
-4,
-6,
-9,
-13,
-18,
-25,
-32,
-35,
-45,
-57,
-69,
-79,
-255
-};*/
-
-
-// As in minecraft, a_n+1 = a_n * 0.8
-// NOTE: This doesn't really work that well because this defines
-// LIGHT_MAX as dimmer than LIGHT_SUN
-// NOTE: Uh, this has had 34 left out; forget this.
-/*u8 light_decode_table[LIGHT_MAX+1] =
-{
-8,
-11,
-14,
-17,
-21,
-27,
-42,
-53,
-66,
-83,
-104,
-130,
-163,
-204,
-255,
-};*/
-
-// This was a quick try of more light, manually quickly made
-/*u8 light_decode_table[LIGHT_MAX+1] =
-{
-0,
-7,
-11,
-15,
-21,
-29,
-42,
-53,
-69,
-85,
-109,
-135,
-167,
-205,
-255,
-};*/
-
-// This was used for a long time, manually made
-/*u8 light_decode_table[LIGHT_MAX+1] =
-{
-0,
-6,
-8,
-11,
-14,
-19,
-26,
-34,
-45,
-61,
-81,
-108,
-143,
-191,
-255,
-};*/
-
-/*u8 light_decode_table[LIGHT_MAX+1] =
-{
-0,
-3,
-6,
-10,
-18,
-25,
-35,
-50,
-75,
-95,
-120,
-150,
-185,
-215,
-255,
-};*/
-/*u8 light_decode_table[LIGHT_MAX+1] =
-{
-0,
-5,
-12,
-22,
-35,
-50,
-65,
-85,
-100,
-120,
-140,
-160,
-185,
-215,
-255,
-};*/
-// LIGHT_MAX is 14, 0-14 is 15 values
-/*u8 light_decode_table[LIGHT_MAX+1] =
-{
-0,
-9,
-12,
-14,
-16,
-20,
-26,
-34,
-45,
-61,
-81,
-108,
-143,
-191,
-255,
-};*/
-
-#if 0
-/*
-#!/usr/bin/python
-
-from math import *
-from sys import stdout
-
-# We want 0 at light=0 and 255 at light=LIGHT_MAX
-LIGHT_MAX = 14
-#FACTOR = 0.69
-FACTOR = 0.75
-
-L = []
-for i in range(1,LIGHT_MAX+1):
- L.append(int(round(255.0 * FACTOR ** (i-1))))
-L.append(0)
-
-L.reverse()
-for i in L:
- stdout.write(str(i)+",\n")
-*/
-u8 light_decode_table[LIGHT_MAX+1] =
-{
-0,
-6,
-8,
-11,
-14,
-19,
-26,
-34,
-45,
-61,
-81,
-108,
-143,
-191,
-255,
-};
-#endif
-
-
diff --git a/src/light.h b/src/light.h
index 984e6d7c2..30a647581 100644
--- a/src/light.h
+++ b/src/light.h
@@ -38,30 +38,30 @@ with this program; if not, write to the Free Software Foundation, Inc.,
inline u8 diminish_light(u8 light)
{
- if(light == 0)
+ if (light == 0)
return 0;
- if(light >= LIGHT_MAX)
+ if (light >= LIGHT_MAX)
return LIGHT_MAX - 1;
-
+
return light - 1;
}
inline u8 diminish_light(u8 light, u8 distance)
{
- if(distance >= light)
+ if (distance >= light)
return 0;
- return light - distance;
+ return light - distance;
}
inline u8 undiminish_light(u8 light)
{
// We don't know if light should undiminish from this particular 0.
// Thus, keep it at 0.
- if(light == 0)
+ if (light == 0)
return 0;
- if(light == LIGHT_MAX)
+ if (light == LIGHT_MAX)
return light;
-
+
return light + 1;
}
@@ -85,9 +85,9 @@ extern const u8 *light_decode_table;
// 0 <= return value <= 255
inline u8 decode_light(u8 light)
{
- if(light > LIGHT_MAX)
+ if (light > LIGHT_MAX)
light = LIGHT_MAX;
-
+
return light_decode_table[light];
}
@@ -97,12 +97,12 @@ inline float decode_light_f(float light_f)
{
s32 i = (u32)(light_f * LIGHT_MAX + 0.5);
- if(i <= 0)
+ if (i <= 0)
return (float)light_decode_table[0] / 255.0;
- if(i >= LIGHT_MAX)
+ if (i >= LIGHT_MAX)
return (float)light_decode_table[LIGHT_MAX] / 255.0;
- float v1 = (float)light_decode_table[i-1] / 255.0;
+ float v1 = (float)light_decode_table[i - 1] / 255.0;
float v2 = (float)light_decode_table[i] / 255.0;
float f0 = (float)i - 0.5;
float f = light_f * LIGHT_MAX - f0;
@@ -119,11 +119,10 @@ void set_light_table(float gamma);
inline u8 blend_light(u32 daylight_factor, u8 lightday, u8 lightnight)
{
u32 c = 1000;
- u32 l = ((daylight_factor * lightday + (c-daylight_factor) * lightnight))/c;
- if(l > LIGHT_SUN)
+ u32 l = ((daylight_factor * lightday + (c - daylight_factor) * lightnight)) / c;
+ if (l > LIGHT_SUN)
l = LIGHT_SUN;
return l;
}
#endif
-
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 4d0ca0600..b587f7bbb 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -21,22 +21,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "event.h"
#include "collision.h"
-#include "gamedef.h"
#include "nodedef.h"
#include "settings.h"
#include "environment.h"
#include "map.h"
#include "client.h"
+#include "content_cao.h"
/*
LocalPlayer
*/
-LocalPlayer::LocalPlayer(Client *gamedef, const char *name):
- Player(name, gamedef->idef()),
+LocalPlayer::LocalPlayer(Client *client, const char *name):
+ Player(name, client->idef()),
parent(0),
hp(PLAYER_MAX_HP),
- got_teleported(false),
isAttached(false),
touching_ground(false),
in_liquid(false),
@@ -49,7 +48,8 @@ LocalPlayer::LocalPlayer(Client *gamedef, const char *name):
physics_override_jump(1.0f),
physics_override_gravity(1.0f),
physics_override_sneak(true),
- physics_override_sneak_glitch(true),
+ physics_override_sneak_glitch(false),
+ physics_override_new_move(true), // Temporary option for old move code
overridePosition(v3f(0,0,0)),
last_position(v3f(0,0,0)),
last_speed(v3f(0,0,0)),
@@ -59,6 +59,7 @@ LocalPlayer::LocalPlayer(Client *gamedef, const char *name):
last_camera_fov(0),
last_wanted_range(0),
camera_impact(0.f),
+ makes_footstep_sound(true),
last_animation(NO_ANIM),
hotbar_image(""),
hotbar_selected_image(""),
@@ -67,9 +68,12 @@ LocalPlayer::LocalPlayer(Client *gamedef, const char *name):
hurt_tilt_strength(0.0f),
m_position(0,0,0),
m_sneak_node(32767,32767,32767),
+ m_sneak_node_bb_ymax(0), // To support temporary option for old move code
+ m_sneak_node_bb_top(0,0,0,0,0,0),
m_sneak_node_exists(false),
m_need_to_get_new_sneak_node(true),
- m_sneak_node_bb_ymax(0),
+ m_sneak_ladder_detected(false),
+ m_ledge_detected(false),
m_old_node_below(32767,32767,32767),
m_old_node_below_type("air"),
m_can_jump(false),
@@ -79,7 +83,7 @@ LocalPlayer::LocalPlayer(Client *gamedef, const char *name):
camera_barely_in_ceiling(false),
m_collisionbox(-BS * 0.30, 0.0, -BS * 0.30, BS * 0.30, BS * 1.75, BS * 0.30),
m_cao(NULL),
- m_gamedef(gamedef)
+ m_client(client)
{
// Initialize hp to 0, so that no hearts will be shown if server
// doesn't support health points
@@ -92,11 +96,99 @@ LocalPlayer::~LocalPlayer()
{
}
+static aabb3f getTopBoundingBox(const std::vector<aabb3f> &nodeboxes)
+{
+ aabb3f b_max;
+ b_max.reset(-BS, -BS, -BS);
+ for (std::vector<aabb3f>::const_iterator it = nodeboxes.begin();
+ it != nodeboxes.end(); ++it) {
+ aabb3f box = *it;
+ if (box.MaxEdge.Y > b_max.MaxEdge.Y)
+ b_max = box;
+ else if (box.MaxEdge.Y == b_max.MaxEdge.Y)
+ b_max.addInternalBox(box);
+ }
+ return aabb3f(v3f(b_max.MinEdge.X, b_max.MaxEdge.Y, b_max.MinEdge.Z), b_max.MaxEdge);
+}
+
+#define GETNODE(map, p3, v2, y, valid) \
+ (map)->getNodeNoEx((p3) + v3s16((v2).X, y, (v2).Y), valid)
+
+// pos is the node the player is standing inside(!)
+static bool detectSneakLadder(Map *map, INodeDefManager *nodemgr, v3s16 pos)
+{
+ // Detects a structure known as "sneak ladder" or "sneak elevator"
+ // that relies on bugs to provide a fast means of vertical transportation,
+ // the bugs have since been fixed but this function remains to keep it working.
+ // NOTE: This is just entirely a huge hack and causes way too many problems.
+ bool is_valid_position;
+ MapNode node;
+ // X/Z vectors for 4 neighboring nodes
+ static const v2s16 vecs[] = { v2s16(-1, 0), v2s16(1, 0), v2s16(0, -1), v2s16(0, 1) };
+
+ for (u16 i = 0; i < ARRLEN(vecs); i++) {
+ const v2s16 vec = vecs[i];
+
+ // walkability of bottom & top node should differ
+ node = GETNODE(map, pos, vec, 0, &is_valid_position);
+ if (!is_valid_position)
+ continue;
+ bool w = nodemgr->get(node).walkable;
+ node = GETNODE(map, pos, vec, 1, &is_valid_position);
+ if (!is_valid_position || w == nodemgr->get(node).walkable)
+ continue;
+
+ // check one more node above OR below with corresponding walkability
+ node = GETNODE(map, pos, vec, -1, &is_valid_position);
+ bool ok = is_valid_position && w != nodemgr->get(node).walkable;
+ if (!ok) {
+ node = GETNODE(map, pos, vec, 2, &is_valid_position);
+ ok = is_valid_position && w == nodemgr->get(node).walkable;
+ }
+
+ if (ok)
+ return true;
+ }
+
+ return false;
+}
+
+static bool detectLedge(Map *map, INodeDefManager *nodemgr, v3s16 pos)
+{
+ bool is_valid_position;
+ MapNode node;
+ // X/Z vectors for 4 neighboring nodes
+ static const v2s16 vecs[] = {v2s16(-1, 0), v2s16(1, 0), v2s16(0, -1), v2s16(0, 1)};
+
+ for (u16 i = 0; i < ARRLEN(vecs); i++) {
+ const v2s16 vec = vecs[i];
+
+ node = GETNODE(map, pos, vec, 1, &is_valid_position);
+ if (is_valid_position && nodemgr->get(node).walkable) {
+ // Ledge exists
+ node = GETNODE(map, pos, vec, 2, &is_valid_position);
+ if (is_valid_position && !nodemgr->get(node).walkable)
+ // Space above ledge exists
+ return true;
+ }
+ }
+
+ return false;
+}
+
+#undef GETNODE
+
void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
std::vector<CollisionInfo> *collision_info)
{
+ // Temporary option for old move code
+ if (!physics_override_new_move) {
+ old_move(dtime, env, pos_max_d, collision_info);
+ return;
+ }
+
Map *map = &env->getMap();
- INodeDefManager *nodemgr = m_gamedef->ndef();
+ INodeDefManager *nodemgr = m_client->ndef();
v3f position = getPosition();
@@ -109,8 +201,8 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
}
// Skip collision detection if noclip mode is used
- bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
- bool noclip = m_gamedef->checkLocalPrivilege("noclip") &&
+ bool fly_allowed = m_client->checkLocalPrivilege("fly");
+ bool noclip = m_client->checkLocalPrivilege("noclip") &&
g_settings->getBool("noclip");
bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
if (free_move) {
@@ -199,49 +291,69 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
// This should always apply, otherwise there are glitches
sanity_check(d > pos_max_d);
- // Maximum distance over border for sneaking
- f32 sneak_max = BS*0.4;
+ // Max. distance (X, Z) over border for sneaking determined by collision box
+ // * 0.49 to keep the center just barely on the node
+ v3f sneak_max = m_collisionbox.getExtent() * 0.49;
+ if (m_sneak_ladder_detected) {
+ // restore legacy behaviour (this makes the m_speed.Y hack necessary)
+ sneak_max = v3f(0.4 * BS, 0, 0.4 * BS);
+ }
/*
If sneaking, keep in range from the last walked node and don't
fall off from it
*/
if (control.sneak && m_sneak_node_exists &&
- !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid &&
- physics_override_sneak && !got_teleported) {
- f32 maxd = 0.5 * BS + sneak_max;
- v3f lwn_f = intToFloat(m_sneak_node, BS);
- position.X = rangelim(position.X, lwn_f.X-maxd, lwn_f.X+maxd);
- position.Z = rangelim(position.Z, lwn_f.Z-maxd, lwn_f.Z+maxd);
+ !(fly_allowed && g_settings->getBool("free_move")) &&
+ !in_liquid && !is_climbing &&
+ physics_override_sneak) {
+ const v3f sn_f = intToFloat(m_sneak_node, BS);
+ const v3f bmin = sn_f + m_sneak_node_bb_top.MinEdge;
+ const v3f bmax = sn_f + m_sneak_node_bb_top.MaxEdge;
+ const v3f old_pos = position;
+ const v3f old_speed = m_speed;
+
+ position.X = rangelim(position.X,
+ bmin.X - sneak_max.X, bmax.X + sneak_max.X);
+ position.Z = rangelim(position.Z,
+ bmin.Z - sneak_max.Z, bmax.Z + sneak_max.Z);
+
+ if (position.X != old_pos.X)
+ m_speed.X = 0;
+ if (position.Z != old_pos.Z)
+ m_speed.Z = 0;
+
+ // Because we keep the player collision box on the node, limiting
+ // position.Y is not necessary but useful to prevent players from
+ // being inside a node if sneaking on e.g. the lower part of a stair
+ if (!m_sneak_ladder_detected) {
+ position.Y = MYMAX(position.Y, bmax.Y);
+ } else {
+ // legacy behaviour that sometimes causes some weird slow sinking
+ m_speed.Y = MYMAX(m_speed.Y, 0);
+ }
- if (!is_climbing) {
- // Move up if necessary
- f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
- if (position.Y < new_y)
- position.Y = new_y;
- /*
- Collision seems broken, since player is sinking when
- sneaking over the edges of current sneaking_node.
- TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
- */
- if (m_speed.Y < 0)
- m_speed.Y = 0;
+ if (collision_info != NULL &&
+ m_speed.Y - old_speed.Y > BS) {
+ // Collide with sneak node, report fall damage
+ CollisionInfo sn_info;
+ sn_info.node_p = m_sneak_node;
+ sn_info.old_speed = old_speed;
+ sn_info.new_speed = m_speed;
+ collision_info->push_back(sn_info);
}
}
- if (got_teleported)
- got_teleported = false;
-
- // this shouldn't be hardcoded but transmitted from server
- float player_stepheight = touching_ground ? (BS*0.6) : (BS*0.2);
+ // TODO: this shouldn't be hardcoded but transmitted from server
+ float player_stepheight = (touching_ground) ? (BS * 0.6f) : (BS * 0.2f);
#ifdef __ANDROID__
- player_stepheight += (0.6 * BS);
+ player_stepheight += (0.6f * BS);
#endif
v3f accel_f = v3f(0,0,0);
- collisionMoveResult result = collisionMoveSimple(env, m_gamedef,
+ collisionMoveResult result = collisionMoveSimple(env, m_client,
pos_max_d, m_collisionbox, player_stepheight, dtime,
&position, &m_speed, accel_f);
@@ -254,17 +366,18 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
bool touching_ground_was = touching_ground;
touching_ground = result.touching_ground;
- //bool standing_on_unloaded = result.standing_on_unloaded;
-
+ // We want the top of the sneak node to be below the players feet
+ f32 position_y_mod;
+ if (m_sneak_node_exists)
+ position_y_mod = m_sneak_node_bb_top.MaxEdge.Y - 0.05 * BS;
+ else
+ position_y_mod = (0.5 - 0.05) * BS;
+ v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
/*
Check the nodes under the player to see from which node the
player is sneaking from, if any. If the node from under
the player has been removed, the player falls.
*/
- f32 position_y_mod = 0.05 * BS;
- if (m_sneak_node_bb_ymax > 0)
- position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
- v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
if (m_sneak_node_exists &&
nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
m_old_node_below_type != "air") {
@@ -279,88 +392,83 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
}
if (m_need_to_get_new_sneak_node && physics_override_sneak) {
- m_sneak_node_bb_ymax = 0;
- v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS);
v2f player_p2df(position.X, position.Z);
f32 min_distance_f = 100000.0 * BS;
- // If already seeking from some node, compare to it.
- /*if(m_sneak_node_exists)
- {
- v3f sneaknode_pf = intToFloat(m_sneak_node, BS);
- v2f sneaknode_p2df(sneaknode_pf.X, sneaknode_pf.Z);
- f32 d_horiz_f = player_p2df.getDistanceFrom(sneaknode_p2df);
- f32 d_vert_f = fabs(sneaknode_pf.Y + BS*0.5 - position.Y);
- // Ignore if player is not on the same level (likely dropped)
- if(d_vert_f < 0.15*BS)
- min_distance_f = d_horiz_f;
- }*/
v3s16 new_sneak_node = m_sneak_node;
for(s16 x=-1; x<=1; x++)
for(s16 z=-1; z<=1; z++)
{
- v3s16 p = pos_i_bottom + v3s16(x,0,z);
+ v3s16 p = current_node + v3s16(x,0,z);
v3f pf = intToFloat(p, BS);
v2f node_p2df(pf.X, pf.Z);
f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
- f32 max_axis_distance_f = MYMAX(
- fabs(player_p2df.X-node_p2df.X),
- fabs(player_p2df.Y-node_p2df.Y));
- if(distance_f > min_distance_f ||
- max_axis_distance_f > 0.5*BS + sneak_max + 0.1*BS)
+ if (distance_f > min_distance_f ||
+ fabs(player_p2df.X-node_p2df.X) > (.5+.1)*BS + sneak_max.X ||
+ fabs(player_p2df.Y-node_p2df.Y) > (.5+.1)*BS + sneak_max.Z)
continue;
// The node to be sneaked on has to be walkable
node = map->getNodeNoEx(p, &is_valid_position);
- if (!is_valid_position || nodemgr->get(node).walkable == false)
- continue;
- // And the node above it has to be nonwalkable
- node = map->getNodeNoEx(p + v3s16(0,1,0), &is_valid_position);
- if (!is_valid_position || nodemgr->get(node).walkable) {
+ if (!is_valid_position || !nodemgr->get(node).walkable)
continue;
- }
+ // And the node(s) above have to be nonwalkable
+ bool ok = true;
if (!physics_override_sneak_glitch) {
- node =map->getNodeNoEx(p + v3s16(0,2,0), &is_valid_position);
- if (!is_valid_position || nodemgr->get(node).walkable)
- continue;
+ u16 height = ceilf(
+ (m_collisionbox.MaxEdge.Y - m_collisionbox.MinEdge.Y) / BS
+ );
+ for (u16 y = 1; y <= height; y++) {
+ node = map->getNodeNoEx(p + v3s16(0,y,0), &is_valid_position);
+ if (!is_valid_position || nodemgr->get(node).walkable) {
+ ok = false;
+ break;
+ }
+ }
+ } else {
+ // legacy behaviour: check just one node
+ node = map->getNodeNoEx(p + v3s16(0,1,0), &is_valid_position);
+ ok = is_valid_position && !nodemgr->get(node).walkable;
}
+ if (!ok)
+ continue;
min_distance_f = distance_f;
new_sneak_node = p;
}
- bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);
-
+ bool sneak_node_found = (min_distance_f < 100000.0 * BS);
m_sneak_node = new_sneak_node;
m_sneak_node_exists = sneak_node_found;
if (sneak_node_found) {
- f32 cb_max = 0;
+ // Update saved top bounding box of sneak node
MapNode n = map->getNodeNoEx(m_sneak_node);
std::vector<aabb3f> nodeboxes;
n.getCollisionBoxes(nodemgr, &nodeboxes);
- for (std::vector<aabb3f>::iterator it = nodeboxes.begin();
- it != nodeboxes.end(); ++it) {
- aabb3f box = *it;
- if (box.MaxEdge.Y > cb_max)
- cb_max = box.MaxEdge.Y;
- }
- m_sneak_node_bb_ymax = cb_max;
- }
+ m_sneak_node_bb_top = getTopBoundingBox(nodeboxes);
- /*
- If sneaking, the player's collision box can be in air, so
- this has to be set explicitly
- */
- if(sneak_node_found && control.sneak)
- touching_ground = true;
+ m_sneak_ladder_detected = physics_override_sneak_glitch &&
+ detectSneakLadder(map, nodemgr, floatToInt(position, BS));
+ } else {
+ m_sneak_ladder_detected = false;
+ }
}
/*
- Set new position
+ If 'sneak glitch' enabled detect ledge for old sneak-jump
+ behaviour of climbing onto a ledge 2 nodes up.
*/
+ if (physics_override_sneak_glitch && control.sneak && control.jump)
+ m_ledge_detected = detectLedge(map, nodemgr, floatToInt(position, BS));
+
+ /*
+ Set new position but keep sneak node set
+ */
+ bool sneak_node_exists = m_sneak_node_exists;
setPosition(position);
+ m_sneak_node_exists = sneak_node_exists;
/*
Report collisions
@@ -376,7 +484,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
if(!result.standing_on_object && !touching_ground_was && touching_ground) {
MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
- m_gamedef->event()->put(e);
+ m_client->event()->put(e);
// Set camera impact value to be used for view bobbing
camera_impact = getSpeed().Y * -1;
@@ -405,8 +513,11 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
// Determine if jumping is possible
m_can_jump = touching_ground && !in_liquid;
- if(itemgroup_get(f.groups, "disable_jump"))
+ if (itemgroup_get(f.groups, "disable_jump"))
m_can_jump = false;
+ else if (control.sneak && m_sneak_ladder_detected && !in_liquid && !is_climbing)
+ m_can_jump = true;
+
// Jump key pressed while jumping off from a bouncy block
if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
m_speed.Y >= -0.5 * BS) {
@@ -448,8 +559,8 @@ void LocalPlayer::applyControl(float dtime)
v3f speedH = v3f(0,0,0); // Horizontal (X, Z)
v3f speedV = v3f(0,0,0); // Vertical (Y)
- bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
- bool fast_allowed = m_gamedef->checkLocalPrivilege("fast");
+ bool fly_allowed = m_client->checkLocalPrivilege("fly");
+ bool fast_allowed = m_client->checkLocalPrivilege("fast");
bool free_move = fly_allowed && g_settings->getBool("free_move");
bool fast_move = fast_allowed && g_settings->getBool("fast_move");
@@ -593,13 +704,21 @@ void LocalPlayer::applyControl(float dtime)
at its starting value
*/
v3f speedJ = getSpeed();
- if(speedJ.Y >= -0.5 * BS)
- {
- speedJ.Y = movement_speed_jump * physics_override_jump;
- setSpeed(speedJ);
+ if(speedJ.Y >= -0.5 * BS) {
+ if (m_ledge_detected) {
+ // Limit jump speed to a minimum that allows
+ // jumping up onto a ledge 2 nodes up.
+ speedJ.Y = movement_speed_jump *
+ MYMAX(physics_override_jump, 1.3f);
+ setSpeed(speedJ);
+ m_ledge_detected = false;
+ } else {
+ speedJ.Y = movement_speed_jump * physics_override_jump;
+ setSpeed(speedJ);
+ }
MtEvent *e = new SimpleTriggerEvent("PlayerJump");
- m_gamedef->event()->put(e);
+ m_client->event()->put(e);
}
}
else if(in_liquid)
@@ -656,6 +775,29 @@ v3s16 LocalPlayer::getStandingNodePos()
return floatToInt(getPosition() - v3f(0, BS, 0), BS);
}
+v3s16 LocalPlayer::getFootstepNodePos()
+{
+ if (touching_ground)
+ // BS * 0.05 below the player's feet ensures a 1/16th height
+ // nodebox is detected instead of the node below it.
+ return floatToInt(getPosition() - v3f(0, BS * 0.05f, 0), BS);
+ // A larger distance below is necessary for a footstep sound
+ // when landing after a jump or fall. BS * 0.5 ensures water
+ // sounds when swimming in 1 node deep water.
+ return floatToInt(getPosition() - v3f(0, BS * 0.5f, 0), BS);
+}
+
+v3s16 LocalPlayer::getLightPosition() const
+{
+ return floatToInt(m_position + v3f(0,BS+BS/2,0), BS);
+}
+
+v3f LocalPlayer::getEyeOffset() const
+{
+ float eye_height = camera_barely_in_ceiling ? 1.5f : 1.625f;
+ return v3f(0, BS * eye_height, 0);
+}
+
// Horizontal acceleration (X and Z), Y direction is ignored
void LocalPlayer::accelerateHorizontal(const v3f &target_speed, const f32 max_increase)
{
@@ -689,3 +831,303 @@ void LocalPlayer::accelerateVertical(const v3f &target_speed, const f32 max_incr
m_speed.Y += d_wanted;
}
+// Temporary option for old move code
+void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
+ std::vector<CollisionInfo> *collision_info)
+{
+ Map *map = &env->getMap();
+ INodeDefManager *nodemgr = m_client->ndef();
+
+ v3f position = getPosition();
+
+ // Copy parent position if local player is attached
+ if (isAttached) {
+ setPosition(overridePosition);
+ m_sneak_node_exists = false;
+ return;
+ }
+
+ // Skip collision detection if noclip mode is used
+ bool fly_allowed = m_client->checkLocalPrivilege("fly");
+ bool noclip = m_client->checkLocalPrivilege("noclip") &&
+ g_settings->getBool("noclip");
+ bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
+ if (free_move) {
+ position += m_speed * dtime;
+ setPosition(position);
+ m_sneak_node_exists = false;
+ return;
+ }
+
+ /*
+ Collision detection
+ */
+ bool is_valid_position;
+ MapNode node;
+ v3s16 pp;
+
+ /*
+ Check if player is in liquid (the oscillating value)
+ */
+ if (in_liquid) {
+ // If in liquid, the threshold of coming out is at higher y
+ pp = floatToInt(position + v3f(0, BS * 0.1, 0), BS);
+ node = map->getNodeNoEx(pp, &is_valid_position);
+ if (is_valid_position) {
+ in_liquid = nodemgr->get(node.getContent()).isLiquid();
+ liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
+ } else {
+ in_liquid = false;
+ }
+ } else {
+ // If not in liquid, the threshold of going in is at lower y
+ pp = floatToInt(position + v3f(0, BS * 0.5, 0), BS);
+ node = map->getNodeNoEx(pp, &is_valid_position);
+ if (is_valid_position) {
+ in_liquid = nodemgr->get(node.getContent()).isLiquid();
+ liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
+ } else {
+ in_liquid = false;
+ }
+ }
+
+ /*
+ Check if player is in liquid (the stable value)
+ */
+ pp = floatToInt(position + v3f(0, 0, 0), BS);
+ node = map->getNodeNoEx(pp, &is_valid_position);
+ if (is_valid_position)
+ in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
+ else
+ in_liquid_stable = false;
+
+ /*
+ Check if player is climbing
+ */
+ pp = floatToInt(position + v3f(0, 0.5 * BS, 0), BS);
+ v3s16 pp2 = floatToInt(position + v3f(0, -0.2 * BS, 0), BS);
+ node = map->getNodeNoEx(pp, &is_valid_position);
+ bool is_valid_position2;
+ MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
+
+ if (!(is_valid_position && is_valid_position2))
+ is_climbing = false;
+ else
+ is_climbing = (nodemgr->get(node.getContent()).climbable ||
+ nodemgr->get(node2.getContent()).climbable) && !free_move;
+
+ /*
+ Collision uncertainty radius
+ Make it a bit larger than the maximum distance of movement
+ */
+ //f32 d = pos_max_d * 1.1;
+ // A fairly large value in here makes moving smoother
+ f32 d = 0.15 * BS;
+ // This should always apply, otherwise there are glitches
+ sanity_check(d > pos_max_d);
+ // Maximum distance over border for sneaking
+ f32 sneak_max = BS * 0.4;
+
+ /*
+ If sneaking, keep in range from the last walked node and don't
+ fall off from it
+ */
+ if (control.sneak && m_sneak_node_exists &&
+ !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid &&
+ physics_override_sneak) {
+ f32 maxd = 0.5 * BS + sneak_max;
+ v3f lwn_f = intToFloat(m_sneak_node, BS);
+ position.X = rangelim(position.X, lwn_f.X - maxd, lwn_f.X + maxd);
+ position.Z = rangelim(position.Z, lwn_f.Z - maxd, lwn_f.Z + maxd);
+
+ if (!is_climbing) {
+ // Move up if necessary
+ f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
+ if (position.Y < new_y)
+ position.Y = new_y;
+ /*
+ Collision seems broken, since player is sinking when
+ sneaking over the edges of current sneaking_node.
+ TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
+ */
+ if (m_speed.Y < 0)
+ m_speed.Y = 0;
+ }
+ }
+
+ // this shouldn't be hardcoded but transmitted from server
+ float player_stepheight = touching_ground ? (BS * 0.6) : (BS * 0.2);
+
+#ifdef __ANDROID__
+ player_stepheight += (0.6 * BS);
+#endif
+
+ v3f accel_f = v3f(0, 0, 0);
+
+ collisionMoveResult result = collisionMoveSimple(env, m_client,
+ pos_max_d, m_collisionbox, player_stepheight, dtime,
+ &position, &m_speed, accel_f);
+
+ /*
+ If the player's feet touch the topside of any node, this is
+ set to true.
+
+ Player is allowed to jump when this is true.
+ */
+ bool touching_ground_was = touching_ground;
+ touching_ground = result.touching_ground;
+
+ //bool standing_on_unloaded = result.standing_on_unloaded;
+
+ /*
+ Check the nodes under the player to see from which node the
+ player is sneaking from, if any. If the node from under
+ the player has been removed, the player falls.
+ */
+ f32 position_y_mod = 0.05 * BS;
+ if (m_sneak_node_bb_ymax > 0)
+ position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
+ v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
+ if (m_sneak_node_exists &&
+ nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
+ m_old_node_below_type != "air") {
+ // Old node appears to have been removed; that is,
+ // it wasn't air before but now it is
+ m_need_to_get_new_sneak_node = false;
+ m_sneak_node_exists = false;
+ } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
+ // We are on something, so make sure to recalculate the sneak
+ // node.
+ m_need_to_get_new_sneak_node = true;
+ }
+
+ if (m_need_to_get_new_sneak_node && physics_override_sneak) {
+ m_sneak_node_bb_ymax = 0;
+ v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS);
+ v2f player_p2df(position.X, position.Z);
+ f32 min_distance_f = 100000.0 * BS;
+ // If already seeking from some node, compare to it.
+ v3s16 new_sneak_node = m_sneak_node;
+ for (s16 x= -1; x <= 1; x++)
+ for (s16 z= -1; z <= 1; z++) {
+ v3s16 p = pos_i_bottom + v3s16(x, 0, z);
+ v3f pf = intToFloat(p, BS);
+ v2f node_p2df(pf.X, pf.Z);
+ f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
+ f32 max_axis_distance_f = MYMAX(
+ fabs(player_p2df.X - node_p2df.X),
+ fabs(player_p2df.Y - node_p2df.Y));
+
+ if (distance_f > min_distance_f ||
+ max_axis_distance_f > 0.5 * BS + sneak_max + 0.1 * BS)
+ continue;
+
+ // The node to be sneaked on has to be walkable
+ node = map->getNodeNoEx(p, &is_valid_position);
+ if (!is_valid_position || nodemgr->get(node).walkable == false)
+ continue;
+ // And the node above it has to be nonwalkable
+ node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position);
+ if (!is_valid_position || nodemgr->get(node).walkable)
+ continue;
+ // If not 'sneak_glitch' the node 2 nodes above it has to be nonwalkable
+ if (!physics_override_sneak_glitch) {
+ node =map->getNodeNoEx(p + v3s16(0, 2, 0), &is_valid_position);
+ if (!is_valid_position || nodemgr->get(node).walkable)
+ continue;
+ }
+
+ min_distance_f = distance_f;
+ new_sneak_node = p;
+ }
+
+ bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);
+
+ m_sneak_node = new_sneak_node;
+ m_sneak_node_exists = sneak_node_found;
+
+ if (sneak_node_found) {
+ f32 cb_max = 0;
+ MapNode n = map->getNodeNoEx(m_sneak_node);
+ std::vector<aabb3f> nodeboxes;
+ n.getCollisionBoxes(nodemgr, &nodeboxes);
+ for (std::vector<aabb3f>::iterator it = nodeboxes.begin();
+ it != nodeboxes.end(); ++it) {
+ aabb3f box = *it;
+ if (box.MaxEdge.Y > cb_max)
+ cb_max = box.MaxEdge.Y;
+ }
+ m_sneak_node_bb_ymax = cb_max;
+ }
+
+ /*
+ If sneaking, the player's collision box can be in air, so
+ this has to be set explicitly
+ */
+ if (sneak_node_found && control.sneak)
+ touching_ground = true;
+ }
+
+ /*
+ Set new position but keep sneak node set
+ */
+ bool sneak_node_exists = m_sneak_node_exists;
+ setPosition(position);
+ m_sneak_node_exists = sneak_node_exists;
+
+ /*
+ Report collisions
+ */
+ // Dont report if flying
+ if (collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
+ for (size_t i = 0; i < result.collisions.size(); i++) {
+ const CollisionInfo &info = result.collisions[i];
+ collision_info->push_back(info);
+ }
+ }
+
+ if (!result.standing_on_object && !touching_ground_was && touching_ground) {
+ MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
+ m_client->event()->put(e);
+ // Set camera impact value to be used for view bobbing
+ camera_impact = getSpeed().Y * -1;
+ }
+
+ {
+ camera_barely_in_ceiling = false;
+ v3s16 camera_np = floatToInt(getEyePosition(), BS);
+ MapNode n = map->getNodeNoEx(camera_np);
+ if (n.getContent() != CONTENT_IGNORE) {
+ if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2)
+ camera_barely_in_ceiling = true;
+ }
+ }
+
+ /*
+ Update the node last under the player
+ */
+ m_old_node_below = floatToInt(position - v3f(0, BS / 2, 0), BS);
+ m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
+
+ /*
+ Check properties of the node on which the player is standing
+ */
+ const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
+ // Determine if jumping is possible
+ m_can_jump = touching_ground && !in_liquid;
+ if (itemgroup_get(f.groups, "disable_jump"))
+ m_can_jump = false;
+ // Jump key pressed while jumping off from a bouncy block
+ if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
+ m_speed.Y >= -0.5 * BS) {
+ float jumpspeed = movement_speed_jump * physics_override_jump;
+ if (m_speed.Y > 1) {
+ // Reduce boost when speed already is high
+ m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
+ } else {
+ m_speed.Y += jumpspeed;
+ }
+ setSpeed(m_speed);
+ m_can_jump = false;
+ }
+}
diff --git a/src/localplayer.h b/src/localplayer.h
index 7a1cb7466..9cbefae23 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -30,18 +30,23 @@ class GenericCAO;
class ClientActiveObject;
class IGameDef;
-enum LocalPlayerAnimations {NO_ANIM, WALK_ANIM, DIG_ANIM, WD_ANIM}; // no local animation, walking, digging, both
+enum LocalPlayerAnimations
+{
+ NO_ANIM,
+ WALK_ANIM,
+ DIG_ANIM,
+ WD_ANIM
+}; // no local animation, walking, digging, both
class LocalPlayer : public Player
{
public:
- LocalPlayer(Client *gamedef, const char *name);
+ LocalPlayer(Client *client, const char *name);
virtual ~LocalPlayer();
ClientActiveObject *parent;
u16 hp;
- bool got_teleported;
bool isAttached;
bool touching_ground;
// This oscillates so that the player jumps a bit above the surface
@@ -58,16 +63,22 @@ public:
float physics_override_gravity;
bool physics_override_sneak;
bool physics_override_sneak_glitch;
+ // Temporary option for old move code
+ bool physics_override_new_move;
v3f overridePosition;
void move(f32 dtime, Environment *env, f32 pos_max_d);
void move(f32 dtime, Environment *env, f32 pos_max_d,
std::vector<CollisionInfo> *collision_info);
+ // Temporary option for old move code
+ void old_move(f32 dtime, Environment *env, f32 pos_max_d,
+ std::vector<CollisionInfo> *collision_info);
void applyControl(float dtime);
v3s16 getStandingNodePos();
+ v3s16 getFootstepNodePos();
// Used to check if anything changed and prevent sending packets if not
v3f last_position;
@@ -80,6 +91,8 @@ public:
float camera_impact;
+ bool makes_footstep_sound;
+
int last_animation;
float last_animation_speed;
@@ -91,12 +104,11 @@ public:
float hurt_tilt_timer;
float hurt_tilt_strength;
- GenericCAO* getCAO() const {
- return m_cao;
- }
+ GenericCAO *getCAO() const { return m_cao; }
- void setCAO(GenericCAO* toset) {
- assert( m_cao == NULL ); // Pre-condition
+ void setCAO(GenericCAO *toset)
+ {
+ assert(m_cao == NULL); // Pre-condition
m_cao = toset;
}
@@ -105,51 +117,49 @@ public:
u16 getBreath() const { return m_breath; }
void setBreath(u16 breath) { m_breath = breath; }
- v3s16 getLightPosition() const
- {
- return floatToInt(m_position + v3f(0,BS+BS/2,0), BS);
- }
+ v3s16 getLightPosition() const;
- void setYaw(f32 yaw)
- {
- m_yaw = yaw;
- }
+ void setYaw(f32 yaw) { m_yaw = yaw; }
f32 getYaw() const { return m_yaw; }
- void setPitch(f32 pitch)
- {
- m_pitch = pitch;
- }
+ void setPitch(f32 pitch) { m_pitch = pitch; }
f32 getPitch() const { return m_pitch; }
- void setPosition(const v3f &position)
+ inline void setPosition(const v3f &position)
{
m_position = position;
+ m_sneak_node_exists = false;
}
v3f getPosition() const { return m_position; }
v3f getEyePosition() const { return m_position + getEyeOffset(); }
- v3f getEyeOffset() const
- {
- float eye_height = camera_barely_in_ceiling ? 1.5f : 1.625f;
- return v3f(0, BS * eye_height, 0);
- }
+ v3f getEyeOffset() const;
+
private:
void accelerateHorizontal(const v3f &target_speed, const f32 max_increase);
void accelerateVertical(const v3f &target_speed, const f32 max_increase);
v3f m_position;
- // This is used for determining the sneaking range
+
v3s16 m_sneak_node;
+ // Stores the max player uplift by m_sneak_node
+ // To support temporary option for old move code
+ f32 m_sneak_node_bb_ymax;
+ // Stores the top bounding box of m_sneak_node
+ aabb3f m_sneak_node_bb_top;
// Whether the player is allowed to sneak
bool m_sneak_node_exists;
- // Whether recalculation of the sneak node is needed
+ // Whether recalculation of m_sneak_node and its top bbox is needed
bool m_need_to_get_new_sneak_node;
- // Stores the max player uplift by m_sneak_node and is updated
- // when m_need_to_get_new_sneak_node == true
- f32 m_sneak_node_bb_ymax;
+ // Whether a "sneak ladder" structure is detected at the players pos
+ // see detectSneakLadder() in the .cpp for more info (always false if disabled)
+ bool m_sneak_ladder_detected;
+ // Whether a 2-node-up ledge is detected at the players pos,
+ // see detectLedge() in the .cpp for more info (always false if disabled).
+ bool m_ledge_detected;
+
// Node below player, used to determine whether it has been removed,
// and its old type
v3s16 m_old_node_below;
@@ -161,9 +171,8 @@ private:
bool camera_barely_in_ceiling;
aabb3f m_collisionbox;
- GenericCAO* m_cao;
- Client *m_gamedef;
+ GenericCAO *m_cao;
+ Client *m_client;
};
#endif
-
diff --git a/src/lua/CMakeLists.txt b/src/lua/CMakeLists.txt
deleted file mode 100644
index 119dd6302..000000000
--- a/src/lua/CMakeLists.txt
+++ /dev/null
@@ -1,77 +0,0 @@
-cmake_minimum_required(VERSION 2.4 FATAL_ERROR)
-
-project(lua C)
-
-set(LUA_VERSION_MAJOR 5)
-set(LUA_VERSION_MINOR 1)
-set(LUA_VERSION_PATCH 4)
-set(LUA_VERSION "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}.${LUA_VERSION_PATCH}")
-
-set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
-
-set(COMMON_CFLAGS)
-set(COMMON_LDFLAGS)
-set(LIBS)
-
-if(APPLE)
- set(DEFAULT_POSIX TRUE)
- set(DEFAULT_DLOPEN ON)
- # use this on Mac OS X 10.3-
- option(LUA_USE_MACOSX "Mac OS X 10.3-" OFF)
-elseif(UNIX OR CYGWIN)
- set(DEFAULT_POSIX TRUE)
-elseif(WIN32)
- set(LUA_WIN TRUE)
- set(COMMON_CFLAGS "${COMMON_CFLAGS} -DLUA_BUILD_AS_DLL")
-else()
- set(DEFAULT_ANSI TRUE)
-endif()
-
-if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
- set(COMMON_LDFLAGS "${COMMON_LDFLAGS} -Wl,-E -lm")
- set(DEFAULT_DLOPEN ON)
-endif()
-
-# For "Mac OS X 10.3-"
-if(LUA_USE_MACOSX)
- set(COMMON_CFLAGS "${COMMON_CFLAGS} -DLUA_USE_MACOSX")
- set(LUA_USE_DLOPEN FALSE)
-endif(LUA_USE_MACOSX)
-
-option(LUA_USE_DLOPEN "Enable dlopen support." ${DEFAULT_DLOPEN})
-mark_as_advanced(LUA_USE_DLOPEN)
-
-option(LUA_ANSI "Disable non-ANSI features." ${DEFAULT_ANSI})
-mark_as_advanced(LUA_ANSI)
-
-if(LUA_USE_DLOPEN)
- set(COMMON_CFLAGS "${COMMON_CFLAGS} -DLUA_USE_DLOPEN")
- if(NOT APPLE)
- set(COMMON_LDFLAGS "${COMMON_LDFLAGS} -ldl ")
- endif(NOT APPLE)
-endif(LUA_USE_DLOPEN)
-
-if(DEFAULT_POSIX)
- set(COMMON_CFLAGS "${COMMON_CFLAGS} -DLUA_USE_POSIX")
-endif(DEFAULT_POSIX)
-
-if(LUA_ANSI)
- set(COMMON_CFLAGS "${COMMON_CFLAGS} -DLUA_ANSI")
-endif(LUA_ANSI)
-
-# COMMON_CFLAGS has no effect without this line
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COMMON_CFLAGS}")
-
-
-# Standard flags to use for each build type.
-if(CMAKE_COMPILER_IS_GNUCC)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pipe -Wall -Wextra -Wshadow -W -pedantic -std=gnu99")
- set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
- set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -g")
- set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_PROFILE} -O1 -g")
- set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_WITHDEBINFO} -O2 -g")
-endif(CMAKE_COMPILER_IS_GNUCC)
-
-
-add_subdirectory(src build)
-
diff --git a/src/lua/COPYRIGHT b/src/lua/COPYRIGHT
deleted file mode 100644
index 3a53e741e..000000000
--- a/src/lua/COPYRIGHT
+++ /dev/null
@@ -1,34 +0,0 @@
-Lua License
------------
-
-Lua is licensed under the terms of the MIT license reproduced below.
-This means that Lua is free software and can be used for both academic
-and commercial purposes at absolutely no cost.
-
-For details and rationale, see http://www.lua.org/license.html .
-
-===============================================================================
-
-Copyright (C) 1994-2008 Lua.org, PUC-Rio.
-
-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.
-
-===============================================================================
-
-(end of COPYRIGHT)
diff --git a/src/lua/src/CMakeLists.txt b/src/lua/src/CMakeLists.txt
deleted file mode 100644
index 8f6cc1213..000000000
--- a/src/lua/src/CMakeLists.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-
-# Lua core source files.
-set(LUA_CORE_SRC
- lapi.c
- lauxlib.c
- lbaselib.c
- lcode.c
- ldblib.c
- ldebug.c
- ldo.c
- ldump.c
- lfunc.c
- lgc.c
- linit.c
- liolib.c
- llex.c
- lmathlib.c
- lmem.c
- loadlib.c
- lobject.c
- lopcodes.c
- loslib.c
- lparser.c
- lstate.c
- lstring.c
- lstrlib.c
- ltable.c
- ltablib.c
- ltm.c
- lundump.c
- lvm.c
- lzio.c
-)
-set(LUA_LIB_HEADERS
- lua.h
- lualib.h
- lauxlib.h
- luaconf.h
-)
-
-include_directories(${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_CURRENT_BINARY_DIR})
-
-# Lua library.
-add_library(lua STATIC ${LUA_CORE_SRC})
-target_link_libraries(lua ${LIBS})
-set(LUA_STATIC_LIB lua)
-set(LUA_LIBS lua)
-
-set_target_properties(${LUA_LIBS} PROPERTIES
- VERSION ${LUA_VERSION}
- CLEAN_DIRECT_OUTPUT 1
-)
-
diff --git a/src/lua/src/lapi.c b/src/lua/src/lapi.c
deleted file mode 100644
index 5d5145d2e..000000000
--- a/src/lua/src/lapi.c
+++ /dev/null
@@ -1,1087 +0,0 @@
-/*
-** $Id: lapi.c,v 2.55.1.5 2008/07/04 18:41:18 roberto Exp $
-** Lua API
-** See Copyright Notice in lua.h
-*/
-
-
-#include <assert.h>
-#include <math.h>
-#include <stdarg.h>
-#include <string.h>
-
-#define lapi_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "lapi.h"
-#include "ldebug.h"
-#include "ldo.h"
-#include "lfunc.h"
-#include "lgc.h"
-#include "lmem.h"
-#include "lobject.h"
-#include "lstate.h"
-#include "lstring.h"
-#include "ltable.h"
-#include "ltm.h"
-#include "lundump.h"
-#include "lvm.h"
-
-
-
-const char lua_ident[] =
- "$Lua: " LUA_RELEASE " " LUA_COPYRIGHT " $\n"
- "$Authors: " LUA_AUTHORS " $\n"
- "$URL: www.lua.org $\n";
-
-
-
-#define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base))
-
-#define api_checkvalidindex(L, i) api_check(L, (i) != luaO_nilobject)
-
-#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;}
-
-
-
-static TValue *index2adr (lua_State *L, int idx) {
- if (idx > 0) {
- TValue *o = L->base + (idx - 1);
- api_check(L, idx <= L->ci->top - L->base);
- if (o >= L->top) return cast(TValue *, luaO_nilobject);
- else return o;
- }
- else if (idx > LUA_REGISTRYINDEX) {
- api_check(L, idx != 0 && -idx <= L->top - L->base);
- return L->top + idx;
- }
- else switch (idx) { /* pseudo-indices */
- case LUA_REGISTRYINDEX: return registry(L);
- case LUA_ENVIRONINDEX: {
- Closure *func = curr_func(L);
- sethvalue(L, &L->env, func->c.env);
- return &L->env;
- }
- case LUA_GLOBALSINDEX: return gt(L);
- default: {
- Closure *func = curr_func(L);
- idx = LUA_GLOBALSINDEX - idx;
- return (idx <= func->c.nupvalues)
- ? &func->c.upvalue[idx-1]
- : cast(TValue *, luaO_nilobject);
- }
- }
-}
-
-
-static Table *getcurrenv (lua_State *L) {
- if (L->ci == L->base_ci) /* no enclosing function? */
- return hvalue(gt(L)); /* use global table as environment */
- else {
- Closure *func = curr_func(L);
- return func->c.env;
- }
-}
-
-
-void luaA_pushobject (lua_State *L, const TValue *o) {
- setobj2s(L, L->top, o);
- api_incr_top(L);
-}
-
-
-LUA_API int lua_checkstack (lua_State *L, int size) {
- int res = 1;
- lua_lock(L);
- if (size > LUAI_MAXCSTACK || (L->top - L->base + size) > LUAI_MAXCSTACK)
- res = 0; /* stack overflow */
- else if (size > 0) {
- luaD_checkstack(L, size);
- if (L->ci->top < L->top + size)
- L->ci->top = L->top + size;
- }
- lua_unlock(L);
- return res;
-}
-
-
-LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
- int i;
- if (from == to) return;
- lua_lock(to);
- api_checknelems(from, n);
- api_check(from, G(from) == G(to));
- api_check(from, to->ci->top - to->top >= n);
- from->top -= n;
- for (i = 0; i < n; i++) {
- setobj2s(to, to->top++, from->top + i);
- }
- lua_unlock(to);
-}
-
-
-LUA_API void lua_setlevel (lua_State *from, lua_State *to) {
- to->nCcalls = from->nCcalls;
-}
-
-
-LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) {
- lua_CFunction old;
- lua_lock(L);
- old = G(L)->panic;
- G(L)->panic = panicf;
- lua_unlock(L);
- return old;
-}
-
-
-LUA_API lua_State *lua_newthread (lua_State *L) {
- lua_State *L1;
- lua_lock(L);
- luaC_checkGC(L);
- L1 = luaE_newthread(L);
- setthvalue(L, L->top, L1);
- api_incr_top(L);
- lua_unlock(L);
- luai_userstatethread(L, L1);
- return L1;
-}
-
-
-
-/*
-** basic stack manipulation
-*/
-
-
-LUA_API int lua_gettop (lua_State *L) {
- return cast_int(L->top - L->base);
-}
-
-
-LUA_API void lua_settop (lua_State *L, int idx) {
- lua_lock(L);
- if (idx >= 0) {
- api_check(L, idx <= L->stack_last - L->base);
- while (L->top < L->base + idx)
- setnilvalue(L->top++);
- L->top = L->base + idx;
- }
- else {
- api_check(L, -(idx+1) <= (L->top - L->base));
- L->top += idx+1; /* `subtract' index (index is negative) */
- }
- lua_unlock(L);
-}
-
-
-LUA_API void lua_remove (lua_State *L, int idx) {
- StkId p;
- lua_lock(L);
- p = index2adr(L, idx);
- api_checkvalidindex(L, p);
- while (++p < L->top) setobjs2s(L, p-1, p);
- L->top--;
- lua_unlock(L);
-}
-
-
-LUA_API void lua_insert (lua_State *L, int idx) {
- StkId p;
- StkId q;
- lua_lock(L);
- p = index2adr(L, idx);
- api_checkvalidindex(L, p);
- for (q = L->top; q>p; q--) setobjs2s(L, q, q-1);
- setobjs2s(L, p, L->top);
- lua_unlock(L);
-}
-
-
-LUA_API void lua_replace (lua_State *L, int idx) {
- StkId o;
- lua_lock(L);
- /* explicit test for incompatible code */
- if (idx == LUA_ENVIRONINDEX && L->ci == L->base_ci)
- luaG_runerror(L, "no calling environment");
- api_checknelems(L, 1);
- o = index2adr(L, idx);
- api_checkvalidindex(L, o);
- if (idx == LUA_ENVIRONINDEX) {
- Closure *func = curr_func(L);
- api_check(L, ttistable(L->top - 1));
- func->c.env = hvalue(L->top - 1);
- luaC_barrier(L, func, L->top - 1);
- }
- else {
- setobj(L, o, L->top - 1);
- if (idx < LUA_GLOBALSINDEX) /* function upvalue? */
- luaC_barrier(L, curr_func(L), L->top - 1);
- }
- L->top--;
- lua_unlock(L);
-}
-
-
-LUA_API void lua_pushvalue (lua_State *L, int idx) {
- lua_lock(L);
- setobj2s(L, L->top, index2adr(L, idx));
- api_incr_top(L);
- lua_unlock(L);
-}
-
-
-
-/*
-** access functions (stack -> C)
-*/
-
-
-LUA_API int lua_type (lua_State *L, int idx) {
- StkId o = index2adr(L, idx);
- return (o == luaO_nilobject) ? LUA_TNONE : ttype(o);
-}
-
-
-LUA_API const char *lua_typename (lua_State *L, int t) {
- UNUSED(L);
- return (t == LUA_TNONE) ? "no value" : luaT_typenames[t];
-}
-
-
-LUA_API int lua_iscfunction (lua_State *L, int idx) {
- StkId o = index2adr(L, idx);
- return iscfunction(o);
-}
-
-
-LUA_API int lua_isnumber (lua_State *L, int idx) {
- TValue n;
- const TValue *o = index2adr(L, idx);
- return tonumber(o, &n);
-}
-
-
-LUA_API int lua_isstring (lua_State *L, int idx) {
- int t = lua_type(L, idx);
- return (t == LUA_TSTRING || t == LUA_TNUMBER);
-}
-
-
-LUA_API int lua_isuserdata (lua_State *L, int idx) {
- const TValue *o = index2adr(L, idx);
- return (ttisuserdata(o) || ttislightuserdata(o));
-}
-
-
-LUA_API int lua_rawequal (lua_State *L, int index1, int index2) {
- StkId o1 = index2adr(L, index1);
- StkId o2 = index2adr(L, index2);
- return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0
- : luaO_rawequalObj(o1, o2);
-}
-
-
-LUA_API int lua_equal (lua_State *L, int index1, int index2) {
- StkId o1, o2;
- int i;
- lua_lock(L); /* may call tag method */
- o1 = index2adr(L, index1);
- o2 = index2adr(L, index2);
- i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : equalobj(L, o1, o2);
- lua_unlock(L);
- return i;
-}
-
-
-LUA_API int lua_lessthan (lua_State *L, int index1, int index2) {
- StkId o1, o2;
- int i;
- lua_lock(L); /* may call tag method */
- o1 = index2adr(L, index1);
- o2 = index2adr(L, index2);
- i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0
- : luaV_lessthan(L, o1, o2);
- lua_unlock(L);
- return i;
-}
-
-
-
-LUA_API lua_Number lua_tonumber (lua_State *L, int idx) {
- TValue n;
- const TValue *o = index2adr(L, idx);
- if (tonumber(o, &n))
- return nvalue(o);
- else
- return 0;
-}
-
-
-LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) {
- TValue n;
- const TValue *o = index2adr(L, idx);
- if (tonumber(o, &n)) {
- lua_Integer res;
- lua_Number num = nvalue(o);
- lua_number2integer(res, num);
- return res;
- }
- else
- return 0;
-}
-
-
-LUA_API int lua_toboolean (lua_State *L, int idx) {
- const TValue *o = index2adr(L, idx);
- return !l_isfalse(o);
-}
-
-
-LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
- StkId o = index2adr(L, idx);
- if (!ttisstring(o)) {
- lua_lock(L); /* `luaV_tostring' may create a new string */
- if (!luaV_tostring(L, o)) { /* conversion failed? */
- if (len != NULL) *len = 0;
- lua_unlock(L);
- return NULL;
- }
- luaC_checkGC(L);
- o = index2adr(L, idx); /* previous call may reallocate the stack */
- lua_unlock(L);
- }
- if (len != NULL) *len = tsvalue(o)->len;
- return svalue(o);
-}
-
-
-LUA_API size_t lua_objlen (lua_State *L, int idx) {
- StkId o = index2adr(L, idx);
- switch (ttype(o)) {
- case LUA_TSTRING: return tsvalue(o)->len;
- case LUA_TUSERDATA: return uvalue(o)->len;
- case LUA_TTABLE: return luaH_getn(hvalue(o));
- case LUA_TNUMBER: {
- size_t l;
- lua_lock(L); /* `luaV_tostring' may create a new string */
- l = (luaV_tostring(L, o) ? tsvalue(o)->len : 0);
- lua_unlock(L);
- return l;
- }
- default: return 0;
- }
-}
-
-
-LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) {
- StkId o = index2adr(L, idx);
- return (!iscfunction(o)) ? NULL : clvalue(o)->c.f;
-}
-
-
-LUA_API void *lua_touserdata (lua_State *L, int idx) {
- StkId o = index2adr(L, idx);
- switch (ttype(o)) {
- case LUA_TUSERDATA: return (rawuvalue(o) + 1);
- case LUA_TLIGHTUSERDATA: return pvalue(o);
- default: return NULL;
- }
-}
-
-
-LUA_API lua_State *lua_tothread (lua_State *L, int idx) {
- StkId o = index2adr(L, idx);
- return (!ttisthread(o)) ? NULL : thvalue(o);
-}
-
-
-LUA_API const void *lua_topointer (lua_State *L, int idx) {
- StkId o = index2adr(L, idx);
- switch (ttype(o)) {
- case LUA_TTABLE: return hvalue(o);
- case LUA_TFUNCTION: return clvalue(o);
- case LUA_TTHREAD: return thvalue(o);
- case LUA_TUSERDATA:
- case LUA_TLIGHTUSERDATA:
- return lua_touserdata(L, idx);
- default: return NULL;
- }
-}
-
-
-
-/*
-** push functions (C -> stack)
-*/
-
-
-LUA_API void lua_pushnil (lua_State *L) {
- lua_lock(L);
- setnilvalue(L->top);
- api_incr_top(L);
- lua_unlock(L);
-}
-
-
-LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
- lua_lock(L);
- setnvalue(L->top, n);
- api_incr_top(L);
- lua_unlock(L);
-}
-
-
-LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
- lua_lock(L);
- setnvalue(L->top, cast_num(n));
- api_incr_top(L);
- lua_unlock(L);
-}
-
-
-LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) {
- lua_lock(L);
- luaC_checkGC(L);
- setsvalue2s(L, L->top, luaS_newlstr(L, s, len));
- api_incr_top(L);
- lua_unlock(L);
-}
-
-
-LUA_API void lua_pushstring (lua_State *L, const char *s) {
- if (s == NULL)
- lua_pushnil(L);
- else
- lua_pushlstring(L, s, strlen(s));
-}
-
-
-LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt,
- va_list argp) {
- const char *ret;
- lua_lock(L);
- luaC_checkGC(L);
- ret = luaO_pushvfstring(L, fmt, argp);
- lua_unlock(L);
- return ret;
-}
-
-
-LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
- const char *ret;
- va_list argp;
- lua_lock(L);
- luaC_checkGC(L);
- va_start(argp, fmt);
- ret = luaO_pushvfstring(L, fmt, argp);
- va_end(argp);
- lua_unlock(L);
- return ret;
-}
-
-
-LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
- Closure *cl;
- lua_lock(L);
- luaC_checkGC(L);
- api_checknelems(L, n);
- cl = luaF_newCclosure(L, n, getcurrenv(L));
- cl->c.f = fn;
- L->top -= n;
- while (n--)
- setobj2n(L, &cl->c.upvalue[n], L->top+n);
- setclvalue(L, L->top, cl);
- lua_assert(iswhite(obj2gco(cl)));
- api_incr_top(L);
- lua_unlock(L);
-}
-
-
-LUA_API void lua_pushboolean (lua_State *L, int b) {
- lua_lock(L);
- setbvalue(L->top, (b != 0)); /* ensure that true is 1 */
- api_incr_top(L);
- lua_unlock(L);
-}
-
-
-LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
- lua_lock(L);
- setpvalue(L->top, p);
- api_incr_top(L);
- lua_unlock(L);
-}
-
-
-LUA_API int lua_pushthread (lua_State *L) {
- lua_lock(L);
- setthvalue(L, L->top, L);
- api_incr_top(L);
- lua_unlock(L);
- return (G(L)->mainthread == L);
-}
-
-
-
-/*
-** get functions (Lua -> stack)
-*/
-
-
-LUA_API void lua_gettable (lua_State *L, int idx) {
- StkId t;
- lua_lock(L);
- t = index2adr(L, idx);
- api_checkvalidindex(L, t);
- luaV_gettable(L, t, L->top - 1, L->top - 1);
- lua_unlock(L);
-}
-
-
-LUA_API void lua_getfield (lua_State *L, int idx, const char *k) {
- StkId t;
- TValue key;
- lua_lock(L);
- t = index2adr(L, idx);
- api_checkvalidindex(L, t);
- setsvalue(L, &key, luaS_new(L, k));
- luaV_gettable(L, t, &key, L->top);
- api_incr_top(L);
- lua_unlock(L);
-}
-
-
-LUA_API void lua_rawget (lua_State *L, int idx) {
- StkId t;
- lua_lock(L);
- t = index2adr(L, idx);
- api_check(L, ttistable(t));
- setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1));
- lua_unlock(L);
-}
-
-
-LUA_API void lua_rawgeti (lua_State *L, int idx, int n) {
- StkId o;
- lua_lock(L);
- o = index2adr(L, idx);
- api_check(L, ttistable(o));
- setobj2s(L, L->top, luaH_getnum(hvalue(o), n));
- api_incr_top(L);
- lua_unlock(L);
-}
-
-
-LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
- lua_lock(L);
- luaC_checkGC(L);
- sethvalue(L, L->top, luaH_new(L, narray, nrec));
- api_incr_top(L);
- lua_unlock(L);
-}
-
-
-LUA_API int lua_getmetatable (lua_State *L, int objindex) {
- const TValue *obj;
- Table *mt = NULL;
- int res;
- lua_lock(L);
- obj = index2adr(L, objindex);
- switch (ttype(obj)) {
- case LUA_TTABLE:
- mt = hvalue(obj)->metatable;
- break;
- case LUA_TUSERDATA:
- mt = uvalue(obj)->metatable;
- break;
- default:
- mt = G(L)->mt[ttype(obj)];
- break;
- }
- if (mt == NULL)
- res = 0;
- else {
- sethvalue(L, L->top, mt);
- api_incr_top(L);
- res = 1;
- }
- lua_unlock(L);
- return res;
-}
-
-
-LUA_API void lua_getfenv (lua_State *L, int idx) {
- StkId o;
- lua_lock(L);
- o = index2adr(L, idx);
- api_checkvalidindex(L, o);
- switch (ttype(o)) {
- case LUA_TFUNCTION:
- sethvalue(L, L->top, clvalue(o)->c.env);
- break;
- case LUA_TUSERDATA:
- sethvalue(L, L->top, uvalue(o)->env);
- break;
- case LUA_TTHREAD:
- setobj2s(L, L->top, gt(thvalue(o)));
- break;
- default:
- setnilvalue(L->top);
- break;
- }
- api_incr_top(L);
- lua_unlock(L);
-}
-
-
-/*
-** set functions (stack -> Lua)
-*/
-
-
-LUA_API void lua_settable (lua_State *L, int idx) {
- StkId t;
- lua_lock(L);
- api_checknelems(L, 2);
- t = index2adr(L, idx);
- api_checkvalidindex(L, t);
- luaV_settable(L, t, L->top - 2, L->top - 1);
- L->top -= 2; /* pop index and value */
- lua_unlock(L);
-}
-
-
-LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
- StkId t;
- TValue key;
- lua_lock(L);
- api_checknelems(L, 1);
- t = index2adr(L, idx);
- api_checkvalidindex(L, t);
- setsvalue(L, &key, luaS_new(L, k));
- luaV_settable(L, t, &key, L->top - 1);
- L->top--; /* pop value */
- lua_unlock(L);
-}
-
-
-LUA_API void lua_rawset (lua_State *L, int idx) {
- StkId t;
- lua_lock(L);
- api_checknelems(L, 2);
- t = index2adr(L, idx);
- api_check(L, ttistable(t));
- setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1);
- luaC_barriert(L, hvalue(t), L->top-1);
- L->top -= 2;
- lua_unlock(L);
-}
-
-
-LUA_API void lua_rawseti (lua_State *L, int idx, int n) {
- StkId o;
- lua_lock(L);
- api_checknelems(L, 1);
- o = index2adr(L, idx);
- api_check(L, ttistable(o));
- setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1);
- luaC_barriert(L, hvalue(o), L->top-1);
- L->top--;
- lua_unlock(L);
-}
-
-
-LUA_API int lua_setmetatable (lua_State *L, int objindex) {
- TValue *obj;
- Table *mt;
- lua_lock(L);
- api_checknelems(L, 1);
- obj = index2adr(L, objindex);
- api_checkvalidindex(L, obj);
- if (ttisnil(L->top - 1))
- mt = NULL;
- else {
- api_check(L, ttistable(L->top - 1));
- mt = hvalue(L->top - 1);
- }
- switch (ttype(obj)) {
- case LUA_TTABLE: {
- hvalue(obj)->metatable = mt;
- if (mt)
- luaC_objbarriert(L, hvalue(obj), mt);
- break;
- }
- case LUA_TUSERDATA: {
- uvalue(obj)->metatable = mt;
- if (mt)
- luaC_objbarrier(L, rawuvalue(obj), mt);
- break;
- }
- default: {
- G(L)->mt[ttype(obj)] = mt;
- break;
- }
- }
- L->top--;
- lua_unlock(L);
- return 1;
-}
-
-
-LUA_API int lua_setfenv (lua_State *L, int idx) {
- StkId o;
- int res = 1;
- lua_lock(L);
- api_checknelems(L, 1);
- o = index2adr(L, idx);
- api_checkvalidindex(L, o);
- api_check(L, ttistable(L->top - 1));
- switch (ttype(o)) {
- case LUA_TFUNCTION:
- clvalue(o)->c.env = hvalue(L->top - 1);
- break;
- case LUA_TUSERDATA:
- uvalue(o)->env = hvalue(L->top - 1);
- break;
- case LUA_TTHREAD:
- sethvalue(L, gt(thvalue(o)), hvalue(L->top - 1));
- break;
- default:
- res = 0;
- break;
- }
- if (res) luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1));
- L->top--;
- lua_unlock(L);
- return res;
-}
-
-
-/*
-** `load' and `call' functions (run Lua code)
-*/
-
-
-#define adjustresults(L,nres) \
- { if (nres == LUA_MULTRET && L->top >= L->ci->top) L->ci->top = L->top; }
-
-
-#define checkresults(L,na,nr) \
- api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)))
-
-
-LUA_API void lua_call (lua_State *L, int nargs, int nresults) {
- StkId func;
- lua_lock(L);
- api_checknelems(L, nargs+1);
- checkresults(L, nargs, nresults);
- func = L->top - (nargs+1);
- luaD_call(L, func, nresults);
- adjustresults(L, nresults);
- lua_unlock(L);
-}
-
-
-
-/*
-** Execute a protected call.
-*/
-struct CallS { /* data to `f_call' */
- StkId func;
- int nresults;
-};
-
-
-static void f_call (lua_State *L, void *ud) {
- struct CallS *c = cast(struct CallS *, ud);
- luaD_call(L, c->func, c->nresults);
-}
-
-
-
-LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) {
- struct CallS c;
- int status;
- ptrdiff_t func;
- lua_lock(L);
- api_checknelems(L, nargs+1);
- checkresults(L, nargs, nresults);
- if (errfunc == 0)
- func = 0;
- else {
- StkId o = index2adr(L, errfunc);
- api_checkvalidindex(L, o);
- func = savestack(L, o);
- }
- c.func = L->top - (nargs+1); /* function to be called */
- c.nresults = nresults;
- status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
- adjustresults(L, nresults);
- lua_unlock(L);
- return status;
-}
-
-
-/*
-** Execute a protected C call.
-*/
-struct CCallS { /* data to `f_Ccall' */
- lua_CFunction func;
- void *ud;
-};
-
-
-static void f_Ccall (lua_State *L, void *ud) {
- struct CCallS *c = cast(struct CCallS *, ud);
- Closure *cl;
- cl = luaF_newCclosure(L, 0, getcurrenv(L));
- cl->c.f = c->func;
- setclvalue(L, L->top, cl); /* push function */
- api_incr_top(L);
- setpvalue(L->top, c->ud); /* push only argument */
- api_incr_top(L);
- luaD_call(L, L->top - 2, 0);
-}
-
-
-LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) {
- struct CCallS c;
- int status;
- lua_lock(L);
- c.func = func;
- c.ud = ud;
- status = luaD_pcall(L, f_Ccall, &c, savestack(L, L->top), 0);
- lua_unlock(L);
- return status;
-}
-
-
-LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
- const char *chunkname) {
- ZIO z;
- int status;
- lua_lock(L);
- if (!chunkname) chunkname = "?";
- luaZ_init(L, &z, reader, data);
- status = luaD_protectedparser(L, &z, chunkname);
- lua_unlock(L);
- return status;
-}
-
-
-LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) {
- int status;
- TValue *o;
- lua_lock(L);
- api_checknelems(L, 1);
- o = L->top - 1;
- if (isLfunction(o))
- status = luaU_dump(L, clvalue(o)->l.p, writer, data, 0);
- else
- status = 1;
- lua_unlock(L);
- return status;
-}
-
-
-LUA_API int lua_status (lua_State *L) {
- return L->status;
-}
-
-
-/*
-** Garbage-collection function
-*/
-
-LUA_API int lua_gc (lua_State *L, int what, int data) {
- int res = 0;
- global_State *g;
- lua_lock(L);
- g = G(L);
- switch (what) {
- case LUA_GCSTOP: {
- g->GCthreshold = MAX_LUMEM;
- break;
- }
- case LUA_GCRESTART: {
- g->GCthreshold = g->totalbytes;
- break;
- }
- case LUA_GCCOLLECT: {
- luaC_fullgc(L);
- break;
- }
- case LUA_GCCOUNT: {
- /* GC values are expressed in Kbytes: #bytes/2^10 */
- res = cast_int(g->totalbytes >> 10);
- break;
- }
- case LUA_GCCOUNTB: {
- res = cast_int(g->totalbytes & 0x3ff);
- break;
- }
- case LUA_GCSTEP: {
- lu_mem a = (cast(lu_mem, data) << 10);
- if (a <= g->totalbytes)
- g->GCthreshold = g->totalbytes - a;
- else
- g->GCthreshold = 0;
- while (g->GCthreshold <= g->totalbytes) {
- luaC_step(L);
- if (g->gcstate == GCSpause) { /* end of cycle? */
- res = 1; /* signal it */
- break;
- }
- }
- break;
- }
- case LUA_GCSETPAUSE: {
- res = g->gcpause;
- g->gcpause = data;
- break;
- }
- case LUA_GCSETSTEPMUL: {
- res = g->gcstepmul;
- g->gcstepmul = data;
- break;
- }
- default: res = -1; /* invalid option */
- }
- lua_unlock(L);
- return res;
-}
-
-
-
-/*
-** miscellaneous functions
-*/
-
-
-LUA_API int lua_error (lua_State *L) {
- lua_lock(L);
- api_checknelems(L, 1);
- luaG_errormsg(L);
- lua_unlock(L);
- return 0; /* to avoid warnings */
-}
-
-
-LUA_API int lua_next (lua_State *L, int idx) {
- StkId t;
- int more;
- lua_lock(L);
- t = index2adr(L, idx);
- api_check(L, ttistable(t));
- more = luaH_next(L, hvalue(t), L->top - 1);
- if (more) {
- api_incr_top(L);
- }
- else /* no more elements */
- L->top -= 1; /* remove key */
- lua_unlock(L);
- return more;
-}
-
-
-LUA_API void lua_concat (lua_State *L, int n) {
- lua_lock(L);
- api_checknelems(L, n);
- if (n >= 2) {
- luaC_checkGC(L);
- luaV_concat(L, n, cast_int(L->top - L->base) - 1);
- L->top -= (n-1);
- }
- else if (n == 0) { /* push empty string */
- setsvalue2s(L, L->top, luaS_newlstr(L, "", 0));
- api_incr_top(L);
- }
- /* else n == 1; nothing to do */
- lua_unlock(L);
-}
-
-
-LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) {
- lua_Alloc f;
- lua_lock(L);
- if (ud) *ud = G(L)->ud;
- f = G(L)->frealloc;
- lua_unlock(L);
- return f;
-}
-
-
-LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) {
- lua_lock(L);
- G(L)->ud = ud;
- G(L)->frealloc = f;
- lua_unlock(L);
-}
-
-
-LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
- Udata *u;
- lua_lock(L);
- luaC_checkGC(L);
- u = luaS_newudata(L, size, getcurrenv(L));
- setuvalue(L, L->top, u);
- api_incr_top(L);
- lua_unlock(L);
- return u + 1;
-}
-
-
-
-
-static const char *aux_upvalue (StkId fi, int n, TValue **val) {
- Closure *f;
- if (!ttisfunction(fi)) return NULL;
- f = clvalue(fi);
- if (f->c.isC) {
- if (!(1 <= n && n <= f->c.nupvalues)) return NULL;
- *val = &f->c.upvalue[n-1];
- return "";
- }
- else {
- Proto *p = f->l.p;
- if (!(1 <= n && n <= p->sizeupvalues)) return NULL;
- *val = f->l.upvals[n-1]->v;
- return getstr(p->upvalues[n-1]);
- }
-}
-
-
-LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
- const char *name;
- TValue *val;
- lua_lock(L);
- name = aux_upvalue(index2adr(L, funcindex), n, &val);
- if (name) {
- setobj2s(L, L->top, val);
- api_incr_top(L);
- }
- lua_unlock(L);
- return name;
-}
-
-
-LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
- const char *name;
- TValue *val;
- StkId fi;
- lua_lock(L);
- fi = index2adr(L, funcindex);
- api_checknelems(L, 1);
- name = aux_upvalue(fi, n, &val);
- if (name) {
- L->top--;
- setobj(L, val, L->top);
- luaC_barrier(L, clvalue(fi), L->top);
- }
- lua_unlock(L);
- return name;
-}
-
diff --git a/src/lua/src/lapi.h b/src/lua/src/lapi.h
deleted file mode 100644
index 2c3fab244..000000000
--- a/src/lua/src/lapi.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
-** $Id: lapi.h,v 2.2.1.1 2007/12/27 13:02:25 roberto Exp $
-** Auxiliary functions from Lua API
-** See Copyright Notice in lua.h
-*/
-
-#ifndef lapi_h
-#define lapi_h
-
-
-#include "lobject.h"
-
-
-LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o);
-
-#endif
diff --git a/src/lua/src/lauxlib.c b/src/lua/src/lauxlib.c
deleted file mode 100644
index be41ebcd3..000000000
--- a/src/lua/src/lauxlib.c
+++ /dev/null
@@ -1,653 +0,0 @@
-/*
-** $Id: lauxlib.c,v 1.159.1.3 2008/01/21 13:20:51 roberto Exp $
-** Auxiliary functions for building Lua libraries
-** See Copyright Notice in lua.h
-*/
-
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-
-/* This file uses only the official API of Lua.
-** Any function declared here could be written as an application function.
-*/
-
-#define lauxlib_c
-#define LUA_LIB
-
-#include "lua.h"
-
-#include "lauxlib.h"
-
-
-#define FREELIST_REF 0 /* free list of references */
-
-
-/* convert a stack index to positive */
-#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \
- lua_gettop(L) + (i) + 1)
-
-
-/*
-** {======================================================
-** Error-report functions
-** =======================================================
-*/
-
-
-LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) {
- lua_Debug ar;
- if (!lua_getstack(L, 0, &ar)) /* no stack frame? */
- return luaL_error(L, "bad argument #%d (%s)", narg, extramsg);
- lua_getinfo(L, "n", &ar);
- if (strcmp(ar.namewhat, "method") == 0) {
- narg--; /* do not count `self' */
- if (narg == 0) /* error is in the self argument itself? */
- return luaL_error(L, "calling " LUA_QS " on bad self (%s)",
- ar.name, extramsg);
- }
- if (ar.name == NULL)
- ar.name = "?";
- return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)",
- narg, ar.name, extramsg);
-}
-
-
-LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) {
- const char *msg = lua_pushfstring(L, "%s expected, got %s",
- tname, luaL_typename(L, narg));
- return luaL_argerror(L, narg, msg);
-}
-
-
-static void tag_error (lua_State *L, int narg, int tag) {
- luaL_typerror(L, narg, lua_typename(L, tag));
-}
-
-
-LUALIB_API void luaL_where (lua_State *L, int level) {
- lua_Debug ar;
- if (lua_getstack(L, level, &ar)) { /* check function at level */
- lua_getinfo(L, "Sl", &ar); /* get info about it */
- if (ar.currentline > 0) { /* is there info? */
- lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
- return;
- }
- }
- lua_pushliteral(L, ""); /* else, no information available... */
-}
-
-
-LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
- va_list argp;
- va_start(argp, fmt);
- luaL_where(L, 1);
- lua_pushvfstring(L, fmt, argp);
- va_end(argp);
- lua_concat(L, 2);
- return lua_error(L);
-}
-
-/* }====================================================== */
-
-
-LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def,
- const char *const lst[]) {
- const char *name = (def) ? luaL_optstring(L, narg, def) :
- luaL_checkstring(L, narg);
- int i;
- for (i=0; lst[i]; i++)
- if (strcmp(lst[i], name) == 0)
- return i;
- return luaL_argerror(L, narg,
- lua_pushfstring(L, "invalid option " LUA_QS, name));
-}
-
-
-LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
- lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get registry.name */
- if (!lua_isnil(L, -1)) /* name already in use? */
- return 0; /* leave previous value on top, but return 0 */
- lua_pop(L, 1);
- lua_newtable(L); /* create metatable */
- lua_pushvalue(L, -1);
- lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */
- return 1;
-}
-
-
-LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {
- void *p = lua_touserdata(L, ud);
- if (p != NULL) { /* value is a userdata? */
- if (lua_getmetatable(L, ud)) { /* does it have a metatable? */
- lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */
- if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */
- lua_pop(L, 2); /* remove both metatables */
- return p;
- }
- }
- }
- luaL_typerror(L, ud, tname); /* else error */
- return NULL; /* to avoid warnings */
-}
-
-
-LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) {
- if (!lua_checkstack(L, space))
- luaL_error(L, "stack overflow (%s)", mes);
-}
-
-
-LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) {
- if (lua_type(L, narg) != t)
- tag_error(L, narg, t);
-}
-
-
-LUALIB_API void luaL_checkany (lua_State *L, int narg) {
- if (lua_type(L, narg) == LUA_TNONE)
- luaL_argerror(L, narg, "value expected");
-}
-
-
-LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) {
- const char *s = lua_tolstring(L, narg, len);
- if (!s) tag_error(L, narg, LUA_TSTRING);
- return s;
-}
-
-
-LUALIB_API const char *luaL_optlstring (lua_State *L, int narg,
- const char *def, size_t *len) {
- if (lua_isnoneornil(L, narg)) {
- if (len)
- *len = (def ? strlen(def) : 0);
- return def;
- }
- else return luaL_checklstring(L, narg, len);
-}
-
-
-LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) {
- lua_Number d = lua_tonumber(L, narg);
- if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */
- tag_error(L, narg, LUA_TNUMBER);
- return d;
-}
-
-
-LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) {
- return luaL_opt(L, luaL_checknumber, narg, def);
-}
-
-
-LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) {
- lua_Integer d = lua_tointeger(L, narg);
- if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */
- tag_error(L, narg, LUA_TNUMBER);
- return d;
-}
-
-
-LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg,
- lua_Integer def) {
- return luaL_opt(L, luaL_checkinteger, narg, def);
-}
-
-
-LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
- if (!lua_getmetatable(L, obj)) /* no metatable? */
- return 0;
- lua_pushstring(L, event);
- lua_rawget(L, -2);
- if (lua_isnil(L, -1)) {
- lua_pop(L, 2); /* remove metatable and metafield */
- return 0;
- }
- else {
- lua_remove(L, -2); /* remove only metatable */
- return 1;
- }
-}
-
-
-LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) {
- obj = abs_index(L, obj);
- if (!luaL_getmetafield(L, obj, event)) /* no metafield? */
- return 0;
- lua_pushvalue(L, obj);
- lua_call(L, 1, 1);
- return 1;
-}
-
-
-LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
- const luaL_Reg *l) {
- luaI_openlib(L, libname, l, 0);
-}
-
-
-static int libsize (const luaL_Reg *l) {
- int size = 0;
- for (; l->name; l++) size++;
- return size;
-}
-
-
-LUALIB_API void luaI_openlib (lua_State *L, const char *libname,
- const luaL_Reg *l, int nup) {
- if (libname) {
- int size = libsize(l);
- /* check whether lib already exists */
- luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1);
- lua_getfield(L, -1, libname); /* get _LOADED[libname] */
- if (!lua_istable(L, -1)) { /* not found? */
- lua_pop(L, 1); /* remove previous result */
- /* try global variable (and create one if it does not exist) */
- if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL)
- luaL_error(L, "name conflict for module " LUA_QS, libname);
- lua_pushvalue(L, -1);
- lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */
- }
- lua_remove(L, -2); /* remove _LOADED table */
- lua_insert(L, -(nup+1)); /* move library table to below upvalues */
- }
- for (; l->name; l++) {
- int i;
- for (i=0; i<nup; i++) /* copy upvalues to the top */
- lua_pushvalue(L, -nup);
- lua_pushcclosure(L, l->func, nup);
- lua_setfield(L, -(nup+2), l->name);
- }
- lua_pop(L, nup); /* remove upvalues */
-}
-
-
-
-/*
-** {======================================================
-** getn-setn: size for arrays
-** =======================================================
-*/
-
-#if defined(LUA_COMPAT_GETN)
-
-static int checkint (lua_State *L, int topop) {
- int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1;
- lua_pop(L, topop);
- return n;
-}
-
-
-static void getsizes (lua_State *L) {
- lua_getfield(L, LUA_REGISTRYINDEX, "LUA_SIZES");
- if (lua_isnil(L, -1)) { /* no `size' table? */
- lua_pop(L, 1); /* remove nil */
- lua_newtable(L); /* create it */
- lua_pushvalue(L, -1); /* `size' will be its own metatable */
- lua_setmetatable(L, -2);
- lua_pushliteral(L, "kv");
- lua_setfield(L, -2, "__mode"); /* metatable(N).__mode = "kv" */
- lua_pushvalue(L, -1);
- lua_setfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); /* store in register */
- }
-}
-
-
-LUALIB_API void luaL_setn (lua_State *L, int t, int n) {
- t = abs_index(L, t);
- lua_pushliteral(L, "n");
- lua_rawget(L, t);
- if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */
- lua_pushliteral(L, "n"); /* use it */
- lua_pushinteger(L, n);
- lua_rawset(L, t);
- }
- else { /* use `sizes' */
- getsizes(L);
- lua_pushvalue(L, t);
- lua_pushinteger(L, n);
- lua_rawset(L, -3); /* sizes[t] = n */
- lua_pop(L, 1); /* remove `sizes' */
- }
-}
-
-
-LUALIB_API int luaL_getn (lua_State *L, int t) {
- int n;
- t = abs_index(L, t);
- lua_pushliteral(L, "n"); /* try t.n */
- lua_rawget(L, t);
- if ((n = checkint(L, 1)) >= 0) return n;
- getsizes(L); /* else try sizes[t] */
- lua_pushvalue(L, t);
- lua_rawget(L, -2);
- if ((n = checkint(L, 2)) >= 0) return n;
- return (int)lua_objlen(L, t);
-}
-
-#endif
-
-/* }====================================================== */
-
-
-
-LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p,
- const char *r) {
- const char *wild;
- size_t l = strlen(p);
- luaL_Buffer b;
- luaL_buffinit(L, &b);
- while ((wild = strstr(s, p)) != NULL) {
- luaL_addlstring(&b, s, wild - s); /* push prefix */
- luaL_addstring(&b, r); /* push replacement in place of pattern */
- s = wild + l; /* continue after `p' */
- }
- luaL_addstring(&b, s); /* push last suffix */
- luaL_pushresult(&b);
- return lua_tostring(L, -1);
-}
-
-
-LUALIB_API const char *luaL_findtable (lua_State *L, int idx,
- const char *fname, int szhint) {
- const char *e;
- lua_pushvalue(L, idx);
- do {
- e = strchr(fname, '.');
- if (e == NULL) e = fname + strlen(fname);
- lua_pushlstring(L, fname, e - fname);
- lua_rawget(L, -2);
- if (lua_isnil(L, -1)) { /* no such field? */
- lua_pop(L, 1); /* remove this nil */
- lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
- lua_pushlstring(L, fname, e - fname);
- lua_pushvalue(L, -2);
- lua_settable(L, -4); /* set new table into field */
- }
- else if (!lua_istable(L, -1)) { /* field has a non-table value? */
- lua_pop(L, 2); /* remove table and value */
- return fname; /* return problematic part of the name */
- }
- lua_remove(L, -2); /* remove previous table */
- fname = e + 1;
- } while (*e == '.');
- return NULL;
-}
-
-
-
-/*
-** {======================================================
-** Generic Buffer manipulation
-** =======================================================
-*/
-
-
-#define bufflen(B) ((B)->p - (B)->buffer)
-#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
-
-#define LIMIT (LUA_MINSTACK/2)
-
-
-static int emptybuffer (luaL_Buffer *B) {
- size_t l = bufflen(B);
- if (l == 0) return 0; /* put nothing on stack */
- else {
- lua_pushlstring(B->L, B->buffer, l);
- B->p = B->buffer;
- B->lvl++;
- return 1;
- }
-}
-
-
-static void adjuststack (luaL_Buffer *B) {
- if (B->lvl > 1) {
- lua_State *L = B->L;
- int toget = 1; /* number of levels to concat */
- size_t toplen = lua_strlen(L, -1);
- do {
- size_t l = lua_strlen(L, -(toget+1));
- if (B->lvl - toget + 1 >= LIMIT || toplen > l) {
- toplen += l;
- toget++;
- }
- else break;
- } while (toget < B->lvl);
- lua_concat(L, toget);
- B->lvl = B->lvl - toget + 1;
- }
-}
-
-
-LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) {
- if (emptybuffer(B))
- adjuststack(B);
- return B->buffer;
-}
-
-
-LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
- while (l--)
- luaL_addchar(B, *s++);
-}
-
-
-LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
- luaL_addlstring(B, s, strlen(s));
-}
-
-
-LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
- emptybuffer(B);
- lua_concat(B->L, B->lvl);
- B->lvl = 1;
-}
-
-
-LUALIB_API void luaL_addvalue (luaL_Buffer *B) {
- lua_State *L = B->L;
- size_t vl;
- const char *s = lua_tolstring(L, -1, &vl);
- if (vl <= bufffree(B)) { /* fit into buffer? */
- memcpy(B->p, s, vl); /* put it there */
- B->p += vl;
- lua_pop(L, 1); /* remove from stack */
- }
- else {
- if (emptybuffer(B))
- lua_insert(L, -2); /* put buffer before new value */
- B->lvl++; /* add new value into B stack */
- adjuststack(B);
- }
-}
-
-
-LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
- B->L = L;
- B->p = B->buffer;
- B->lvl = 0;
-}
-
-/* }====================================================== */
-
-
-LUALIB_API int luaL_ref (lua_State *L, int t) {
- int ref;
- t = abs_index(L, t);
- if (lua_isnil(L, -1)) {
- lua_pop(L, 1); /* remove from stack */
- return LUA_REFNIL; /* `nil' has a unique fixed reference */
- }
- lua_rawgeti(L, t, FREELIST_REF); /* get first free element */
- ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */
- lua_pop(L, 1); /* remove it from stack */
- if (ref != 0) { /* any free element? */
- lua_rawgeti(L, t, ref); /* remove it from list */
- lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */
- }
- else { /* no free elements */
- ref = (int)lua_objlen(L, t);
- ref++; /* create new reference */
- }
- lua_rawseti(L, t, ref);
- return ref;
-}
-
-
-LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
- if (ref >= 0) {
- t = abs_index(L, t);
- lua_rawgeti(L, t, FREELIST_REF);
- lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */
- lua_pushinteger(L, ref);
- lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */
- }
-}
-
-
-
-/*
-** {======================================================
-** Load functions
-** =======================================================
-*/
-
-typedef struct LoadF {
- int extraline;
- FILE *f;
- char buff[LUAL_BUFFERSIZE];
-} LoadF;
-
-
-static const char *getF (lua_State *L, void *ud, size_t *size) {
- LoadF *lf = (LoadF *)ud;
- (void)L;
- if (lf->extraline) {
- lf->extraline = 0;
- *size = 1;
- return "\n";
- }
- if (feof(lf->f)) return NULL;
- *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);
- return (*size > 0) ? lf->buff : NULL;
-}
-
-
-static int errfile (lua_State *L, const char *what, int fnameindex) {
- const char *serr = strerror(errno);
- const char *filename = lua_tostring(L, fnameindex) + 1;
- lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
- lua_remove(L, fnameindex);
- return LUA_ERRFILE;
-}
-
-
-LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {
- LoadF lf;
- int status, readstatus;
- int c;
- int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */
- lf.extraline = 0;
- if (filename == NULL) {
- lua_pushliteral(L, "=stdin");
- lf.f = stdin;
- }
- else {
- lua_pushfstring(L, "@%s", filename);
- lf.f = fopen(filename, "r");
- if (lf.f == NULL) return errfile(L, "open", fnameindex);
- }
- c = getc(lf.f);
- if (c == '#') { /* Unix exec. file? */
- lf.extraline = 1;
- while ((c = getc(lf.f)) != EOF && c != '\n') ; /* skip first line */
- if (c == '\n') c = getc(lf.f);
- }
- if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
- lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
- if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
- /* skip eventual `#!...' */
- while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0])
- {}
- lf.extraline = 0;
- }
- ungetc(c, lf.f);
- status = lua_load(L, getF, &lf, lua_tostring(L, -1));
- readstatus = ferror(lf.f);
- if (filename) fclose(lf.f); /* close file (even in case of errors) */
- if (readstatus) {
- lua_settop(L, fnameindex); /* ignore results from `lua_load' */
- return errfile(L, "read", fnameindex);
- }
- lua_remove(L, fnameindex);
- return status;
-}
-
-
-typedef struct LoadS {
- const char *s;
- size_t size;
-} LoadS;
-
-
-static const char *getS (lua_State *L, void *ud, size_t *size) {
- LoadS *ls = (LoadS *)ud;
- (void)L;
- if (ls->size == 0) return NULL;
- *size = ls->size;
- ls->size = 0;
- return ls->s;
-}
-
-
-LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size,
- const char *name) {
- LoadS ls;
- ls.s = buff;
- ls.size = size;
- return lua_load(L, getS, &ls, name);
-}
-
-
-LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) {
- return luaL_loadbuffer(L, s, strlen(s), s);
-}
-
-
-
-/* }====================================================== */
-
-
-static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
- (void)ud;
- (void)osize;
- if (nsize == 0) {
- free(ptr);
- return NULL;
- }
- else
- return realloc(ptr, nsize);
-}
-
-
-static int panic (lua_State *L) {
- (void)L; /* to avoid warnings */
- fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n",
- lua_tostring(L, -1));
- return 0;
-}
-
-
-LUALIB_API lua_State *luaL_newstate (void) {
- lua_State *L = lua_newstate(l_alloc, NULL);
- if (L) lua_atpanic(L, &panic);
- return L;
-}
-
diff --git a/src/lua/src/lauxlib.h b/src/lua/src/lauxlib.h
deleted file mode 100644
index 34258235d..000000000
--- a/src/lua/src/lauxlib.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
-** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $
-** Auxiliary functions for building Lua libraries
-** See Copyright Notice in lua.h
-*/
-
-
-#ifndef lauxlib_h
-#define lauxlib_h
-
-
-#include <stddef.h>
-#include <stdio.h>
-
-#include "lua.h"
-
-
-#if defined(LUA_COMPAT_GETN)
-LUALIB_API int (luaL_getn) (lua_State *L, int t);
-LUALIB_API void (luaL_setn) (lua_State *L, int t, int n);
-#else
-#define luaL_getn(L,i) ((int)lua_objlen(L, i))
-#define luaL_setn(L,i,j) ((void)0) /* no op! */
-#endif
-
-#if defined(LUA_COMPAT_OPENLIB)
-#define luaI_openlib luaL_openlib
-#endif
-
-
-/* extra error code for `luaL_load' */
-#define LUA_ERRFILE (LUA_ERRERR+1)
-
-
-typedef struct luaL_Reg {
- const char *name;
- lua_CFunction func;
-} luaL_Reg;
-
-
-
-LUALIB_API void (luaI_openlib) (lua_State *L, const char *libname,
- const luaL_Reg *l, int nup);
-LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
- const luaL_Reg *l);
-LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
-LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
-LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname);
-LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
-LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
- size_t *l);
-LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
- const char *def, size_t *l);
-LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
-LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);
-
-LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
-LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
- lua_Integer def);
-
-LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
-LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
-LUALIB_API void (luaL_checkany) (lua_State *L, int narg);
-
-LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
-LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
-
-LUALIB_API void (luaL_where) (lua_State *L, int lvl);
-LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
-
-LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
- const char *const lst[]);
-
-LUALIB_API int (luaL_ref) (lua_State *L, int t);
-LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
-
-LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename);
-LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz,
- const char *name);
-LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
-
-LUALIB_API lua_State *(luaL_newstate) (void);
-
-
-LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
- const char *r);
-
-LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx,
- const char *fname, int szhint);
-
-
-
-
-/*
-** ===============================================================
-** some useful macros
-** ===============================================================
-*/
-
-#define luaL_argcheck(L, cond,numarg,extramsg) \
- ((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
-#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
-#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
-#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
-#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
-#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
-#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
-
-#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
-
-#define luaL_dofile(L, fn) \
- (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
-
-#define luaL_dostring(L, s) \
- (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
-
-#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
-
-#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
-
-/*
-** {======================================================
-** Generic Buffer manipulation
-** =======================================================
-*/
-
-
-
-typedef struct luaL_Buffer {
- char *p; /* current position in buffer */
- int lvl; /* number of strings in the stack (level) */
- lua_State *L;
- char buffer[LUAL_BUFFERSIZE];
-} luaL_Buffer;
-
-#define luaL_addchar(B,c) \
- ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
- (*(B)->p++ = (char)(c)))
-
-/* compatibility only */
-#define luaL_putchar(B,c) luaL_addchar(B,c)
-
-#define luaL_addsize(B,n) ((B)->p += (n))
-
-LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
-LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B);
-LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
-LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
-LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
-LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
-
-
-/* }====================================================== */
-
-
-/* compatibility with ref system */
-
-/* pre-defined references */
-#define LUA_NOREF (-2)
-#define LUA_REFNIL (-1)
-
-#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \
- (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0))
-
-#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref))
-
-#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref))
-
-
-#define luaL_reg luaL_Reg
-
-#endif
-
-
diff --git a/src/lua/src/lbaselib.c b/src/lua/src/lbaselib.c
deleted file mode 100644
index 2a4c079d3..000000000
--- a/src/lua/src/lbaselib.c
+++ /dev/null
@@ -1,653 +0,0 @@
-/*
-** $Id: lbaselib.c,v 1.191.1.6 2008/02/14 16:46:22 roberto Exp $
-** Basic library
-** See Copyright Notice in lua.h
-*/
-
-
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define lbaselib_c
-#define LUA_LIB
-
-#include "lua.h"
-
-#include "lauxlib.h"
-#include "lualib.h"
-
-
-
-
-/*
-** If your system does not support `stdout', you can just remove this function.
-** If you need, you can define your own `print' function, following this
-** model but changing `fputs' to put the strings at a proper place
-** (a console window or a log file, for instance).
-*/
-static int luaB_print (lua_State *L) {
- int n = lua_gettop(L); /* number of arguments */
- int i;
- lua_getglobal(L, "tostring");
- for (i=1; i<=n; i++) {
- const char *s;
- lua_pushvalue(L, -1); /* function to be called */
- lua_pushvalue(L, i); /* value to print */
- lua_call(L, 1, 1);
- s = lua_tostring(L, -1); /* get result */
- if (s == NULL)
- return luaL_error(L, LUA_QL("tostring") " must return a string to "
- LUA_QL("print"));
- if (i>1) fputs("\t", stdout);
- fputs(s, stdout);
- lua_pop(L, 1); /* pop result */
- }
- fputs("\n", stdout);
- return 0;
-}
-
-
-static int luaB_tonumber (lua_State *L) {
- int base = luaL_optint(L, 2, 10);
- if (base == 10) { /* standard conversion */
- luaL_checkany(L, 1);
- if (lua_isnumber(L, 1)) {
- lua_pushnumber(L, lua_tonumber(L, 1));
- return 1;
- }
- }
- else {
- const char *s1 = luaL_checkstring(L, 1);
- char *s2;
- unsigned long n;
- luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
- n = strtoul(s1, &s2, base);
- if (s1 != s2) { /* at least one valid digit? */
- while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */
- if (*s2 == '\0') { /* no invalid trailing characters? */
- lua_pushnumber(L, (lua_Number)n);
- return 1;
- }
- }
- }
- lua_pushnil(L); /* else not a number */
- return 1;
-}
-
-
-static int luaB_error (lua_State *L) {
- int level = luaL_optint(L, 2, 1);
- lua_settop(L, 1);
- if (lua_isstring(L, 1) && level > 0) { /* add extra information? */
- luaL_where(L, level);
- lua_pushvalue(L, 1);
- lua_concat(L, 2);
- }
- return lua_error(L);
-}
-
-
-static int luaB_getmetatable (lua_State *L) {
- luaL_checkany(L, 1);
- if (!lua_getmetatable(L, 1)) {
- lua_pushnil(L);
- return 1; /* no metatable */
- }
- luaL_getmetafield(L, 1, "__metatable");
- return 1; /* returns either __metatable field (if present) or metatable */
-}
-
-
-static int luaB_setmetatable (lua_State *L) {
- int t = lua_type(L, 2);
- luaL_checktype(L, 1, LUA_TTABLE);
- luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
- "nil or table expected");
- if (luaL_getmetafield(L, 1, "__metatable"))
- luaL_error(L, "cannot change a protected metatable");
- lua_settop(L, 2);
- lua_setmetatable(L, 1);
- return 1;
-}
-
-
-static void getfunc (lua_State *L, int opt) {
- if (lua_isfunction(L, 1)) lua_pushvalue(L, 1);
- else {
- lua_Debug ar;
- int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1);
- luaL_argcheck(L, level >= 0, 1, "level must be non-negative");
- if (lua_getstack(L, level, &ar) == 0)
- luaL_argerror(L, 1, "invalid level");
- lua_getinfo(L, "f", &ar);
- if (lua_isnil(L, -1))
- luaL_error(L, "no function environment for tail call at level %d",
- level);
- }
-}
-
-
-static int luaB_getfenv (lua_State *L) {
- getfunc(L, 1);
- if (lua_iscfunction(L, -1)) /* is a C function? */
- lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */
- else
- lua_getfenv(L, -1);
- return 1;
-}
-
-
-static int luaB_setfenv (lua_State *L) {
- luaL_checktype(L, 2, LUA_TTABLE);
- getfunc(L, 0);
- lua_pushvalue(L, 2);
- if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) {
- /* change environment of current thread */
- lua_pushthread(L);
- lua_insert(L, -2);
- lua_setfenv(L, -2);
- return 0;
- }
- else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0)
- luaL_error(L,
- LUA_QL("setfenv") " cannot change environment of given object");
- return 1;
-}
-
-
-static int luaB_rawequal (lua_State *L) {
- luaL_checkany(L, 1);
- luaL_checkany(L, 2);
- lua_pushboolean(L, lua_rawequal(L, 1, 2));
- return 1;
-}
-
-
-static int luaB_rawget (lua_State *L) {
- luaL_checktype(L, 1, LUA_TTABLE);
- luaL_checkany(L, 2);
- lua_settop(L, 2);
- lua_rawget(L, 1);
- return 1;
-}
-
-static int luaB_rawset (lua_State *L) {
- luaL_checktype(L, 1, LUA_TTABLE);
- luaL_checkany(L, 2);
- luaL_checkany(L, 3);
- lua_settop(L, 3);
- lua_rawset(L, 1);
- return 1;
-}
-
-
-static int luaB_gcinfo (lua_State *L) {
- lua_pushinteger(L, lua_getgccount(L));
- return 1;
-}
-
-
-static int luaB_collectgarbage (lua_State *L) {
- static const char *const opts[] = {"stop", "restart", "collect",
- "count", "step", "setpause", "setstepmul", NULL};
- static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
- LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL};
- int o = luaL_checkoption(L, 1, "collect", opts);
- int ex = luaL_optint(L, 2, 0);
- int res = lua_gc(L, optsnum[o], ex);
- switch (optsnum[o]) {
- case LUA_GCCOUNT: {
- int b = lua_gc(L, LUA_GCCOUNTB, 0);
- lua_pushnumber(L, res + ((lua_Number)b/1024));
- return 1;
- }
- case LUA_GCSTEP: {
- lua_pushboolean(L, res);
- return 1;
- }
- default: {
- lua_pushnumber(L, res);
- return 1;
- }
- }
-}
-
-
-static int luaB_type (lua_State *L) {
- luaL_checkany(L, 1);
- lua_pushstring(L, luaL_typename(L, 1));
- return 1;
-}
-
-
-static int luaB_next (lua_State *L) {
- luaL_checktype(L, 1, LUA_TTABLE);
- lua_settop(L, 2); /* create a 2nd argument if there isn't one */
- if (lua_next(L, 1))
- return 2;
- else {
- lua_pushnil(L);
- return 1;
- }
-}
-
-
-static int luaB_pairs (lua_State *L) {
- luaL_checktype(L, 1, LUA_TTABLE);
- lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
- lua_pushvalue(L, 1); /* state, */
- lua_pushnil(L); /* and initial value */
- return 3;
-}
-
-
-static int ipairsaux (lua_State *L) {
- int i = luaL_checkint(L, 2);
- luaL_checktype(L, 1, LUA_TTABLE);
- i++; /* next value */
- lua_pushinteger(L, i);
- lua_rawgeti(L, 1, i);
- return (lua_isnil(L, -1)) ? 0 : 2;
-}
-
-
-static int luaB_ipairs (lua_State *L) {
- luaL_checktype(L, 1, LUA_TTABLE);
- lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
- lua_pushvalue(L, 1); /* state, */
- lua_pushinteger(L, 0); /* and initial value */
- return 3;
-}
-
-
-static int load_aux (lua_State *L, int status) {
- if (status == 0) /* OK? */
- return 1;
- else {
- lua_pushnil(L);
- lua_insert(L, -2); /* put before error message */
- return 2; /* return nil plus error message */
- }
-}
-
-
-static int luaB_loadstring (lua_State *L) {
- size_t l;
- const char *s = luaL_checklstring(L, 1, &l);
- const char *chunkname = luaL_optstring(L, 2, s);
- return load_aux(L, luaL_loadbuffer(L, s, l, chunkname));
-}
-
-
-static int luaB_loadfile (lua_State *L) {
- const char *fname = luaL_optstring(L, 1, NULL);
- return load_aux(L, luaL_loadfile(L, fname));
-}
-
-
-/*
-** Reader for generic `load' function: `lua_load' uses the
-** stack for internal stuff, so the reader cannot change the
-** stack top. Instead, it keeps its resulting string in a
-** reserved slot inside the stack.
-*/
-static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
- (void)ud; /* to avoid warnings */
- luaL_checkstack(L, 2, "too many nested functions");
- lua_pushvalue(L, 1); /* get function */
- lua_call(L, 0, 1); /* call it */
- if (lua_isnil(L, -1)) {
- *size = 0;
- return NULL;
- }
- else if (lua_isstring(L, -1)) {
- lua_replace(L, 3); /* save string in a reserved stack slot */
- return lua_tolstring(L, 3, size);
- }
- else luaL_error(L, "reader function must return a string");
- return NULL; /* to avoid warnings */
-}
-
-
-static int luaB_load (lua_State *L) {
- int status;
- const char *cname = luaL_optstring(L, 2, "=(load)");
- luaL_checktype(L, 1, LUA_TFUNCTION);
- lua_settop(L, 3); /* function, eventual name, plus one reserved slot */
- status = lua_load(L, generic_reader, NULL, cname);
- return load_aux(L, status);
-}
-
-
-static int luaB_dofile (lua_State *L) {
- const char *fname = luaL_optstring(L, 1, NULL);
- int n = lua_gettop(L);
- if (luaL_loadfile(L, fname) != 0) lua_error(L);
- lua_call(L, 0, LUA_MULTRET);
- return lua_gettop(L) - n;
-}
-
-
-static int luaB_assert (lua_State *L) {
- luaL_checkany(L, 1);
- if (!lua_toboolean(L, 1))
- return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!"));
- return lua_gettop(L);
-}
-
-
-static int luaB_unpack (lua_State *L) {
- int i, e, n;
- luaL_checktype(L, 1, LUA_TTABLE);
- i = luaL_optint(L, 2, 1);
- e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1));
- if (i > e) return 0; /* empty range */
- n = e - i + 1; /* number of elements */
- if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */
- return luaL_error(L, "too many results to unpack");
- lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */
- while (i++ < e) /* push arg[i + 1...e] */
- lua_rawgeti(L, 1, i);
- return n;
-}
-
-
-static int luaB_select (lua_State *L) {
- int n = lua_gettop(L);
- if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') {
- lua_pushinteger(L, n-1);
- return 1;
- }
- else {
- int i = luaL_checkint(L, 1);
- if (i < 0) i = n + i;
- else if (i > n) i = n;
- luaL_argcheck(L, 1 <= i, 1, "index out of range");
- return n - i;
- }
-}
-
-
-static int luaB_pcall (lua_State *L) {
- int status;
- luaL_checkany(L, 1);
- status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0);
- lua_pushboolean(L, (status == 0));
- lua_insert(L, 1);
- return lua_gettop(L); /* return status + all results */
-}
-
-
-static int luaB_xpcall (lua_State *L) {
- int status;
- luaL_checkany(L, 2);
- lua_settop(L, 2);
- lua_insert(L, 1); /* put error function under function to be called */
- status = lua_pcall(L, 0, LUA_MULTRET, 1);
- lua_pushboolean(L, (status == 0));
- lua_replace(L, 1);
- return lua_gettop(L); /* return status + all results */
-}
-
-
-static int luaB_tostring (lua_State *L) {
- luaL_checkany(L, 1);
- if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */
- return 1; /* use its value */
- switch (lua_type(L, 1)) {
- case LUA_TNUMBER:
- lua_pushstring(L, lua_tostring(L, 1));
- break;
- case LUA_TSTRING:
- lua_pushvalue(L, 1);
- break;
- case LUA_TBOOLEAN:
- lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false"));
- break;
- case LUA_TNIL:
- lua_pushliteral(L, "nil");
- break;
- default:
- lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1));
- break;
- }
- return 1;
-}
-
-
-static int luaB_newproxy (lua_State *L) {
- lua_settop(L, 1);
- lua_newuserdata(L, 0); /* create proxy */
- if (lua_toboolean(L, 1) == 0)
- return 1; /* no metatable */
- else if (lua_isboolean(L, 1)) {
- lua_newtable(L); /* create a new metatable `m' ... */
- lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */
- lua_pushboolean(L, 1);
- lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */
- }
- else {
- int validproxy = 0; /* to check if weaktable[metatable(u)] == true */
- if (lua_getmetatable(L, 1)) {
- lua_rawget(L, lua_upvalueindex(1));
- validproxy = lua_toboolean(L, -1);
- lua_pop(L, 1); /* remove value */
- }
- luaL_argcheck(L, validproxy, 1, "boolean or proxy expected");
- lua_getmetatable(L, 1); /* metatable is valid; get it */
- }
- lua_setmetatable(L, 2);
- return 1;
-}
-
-
-static const luaL_Reg base_funcs[] = {
- {"assert", luaB_assert},
- {"collectgarbage", luaB_collectgarbage},
- {"dofile", luaB_dofile},
- {"error", luaB_error},
- {"gcinfo", luaB_gcinfo},
- {"getfenv", luaB_getfenv},
- {"getmetatable", luaB_getmetatable},
- {"loadfile", luaB_loadfile},
- {"load", luaB_load},
- {"loadstring", luaB_loadstring},
- {"next", luaB_next},
- {"pcall", luaB_pcall},
- {"print", luaB_print},
- {"rawequal", luaB_rawequal},
- {"rawget", luaB_rawget},
- {"rawset", luaB_rawset},
- {"select", luaB_select},
- {"setfenv", luaB_setfenv},
- {"setmetatable", luaB_setmetatable},
- {"tonumber", luaB_tonumber},
- {"tostring", luaB_tostring},
- {"type", luaB_type},
- {"unpack", luaB_unpack},
- {"xpcall", luaB_xpcall},
- {NULL, NULL}
-};
-
-
-/*
-** {======================================================
-** Coroutine library
-** =======================================================
-*/
-
-#define CO_RUN 0 /* running */
-#define CO_SUS 1 /* suspended */
-#define CO_NOR 2 /* 'normal' (it resumed another coroutine) */
-#define CO_DEAD 3
-
-static const char *const statnames[] =
- {"running", "suspended", "normal", "dead"};
-
-static int costatus (lua_State *L, lua_State *co) {
- if (L == co) return CO_RUN;
- switch (lua_status(co)) {
- case LUA_YIELD:
- return CO_SUS;
- case 0: {
- lua_Debug ar;
- if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */
- return CO_NOR; /* it is running */
- else if (lua_gettop(co) == 0)
- return CO_DEAD;
- else
- return CO_SUS; /* initial state */
- }
- default: /* some error occured */
- return CO_DEAD;
- }
-}
-
-
-static int luaB_costatus (lua_State *L) {
- lua_State *co = lua_tothread(L, 1);
- luaL_argcheck(L, co, 1, "coroutine expected");
- lua_pushstring(L, statnames[costatus(L, co)]);
- return 1;
-}
-
-
-static int auxresume (lua_State *L, lua_State *co, int narg) {
- int status = costatus(L, co);
- if (!lua_checkstack(co, narg))
- luaL_error(L, "too many arguments to resume");
- if (status != CO_SUS) {
- lua_pushfstring(L, "cannot resume %s coroutine", statnames[status]);
- return -1; /* error flag */
- }
- lua_xmove(L, co, narg);
- lua_setlevel(L, co);
- status = lua_resume(co, narg);
- if (status == 0 || status == LUA_YIELD) {
- int nres = lua_gettop(co);
- if (!lua_checkstack(L, nres + 1))
- luaL_error(L, "too many results to resume");
- lua_xmove(co, L, nres); /* move yielded values */
- return nres;
- }
- else {
- lua_xmove(co, L, 1); /* move error message */
- return -1; /* error flag */
- }
-}
-
-
-static int luaB_coresume (lua_State *L) {
- lua_State *co = lua_tothread(L, 1);
- int r;
- luaL_argcheck(L, co, 1, "coroutine expected");
- r = auxresume(L, co, lua_gettop(L) - 1);
- if (r < 0) {
- lua_pushboolean(L, 0);
- lua_insert(L, -2);
- return 2; /* return false + error message */
- }
- else {
- lua_pushboolean(L, 1);
- lua_insert(L, -(r + 1));
- return r + 1; /* return true + `resume' returns */
- }
-}
-
-
-static int luaB_auxwrap (lua_State *L) {
- lua_State *co = lua_tothread(L, lua_upvalueindex(1));
- int r = auxresume(L, co, lua_gettop(L));
- if (r < 0) {
- if (lua_isstring(L, -1)) { /* error object is a string? */
- luaL_where(L, 1); /* add extra info */
- lua_insert(L, -2);
- lua_concat(L, 2);
- }
- lua_error(L); /* propagate error */
- }
- return r;
-}
-
-
-static int luaB_cocreate (lua_State *L) {
- lua_State *NL = lua_newthread(L);
- luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
- "Lua function expected");
- lua_pushvalue(L, 1); /* move function to top */
- lua_xmove(L, NL, 1); /* move function from L to NL */
- return 1;
-}
-
-
-static int luaB_cowrap (lua_State *L) {
- luaB_cocreate(L);
- lua_pushcclosure(L, luaB_auxwrap, 1);
- return 1;
-}
-
-
-static int luaB_yield (lua_State *L) {
- return lua_yield(L, lua_gettop(L));
-}
-
-
-static int luaB_corunning (lua_State *L) {
- if (lua_pushthread(L))
- lua_pushnil(L); /* main thread is not a coroutine */
- return 1;
-}
-
-
-static const luaL_Reg co_funcs[] = {
- {"create", luaB_cocreate},
- {"resume", luaB_coresume},
- {"running", luaB_corunning},
- {"status", luaB_costatus},
- {"wrap", luaB_cowrap},
- {"yield", luaB_yield},
- {NULL, NULL}
-};
-
-/* }====================================================== */
-
-
-static void auxopen (lua_State *L, const char *name,
- lua_CFunction f, lua_CFunction u) {
- lua_pushcfunction(L, u);
- lua_pushcclosure(L, f, 1);
- lua_setfield(L, -2, name);
-}
-
-
-static void base_open (lua_State *L) {
- /* set global _G */
- lua_pushvalue(L, LUA_GLOBALSINDEX);
- lua_setglobal(L, "_G");
- /* open lib into global table */
- luaL_register(L, "_G", base_funcs);
- lua_pushliteral(L, LUA_VERSION);
- lua_setglobal(L, "_VERSION"); /* set global _VERSION */
- /* `ipairs' and `pairs' need auxliliary functions as upvalues */
- auxopen(L, "ipairs", luaB_ipairs, ipairsaux);
- auxopen(L, "pairs", luaB_pairs, luaB_next);
- /* `newproxy' needs a weaktable as upvalue */
- lua_createtable(L, 0, 1); /* new table `w' */
- lua_pushvalue(L, -1); /* `w' will be its own metatable */
- lua_setmetatable(L, -2);
- lua_pushliteral(L, "kv");
- lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */
- lua_pushcclosure(L, luaB_newproxy, 1);
- lua_setglobal(L, "newproxy"); /* set global `newproxy' */
-}
-
-
-LUALIB_API int luaopen_base (lua_State *L) {
- base_open(L);
- luaL_register(L, LUA_COLIBNAME, co_funcs);
- return 2;
-}
-
diff --git a/src/lua/src/lcode.c b/src/lua/src/lcode.c
deleted file mode 100644
index cff626b7f..000000000
--- a/src/lua/src/lcode.c
+++ /dev/null
@@ -1,839 +0,0 @@
-/*
-** $Id: lcode.c,v 2.25.1.3 2007/12/28 15:32:23 roberto Exp $
-** Code generator for Lua
-** See Copyright Notice in lua.h
-*/
-
-
-#include <stdlib.h>
-
-#define lcode_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "lcode.h"
-#include "ldebug.h"
-#include "ldo.h"
-#include "lgc.h"
-#include "llex.h"
-#include "lmem.h"
-#include "lobject.h"
-#include "lopcodes.h"
-#include "lparser.h"
-#include "ltable.h"
-
-
-#define hasjumps(e) ((e)->t != (e)->f)
-
-
-static int isnumeral(expdesc *e) {
- return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
-}
-
-
-void luaK_nil (FuncState *fs, int from, int n) {
- Instruction *previous;
- if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
- if (fs->pc == 0) { /* function start? */
- if (from >= fs->nactvar)
- return; /* positions are already clean */
- }
- else {
- previous = &fs->f->code[fs->pc-1];
- if (GET_OPCODE(*previous) == OP_LOADNIL) {
- int pfrom = GETARG_A(*previous);
- int pto = GETARG_B(*previous);
- if (pfrom <= from && from <= pto+1) { /* can connect both? */
- if (from+n-1 > pto)
- SETARG_B(*previous, from+n-1);
- return;
- }
- }
- }
- }
- luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */
-}
-
-
-int luaK_jump (FuncState *fs) {
- int jpc = fs->jpc; /* save list of jumps to here */
- int j;
- fs->jpc = NO_JUMP;
- j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
- luaK_concat(fs, &j, jpc); /* keep them on hold */
- return j;
-}
-
-
-void luaK_ret (FuncState *fs, int first, int nret) {
- luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
-}
-
-
-static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
- luaK_codeABC(fs, op, A, B, C);
- return luaK_jump(fs);
-}
-
-
-static void fixjump (FuncState *fs, int pc, int dest) {
- Instruction *jmp = &fs->f->code[pc];
- int offset = dest-(pc+1);
- lua_assert(dest != NO_JUMP);
- if (abs(offset) > MAXARG_sBx)
- luaX_syntaxerror(fs->ls, "control structure too long");
- SETARG_sBx(*jmp, offset);
-}
-
-
-/*
-** returns current `pc' and marks it as a jump target (to avoid wrong
-** optimizations with consecutive instructions not in the same basic block).
-*/
-int luaK_getlabel (FuncState *fs) {
- fs->lasttarget = fs->pc;
- return fs->pc;
-}
-
-
-static int getjump (FuncState *fs, int pc) {
- int offset = GETARG_sBx(fs->f->code[pc]);
- if (offset == NO_JUMP) /* point to itself represents end of list */
- return NO_JUMP; /* end of list */
- else
- return (pc+1)+offset; /* turn offset into absolute position */
-}
-
-
-static Instruction *getjumpcontrol (FuncState *fs, int pc) {
- Instruction *pi = &fs->f->code[pc];
- if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
- return pi-1;
- else
- return pi;
-}
-
-
-/*
-** check whether list has any jump that do not produce a value
-** (or produce an inverted value)
-*/
-static int need_value (FuncState *fs, int list) {
- for (; list != NO_JUMP; list = getjump(fs, list)) {
- Instruction i = *getjumpcontrol(fs, list);
- if (GET_OPCODE(i) != OP_TESTSET) return 1;
- }
- return 0; /* not found */
-}
-
-
-static int patchtestreg (FuncState *fs, int node, int reg) {
- Instruction *i = getjumpcontrol(fs, node);
- if (GET_OPCODE(*i) != OP_TESTSET)
- return 0; /* cannot patch other instructions */
- if (reg != NO_REG && reg != GETARG_B(*i))
- SETARG_A(*i, reg);
- else /* no register to put value or register already has the value */
- *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
-
- return 1;
-}
-
-
-static void removevalues (FuncState *fs, int list) {
- for (; list != NO_JUMP; list = getjump(fs, list))
- patchtestreg(fs, list, NO_REG);
-}
-
-
-static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
- int dtarget) {
- while (list != NO_JUMP) {
- int next = getjump(fs, list);
- if (patchtestreg(fs, list, reg))
- fixjump(fs, list, vtarget);
- else
- fixjump(fs, list, dtarget); /* jump to default target */
- list = next;
- }
-}
-
-
-static void dischargejpc (FuncState *fs) {
- patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
- fs->jpc = NO_JUMP;
-}
-
-
-void luaK_patchlist (FuncState *fs, int list, int target) {
- if (target == fs->pc)
- luaK_patchtohere(fs, list);
- else {
- lua_assert(target < fs->pc);
- patchlistaux(fs, list, target, NO_REG, target);
- }
-}
-
-
-void luaK_patchtohere (FuncState *fs, int list) {
- luaK_getlabel(fs);
- luaK_concat(fs, &fs->jpc, list);
-}
-
-
-void luaK_concat (FuncState *fs, int *l1, int l2) {
- if (l2 == NO_JUMP) return;
- else if (*l1 == NO_JUMP)
- *l1 = l2;
- else {
- int list = *l1;
- int next;
- while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */
- list = next;
- fixjump(fs, list, l2);
- }
-}
-
-
-void luaK_checkstack (FuncState *fs, int n) {
- int newstack = fs->freereg + n;
- if (newstack > fs->f->maxstacksize) {
- if (newstack >= MAXSTACK)
- luaX_syntaxerror(fs->ls, "function or expression too complex");
- fs->f->maxstacksize = cast_byte(newstack);
- }
-}
-
-
-void luaK_reserveregs (FuncState *fs, int n) {
- luaK_checkstack(fs, n);
- fs->freereg += n;
-}
-
-
-static void freereg (FuncState *fs, int reg) {
- if (!ISK(reg) && reg >= fs->nactvar) {
- fs->freereg--;
- lua_assert(reg == fs->freereg);
- }
-}
-
-
-static void freeexp (FuncState *fs, expdesc *e) {
- if (e->k == VNONRELOC)
- freereg(fs, e->u.s.info);
-}
-
-
-static int addk (FuncState *fs, TValue *k, TValue *v) {
- lua_State *L = fs->L;
- TValue *idx = luaH_set(L, fs->h, k);
- Proto *f = fs->f;
- int oldsize = f->sizek;
- if (ttisnumber(idx)) {
- lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v));
- return cast_int(nvalue(idx));
- }
- else { /* constant not found; create a new entry */
- setnvalue(idx, cast_num(fs->nk));
- luaM_growvector(L, f->k, fs->nk, f->sizek, TValue,
- MAXARG_Bx, "constant table overflow");
- while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
- setobj(L, &f->k[fs->nk], v);
- luaC_barrier(L, f, v);
- return fs->nk++;
- }
-}
-
-
-int luaK_stringK (FuncState *fs, TString *s) {
- TValue o;
- setsvalue(fs->L, &o, s);
- return addk(fs, &o, &o);
-}
-
-
-int luaK_numberK (FuncState *fs, lua_Number r) {
- TValue o;
- setnvalue(&o, r);
- return addk(fs, &o, &o);
-}
-
-
-static int boolK (FuncState *fs, int b) {
- TValue o;
- setbvalue(&o, b);
- return addk(fs, &o, &o);
-}
-
-
-static int nilK (FuncState *fs) {
- TValue k, v;
- setnilvalue(&v);
- /* cannot use nil as key; instead use table itself to represent nil */
- sethvalue(fs->L, &k, fs->h);
- return addk(fs, &k, &v);
-}
-
-
-void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
- if (e->k == VCALL) { /* expression is an open function call? */
- SETARG_C(getcode(fs, e), nresults+1);
- }
- else if (e->k == VVARARG) {
- SETARG_B(getcode(fs, e), nresults+1);
- SETARG_A(getcode(fs, e), fs->freereg);
- luaK_reserveregs(fs, 1);
- }
-}
-
-
-void luaK_setoneret (FuncState *fs, expdesc *e) {
- if (e->k == VCALL) { /* expression is an open function call? */
- e->k = VNONRELOC;
- e->u.s.info = GETARG_A(getcode(fs, e));
- }
- else if (e->k == VVARARG) {
- SETARG_B(getcode(fs, e), 2);
- e->k = VRELOCABLE; /* can relocate its simple result */
- }
-}
-
-
-void luaK_dischargevars (FuncState *fs, expdesc *e) {
- switch (e->k) {
- case VLOCAL: {
- e->k = VNONRELOC;
- break;
- }
- case VUPVAL: {
- e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0);
- e->k = VRELOCABLE;
- break;
- }
- case VGLOBAL: {
- e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info);
- e->k = VRELOCABLE;
- break;
- }
- case VINDEXED: {
- freereg(fs, e->u.s.aux);
- freereg(fs, e->u.s.info);
- e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux);
- e->k = VRELOCABLE;
- break;
- }
- case VVARARG:
- case VCALL: {
- luaK_setoneret(fs, e);
- break;
- }
- default: break; /* there is one value available (somewhere) */
- }
-}
-
-
-static int code_label (FuncState *fs, int A, int b, int jump) {
- luaK_getlabel(fs); /* those instructions may be jump targets */
- return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
-}
-
-
-static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
- luaK_dischargevars(fs, e);
- switch (e->k) {
- case VNIL: {
- luaK_nil(fs, reg, 1);
- break;
- }
- case VFALSE: case VTRUE: {
- luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
- break;
- }
- case VK: {
- luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info);
- break;
- }
- case VKNUM: {
- luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval));
- break;
- }
- case VRELOCABLE: {
- Instruction *pc = &getcode(fs, e);
- SETARG_A(*pc, reg);
- break;
- }
- case VNONRELOC: {
- if (reg != e->u.s.info)
- luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0);
- break;
- }
- default: {
- lua_assert(e->k == VVOID || e->k == VJMP);
- return; /* nothing to do... */
- }
- }
- e->u.s.info = reg;
- e->k = VNONRELOC;
-}
-
-
-static void discharge2anyreg (FuncState *fs, expdesc *e) {
- if (e->k != VNONRELOC) {
- luaK_reserveregs(fs, 1);
- discharge2reg(fs, e, fs->freereg-1);
- }
-}
-
-
-static void exp2reg (FuncState *fs, expdesc *e, int reg) {
- discharge2reg(fs, e, reg);
- if (e->k == VJMP)
- luaK_concat(fs, &e->t, e->u.s.info); /* put this jump in `t' list */
- if (hasjumps(e)) {
- int final; /* position after whole expression */
- int p_f = NO_JUMP; /* position of an eventual LOAD false */
- int p_t = NO_JUMP; /* position of an eventual LOAD true */
- if (need_value(fs, e->t) || need_value(fs, e->f)) {
- int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
- p_f = code_label(fs, reg, 0, 1);
- p_t = code_label(fs, reg, 1, 0);
- luaK_patchtohere(fs, fj);
- }
- final = luaK_getlabel(fs);
- patchlistaux(fs, e->f, final, reg, p_f);
- patchlistaux(fs, e->t, final, reg, p_t);
- }
- e->f = e->t = NO_JUMP;
- e->u.s.info = reg;
- e->k = VNONRELOC;
-}
-
-
-void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
- luaK_dischargevars(fs, e);
- freeexp(fs, e);
- luaK_reserveregs(fs, 1);
- exp2reg(fs, e, fs->freereg - 1);
-}
-
-
-int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
- luaK_dischargevars(fs, e);
- if (e->k == VNONRELOC) {
- if (!hasjumps(e)) return e->u.s.info; /* exp is already in a register */
- if (e->u.s.info >= fs->nactvar) { /* reg. is not a local? */
- exp2reg(fs, e, e->u.s.info); /* put value on it */
- return e->u.s.info;
- }
- }
- luaK_exp2nextreg(fs, e); /* default */
- return e->u.s.info;
-}
-
-
-void luaK_exp2val (FuncState *fs, expdesc *e) {
- if (hasjumps(e))
- luaK_exp2anyreg(fs, e);
- else
- luaK_dischargevars(fs, e);
-}
-
-
-int luaK_exp2RK (FuncState *fs, expdesc *e) {
- luaK_exp2val(fs, e);
- switch (e->k) {
- case VKNUM:
- case VTRUE:
- case VFALSE:
- case VNIL: {
- if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */
- e->u.s.info = (e->k == VNIL) ? nilK(fs) :
- (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) :
- boolK(fs, (e->k == VTRUE));
- e->k = VK;
- return RKASK(e->u.s.info);
- }
- else break;
- }
- case VK: {
- if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */
- return RKASK(e->u.s.info);
- else break;
- }
- default: break;
- }
- /* not a constant in the right range: put it in a register */
- return luaK_exp2anyreg(fs, e);
-}
-
-
-void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
- switch (var->k) {
- case VLOCAL: {
- freeexp(fs, ex);
- exp2reg(fs, ex, var->u.s.info);
- return;
- }
- case VUPVAL: {
- int e = luaK_exp2anyreg(fs, ex);
- luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0);
- break;
- }
- case VGLOBAL: {
- int e = luaK_exp2anyreg(fs, ex);
- luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info);
- break;
- }
- case VINDEXED: {
- int e = luaK_exp2RK(fs, ex);
- luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e);
- break;
- }
- default: {
- lua_assert(0); /* invalid var kind to store */
- break;
- }
- }
- freeexp(fs, ex);
-}
-
-
-void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
- int func;
- luaK_exp2anyreg(fs, e);
- freeexp(fs, e);
- func = fs->freereg;
- luaK_reserveregs(fs, 2);
- luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key));
- freeexp(fs, key);
- e->u.s.info = func;
- e->k = VNONRELOC;
-}
-
-
-static void invertjump (FuncState *fs, expdesc *e) {
- Instruction *pc = getjumpcontrol(fs, e->u.s.info);
- lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
- GET_OPCODE(*pc) != OP_TEST);
- SETARG_A(*pc, !(GETARG_A(*pc)));
-}
-
-
-static int jumponcond (FuncState *fs, expdesc *e, int cond) {
- if (e->k == VRELOCABLE) {
- Instruction ie = getcode(fs, e);
- if (GET_OPCODE(ie) == OP_NOT) {
- fs->pc--; /* remove previous OP_NOT */
- return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
- }
- /* else go through */
- }
- discharge2anyreg(fs, e);
- freeexp(fs, e);
- return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond);
-}
-
-
-void luaK_goiftrue (FuncState *fs, expdesc *e) {
- int pc; /* pc of last jump */
- luaK_dischargevars(fs, e);
- switch (e->k) {
- case VK: case VKNUM: case VTRUE: {
- pc = NO_JUMP; /* always true; do nothing */
- break;
- }
- case VFALSE: {
- pc = luaK_jump(fs); /* always jump */
- break;
- }
- case VJMP: {
- invertjump(fs, e);
- pc = e->u.s.info;
- break;
- }
- default: {
- pc = jumponcond(fs, e, 0);
- break;
- }
- }
- luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */
- luaK_patchtohere(fs, e->t);
- e->t = NO_JUMP;
-}
-
-
-static void luaK_goiffalse (FuncState *fs, expdesc *e) {
- int pc; /* pc of last jump */
- luaK_dischargevars(fs, e);
- switch (e->k) {
- case VNIL: case VFALSE: {
- pc = NO_JUMP; /* always false; do nothing */
- break;
- }
- case VTRUE: {
- pc = luaK_jump(fs); /* always jump */
- break;
- }
- case VJMP: {
- pc = e->u.s.info;
- break;
- }
- default: {
- pc = jumponcond(fs, e, 1);
- break;
- }
- }
- luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */
- luaK_patchtohere(fs, e->f);
- e->f = NO_JUMP;
-}
-
-
-static void codenot (FuncState *fs, expdesc *e) {
- luaK_dischargevars(fs, e);
- switch (e->k) {
- case VNIL: case VFALSE: {
- e->k = VTRUE;
- break;
- }
- case VK: case VKNUM: case VTRUE: {
- e->k = VFALSE;
- break;
- }
- case VJMP: {
- invertjump(fs, e);
- break;
- }
- case VRELOCABLE:
- case VNONRELOC: {
- discharge2anyreg(fs, e);
- freeexp(fs, e);
- e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0);
- e->k = VRELOCABLE;
- break;
- }
- default: {
- lua_assert(0); /* cannot happen */
- break;
- }
- }
- /* interchange true and false lists */
- { int temp = e->f; e->f = e->t; e->t = temp; }
- removevalues(fs, e->f);
- removevalues(fs, e->t);
-}
-
-
-void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
- t->u.s.aux = luaK_exp2RK(fs, k);
- t->k = VINDEXED;
-}
-
-
-static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
- lua_Number v1, v2, r;
- if (!isnumeral(e1) || !isnumeral(e2)) return 0;
- v1 = e1->u.nval;
- v2 = e2->u.nval;
- switch (op) {
- case OP_ADD: r = luai_numadd(v1, v2); break;
- case OP_SUB: r = luai_numsub(v1, v2); break;
- case OP_MUL: r = luai_nummul(v1, v2); break;
- case OP_DIV:
- if (v2 == 0) return 0; /* do not attempt to divide by 0 */
- r = luai_numdiv(v1, v2); break;
- case OP_MOD:
- if (v2 == 0) return 0; /* do not attempt to divide by 0 */
- r = luai_nummod(v1, v2); break;
- case OP_POW: r = luai_numpow(v1, v2); break;
- case OP_UNM: r = luai_numunm(v1); break;
- case OP_LEN: return 0; /* no constant folding for 'len' */
- default: lua_assert(0); r = 0; break;
- }
- if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */
- e1->u.nval = r;
- return 1;
-}
-
-
-static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
- if (constfolding(op, e1, e2))
- return;
- else {
- int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0;
- int o1 = luaK_exp2RK(fs, e1);
- if (o1 > o2) {
- freeexp(fs, e1);
- freeexp(fs, e2);
- }
- else {
- freeexp(fs, e2);
- freeexp(fs, e1);
- }
- e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2);
- e1->k = VRELOCABLE;
- }
-}
-
-
-static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
- expdesc *e2) {
- int o1 = luaK_exp2RK(fs, e1);
- int o2 = luaK_exp2RK(fs, e2);
- freeexp(fs, e2);
- freeexp(fs, e1);
- if (cond == 0 && op != OP_EQ) {
- int temp; /* exchange args to replace by `<' or `<=' */
- temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */
- cond = 1;
- }
- e1->u.s.info = condjump(fs, op, cond, o1, o2);
- e1->k = VJMP;
-}
-
-
-void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
- expdesc e2;
- e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
- switch (op) {
- case OPR_MINUS: {
- if (!isnumeral(e))
- luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */
- codearith(fs, OP_UNM, e, &e2);
- break;
- }
- case OPR_NOT: codenot(fs, e); break;
- case OPR_LEN: {
- luaK_exp2anyreg(fs, e); /* cannot operate on constants */
- codearith(fs, OP_LEN, e, &e2);
- break;
- }
- default: lua_assert(0);
- }
-}
-
-
-void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
- switch (op) {
- case OPR_AND: {
- luaK_goiftrue(fs, v);
- break;
- }
- case OPR_OR: {
- luaK_goiffalse(fs, v);
- break;
- }
- case OPR_CONCAT: {
- luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */
- break;
- }
- case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
- case OPR_MOD: case OPR_POW: {
- if (!isnumeral(v)) luaK_exp2RK(fs, v);
- break;
- }
- default: {
- luaK_exp2RK(fs, v);
- break;
- }
- }
-}
-
-
-void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
- switch (op) {
- case OPR_AND: {
- lua_assert(e1->t == NO_JUMP); /* list must be closed */
- luaK_dischargevars(fs, e2);
- luaK_concat(fs, &e2->f, e1->f);
- *e1 = *e2;
- break;
- }
- case OPR_OR: {
- lua_assert(e1->f == NO_JUMP); /* list must be closed */
- luaK_dischargevars(fs, e2);
- luaK_concat(fs, &e2->t, e1->t);
- *e1 = *e2;
- break;
- }
- case OPR_CONCAT: {
- luaK_exp2val(fs, e2);
- if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
- lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1);
- freeexp(fs, e1);
- SETARG_B(getcode(fs, e2), e1->u.s.info);
- e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info;
- }
- else {
- luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
- codearith(fs, OP_CONCAT, e1, e2);
- }
- break;
- }
- case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break;
- case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break;
- case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break;
- case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break;
- case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break;
- case OPR_POW: codearith(fs, OP_POW, e1, e2); break;
- case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break;
- case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break;
- case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break;
- case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break;
- case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break;
- case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break;
- default: lua_assert(0);
- }
-}
-
-
-void luaK_fixline (FuncState *fs, int line) {
- fs->f->lineinfo[fs->pc - 1] = line;
-}
-
-
-static int luaK_code (FuncState *fs, Instruction i, int line) {
- Proto *f = fs->f;
- dischargejpc(fs); /* `pc' will change */
- /* put new instruction in code array */
- luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction,
- MAX_INT, "code size overflow");
- f->code[fs->pc] = i;
- /* save corresponding line information */
- luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
- MAX_INT, "code size overflow");
- f->lineinfo[fs->pc] = line;
- return fs->pc++;
-}
-
-
-int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
- lua_assert(getOpMode(o) == iABC);
- lua_assert(getBMode(o) != OpArgN || b == 0);
- lua_assert(getCMode(o) != OpArgN || c == 0);
- return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline);
-}
-
-
-int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
- lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
- lua_assert(getCMode(o) == OpArgN);
- return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline);
-}
-
-
-void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
- int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1;
- int b = (tostore == LUA_MULTRET) ? 0 : tostore;
- lua_assert(tostore != 0);
- if (c <= MAXARG_C)
- luaK_codeABC(fs, OP_SETLIST, base, b, c);
- else {
- luaK_codeABC(fs, OP_SETLIST, base, b, 0);
- luaK_code(fs, cast(Instruction, c), fs->ls->lastline);
- }
- fs->freereg = base + 1; /* free registers with list values */
-}
-
diff --git a/src/lua/src/lcode.h b/src/lua/src/lcode.h
deleted file mode 100644
index b941c6072..000000000
--- a/src/lua/src/lcode.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
-** $Id: lcode.h,v 1.48.1.1 2007/12/27 13:02:25 roberto Exp $
-** Code generator for Lua
-** See Copyright Notice in lua.h
-*/
-
-#ifndef lcode_h
-#define lcode_h
-
-#include "llex.h"
-#include "lobject.h"
-#include "lopcodes.h"
-#include "lparser.h"
-
-
-/*
-** Marks the end of a patch list. It is an invalid value both as an absolute
-** address, and as a list link (would link an element to itself).
-*/
-#define NO_JUMP (-1)
-
-
-/*
-** grep "ORDER OPR" if you change these enums
-*/
-typedef enum BinOpr {
- OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW,
- OPR_CONCAT,
- OPR_NE, OPR_EQ,
- OPR_LT, OPR_LE, OPR_GT, OPR_GE,
- OPR_AND, OPR_OR,
- OPR_NOBINOPR
-} BinOpr;
-
-
-typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
-
-
-#define getcode(fs,e) ((fs)->f->code[(e)->u.s.info])
-
-#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
-
-#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET)
-
-LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
-LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
-LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
-LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
-LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
-LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
-LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s);
-LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r);
-LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
-LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
-LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
-LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
-LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
-LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
-LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
-LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
-LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
-LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
-LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
-LUAI_FUNC int luaK_jump (FuncState *fs);
-LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret);
-LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);
-LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
-LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);
-LUAI_FUNC int luaK_getlabel (FuncState *fs);
-LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v);
-LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
-LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2);
-LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
-
-
-#endif
diff --git a/src/lua/src/ldblib.c b/src/lua/src/ldblib.c
deleted file mode 100644
index 67de1222a..000000000
--- a/src/lua/src/ldblib.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
-** $Id: ldblib.c,v 1.104.1.3 2008/01/21 13:11:21 roberto Exp $
-** Interface from Lua to its debug API
-** See Copyright Notice in lua.h
-*/
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define ldblib_c
-#define LUA_LIB
-
-#include "lua.h"
-
-#include "lauxlib.h"
-#include "lualib.h"
-
-
-
-static int db_getregistry (lua_State *L) {
- lua_pushvalue(L, LUA_REGISTRYINDEX);
- return 1;
-}
-
-
-static int db_getmetatable (lua_State *L) {
- luaL_checkany(L, 1);
- if (!lua_getmetatable(L, 1)) {
- lua_pushnil(L); /* no metatable */
- }
- return 1;
-}
-
-
-static int db_setmetatable (lua_State *L) {
- int t = lua_type(L, 2);
- luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
- "nil or table expected");
- lua_settop(L, 2);
- lua_pushboolean(L, lua_setmetatable(L, 1));
- return 1;
-}
-
-
-static int db_getfenv (lua_State *L) {
- lua_getfenv(L, 1);
- return 1;
-}
-
-
-static int db_setfenv (lua_State *L) {
- luaL_checktype(L, 2, LUA_TTABLE);
- lua_settop(L, 2);
- if (lua_setfenv(L, 1) == 0)
- luaL_error(L, LUA_QL("setfenv")
- " cannot change environment of given object");
- return 1;
-}
-
-
-static void settabss (lua_State *L, const char *i, const char *v) {
- lua_pushstring(L, v);
- lua_setfield(L, -2, i);
-}
-
-
-static void settabsi (lua_State *L, const char *i, int v) {
- lua_pushinteger(L, v);
- lua_setfield(L, -2, i);
-}
-
-
-static lua_State *getthread (lua_State *L, int *arg) {
- if (lua_isthread(L, 1)) {
- *arg = 1;
- return lua_tothread(L, 1);
- }
- else {
- *arg = 0;
- return L;
- }
-}
-
-
-static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
- if (L == L1) {
- lua_pushvalue(L, -2);
- lua_remove(L, -3);
- }
- else
- lua_xmove(L1, L, 1);
- lua_setfield(L, -2, fname);
-}
-
-
-static int db_getinfo (lua_State *L) {
- lua_Debug ar;
- int arg;
- lua_State *L1 = getthread(L, &arg);
- const char *options = luaL_optstring(L, arg+2, "flnSu");
- if (lua_isnumber(L, arg+1)) {
- if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
- lua_pushnil(L); /* level out of range */
- return 1;
- }
- }
- else if (lua_isfunction(L, arg+1)) {
- lua_pushfstring(L, ">%s", options);
- options = lua_tostring(L, -1);
- lua_pushvalue(L, arg+1);
- lua_xmove(L, L1, 1);
- }
- else
- return luaL_argerror(L, arg+1, "function or level expected");
- if (!lua_getinfo(L1, options, &ar))
- return luaL_argerror(L, arg+2, "invalid option");
- lua_createtable(L, 0, 2);
- if (strchr(options, 'S')) {
- settabss(L, "source", ar.source);
- settabss(L, "short_src", ar.short_src);
- settabsi(L, "linedefined", ar.linedefined);
- settabsi(L, "lastlinedefined", ar.lastlinedefined);
- settabss(L, "what", ar.what);
- }
- if (strchr(options, 'l'))
- settabsi(L, "currentline", ar.currentline);
- if (strchr(options, 'u'))
- settabsi(L, "nups", ar.nups);
- if (strchr(options, 'n')) {
- settabss(L, "name", ar.name);
- settabss(L, "namewhat", ar.namewhat);
- }
- if (strchr(options, 'L'))
- treatstackoption(L, L1, "activelines");
- if (strchr(options, 'f'))
- treatstackoption(L, L1, "func");
- return 1; /* return table */
-}
-
-
-static int db_getlocal (lua_State *L) {
- int arg;
- lua_State *L1 = getthread(L, &arg);
- lua_Debug ar;
- const char *name;
- if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
- return luaL_argerror(L, arg+1, "level out of range");
- name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2));
- if (name) {
- lua_xmove(L1, L, 1);
- lua_pushstring(L, name);
- lua_pushvalue(L, -2);
- return 2;
- }
- else {
- lua_pushnil(L);
- return 1;
- }
-}
-
-
-static int db_setlocal (lua_State *L) {
- int arg;
- lua_State *L1 = getthread(L, &arg);
- lua_Debug ar;
- if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
- return luaL_argerror(L, arg+1, "level out of range");
- luaL_checkany(L, arg+3);
- lua_settop(L, arg+3);
- lua_xmove(L, L1, 1);
- lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2)));
- return 1;
-}
-
-
-static int auxupvalue (lua_State *L, int get) {
- const char *name;
- int n = luaL_checkint(L, 2);
- luaL_checktype(L, 1, LUA_TFUNCTION);
- if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */
- name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
- if (name == NULL) return 0;
- lua_pushstring(L, name);
- lua_insert(L, -(get+1));
- return get + 1;
-}
-
-
-static int db_getupvalue (lua_State *L) {
- return auxupvalue(L, 1);
-}
-
-
-static int db_setupvalue (lua_State *L) {
- luaL_checkany(L, 3);
- return auxupvalue(L, 0);
-}
-
-
-
-static const char KEY_HOOK = 'h';
-
-
-static void hookf (lua_State *L, lua_Debug *ar) {
- static const char *const hooknames[] =
- {"call", "return", "line", "count", "tail return"};
- lua_pushlightuserdata(L, (void *)&KEY_HOOK);
- lua_rawget(L, LUA_REGISTRYINDEX);
- lua_pushlightuserdata(L, L);
- lua_rawget(L, -2);
- if (lua_isfunction(L, -1)) {
- lua_pushstring(L, hooknames[(int)ar->event]);
- if (ar->currentline >= 0)
- lua_pushinteger(L, ar->currentline);
- else lua_pushnil(L);
- lua_assert(lua_getinfo(L, "lS", ar));
- lua_call(L, 2, 0);
- }
-}
-
-
-static int makemask (const char *smask, int count) {
- int mask = 0;
- if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
- if (strchr(smask, 'r')) mask |= LUA_MASKRET;
- if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
- if (count > 0) mask |= LUA_MASKCOUNT;
- return mask;
-}
-
-
-static char *unmakemask (int mask, char *smask) {
- int i = 0;
- if (mask & LUA_MASKCALL) smask[i++] = 'c';
- if (mask & LUA_MASKRET) smask[i++] = 'r';
- if (mask & LUA_MASKLINE) smask[i++] = 'l';
- smask[i] = '\0';
- return smask;
-}
-
-
-static void gethooktable (lua_State *L) {
- lua_pushlightuserdata(L, (void *)&KEY_HOOK);
- lua_rawget(L, LUA_REGISTRYINDEX);
- if (!lua_istable(L, -1)) {
- lua_pop(L, 1);
- lua_createtable(L, 0, 1);
- lua_pushlightuserdata(L, (void *)&KEY_HOOK);
- lua_pushvalue(L, -2);
- lua_rawset(L, LUA_REGISTRYINDEX);
- }
-}
-
-
-static int db_sethook (lua_State *L) {
- int arg, mask, count;
- lua_Hook func;
- lua_State *L1 = getthread(L, &arg);
- if (lua_isnoneornil(L, arg+1)) {
- lua_settop(L, arg+1);
- func = NULL; mask = 0; count = 0; /* turn off hooks */
- }
- else {
- const char *smask = luaL_checkstring(L, arg+2);
- luaL_checktype(L, arg+1, LUA_TFUNCTION);
- count = luaL_optint(L, arg+3, 0);
- func = hookf; mask = makemask(smask, count);
- }
- gethooktable(L);
- lua_pushlightuserdata(L, L1);
- lua_pushvalue(L, arg+1);
- lua_rawset(L, -3); /* set new hook */
- lua_pop(L, 1); /* remove hook table */
- lua_sethook(L1, func, mask, count); /* set hooks */
- return 0;
-}
-
-
-static int db_gethook (lua_State *L) {
- int arg;
- lua_State *L1 = getthread(L, &arg);
- char buff[5];
- int mask = lua_gethookmask(L1);
- lua_Hook hook = lua_gethook(L1);
- if (hook != NULL && hook != hookf) /* external hook? */
- lua_pushliteral(L, "external hook");
- else {
- gethooktable(L);
- lua_pushlightuserdata(L, L1);
- lua_rawget(L, -2); /* get hook */
- lua_remove(L, -2); /* remove hook table */
- }
- lua_pushstring(L, unmakemask(mask, buff));
- lua_pushinteger(L, lua_gethookcount(L1));
- return 3;
-}
-
-
-static int db_debug (lua_State *L) {
- for (;;) {
- char buffer[250];
- fputs("lua_debug> ", stderr);
- if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
- strcmp(buffer, "cont\n") == 0)
- return 0;
- if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
- lua_pcall(L, 0, 0, 0)) {
- fputs(lua_tostring(L, -1), stderr);
- fputs("\n", stderr);
- }
- lua_settop(L, 0); /* remove eventual returns */
- }
-}
-
-
-#define LEVELS1 12 /* size of the first part of the stack */
-#define LEVELS2 10 /* size of the second part of the stack */
-
-static int db_errorfb (lua_State *L) {
- int level;
- int firstpart = 1; /* still before eventual `...' */
- int arg;
- lua_State *L1 = getthread(L, &arg);
- lua_Debug ar;
- if (lua_isnumber(L, arg+2)) {
- level = (int)lua_tointeger(L, arg+2);
- lua_pop(L, 1);
- }
- else
- level = (L == L1) ? 1 : 0; /* level 0 may be this own function */
- if (lua_gettop(L) == arg)
- lua_pushliteral(L, "");
- else if (!lua_isstring(L, arg+1)) return 1; /* message is not a string */
- else lua_pushliteral(L, "\n");
- lua_pushliteral(L, "stack traceback:");
- while (lua_getstack(L1, level++, &ar)) {
- if (level > LEVELS1 && firstpart) {
- /* no more than `LEVELS2' more levels? */
- if (!lua_getstack(L1, level+LEVELS2, &ar))
- level--; /* keep going */
- else {
- lua_pushliteral(L, "\n\t..."); /* too many levels */
- while (lua_getstack(L1, level+LEVELS2, &ar)) /* find last levels */
- level++;
- }
- firstpart = 0;
- continue;
- }
- lua_pushliteral(L, "\n\t");
- lua_getinfo(L1, "Snl", &ar);
- lua_pushfstring(L, "%s:", ar.short_src);
- if (ar.currentline > 0)
- lua_pushfstring(L, "%d:", ar.currentline);
- if (*ar.namewhat != '\0') /* is there a name? */
- lua_pushfstring(L, " in function " LUA_QS, ar.name);
- else {
- if (*ar.what == 'm') /* main? */
- lua_pushfstring(L, " in main chunk");
- else if (*ar.what == 'C' || *ar.what == 't')
- lua_pushliteral(L, " ?"); /* C function or tail call */
- else
- lua_pushfstring(L, " in function <%s:%d>",
- ar.short_src, ar.linedefined);
- }
- lua_concat(L, lua_gettop(L) - arg);
- }
- lua_concat(L, lua_gettop(L) - arg);
- return 1;
-}
-
-
-static const luaL_Reg dblib[] = {
- {"debug", db_debug},
- {"getfenv", db_getfenv},
- {"gethook", db_gethook},
- {"getinfo", db_getinfo},
- {"getlocal", db_getlocal},
- {"getregistry", db_getregistry},
- {"getmetatable", db_getmetatable},
- {"getupvalue", db_getupvalue},
- {"setfenv", db_setfenv},
- {"sethook", db_sethook},
- {"setlocal", db_setlocal},
- {"setmetatable", db_setmetatable},
- {"setupvalue", db_setupvalue},
- {"traceback", db_errorfb},
- {NULL, NULL}
-};
-
-
-LUALIB_API int luaopen_debug (lua_State *L) {
- luaL_register(L, LUA_DBLIBNAME, dblib);
- return 1;
-}
-
diff --git a/src/lua/src/ldebug.c b/src/lua/src/ldebug.c
deleted file mode 100644
index 50ad3d380..000000000
--- a/src/lua/src/ldebug.c
+++ /dev/null
@@ -1,638 +0,0 @@
-/*
-** $Id: ldebug.c,v 2.29.1.6 2008/05/08 16:56:26 roberto Exp $
-** Debug Interface
-** See Copyright Notice in lua.h
-*/
-
-
-#include <stdarg.h>
-#include <stddef.h>
-#include <string.h>
-
-
-#define ldebug_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "lapi.h"
-#include "lcode.h"
-#include "ldebug.h"
-#include "ldo.h"
-#include "lfunc.h"
-#include "lobject.h"
-#include "lopcodes.h"
-#include "lstate.h"
-#include "lstring.h"
-#include "ltable.h"
-#include "ltm.h"
-#include "lvm.h"
-
-
-
-static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
-
-
-static int currentpc (lua_State *L, CallInfo *ci) {
- if (!isLua(ci)) return -1; /* function is not a Lua function? */
- if (ci == L->ci)
- ci->savedpc = L->savedpc;
- return pcRel(ci->savedpc, ci_func(ci)->l.p);
-}
-
-
-static int currentline (lua_State *L, CallInfo *ci) {
- int pc = currentpc(L, ci);
- if (pc < 0)
- return -1; /* only active lua functions have current-line information */
- else
- return getline(ci_func(ci)->l.p, pc);
-}
-
-
-/*
-** this function can be called asynchronous (e.g. during a signal)
-*/
-LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
- if (func == NULL || mask == 0) { /* turn off hooks? */
- mask = 0;
- func = NULL;
- }
- L->hook = func;
- L->basehookcount = count;
- resethookcount(L);
- L->hookmask = cast_byte(mask);
- return 1;
-}
-
-
-LUA_API lua_Hook lua_gethook (lua_State *L) {
- return L->hook;
-}
-
-
-LUA_API int lua_gethookmask (lua_State *L) {
- return L->hookmask;
-}
-
-
-LUA_API int lua_gethookcount (lua_State *L) {
- return L->basehookcount;
-}
-
-
-LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
- int status;
- CallInfo *ci;
- lua_lock(L);
- for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) {
- level--;
- if (f_isLua(ci)) /* Lua function? */
- level -= ci->tailcalls; /* skip lost tail calls */
- }
- if (level == 0 && ci > L->base_ci) { /* level found? */
- status = 1;
- ar->i_ci = cast_int(ci - L->base_ci);
- }
- else if (level < 0) { /* level is of a lost tail call? */
- status = 1;
- ar->i_ci = 0;
- }
- else status = 0; /* no such level */
- lua_unlock(L);
- return status;
-}
-
-
-static Proto *getluaproto (CallInfo *ci) {
- return (isLua(ci) ? ci_func(ci)->l.p : NULL);
-}
-
-
-static const char *findlocal (lua_State *L, CallInfo *ci, int n) {
- const char *name;
- Proto *fp = getluaproto(ci);
- if (fp && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != NULL)
- return name; /* is a local variable in a Lua function */
- else {
- StkId limit = (ci == L->ci) ? L->top : (ci+1)->func;
- if (limit - ci->base >= n && n > 0) /* is 'n' inside 'ci' stack? */
- return "(*temporary)";
- else
- return NULL;
- }
-}
-
-
-LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
- CallInfo *ci = L->base_ci + ar->i_ci;
- const char *name = findlocal(L, ci, n);
- lua_lock(L);
- if (name)
- luaA_pushobject(L, ci->base + (n - 1));
- lua_unlock(L);
- return name;
-}
-
-
-LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
- CallInfo *ci = L->base_ci + ar->i_ci;
- const char *name = findlocal(L, ci, n);
- lua_lock(L);
- if (name)
- setobjs2s(L, ci->base + (n - 1), L->top - 1);
- L->top--; /* pop value */
- lua_unlock(L);
- return name;
-}
-
-
-static void funcinfo (lua_Debug *ar, Closure *cl) {
- if (cl->c.isC) {
- ar->source = "=[C]";
- ar->linedefined = -1;
- ar->lastlinedefined = -1;
- ar->what = "C";
- }
- else {
- ar->source = getstr(cl->l.p->source);
- ar->linedefined = cl->l.p->linedefined;
- ar->lastlinedefined = cl->l.p->lastlinedefined;
- ar->what = (ar->linedefined == 0) ? "main" : "Lua";
- }
- luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
-}
-
-
-static void info_tailcall (lua_Debug *ar) {
- ar->name = ar->namewhat = "";
- ar->what = "tail";
- ar->lastlinedefined = ar->linedefined = ar->currentline = -1;
- ar->source = "=(tail call)";
- luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
- ar->nups = 0;
-}
-
-
-static void collectvalidlines (lua_State *L, Closure *f) {
- if (f == NULL || f->c.isC) {
- setnilvalue(L->top);
- }
- else {
- Table *t = luaH_new(L, 0, 0);
- int *lineinfo = f->l.p->lineinfo;
- int i;
- for (i=0; i<f->l.p->sizelineinfo; i++)
- setbvalue(luaH_setnum(L, t, lineinfo[i]), 1);
- sethvalue(L, L->top, t);
- }
- incr_top(L);
-}
-
-
-static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
- Closure *f, CallInfo *ci) {
- int status = 1;
- if (f == NULL) {
- info_tailcall(ar);
- return status;
- }
- for (; *what; what++) {
- switch (*what) {
- case 'S': {
- funcinfo(ar, f);
- break;
- }
- case 'l': {
- ar->currentline = (ci) ? currentline(L, ci) : -1;
- break;
- }
- case 'u': {
- ar->nups = f->c.nupvalues;
- break;
- }
- case 'n': {
- ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL;
- if (ar->namewhat == NULL) {
- ar->namewhat = ""; /* not found */
- ar->name = NULL;
- }
- break;
- }
- case 'L':
- case 'f': /* handled by lua_getinfo */
- break;
- default: status = 0; /* invalid option */
- }
- }
- return status;
-}
-
-
-LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
- int status;
- Closure *f = NULL;
- CallInfo *ci = NULL;
- lua_lock(L);
- if (*what == '>') {
- StkId func = L->top - 1;
- luai_apicheck(L, ttisfunction(func));
- what++; /* skip the '>' */
- f = clvalue(func);
- L->top--; /* pop function */
- }
- else if (ar->i_ci != 0) { /* no tail call? */
- ci = L->base_ci + ar->i_ci;
- lua_assert(ttisfunction(ci->func));
- f = clvalue(ci->func);
- }
- status = auxgetinfo(L, what, ar, f, ci);
- if (strchr(what, 'f')) {
- if (f == NULL) setnilvalue(L->top);
- else setclvalue(L, L->top, f);
- incr_top(L);
- }
- if (strchr(what, 'L'))
- collectvalidlines(L, f);
- lua_unlock(L);
- return status;
-}
-
-
-/*
-** {======================================================
-** Symbolic Execution and code checker
-** =======================================================
-*/
-
-#define check(x) if (!(x)) return 0;
-
-#define checkjump(pt,pc) check(0 <= pc && pc < pt->sizecode)
-
-#define checkreg(pt,reg) check((reg) < (pt)->maxstacksize)
-
-
-
-static int precheck (const Proto *pt) {
- check(pt->maxstacksize <= MAXSTACK);
- check(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize);
- check(!(pt->is_vararg & VARARG_NEEDSARG) ||
- (pt->is_vararg & VARARG_HASARG));
- check(pt->sizeupvalues <= pt->nups);
- check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0);
- check(pt->sizecode > 0 && GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN);
- return 1;
-}
-
-
-#define checkopenop(pt,pc) luaG_checkopenop((pt)->code[(pc)+1])
-
-int luaG_checkopenop (Instruction i) {
- switch (GET_OPCODE(i)) {
- case OP_CALL:
- case OP_TAILCALL:
- case OP_RETURN:
- case OP_SETLIST: {
- check(GETARG_B(i) == 0);
- return 1;
- }
- default: return 0; /* invalid instruction after an open call */
- }
-}
-
-
-static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) {
- switch (mode) {
- case OpArgN: check(r == 0); break;
- case OpArgU: break;
- case OpArgR: checkreg(pt, r); break;
- case OpArgK:
- check(ISK(r) ? INDEXK(r) < pt->sizek : r < pt->maxstacksize);
- break;
- }
- return 1;
-}
-
-
-static Instruction symbexec (const Proto *pt, int lastpc, int reg) {
- int pc;
- int last; /* stores position of last instruction that changed `reg' */
- last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */
- check(precheck(pt));
- for (pc = 0; pc < lastpc; pc++) {
- Instruction i = pt->code[pc];
- OpCode op = GET_OPCODE(i);
- int a = GETARG_A(i);
- int b = 0;
- int c = 0;
- check(op < NUM_OPCODES);
- checkreg(pt, a);
- switch (getOpMode(op)) {
- case iABC: {
- b = GETARG_B(i);
- c = GETARG_C(i);
- check(checkArgMode(pt, b, getBMode(op)));
- check(checkArgMode(pt, c, getCMode(op)));
- break;
- }
- case iABx: {
- b = GETARG_Bx(i);
- if (getBMode(op) == OpArgK) check(b < pt->sizek);
- break;
- }
- case iAsBx: {
- b = GETARG_sBx(i);
- if (getBMode(op) == OpArgR) {
- int dest = pc+1+b;
- check(0 <= dest && dest < pt->sizecode);
- if (dest > 0) {
- int j;
- /* check that it does not jump to a setlist count; this
- is tricky, because the count from a previous setlist may
- have the same value of an invalid setlist; so, we must
- go all the way back to the first of them (if any) */
- for (j = 0; j < dest; j++) {
- Instruction d = pt->code[dest-1-j];
- if (!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)) break;
- }
- /* if 'j' is even, previous value is not a setlist (even if
- it looks like one) */
- check((j&1) == 0);
- }
- }
- break;
- }
- }
- if (testAMode(op)) {
- if (a == reg) last = pc; /* change register `a' */
- }
- if (testTMode(op)) {
- check(pc+2 < pt->sizecode); /* check skip */
- check(GET_OPCODE(pt->code[pc+1]) == OP_JMP);
- }
- switch (op) {
- case OP_LOADBOOL: {
- if (c == 1) { /* does it jump? */
- check(pc+2 < pt->sizecode); /* check its jump */
- check(GET_OPCODE(pt->code[pc+1]) != OP_SETLIST ||
- GETARG_C(pt->code[pc+1]) != 0);
- }
- break;
- }
- case OP_LOADNIL: {
- if (a <= reg && reg <= b)
- last = pc; /* set registers from `a' to `b' */
- break;
- }
- case OP_GETUPVAL:
- case OP_SETUPVAL: {
- check(b < pt->nups);
- break;
- }
- case OP_GETGLOBAL:
- case OP_SETGLOBAL: {
- check(ttisstring(&pt->k[b]));
- break;
- }
- case OP_SELF: {
- checkreg(pt, a+1);
- if (reg == a+1) last = pc;
- break;
- }
- case OP_CONCAT: {
- check(b < c); /* at least two operands */
- break;
- }
- case OP_TFORLOOP: {
- check(c >= 1); /* at least one result (control variable) */
- checkreg(pt, a+2+c); /* space for results */
- if (reg >= a+2) last = pc; /* affect all regs above its base */
- break;
- }
- case OP_FORLOOP:
- case OP_FORPREP:
- checkreg(pt, a+3);
- /* go through */
- case OP_JMP: {
- int dest = pc+1+b;
- /* not full check and jump is forward and do not skip `lastpc'? */
- if (reg != NO_REG && pc < dest && dest <= lastpc)
- pc += b; /* do the jump */
- break;
- }
- case OP_CALL:
- case OP_TAILCALL: {
- if (b != 0) {
- checkreg(pt, a+b-1);
- }
- c--; /* c = num. returns */
- if (c == LUA_MULTRET) {
- check(checkopenop(pt, pc));
- }
- else if (c != 0)
- checkreg(pt, a+c-1);
- if (reg >= a) last = pc; /* affect all registers above base */
- break;
- }
- case OP_RETURN: {
- b--; /* b = num. returns */
- if (b > 0) checkreg(pt, a+b-1);
- break;
- }
- case OP_SETLIST: {
- if (b > 0) checkreg(pt, a + b);
- if (c == 0) {
- pc++;
- check(pc < pt->sizecode - 1);
- }
- break;
- }
- case OP_CLOSURE: {
- int nup, j;
- check(b < pt->sizep);
- nup = pt->p[b]->nups;
- check(pc + nup < pt->sizecode);
- for (j = 1; j <= nup; j++) {
- OpCode op1 = GET_OPCODE(pt->code[pc + j]);
- check(op1 == OP_GETUPVAL || op1 == OP_MOVE);
- }
- if (reg != NO_REG) /* tracing? */
- pc += nup; /* do not 'execute' these pseudo-instructions */
- break;
- }
- case OP_VARARG: {
- check((pt->is_vararg & VARARG_ISVARARG) &&
- !(pt->is_vararg & VARARG_NEEDSARG));
- b--;
- if (b == LUA_MULTRET) check(checkopenop(pt, pc));
- checkreg(pt, a+b-1);
- break;
- }
- default: break;
- }
- }
- return pt->code[last];
-}
-
-#undef check
-#undef checkjump
-#undef checkreg
-
-/* }====================================================== */
-
-
-int luaG_checkcode (const Proto *pt) {
- return (symbexec(pt, pt->sizecode, NO_REG) != 0);
-}
-
-
-static const char *kname (Proto *p, int c) {
- if (ISK(c) && ttisstring(&p->k[INDEXK(c)]))
- return svalue(&p->k[INDEXK(c)]);
- else
- return "?";
-}
-
-
-static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos,
- const char **name) {
- if (isLua(ci)) { /* a Lua function? */
- Proto *p = ci_func(ci)->l.p;
- int pc = currentpc(L, ci);
- Instruction i;
- *name = luaF_getlocalname(p, stackpos+1, pc);
- if (*name) /* is a local? */
- return "local";
- i = symbexec(p, pc, stackpos); /* try symbolic execution */
- lua_assert(pc != -1);
- switch (GET_OPCODE(i)) {
- case OP_GETGLOBAL: {
- int g = GETARG_Bx(i); /* global index */
- lua_assert(ttisstring(&p->k[g]));
- *name = svalue(&p->k[g]);
- return "global";
- }
- case OP_MOVE: {
- int a = GETARG_A(i);
- int b = GETARG_B(i); /* move from `b' to `a' */
- if (b < a)
- return getobjname(L, ci, b, name); /* get name for `b' */
- break;
- }
- case OP_GETTABLE: {
- int k = GETARG_C(i); /* key index */
- *name = kname(p, k);
- return "field";
- }
- case OP_GETUPVAL: {
- int u = GETARG_B(i); /* upvalue index */
- *name = p->upvalues ? getstr(p->upvalues[u]) : "?";
- return "upvalue";
- }
- case OP_SELF: {
- int k = GETARG_C(i); /* key index */
- *name = kname(p, k);
- return "method";
- }
- default: break;
- }
- }
- return NULL; /* no useful name found */
-}
-
-
-static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
- Instruction i;
- if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1))
- return NULL; /* calling function is not Lua (or is unknown) */
- ci--; /* calling function */
- i = ci_func(ci)->l.p->code[currentpc(L, ci)];
- if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL ||
- GET_OPCODE(i) == OP_TFORLOOP)
- return getobjname(L, ci, GETARG_A(i), name);
- else
- return NULL; /* no useful name can be found */
-}
-
-
-/* only ANSI way to check whether a pointer points to an array */
-static int isinstack (CallInfo *ci, const TValue *o) {
- StkId p;
- for (p = ci->base; p < ci->top; p++)
- if (o == p) return 1;
- return 0;
-}
-
-
-void luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
- const char *name = NULL;
- const char *t = luaT_typenames[ttype(o)];
- const char *kind = (isinstack(L->ci, o)) ?
- getobjname(L, L->ci, cast_int(o - L->base), &name) :
- NULL;
- if (kind)
- luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)",
- op, kind, name, t);
- else
- luaG_runerror(L, "attempt to %s a %s value", op, t);
-}
-
-
-void luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
- if (ttisstring(p1) || ttisnumber(p1)) p1 = p2;
- lua_assert(!ttisstring(p1) && !ttisnumber(p1));
- luaG_typeerror(L, p1, "concatenate");
-}
-
-
-void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) {
- TValue temp;
- if (luaV_tonumber(p1, &temp) == NULL)
- p2 = p1; /* first operand is wrong */
- luaG_typeerror(L, p2, "perform arithmetic on");
-}
-
-
-int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
- const char *t1 = luaT_typenames[ttype(p1)];
- const char *t2 = luaT_typenames[ttype(p2)];
- if (t1[2] == t2[2])
- luaG_runerror(L, "attempt to compare two %s values", t1);
- else
- luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
- return 0;
-}
-
-
-static void addinfo (lua_State *L, const char *msg) {
- CallInfo *ci = L->ci;
- if (isLua(ci)) { /* is Lua code? */
- char buff[LUA_IDSIZE]; /* add file:line information */
- int line = currentline(L, ci);
- luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE);
- luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
- }
-}
-
-
-void luaG_errormsg (lua_State *L) {
- if (L->errfunc != 0) { /* is there an error handling function? */
- StkId errfunc = restorestack(L, L->errfunc);
- if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR);
- setobjs2s(L, L->top, L->top - 1); /* move argument */
- setobjs2s(L, L->top - 1, errfunc); /* push function */
- incr_top(L);
- luaD_call(L, L->top - 2, 1); /* call it */
- }
- luaD_throw(L, LUA_ERRRUN);
-}
-
-
-void luaG_runerror (lua_State *L, const char *fmt, ...) {
- va_list argp;
- va_start(argp, fmt);
- addinfo(L, luaO_pushvfstring(L, fmt, argp));
- va_end(argp);
- luaG_errormsg(L);
-}
-
diff --git a/src/lua/src/ldebug.h b/src/lua/src/ldebug.h
deleted file mode 100644
index ba28a9724..000000000
--- a/src/lua/src/ldebug.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
-** $Id: ldebug.h,v 2.3.1.1 2007/12/27 13:02:25 roberto Exp $
-** Auxiliary functions from Debug Interface module
-** See Copyright Notice in lua.h
-*/
-
-#ifndef ldebug_h
-#define ldebug_h
-
-
-#include "lstate.h"
-
-
-#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1)
-
-#define getline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0)
-
-#define resethookcount(L) (L->hookcount = L->basehookcount)
-
-
-LUAI_FUNC void luaG_typeerror (lua_State *L, const TValue *o,
- const char *opname);
-LUAI_FUNC void luaG_concaterror (lua_State *L, StkId p1, StkId p2);
-LUAI_FUNC void luaG_aritherror (lua_State *L, const TValue *p1,
- const TValue *p2);
-LUAI_FUNC int luaG_ordererror (lua_State *L, const TValue *p1,
- const TValue *p2);
-LUAI_FUNC void luaG_runerror (lua_State *L, const char *fmt, ...);
-LUAI_FUNC void luaG_errormsg (lua_State *L);
-LUAI_FUNC int luaG_checkcode (const Proto *pt);
-LUAI_FUNC int luaG_checkopenop (Instruction i);
-
-#endif
diff --git a/src/lua/src/ldo.c b/src/lua/src/ldo.c
deleted file mode 100644
index 8de05f728..000000000
--- a/src/lua/src/ldo.c
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
-** $Id: ldo.c,v 2.38.1.3 2008/01/18 22:31:22 roberto Exp $
-** Stack and Call structure of Lua
-** See Copyright Notice in lua.h
-*/
-
-
-#include <setjmp.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define ldo_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "ldebug.h"
-#include "ldo.h"
-#include "lfunc.h"
-#include "lgc.h"
-#include "lmem.h"
-#include "lobject.h"
-#include "lopcodes.h"
-#include "lparser.h"
-#include "lstate.h"
-#include "lstring.h"
-#include "ltable.h"
-#include "ltm.h"
-#include "lundump.h"
-#include "lvm.h"
-#include "lzio.h"
-
-
-
-
-/*
-** {======================================================
-** Error-recovery functions
-** =======================================================
-*/
-
-
-/* chain list of long jump buffers */
-struct lua_longjmp {
- struct lua_longjmp *previous;
- luai_jmpbuf b;
- volatile int status; /* error code */
-};
-
-
-void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
- switch (errcode) {
- case LUA_ERRMEM: {
- setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG));
- break;
- }
- case LUA_ERRERR: {
- setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
- break;
- }
- case LUA_ERRSYNTAX:
- case LUA_ERRRUN: {
- setobjs2s(L, oldtop, L->top - 1); /* error message on current top */
- break;
- }
- }
- L->top = oldtop + 1;
-}
-
-
-static void restore_stack_limit (lua_State *L) {
- lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1);
- if (L->size_ci > LUAI_MAXCALLS) { /* there was an overflow? */
- int inuse = cast_int(L->ci - L->base_ci);
- if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */
- luaD_reallocCI(L, LUAI_MAXCALLS);
- }
-}
-
-
-static void resetstack (lua_State *L, int status) {
- L->ci = L->base_ci;
- L->base = L->ci->base;
- luaF_close(L, L->base); /* close eventual pending closures */
- luaD_seterrorobj(L, status, L->base);
- L->nCcalls = L->baseCcalls;
- L->allowhook = 1;
- restore_stack_limit(L);
- L->errfunc = 0;
- L->errorJmp = NULL;
-}
-
-
-void luaD_throw (lua_State *L, int errcode) {
- if (L->errorJmp) {
- L->errorJmp->status = errcode;
- LUAI_THROW(L, L->errorJmp);
- }
- else {
- L->status = cast_byte(errcode);
- if (G(L)->panic) {
- resetstack(L, errcode);
- lua_unlock(L);
- G(L)->panic(L);
- }
- exit(EXIT_FAILURE);
- }
-}
-
-
-int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
- struct lua_longjmp lj;
- lj.status = 0;
- lj.previous = L->errorJmp; /* chain new error handler */
- L->errorJmp = &lj;
- LUAI_TRY(L, &lj,
- (*f)(L, ud);
- );
- L->errorJmp = lj.previous; /* restore old error handler */
- return lj.status;
-}
-
-/* }====================================================== */
-
-
-static void correctstack (lua_State *L, TValue *oldstack) {
- CallInfo *ci;
- GCObject *up;
- L->top = (L->top - oldstack) + L->stack;
- for (up = L->openupval; up != NULL; up = up->gch.next)
- gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;
- for (ci = L->base_ci; ci <= L->ci; ci++) {
- ci->top = (ci->top - oldstack) + L->stack;
- ci->base = (ci->base - oldstack) + L->stack;
- ci->func = (ci->func - oldstack) + L->stack;
- }
- L->base = (L->base - oldstack) + L->stack;
-}
-
-
-void luaD_reallocstack (lua_State *L, int newsize) {
- TValue *oldstack = L->stack;
- int realsize = newsize + 1 + EXTRA_STACK;
- lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1);
- luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue);
- L->stacksize = realsize;
- L->stack_last = L->stack+newsize;
- correctstack(L, oldstack);
-}
-
-
-void luaD_reallocCI (lua_State *L, int newsize) {
- CallInfo *oldci = L->base_ci;
- luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo);
- L->size_ci = newsize;
- L->ci = (L->ci - oldci) + L->base_ci;
- L->end_ci = L->base_ci + L->size_ci - 1;
-}
-
-
-void luaD_growstack (lua_State *L, int n) {
- if (n <= L->stacksize) /* double size is enough? */
- luaD_reallocstack(L, 2*L->stacksize);
- else
- luaD_reallocstack(L, L->stacksize + n);
-}
-
-
-static CallInfo *growCI (lua_State *L) {
- if (L->size_ci > LUAI_MAXCALLS) /* overflow while handling overflow? */
- luaD_throw(L, LUA_ERRERR);
- else {
- luaD_reallocCI(L, 2*L->size_ci);
- if (L->size_ci > LUAI_MAXCALLS)
- luaG_runerror(L, "stack overflow");
- }
- return ++L->ci;
-}
-
-
-void luaD_callhook (lua_State *L, int event, int line) {
- lua_Hook hook = L->hook;
- if (hook && L->allowhook) {
- ptrdiff_t top = savestack(L, L->top);
- ptrdiff_t ci_top = savestack(L, L->ci->top);
- lua_Debug ar;
- ar.event = event;
- ar.currentline = line;
- if (event == LUA_HOOKTAILRET)
- ar.i_ci = 0; /* tail call; no debug information about it */
- else
- ar.i_ci = cast_int(L->ci - L->base_ci);
- luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
- L->ci->top = L->top + LUA_MINSTACK;
- lua_assert(L->ci->top <= L->stack_last);
- L->allowhook = 0; /* cannot call hooks inside a hook */
- lua_unlock(L);
- (*hook)(L, &ar);
- lua_lock(L);
- lua_assert(!L->allowhook);
- L->allowhook = 1;
- L->ci->top = restorestack(L, ci_top);
- L->top = restorestack(L, top);
- }
-}
-
-
-static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
- int i;
- int nfixargs = p->numparams;
- Table *htab = NULL;
- StkId base, fixed;
- for (; actual < nfixargs; ++actual)
- setnilvalue(L->top++);
-#if defined(LUA_COMPAT_VARARG)
- if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */
- int nvar = actual - nfixargs; /* number of extra arguments */
- lua_assert(p->is_vararg & VARARG_HASARG);
- luaC_checkGC(L);
- htab = luaH_new(L, nvar, 1); /* create `arg' table */
- for (i=0; i<nvar; i++) /* put extra arguments into `arg' table */
- setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i);
- /* store counter in field `n' */
- setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar));
- }
-#endif
- /* move fixed parameters to final position */
- fixed = L->top - actual; /* first fixed argument */
- base = L->top; /* final position of first argument */
- for (i=0; i<nfixargs; i++) {
- setobjs2s(L, L->top++, fixed+i);
- setnilvalue(fixed+i);
- }
- /* add `arg' parameter */
- if (htab) {
- sethvalue(L, L->top++, htab);
- lua_assert(iswhite(obj2gco(htab)));
- }
- return base;
-}
-
-
-static StkId tryfuncTM (lua_State *L, StkId func) {
- const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL);
- StkId p;
- ptrdiff_t funcr = savestack(L, func);
- if (!ttisfunction(tm))
- luaG_typeerror(L, func, "call");
- /* Open a hole inside the stack at `func' */
- for (p = L->top; p > func; p--) setobjs2s(L, p, p-1);
- incr_top(L);
- func = restorestack(L, funcr); /* previous call may change stack */
- setobj2s(L, func, tm); /* tag method is the new function to be called */
- return func;
-}
-
-
-
-#define inc_ci(L) \
- ((L->ci == L->end_ci) ? growCI(L) : \
- (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci))
-
-
-int luaD_precall (lua_State *L, StkId func, int nresults) {
- LClosure *cl;
- ptrdiff_t funcr;
- if (!ttisfunction(func)) /* `func' is not a function? */
- func = tryfuncTM(L, func); /* check the `function' tag method */
- funcr = savestack(L, func);
- cl = &clvalue(func)->l;
- L->ci->savedpc = L->savedpc;
- if (!cl->isC) { /* Lua function? prepare its call */
- CallInfo *ci;
- StkId st, base;
- Proto *p = cl->p;
- luaD_checkstack(L, p->maxstacksize);
- func = restorestack(L, funcr);
- if (!p->is_vararg) { /* no varargs? */
- base = func + 1;
- if (L->top > base + p->numparams)
- L->top = base + p->numparams;
- }
- else { /* vararg function */
- int nargs = cast_int(L->top - func) - 1;
- base = adjust_varargs(L, p, nargs);
- func = restorestack(L, funcr); /* previous call may change the stack */
- }
- ci = inc_ci(L); /* now `enter' new function */
- ci->func = func;
- L->base = ci->base = base;
- ci->top = L->base + p->maxstacksize;
- lua_assert(ci->top <= L->stack_last);
- L->savedpc = p->code; /* starting point */
- ci->tailcalls = 0;
- ci->nresults = nresults;
- for (st = L->top; st < ci->top; st++)
- setnilvalue(st);
- L->top = ci->top;
- if (L->hookmask & LUA_MASKCALL) {
- L->savedpc++; /* hooks assume 'pc' is already incremented */
- luaD_callhook(L, LUA_HOOKCALL, -1);
- L->savedpc--; /* correct 'pc' */
- }
- return PCRLUA;
- }
- else { /* if is a C function, call it */
- CallInfo *ci;
- int n;
- luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
- ci = inc_ci(L); /* now `enter' new function */
- ci->func = restorestack(L, funcr);
- L->base = ci->base = ci->func + 1;
- ci->top = L->top + LUA_MINSTACK;
- lua_assert(ci->top <= L->stack_last);
- ci->nresults = nresults;
- if (L->hookmask & LUA_MASKCALL)
- luaD_callhook(L, LUA_HOOKCALL, -1);
- lua_unlock(L);
- n = (*curr_func(L)->c.f)(L); /* do the actual call */
- lua_lock(L);
- if (n < 0) /* yielding? */
- return PCRYIELD;
- else {
- luaD_poscall(L, L->top - n);
- return PCRC;
- }
- }
-}
-
-
-static StkId callrethooks (lua_State *L, StkId firstResult) {
- ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */
- luaD_callhook(L, LUA_HOOKRET, -1);
- if (f_isLua(L->ci)) { /* Lua function? */
- while ((L->hookmask & LUA_MASKRET) && L->ci->tailcalls--) /* tail calls */
- luaD_callhook(L, LUA_HOOKTAILRET, -1);
- }
- return restorestack(L, fr);
-}
-
-
-int luaD_poscall (lua_State *L, StkId firstResult) {
- StkId res;
- int wanted, i;
- CallInfo *ci;
- if (L->hookmask & LUA_MASKRET)
- firstResult = callrethooks(L, firstResult);
- ci = L->ci--;
- res = ci->func; /* res == final position of 1st result */
- wanted = ci->nresults;
- L->base = (ci - 1)->base; /* restore base */
- L->savedpc = (ci - 1)->savedpc; /* restore savedpc */
- /* move results to correct place */
- for (i = wanted; i != 0 && firstResult < L->top; i--)
- setobjs2s(L, res++, firstResult++);
- while (i-- > 0)
- setnilvalue(res++);
- L->top = res;
- return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */
-}
-
-
-/*
-** Call a function (C or Lua). The function to be called is at *func.
-** The arguments are on the stack, right after the function.
-** When returns, all the results are on the stack, starting at the original
-** function position.
-*/
-void luaD_call (lua_State *L, StkId func, int nResults) {
- if (++L->nCcalls >= LUAI_MAXCCALLS) {
- if (L->nCcalls == LUAI_MAXCCALLS)
- luaG_runerror(L, "C stack overflow");
- else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
- luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
- }
- if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */
- luaV_execute(L, 1); /* call it */
- L->nCcalls--;
- luaC_checkGC(L);
-}
-
-
-static void resume (lua_State *L, void *ud) {
- StkId firstArg = cast(StkId, ud);
- CallInfo *ci = L->ci;
- if (L->status == 0) { /* start coroutine? */
- lua_assert(ci == L->base_ci && firstArg > L->base);
- if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA)
- return;
- }
- else { /* resuming from previous yield */
- lua_assert(L->status == LUA_YIELD);
- L->status = 0;
- if (!f_isLua(ci)) { /* `common' yield? */
- /* finish interrupted execution of `OP_CALL' */
- lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL ||
- GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL);
- if (luaD_poscall(L, firstArg)) /* complete it... */
- L->top = L->ci->top; /* and correct top if not multiple results */
- }
- else /* yielded inside a hook: just continue its execution */
- L->base = L->ci->base;
- }
- luaV_execute(L, cast_int(L->ci - L->base_ci));
-}
-
-
-static int resume_error (lua_State *L, const char *msg) {
- L->top = L->ci->base;
- setsvalue2s(L, L->top, luaS_new(L, msg));
- incr_top(L);
- lua_unlock(L);
- return LUA_ERRRUN;
-}
-
-
-LUA_API int lua_resume (lua_State *L, int nargs) {
- int status;
- lua_lock(L);
- if (L->status != LUA_YIELD && (L->status != 0 || L->ci != L->base_ci))
- return resume_error(L, "cannot resume non-suspended coroutine");
- if (L->nCcalls >= LUAI_MAXCCALLS)
- return resume_error(L, "C stack overflow");
- luai_userstateresume(L, nargs);
- lua_assert(L->errfunc == 0);
- L->baseCcalls = ++L->nCcalls;
- status = luaD_rawrunprotected(L, resume, L->top - nargs);
- if (status != 0) { /* error? */
- L->status = cast_byte(status); /* mark thread as `dead' */
- luaD_seterrorobj(L, status, L->top);
- L->ci->top = L->top;
- }
- else {
- lua_assert(L->nCcalls == L->baseCcalls);
- status = L->status;
- }
- --L->nCcalls;
- lua_unlock(L);
- return status;
-}
-
-
-LUA_API int lua_yield (lua_State *L, int nresults) {
- luai_userstateyield(L, nresults);
- lua_lock(L);
- if (L->nCcalls > L->baseCcalls)
- luaG_runerror(L, "attempt to yield across metamethod/C-call boundary");
- L->base = L->top - nresults; /* protect stack slots below */
- L->status = LUA_YIELD;
- lua_unlock(L);
- return -1;
-}
-
-
-int luaD_pcall (lua_State *L, Pfunc func, void *u,
- ptrdiff_t old_top, ptrdiff_t ef) {
- int status;
- unsigned short oldnCcalls = L->nCcalls;
- ptrdiff_t old_ci = saveci(L, L->ci);
- lu_byte old_allowhooks = L->allowhook;
- ptrdiff_t old_errfunc = L->errfunc;
- L->errfunc = ef;
- status = luaD_rawrunprotected(L, func, u);
- if (status != 0) { /* an error occurred? */
- StkId oldtop = restorestack(L, old_top);
- luaF_close(L, oldtop); /* close eventual pending closures */
- luaD_seterrorobj(L, status, oldtop);
- L->nCcalls = oldnCcalls;
- L->ci = restoreci(L, old_ci);
- L->base = L->ci->base;
- L->savedpc = L->ci->savedpc;
- L->allowhook = old_allowhooks;
- restore_stack_limit(L);
- }
- L->errfunc = old_errfunc;
- return status;
-}
-
-
-
-/*
-** Execute a protected parser.
-*/
-struct SParser { /* data to `f_parser' */
- ZIO *z;
- Mbuffer buff; /* buffer to be used by the scanner */
- const char *name;
-};
-
-static void f_parser (lua_State *L, void *ud) {
- int i;
- Proto *tf;
- Closure *cl;
- struct SParser *p = cast(struct SParser *, ud);
- int c = luaZ_lookahead(p->z);
- luaC_checkGC(L);
- tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z,
- &p->buff, p->name);
- cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L)));
- cl->l.p = tf;
- for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */
- cl->l.upvals[i] = luaF_newupval(L);
- setclvalue(L, L->top, cl);
- incr_top(L);
-}
-
-
-int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) {
- struct SParser p;
- int status;
- p.z = z; p.name = name;
- luaZ_initbuffer(L, &p.buff);
- status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
- luaZ_freebuffer(L, &p.buff);
- return status;
-}
-
-
diff --git a/src/lua/src/ldo.h b/src/lua/src/ldo.h
deleted file mode 100644
index 98fddac59..000000000
--- a/src/lua/src/ldo.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-** $Id: ldo.h,v 2.7.1.1 2007/12/27 13:02:25 roberto Exp $
-** Stack and Call structure of Lua
-** See Copyright Notice in lua.h
-*/
-
-#ifndef ldo_h
-#define ldo_h
-
-
-#include "lobject.h"
-#include "lstate.h"
-#include "lzio.h"
-
-
-#define luaD_checkstack(L,n) \
- if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \
- luaD_growstack(L, n); \
- else condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1));
-
-
-#define incr_top(L) {luaD_checkstack(L,1); L->top++;}
-
-#define savestack(L,p) ((char *)(p) - (char *)L->stack)
-#define restorestack(L,n) ((TValue *)((char *)L->stack + (n)))
-
-#define saveci(L,p) ((char *)(p) - (char *)L->base_ci)
-#define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n)))
-
-
-/* results from luaD_precall */
-#define PCRLUA 0 /* initiated a call to a Lua function */
-#define PCRC 1 /* did a call to a C function */
-#define PCRYIELD 2 /* C funtion yielded */
-
-
-/* type of protected functions, to be ran by `runprotected' */
-typedef void (*Pfunc) (lua_State *L, void *ud);
-
-LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name);
-LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line);
-LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults);
-LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
-LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
- ptrdiff_t oldtop, ptrdiff_t ef);
-LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult);
-LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize);
-LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
-LUAI_FUNC void luaD_growstack (lua_State *L, int n);
-
-LUAI_FUNC void luaD_throw (lua_State *L, int errcode);
-LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
-
-LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop);
-
-#endif
-
diff --git a/src/lua/src/ldump.c b/src/lua/src/ldump.c
deleted file mode 100644
index c9d3d4870..000000000
--- a/src/lua/src/ldump.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
-** $Id: ldump.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
-** save precompiled Lua chunks
-** See Copyright Notice in lua.h
-*/
-
-#include <stddef.h>
-
-#define ldump_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "lobject.h"
-#include "lstate.h"
-#include "lundump.h"
-
-typedef struct {
- lua_State* L;
- lua_Writer writer;
- void* data;
- int strip;
- int status;
-} DumpState;
-
-#define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D)
-#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D)
-
-static void DumpBlock(const void* b, size_t size, DumpState* D)
-{
- if (D->status==0)
- {
- lua_unlock(D->L);
- D->status=(*D->writer)(D->L,b,size,D->data);
- lua_lock(D->L);
- }
-}
-
-static void DumpChar(int y, DumpState* D)
-{
- char x=(char)y;
- DumpVar(x,D);
-}
-
-static void DumpInt(int x, DumpState* D)
-{
- DumpVar(x,D);
-}
-
-static void DumpNumber(lua_Number x, DumpState* D)
-{
- DumpVar(x,D);
-}
-
-static void DumpVector(const void* b, int n, size_t size, DumpState* D)
-{
- DumpInt(n,D);
- DumpMem(b,n,size,D);
-}
-
-static void DumpString(const TString* s, DumpState* D)
-{
- if (s==NULL || getstr(s)==NULL)
- {
- size_t size=0;
- DumpVar(size,D);
- }
- else
- {
- size_t size=s->tsv.len+1; /* include trailing '\0' */
- DumpVar(size,D);
- DumpBlock(getstr(s),size,D);
- }
-}
-
-#define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D)
-
-static void DumpFunction(const Proto* f, const TString* p, DumpState* D);
-
-static void DumpConstants(const Proto* f, DumpState* D)
-{
- int i,n=f->sizek;
- DumpInt(n,D);
- for (i=0; i<n; i++)
- {
- const TValue* o=&f->k[i];
- DumpChar(ttype(o),D);
- switch (ttype(o))
- {
- case LUA_TNIL:
- break;
- case LUA_TBOOLEAN:
- DumpChar(bvalue(o),D);
- break;
- case LUA_TNUMBER:
- DumpNumber(nvalue(o),D);
- break;
- case LUA_TSTRING:
- DumpString(rawtsvalue(o),D);
- break;
- default:
- lua_assert(0); /* cannot happen */
- break;
- }
- }
- n=f->sizep;
- DumpInt(n,D);
- for (i=0; i<n; i++) DumpFunction(f->p[i],f->source,D);
-}
-
-static void DumpDebug(const Proto* f, DumpState* D)
-{
- int i,n;
- n= (D->strip) ? 0 : f->sizelineinfo;
- DumpVector(f->lineinfo,n,sizeof(int),D);
- n= (D->strip) ? 0 : f->sizelocvars;
- DumpInt(n,D);
- for (i=0; i<n; i++)
- {
- DumpString(f->locvars[i].varname,D);
- DumpInt(f->locvars[i].startpc,D);
- DumpInt(f->locvars[i].endpc,D);
- }
- n= (D->strip) ? 0 : f->sizeupvalues;
- DumpInt(n,D);
- for (i=0; i<n; i++) DumpString(f->upvalues[i],D);
-}
-
-static void DumpFunction(const Proto* f, const TString* p, DumpState* D)
-{
- DumpString((f->source==p || D->strip) ? NULL : f->source,D);
- DumpInt(f->linedefined,D);
- DumpInt(f->lastlinedefined,D);
- DumpChar(f->nups,D);
- DumpChar(f->numparams,D);
- DumpChar(f->is_vararg,D);
- DumpChar(f->maxstacksize,D);
- DumpCode(f,D);
- DumpConstants(f,D);
- DumpDebug(f,D);
-}
-
-static void DumpHeader(DumpState* D)
-{
- char h[LUAC_HEADERSIZE];
- luaU_header(h);
- DumpBlock(h,LUAC_HEADERSIZE,D);
-}
-
-/*
-** dump Lua function as precompiled chunk
-*/
-int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
-{
- DumpState D;
- D.L=L;
- D.writer=w;
- D.data=data;
- D.strip=strip;
- D.status=0;
- DumpHeader(&D);
- DumpFunction(f,NULL,&D);
- return D.status;
-}
diff --git a/src/lua/src/lfunc.c b/src/lua/src/lfunc.c
deleted file mode 100644
index 813e88f58..000000000
--- a/src/lua/src/lfunc.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
-** $Id: lfunc.c,v 2.12.1.2 2007/12/28 14:58:43 roberto Exp $
-** Auxiliary functions to manipulate prototypes and closures
-** See Copyright Notice in lua.h
-*/
-
-
-#include <stddef.h>
-
-#define lfunc_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "lfunc.h"
-#include "lgc.h"
-#include "lmem.h"
-#include "lobject.h"
-#include "lstate.h"
-
-
-
-Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) {
- Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems)));
- luaC_link(L, obj2gco(c), LUA_TFUNCTION);
- c->c.isC = 1;
- c->c.env = e;
- c->c.nupvalues = cast_byte(nelems);
- return c;
-}
-
-
-Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) {
- Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems)));
- luaC_link(L, obj2gco(c), LUA_TFUNCTION);
- c->l.isC = 0;
- c->l.env = e;
- c->l.nupvalues = cast_byte(nelems);
- while (nelems--) c->l.upvals[nelems] = NULL;
- return c;
-}
-
-
-UpVal *luaF_newupval (lua_State *L) {
- UpVal *uv = luaM_new(L, UpVal);
- luaC_link(L, obj2gco(uv), LUA_TUPVAL);
- uv->v = &uv->u.value;
- setnilvalue(uv->v);
- return uv;
-}
-
-
-UpVal *luaF_findupval (lua_State *L, StkId level) {
- global_State *g = G(L);
- GCObject **pp = &L->openupval;
- UpVal *p;
- UpVal *uv;
- while (*pp != NULL && (p = ngcotouv(*pp))->v >= level) {
- lua_assert(p->v != &p->u.value);
- if (p->v == level) { /* found a corresponding upvalue? */
- if (isdead(g, obj2gco(p))) /* is it dead? */
- changewhite(obj2gco(p)); /* ressurect it */
- return p;
- }
- pp = &p->next;
- }
- uv = luaM_new(L, UpVal); /* not found: create a new one */
- uv->tt = LUA_TUPVAL;
- uv->marked = luaC_white(g);
- uv->v = level; /* current value lives in the stack */
- uv->next = *pp; /* chain it in the proper position */
- *pp = obj2gco(uv);
- uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */
- uv->u.l.next = g->uvhead.u.l.next;
- uv->u.l.next->u.l.prev = uv;
- g->uvhead.u.l.next = uv;
- lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
- return uv;
-}
-
-
-static void unlinkupval (UpVal *uv) {
- lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
- uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */
- uv->u.l.prev->u.l.next = uv->u.l.next;
-}
-
-
-void luaF_freeupval (lua_State *L, UpVal *uv) {
- if (uv->v != &uv->u.value) /* is it open? */
- unlinkupval(uv); /* remove from open list */
- luaM_free(L, uv); /* free upvalue */
-}
-
-
-void luaF_close (lua_State *L, StkId level) {
- UpVal *uv;
- global_State *g = G(L);
- while (L->openupval != NULL && (uv = ngcotouv(L->openupval))->v >= level) {
- GCObject *o = obj2gco(uv);
- lua_assert(!isblack(o) && uv->v != &uv->u.value);
- L->openupval = uv->next; /* remove from `open' list */
- if (isdead(g, o))
- luaF_freeupval(L, uv); /* free upvalue */
- else {
- unlinkupval(uv);
- setobj(L, &uv->u.value, uv->v);
- uv->v = &uv->u.value; /* now current value lives here */
- luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */
- }
- }
-}
-
-
-Proto *luaF_newproto (lua_State *L) {
- Proto *f = luaM_new(L, Proto);
- luaC_link(L, obj2gco(f), LUA_TPROTO);
- f->k = NULL;
- f->sizek = 0;
- f->p = NULL;
- f->sizep = 0;
- f->code = NULL;
- f->sizecode = 0;
- f->sizelineinfo = 0;
- f->sizeupvalues = 0;
- f->nups = 0;
- f->upvalues = NULL;
- f->numparams = 0;
- f->is_vararg = 0;
- f->maxstacksize = 0;
- f->lineinfo = NULL;
- f->sizelocvars = 0;
- f->locvars = NULL;
- f->linedefined = 0;
- f->lastlinedefined = 0;
- f->source = NULL;
- return f;
-}
-
-
-void luaF_freeproto (lua_State *L, Proto *f) {
- luaM_freearray(L, f->code, f->sizecode, Instruction);
- luaM_freearray(L, f->p, f->sizep, Proto *);
- luaM_freearray(L, f->k, f->sizek, TValue);
- luaM_freearray(L, f->lineinfo, f->sizelineinfo, int);
- luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar);
- luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *);
- luaM_free(L, f);
-}
-
-
-void luaF_freeclosure (lua_State *L, Closure *c) {
- int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) :
- sizeLclosure(c->l.nupvalues);
- luaM_freemem(L, c, size);
-}
-
-
-/*
-** Look for n-th local variable at line `line' in function `func'.
-** Returns NULL if not found.
-*/
-const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
- int i;
- for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
- if (pc < f->locvars[i].endpc) { /* is variable active? */
- local_number--;
- if (local_number == 0)
- return getstr(f->locvars[i].varname);
- }
- }
- return NULL; /* not found */
-}
-
diff --git a/src/lua/src/lfunc.h b/src/lua/src/lfunc.h
deleted file mode 100644
index a68cf5151..000000000
--- a/src/lua/src/lfunc.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-** $Id: lfunc.h,v 2.4.1.1 2007/12/27 13:02:25 roberto Exp $
-** Auxiliary functions to manipulate prototypes and closures
-** See Copyright Notice in lua.h
-*/
-
-#ifndef lfunc_h
-#define lfunc_h
-
-
-#include "lobject.h"
-
-
-#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \
- cast(int, sizeof(TValue)*((n)-1)))
-
-#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \
- cast(int, sizeof(TValue *)*((n)-1)))
-
-
-LUAI_FUNC Proto *luaF_newproto (lua_State *L);
-LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e);
-LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e);
-LUAI_FUNC UpVal *luaF_newupval (lua_State *L);
-LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
-LUAI_FUNC void luaF_close (lua_State *L, StkId level);
-LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
-LUAI_FUNC void luaF_freeclosure (lua_State *L, Closure *c);
-LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv);
-LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
- int pc);
-
-
-#endif
diff --git a/src/lua/src/lgc.c b/src/lua/src/lgc.c
deleted file mode 100644
index d9e0b7829..000000000
--- a/src/lua/src/lgc.c
+++ /dev/null
@@ -1,711 +0,0 @@
-/*
-** $Id: lgc.c,v 2.38.1.1 2007/12/27 13:02:25 roberto Exp $
-** Garbage Collector
-** See Copyright Notice in lua.h
-*/
-
-#include <string.h>
-
-#define lgc_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "ldebug.h"
-#include "ldo.h"
-#include "lfunc.h"
-#include "lgc.h"
-#include "lmem.h"
-#include "lobject.h"
-#include "lstate.h"
-#include "lstring.h"
-#include "ltable.h"
-#include "ltm.h"
-
-
-#define GCSTEPSIZE 1024u
-#define GCSWEEPMAX 40
-#define GCSWEEPCOST 10
-#define GCFINALIZECOST 100
-
-
-#define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS))
-
-#define makewhite(g,x) \
- ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g)))
-
-#define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT)
-#define black2gray(x) resetbit((x)->gch.marked, BLACKBIT)
-
-#define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT)
-
-
-#define isfinalized(u) testbit((u)->marked, FINALIZEDBIT)
-#define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT)
-
-
-#define KEYWEAK bitmask(KEYWEAKBIT)
-#define VALUEWEAK bitmask(VALUEWEAKBIT)
-
-
-
-#define markvalue(g,o) { checkconsistency(o); \
- if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); }
-
-#define markobject(g,t) { if (iswhite(obj2gco(t))) \
- reallymarkobject(g, obj2gco(t)); }
-
-
-#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause)
-
-
-static void removeentry (Node *n) {
- lua_assert(ttisnil(gval(n)));
- if (iscollectable(gkey(n)))
- setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */
-}
-
-
-static void reallymarkobject (global_State *g, GCObject *o) {
- lua_assert(iswhite(o) && !isdead(g, o));
- white2gray(o);
- switch (o->gch.tt) {
- case LUA_TSTRING: {
- return;
- }
- case LUA_TUSERDATA: {
- Table *mt = gco2u(o)->metatable;
- gray2black(o); /* udata are never gray */
- if (mt) markobject(g, mt);
- markobject(g, gco2u(o)->env);
- return;
- }
- case LUA_TUPVAL: {
- UpVal *uv = gco2uv(o);
- markvalue(g, uv->v);
- if (uv->v == &uv->u.value) /* closed? */
- gray2black(o); /* open upvalues are never black */
- return;
- }
- case LUA_TFUNCTION: {
- gco2cl(o)->c.gclist = g->gray;
- g->gray = o;
- break;
- }
- case LUA_TTABLE: {
- gco2h(o)->gclist = g->gray;
- g->gray = o;
- break;
- }
- case LUA_TTHREAD: {
- gco2th(o)->gclist = g->gray;
- g->gray = o;
- break;
- }
- case LUA_TPROTO: {
- gco2p(o)->gclist = g->gray;
- g->gray = o;
- break;
- }
- default: lua_assert(0);
- }
-}
-
-
-static void marktmu (global_State *g) {
- GCObject *u = g->tmudata;
- if (u) {
- do {
- u = u->gch.next;
- makewhite(g, u); /* may be marked, if left from previous GC */
- reallymarkobject(g, u);
- } while (u != g->tmudata);
- }
-}
-
-
-/* move `dead' udata that need finalization to list `tmudata' */
-size_t luaC_separateudata (lua_State *L, int all) {
- global_State *g = G(L);
- size_t deadmem = 0;
- GCObject **p = &g->mainthread->next;
- GCObject *curr;
- while ((curr = *p) != NULL) {
- if (!(iswhite(curr) || all) || isfinalized(gco2u(curr)))
- p = &curr->gch.next; /* don't bother with them */
- else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) {
- markfinalized(gco2u(curr)); /* don't need finalization */
- p = &curr->gch.next;
- }
- else { /* must call its gc method */
- deadmem += sizeudata(gco2u(curr));
- markfinalized(gco2u(curr));
- *p = curr->gch.next;
- /* link `curr' at the end of `tmudata' list */
- if (g->tmudata == NULL) /* list is empty? */
- g->tmudata = curr->gch.next = curr; /* creates a circular list */
- else {
- curr->gch.next = g->tmudata->gch.next;
- g->tmudata->gch.next = curr;
- g->tmudata = curr;
- }
- }
- }
- return deadmem;
-}
-
-
-static int traversetable (global_State *g, Table *h) {
- int i;
- int weakkey = 0;
- int weakvalue = 0;
- const TValue *mode;
- if (h->metatable)
- markobject(g, h->metatable);
- mode = gfasttm(g, h->metatable, TM_MODE);
- if (mode && ttisstring(mode)) { /* is there a weak mode? */
- weakkey = (strchr(svalue(mode), 'k') != NULL);
- weakvalue = (strchr(svalue(mode), 'v') != NULL);
- if (weakkey || weakvalue) { /* is really weak? */
- h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */
- h->marked |= cast_byte((weakkey << KEYWEAKBIT) |
- (weakvalue << VALUEWEAKBIT));
- h->gclist = g->weak; /* must be cleared after GC, ... */
- g->weak = obj2gco(h); /* ... so put in the appropriate list */
- }
- }
- if (weakkey && weakvalue) return 1;
- if (!weakvalue) {
- i = h->sizearray;
- while (i--)
- markvalue(g, &h->array[i]);
- }
- i = sizenode(h);
- while (i--) {
- Node *n = gnode(h, i);
- lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n)));
- if (ttisnil(gval(n)))
- removeentry(n); /* remove empty entries */
- else {
- lua_assert(!ttisnil(gkey(n)));
- if (!weakkey) markvalue(g, gkey(n));
- if (!weakvalue) markvalue(g, gval(n));
- }
- }
- return weakkey || weakvalue;
-}
-
-
-/*
-** All marks are conditional because a GC may happen while the
-** prototype is still being created
-*/
-static void traverseproto (global_State *g, Proto *f) {
- int i;
- if (f->source) stringmark(f->source);
- for (i=0; i<f->sizek; i++) /* mark literals */
- markvalue(g, &f->k[i]);
- for (i=0; i<f->sizeupvalues; i++) { /* mark upvalue names */
- if (f->upvalues[i])
- stringmark(f->upvalues[i]);
- }
- for (i=0; i<f->sizep; i++) { /* mark nested protos */
- if (f->p[i])
- markobject(g, f->p[i]);
- }
- for (i=0; i<f->sizelocvars; i++) { /* mark local-variable names */
- if (f->locvars[i].varname)
- stringmark(f->locvars[i].varname);
- }
-}
-
-
-
-static void traverseclosure (global_State *g, Closure *cl) {
- markobject(g, cl->c.env);
- if (cl->c.isC) {
- int i;
- for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */
- markvalue(g, &cl->c.upvalue[i]);
- }
- else {
- int i;
- lua_assert(cl->l.nupvalues == cl->l.p->nups);
- markobject(g, cl->l.p);
- for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */
- markobject(g, cl->l.upvals[i]);
- }
-}
-
-
-static void checkstacksizes (lua_State *L, StkId max) {
- int ci_used = cast_int(L->ci - L->base_ci); /* number of `ci' in use */
- int s_used = cast_int(max - L->stack); /* part of stack in use */
- if (L->size_ci > LUAI_MAXCALLS) /* handling overflow? */
- return; /* do not touch the stacks */
- if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci)
- luaD_reallocCI(L, L->size_ci/2); /* still big enough... */
- condhardstacktests(luaD_reallocCI(L, ci_used + 1));
- if (4*s_used < L->stacksize &&
- 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize)
- luaD_reallocstack(L, L->stacksize/2); /* still big enough... */
- condhardstacktests(luaD_reallocstack(L, s_used));
-}
-
-
-static void traversestack (global_State *g, lua_State *l) {
- StkId o, lim;
- CallInfo *ci;
- markvalue(g, gt(l));
- lim = l->top;
- for (ci = l->base_ci; ci <= l->ci; ci++) {
- lua_assert(ci->top <= l->stack_last);
- if (lim < ci->top) lim = ci->top;
- }
- for (o = l->stack; o < l->top; o++)
- markvalue(g, o);
- for (; o <= lim; o++)
- setnilvalue(o);
- checkstacksizes(l, lim);
-}
-
-
-/*
-** traverse one gray object, turning it to black.
-** Returns `quantity' traversed.
-*/
-static l_mem propagatemark (global_State *g) {
- GCObject *o = g->gray;
- lua_assert(isgray(o));
- gray2black(o);
- switch (o->gch.tt) {
- case LUA_TTABLE: {
- Table *h = gco2h(o);
- g->gray = h->gclist;
- if (traversetable(g, h)) /* table is weak? */
- black2gray(o); /* keep it gray */
- return sizeof(Table) + sizeof(TValue) * h->sizearray +
- sizeof(Node) * sizenode(h);
- }
- case LUA_TFUNCTION: {
- Closure *cl = gco2cl(o);
- g->gray = cl->c.gclist;
- traverseclosure(g, cl);
- return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) :
- sizeLclosure(cl->l.nupvalues);
- }
- case LUA_TTHREAD: {
- lua_State *th = gco2th(o);
- g->gray = th->gclist;
- th->gclist = g->grayagain;
- g->grayagain = o;
- black2gray(o);
- traversestack(g, th);
- return sizeof(lua_State) + sizeof(TValue) * th->stacksize +
- sizeof(CallInfo) * th->size_ci;
- }
- case LUA_TPROTO: {
- Proto *p = gco2p(o);
- g->gray = p->gclist;
- traverseproto(g, p);
- return sizeof(Proto) + sizeof(Instruction) * p->sizecode +
- sizeof(Proto *) * p->sizep +
- sizeof(TValue) * p->sizek +
- sizeof(int) * p->sizelineinfo +
- sizeof(LocVar) * p->sizelocvars +
- sizeof(TString *) * p->sizeupvalues;
- }
- default: lua_assert(0); return 0;
- }
-}
-
-
-static size_t propagateall (global_State *g) {
- size_t m = 0;
- while (g->gray) m += propagatemark(g);
- return m;
-}
-
-
-/*
-** The next function tells whether a key or value can be cleared from
-** a weak table. Non-collectable objects are never removed from weak
-** tables. Strings behave as `values', so are never removed too. for
-** other objects: if really collected, cannot keep them; for userdata
-** being finalized, keep them in keys, but not in values
-*/
-static int iscleared (const TValue *o, int iskey) {
- if (!iscollectable(o)) return 0;
- if (ttisstring(o)) {
- stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */
- return 0;
- }
- return iswhite(gcvalue(o)) ||
- (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o))));
-}
-
-
-/*
-** clear collected entries from weaktables
-*/
-static void cleartable (GCObject *l) {
- while (l) {
- Table *h = gco2h(l);
- int i = h->sizearray;
- lua_assert(testbit(h->marked, VALUEWEAKBIT) ||
- testbit(h->marked, KEYWEAKBIT));
- if (testbit(h->marked, VALUEWEAKBIT)) {
- while (i--) {
- TValue *o = &h->array[i];
- if (iscleared(o, 0)) /* value was collected? */
- setnilvalue(o); /* remove value */
- }
- }
- i = sizenode(h);
- while (i--) {
- Node *n = gnode(h, i);
- if (!ttisnil(gval(n)) && /* non-empty entry? */
- (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) {
- setnilvalue(gval(n)); /* remove value ... */
- removeentry(n); /* remove entry from table */
- }
- }
- l = h->gclist;
- }
-}
-
-
-static void freeobj (lua_State *L, GCObject *o) {
- switch (o->gch.tt) {
- case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
- case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break;
- case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;
- case LUA_TTABLE: luaH_free(L, gco2h(o)); break;
- case LUA_TTHREAD: {
- lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread);
- luaE_freethread(L, gco2th(o));
- break;
- }
- case LUA_TSTRING: {
- G(L)->strt.nuse--;
- luaM_freemem(L, o, sizestring(gco2ts(o)));
- break;
- }
- case LUA_TUSERDATA: {
- luaM_freemem(L, o, sizeudata(gco2u(o)));
- break;
- }
- default: lua_assert(0);
- }
-}
-
-
-
-#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM)
-
-
-static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
- GCObject *curr;
- global_State *g = G(L);
- int deadmask = otherwhite(g);
- while ((curr = *p) != NULL && count-- > 0) {
- if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */
- sweepwholelist(L, &gco2th(curr)->openupval);
- if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */
- lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT));
- makewhite(g, curr); /* make it white (for next cycle) */
- p = &curr->gch.next;
- }
- else { /* must erase `curr' */
- lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
- *p = curr->gch.next;
- if (curr == g->rootgc) /* is the first element of the list? */
- g->rootgc = curr->gch.next; /* adjust first */
- freeobj(L, curr);
- }
- }
- return p;
-}
-
-
-static void checkSizes (lua_State *L) {
- global_State *g = G(L);
- /* check size of string hash */
- if (g->strt.nuse < cast(lu_int32, g->strt.size/4) &&
- g->strt.size > MINSTRTABSIZE*2)
- luaS_resize(L, g->strt.size/2); /* table is too big */
- /* check size of buffer */
- if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */
- size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
- luaZ_resizebuffer(L, &g->buff, newsize);
- }
-}
-
-
-static void GCTM (lua_State *L) {
- global_State *g = G(L);
- GCObject *o = g->tmudata->gch.next; /* get first element */
- Udata *udata = rawgco2u(o);
- const TValue *tm;
- /* remove udata from `tmudata' */
- if (o == g->tmudata) /* last element? */
- g->tmudata = NULL;
- else
- g->tmudata->gch.next = udata->uv.next;
- udata->uv.next = g->mainthread->next; /* return it to `root' list */
- g->mainthread->next = o;
- makewhite(g, o);
- tm = fasttm(L, udata->uv.metatable, TM_GC);
- if (tm != NULL) {
- lu_byte oldah = L->allowhook;
- lu_mem oldt = g->GCthreshold;
- L->allowhook = 0; /* stop debug hooks during GC tag method */
- g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */
- setobj2s(L, L->top, tm);
- setuvalue(L, L->top+1, udata);
- L->top += 2;
- luaD_call(L, L->top - 2, 0);
- L->allowhook = oldah; /* restore hooks */
- g->GCthreshold = oldt; /* restore threshold */
- }
-}
-
-
-/*
-** Call all GC tag methods
-*/
-void luaC_callGCTM (lua_State *L) {
- while (G(L)->tmudata)
- GCTM(L);
-}
-
-
-void luaC_freeall (lua_State *L) {
- global_State *g = G(L);
- int i;
- g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); /* mask to collect all elements */
- sweepwholelist(L, &g->rootgc);
- for (i = 0; i < g->strt.size; i++) /* free all string lists */
- sweepwholelist(L, &g->strt.hash[i]);
-}
-
-
-static void markmt (global_State *g) {
- int i;
- for (i=0; i<NUM_TAGS; i++)
- if (g->mt[i]) markobject(g, g->mt[i]);
-}
-
-
-/* mark root set */
-static void markroot (lua_State *L) {
- global_State *g = G(L);
- g->gray = NULL;
- g->grayagain = NULL;
- g->weak = NULL;
- markobject(g, g->mainthread);
- /* make global table be traversed before main stack */
- markvalue(g, gt(g->mainthread));
- markvalue(g, registry(L));
- markmt(g);
- g->gcstate = GCSpropagate;
-}
-
-
-static void remarkupvals (global_State *g) {
- UpVal *uv;
- for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
- lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
- if (isgray(obj2gco(uv)))
- markvalue(g, uv->v);
- }
-}
-
-
-static void atomic (lua_State *L) {
- global_State *g = G(L);
- size_t udsize; /* total size of userdata to be finalized */
- /* remark occasional upvalues of (maybe) dead threads */
- remarkupvals(g);
- /* traverse objects cautch by write barrier and by 'remarkupvals' */
- propagateall(g);
- /* remark weak tables */
- g->gray = g->weak;
- g->weak = NULL;
- lua_assert(!iswhite(obj2gco(g->mainthread)));
- markobject(g, L); /* mark running thread */
- markmt(g); /* mark basic metatables (again) */
- propagateall(g);
- /* remark gray again */
- g->gray = g->grayagain;
- g->grayagain = NULL;
- propagateall(g);
- udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */
- marktmu(g); /* mark `preserved' userdata */
- udsize += propagateall(g); /* remark, to propagate `preserveness' */
- cleartable(g->weak); /* remove collected objects from weak tables */
- /* flip current white */
- g->currentwhite = cast_byte(otherwhite(g));
- g->sweepstrgc = 0;
- g->sweepgc = &g->rootgc;
- g->gcstate = GCSsweepstring;
- g->estimate = g->totalbytes - udsize; /* first estimate */
-}
-
-
-static l_mem singlestep (lua_State *L) {
- global_State *g = G(L);
- /*lua_checkmemory(L);*/
- switch (g->gcstate) {
- case GCSpause: {
- markroot(L); /* start a new collection */
- return 0;
- }
- case GCSpropagate: {
- if (g->gray)
- return propagatemark(g);
- else { /* no more `gray' objects */
- atomic(L); /* finish mark phase */
- return 0;
- }
- }
- case GCSsweepstring: {
- lu_mem old = g->totalbytes;
- sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
- if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */
- g->gcstate = GCSsweep; /* end sweep-string phase */
- lua_assert(old >= g->totalbytes);
- g->estimate -= old - g->totalbytes;
- return GCSWEEPCOST;
- }
- case GCSsweep: {
- lu_mem old = g->totalbytes;
- g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
- if (*g->sweepgc == NULL) { /* nothing more to sweep? */
- checkSizes(L);
- g->gcstate = GCSfinalize; /* end sweep phase */
- }
- lua_assert(old >= g->totalbytes);
- g->estimate -= old - g->totalbytes;
- return GCSWEEPMAX*GCSWEEPCOST;
- }
- case GCSfinalize: {
- if (g->tmudata) {
- GCTM(L);
- if (g->estimate > GCFINALIZECOST)
- g->estimate -= GCFINALIZECOST;
- return GCFINALIZECOST;
- }
- else {
- g->gcstate = GCSpause; /* end collection */
- g->gcdept = 0;
- return 0;
- }
- }
- default: lua_assert(0); return 0;
- }
-}
-
-
-void luaC_step (lua_State *L) {
- global_State *g = G(L);
- l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul;
- if (lim == 0)
- lim = (MAX_LUMEM-1)/2; /* no limit */
- g->gcdept += g->totalbytes - g->GCthreshold;
- do {
- lim -= singlestep(L);
- if (g->gcstate == GCSpause)
- break;
- } while (lim > 0);
- if (g->gcstate != GCSpause) {
- if (g->gcdept < GCSTEPSIZE)
- g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/g->gcstepmul;*/
- else {
- g->gcdept -= GCSTEPSIZE;
- g->GCthreshold = g->totalbytes;
- }
- }
- else {
- lua_assert(g->totalbytes >= g->estimate);
- setthreshold(g);
- }
-}
-
-
-void luaC_fullgc (lua_State *L) {
- global_State *g = G(L);
- if (g->gcstate <= GCSpropagate) {
- /* reset sweep marks to sweep all elements (returning them to white) */
- g->sweepstrgc = 0;
- g->sweepgc = &g->rootgc;
- /* reset other collector lists */
- g->gray = NULL;
- g->grayagain = NULL;
- g->weak = NULL;
- g->gcstate = GCSsweepstring;
- }
- lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate);
- /* finish any pending sweep phase */
- while (g->gcstate != GCSfinalize) {
- lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);
- singlestep(L);
- }
- markroot(L);
- while (g->gcstate != GCSpause) {
- singlestep(L);
- }
- setthreshold(g);
-}
-
-
-void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
- global_State *g = G(L);
- lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
- lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
- lua_assert(ttype(&o->gch) != LUA_TTABLE);
- /* must keep invariant? */
- if (g->gcstate == GCSpropagate)
- reallymarkobject(g, v); /* restore invariant */
- else /* don't mind */
- makewhite(g, o); /* mark as white just to avoid other barriers */
-}
-
-
-void luaC_barrierback (lua_State *L, Table *t) {
- global_State *g = G(L);
- GCObject *o = obj2gco(t);
- lua_assert(isblack(o) && !isdead(g, o));
- lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
- black2gray(o); /* make table gray (again) */
- t->gclist = g->grayagain;
- g->grayagain = o;
-}
-
-
-void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
- global_State *g = G(L);
- o->gch.next = g->rootgc;
- g->rootgc = o;
- o->gch.marked = luaC_white(g);
- o->gch.tt = tt;
-}
-
-
-void luaC_linkupval (lua_State *L, UpVal *uv) {
- global_State *g = G(L);
- GCObject *o = obj2gco(uv);
- o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */
- g->rootgc = o;
- if (isgray(o)) {
- if (g->gcstate == GCSpropagate) {
- gray2black(o); /* closed upvalues need barrier */
- luaC_barrier(L, uv, uv->v);
- }
- else { /* sweep phase: sweep it (turning it into white) */
- makewhite(g, o);
- lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
- }
- }
-}
-
diff --git a/src/lua/src/lgc.h b/src/lua/src/lgc.h
deleted file mode 100644
index 5a8dc605b..000000000
--- a/src/lua/src/lgc.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
-** $Id: lgc.h,v 2.15.1.1 2007/12/27 13:02:25 roberto Exp $
-** Garbage Collector
-** See Copyright Notice in lua.h
-*/
-
-#ifndef lgc_h
-#define lgc_h
-
-
-#include "lobject.h"
-
-
-/*
-** Possible states of the Garbage Collector
-*/
-#define GCSpause 0
-#define GCSpropagate 1
-#define GCSsweepstring 2
-#define GCSsweep 3
-#define GCSfinalize 4
-
-
-/*
-** some userful bit tricks
-*/
-#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m)))
-#define setbits(x,m) ((x) |= (m))
-#define testbits(x,m) ((x) & (m))
-#define bitmask(b) (1<<(b))
-#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2))
-#define l_setbit(x,b) setbits(x, bitmask(b))
-#define resetbit(x,b) resetbits(x, bitmask(b))
-#define testbit(x,b) testbits(x, bitmask(b))
-#define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2)))
-#define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2)))
-#define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2)))
-
-
-
-/*
-** Layout for bit use in `marked' field:
-** bit 0 - object is white (type 0)
-** bit 1 - object is white (type 1)
-** bit 2 - object is black
-** bit 3 - for userdata: has been finalized
-** bit 3 - for tables: has weak keys
-** bit 4 - for tables: has weak values
-** bit 5 - object is fixed (should not be collected)
-** bit 6 - object is "super" fixed (only the main thread)
-*/
-
-
-#define WHITE0BIT 0
-#define WHITE1BIT 1
-#define BLACKBIT 2
-#define FINALIZEDBIT 3
-#define KEYWEAKBIT 3
-#define VALUEWEAKBIT 4
-#define FIXEDBIT 5
-#define SFIXEDBIT 6
-#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
-
-
-#define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT)
-#define isblack(x) testbit((x)->gch.marked, BLACKBIT)
-#define isgray(x) (!isblack(x) && !iswhite(x))
-
-#define otherwhite(g) (g->currentwhite ^ WHITEBITS)
-#define isdead(g,v) ((v)->gch.marked & otherwhite(g) & WHITEBITS)
-
-#define changewhite(x) ((x)->gch.marked ^= WHITEBITS)
-#define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT)
-
-#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x)))
-
-#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
-
-
-#define luaC_checkGC(L) { \
- condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \
- if (G(L)->totalbytes >= G(L)->GCthreshold) \
- luaC_step(L); }
-
-
-#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \
- luaC_barrierf(L,obj2gco(p),gcvalue(v)); }
-
-#define luaC_barriert(L,t,v) { if (valiswhite(v) && isblack(obj2gco(t))) \
- luaC_barrierback(L,t); }
-
-#define luaC_objbarrier(L,p,o) \
- { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \
- luaC_barrierf(L,obj2gco(p),obj2gco(o)); }
-
-#define luaC_objbarriert(L,t,o) \
- { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); }
-
-LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all);
-LUAI_FUNC void luaC_callGCTM (lua_State *L);
-LUAI_FUNC void luaC_freeall (lua_State *L);
-LUAI_FUNC void luaC_step (lua_State *L);
-LUAI_FUNC void luaC_fullgc (lua_State *L);
-LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt);
-LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv);
-LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v);
-LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t);
-
-
-#endif
diff --git a/src/lua/src/linit.c b/src/lua/src/linit.c
deleted file mode 100644
index c1f90dfab..000000000
--- a/src/lua/src/linit.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-** $Id: linit.c,v 1.14.1.1 2007/12/27 13:02:25 roberto Exp $
-** Initialization of libraries for lua.c
-** See Copyright Notice in lua.h
-*/
-
-
-#define linit_c
-#define LUA_LIB
-
-#include "lua.h"
-
-#include "lualib.h"
-#include "lauxlib.h"
-
-
-static const luaL_Reg lualibs[] = {
- {"", luaopen_base},
- {LUA_LOADLIBNAME, luaopen_package},
- {LUA_TABLIBNAME, luaopen_table},
- {LUA_IOLIBNAME, luaopen_io},
- {LUA_OSLIBNAME, luaopen_os},
- {LUA_STRLIBNAME, luaopen_string},
- {LUA_MATHLIBNAME, luaopen_math},
- {LUA_DBLIBNAME, luaopen_debug},
- {NULL, NULL}
-};
-
-
-LUALIB_API void luaL_openlibs (lua_State *L) {
- const luaL_Reg *lib = lualibs;
- for (; lib->func; lib++) {
- lua_pushcfunction(L, lib->func);
- lua_pushstring(L, lib->name);
- lua_call(L, 1, 0);
- }
-}
-
diff --git a/src/lua/src/liolib.c b/src/lua/src/liolib.c
deleted file mode 100644
index e79ed1cb2..000000000
--- a/src/lua/src/liolib.c
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
-** $Id: liolib.c,v 2.73.1.3 2008/01/18 17:47:43 roberto Exp $
-** Standard I/O (and system) library
-** See Copyright Notice in lua.h
-*/
-
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define liolib_c
-#define LUA_LIB
-
-#include "lua.h"
-
-#include "lauxlib.h"
-#include "lualib.h"
-
-
-
-#define IO_INPUT 1
-#define IO_OUTPUT 2
-
-
-static const char *const fnames[] = {"input", "output"};
-
-
-static int pushresult (lua_State *L, int i, const char *filename) {
- int en = errno; /* calls to Lua API may change this value */
- if (i) {
- lua_pushboolean(L, 1);
- return 1;
- }
- else {
- lua_pushnil(L);
- if (filename)
- lua_pushfstring(L, "%s: %s", filename, strerror(en));
- else
- lua_pushfstring(L, "%s", strerror(en));
- lua_pushinteger(L, en);
- return 3;
- }
-}
-
-
-static void fileerror (lua_State *L, int arg, const char *filename) {
- lua_pushfstring(L, "%s: %s", filename, strerror(errno));
- luaL_argerror(L, arg, lua_tostring(L, -1));
-}
-
-
-#define tofilep(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE))
-
-
-static int io_type (lua_State *L) {
- void *ud;
- luaL_checkany(L, 1);
- ud = lua_touserdata(L, 1);
- lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
- if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1))
- lua_pushnil(L); /* not a file */
- else if (*((FILE **)ud) == NULL)
- lua_pushliteral(L, "closed file");
- else
- lua_pushliteral(L, "file");
- return 1;
-}
-
-
-static FILE *tofile (lua_State *L) {
- FILE **f = tofilep(L);
- if (*f == NULL)
- luaL_error(L, "attempt to use a closed file");
- return *f;
-}
-
-
-
-/*
-** When creating file handles, always creates a `closed' file handle
-** before opening the actual file; so, if there is a memory error, the
-** file is not left opened.
-*/
-static FILE **newfile (lua_State *L) {
- FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *));
- *pf = NULL; /* file handle is currently `closed' */
- luaL_getmetatable(L, LUA_FILEHANDLE);
- lua_setmetatable(L, -2);
- return pf;
-}
-
-
-/*
-** function to (not) close the standard files stdin, stdout, and stderr
-*/
-static int io_noclose (lua_State *L) {
- lua_pushnil(L);
- lua_pushliteral(L, "cannot close standard file");
- return 2;
-}
-
-
-/*
-** function to close 'popen' files
-*/
-static int io_pclose (lua_State *L) {
- FILE **p = tofilep(L);
- int ok = lua_pclose(L, *p);
- *p = NULL;
- return pushresult(L, ok, NULL);
-}
-
-
-/*
-** function to close regular files
-*/
-static int io_fclose (lua_State *L) {
- FILE **p = tofilep(L);
- int ok = (fclose(*p) == 0);
- *p = NULL;
- return pushresult(L, ok, NULL);
-}
-
-
-static int aux_close (lua_State *L) {
- lua_getfenv(L, 1);
- lua_getfield(L, -1, "__close");
- return (lua_tocfunction(L, -1))(L);
-}
-
-
-static int io_close (lua_State *L) {
- if (lua_isnone(L, 1))
- lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT);
- tofile(L); /* make sure argument is a file */
- return aux_close(L);
-}
-
-
-static int io_gc (lua_State *L) {
- FILE *f = *tofilep(L);
- /* ignore closed files */
- if (f != NULL)
- aux_close(L);
- return 0;
-}
-
-
-static int io_tostring (lua_State *L) {
- FILE *f = *tofilep(L);
- if (f == NULL)
- lua_pushliteral(L, "file (closed)");
- else
- lua_pushfstring(L, "file (%p)", f);
- return 1;
-}
-
-
-static int io_open (lua_State *L) {
- const char *filename = luaL_checkstring(L, 1);
- const char *mode = luaL_optstring(L, 2, "r");
- FILE **pf = newfile(L);
- *pf = fopen(filename, mode);
- return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
-}
-
-
-/*
-** this function has a separated environment, which defines the
-** correct __close for 'popen' files
-*/
-static int io_popen (lua_State *L) {
- const char *filename = luaL_checkstring(L, 1);
- const char *mode = luaL_optstring(L, 2, "r");
- FILE **pf = newfile(L);
- *pf = lua_popen(L, filename, mode);
- return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
-}
-
-
-static int io_tmpfile (lua_State *L) {
- FILE **pf = newfile(L);
- *pf = tmpfile();
- return (*pf == NULL) ? pushresult(L, 0, NULL) : 1;
-}
-
-
-static FILE *getiofile (lua_State *L, int findex) {
- FILE *f;
- lua_rawgeti(L, LUA_ENVIRONINDEX, findex);
- f = *(FILE **)lua_touserdata(L, -1);
- if (f == NULL)
- luaL_error(L, "standard %s file is closed", fnames[findex - 1]);
- return f;
-}
-
-
-static int g_iofile (lua_State *L, int f, const char *mode) {
- if (!lua_isnoneornil(L, 1)) {
- const char *filename = lua_tostring(L, 1);
- if (filename) {
- FILE **pf = newfile(L);
- *pf = fopen(filename, mode);
- if (*pf == NULL)
- fileerror(L, 1, filename);
- }
- else {
- tofile(L); /* check that it's a valid file handle */
- lua_pushvalue(L, 1);
- }
- lua_rawseti(L, LUA_ENVIRONINDEX, f);
- }
- /* return current value */
- lua_rawgeti(L, LUA_ENVIRONINDEX, f);
- return 1;
-}
-
-
-static int io_input (lua_State *L) {
- return g_iofile(L, IO_INPUT, "r");
-}
-
-
-static int io_output (lua_State *L) {
- return g_iofile(L, IO_OUTPUT, "w");
-}
-
-
-static int io_readline (lua_State *L);
-
-
-static void aux_lines (lua_State *L, int idx, int toclose) {
- lua_pushvalue(L, idx);
- lua_pushboolean(L, toclose); /* close/not close file when finished */
- lua_pushcclosure(L, io_readline, 2);
-}
-
-
-static int f_lines (lua_State *L) {
- tofile(L); /* check that it's a valid file handle */
- aux_lines(L, 1, 0);
- return 1;
-}
-
-
-static int io_lines (lua_State *L) {
- if (lua_isnoneornil(L, 1)) { /* no arguments? */
- /* will iterate over default input */
- lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT);
- return f_lines(L);
- }
- else {
- const char *filename = luaL_checkstring(L, 1);
- FILE **pf = newfile(L);
- *pf = fopen(filename, "r");
- if (*pf == NULL)
- fileerror(L, 1, filename);
- aux_lines(L, lua_gettop(L), 1);
- return 1;
- }
-}
-
-
-/*
-** {======================================================
-** READ
-** =======================================================
-*/
-
-
-static int read_number (lua_State *L, FILE *f) {
- lua_Number d;
- if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) {
- lua_pushnumber(L, d);
- return 1;
- }
- else return 0; /* read fails */
-}
-
-
-static int test_eof (lua_State *L, FILE *f) {
- int c = getc(f);
- ungetc(c, f);
- lua_pushlstring(L, NULL, 0);
- return (c != EOF);
-}
-
-
-static int read_line (lua_State *L, FILE *f) {
- luaL_Buffer b;
- luaL_buffinit(L, &b);
- for (;;) {
- size_t l;
- char *p = luaL_prepbuffer(&b);
- if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */
- luaL_pushresult(&b); /* close buffer */
- return (lua_objlen(L, -1) > 0); /* check whether read something */
- }
- l = strlen(p);
- if (l == 0 || p[l-1] != '\n')
- luaL_addsize(&b, l);
- else {
- luaL_addsize(&b, l - 1); /* do not include `eol' */
- luaL_pushresult(&b); /* close buffer */
- return 1; /* read at least an `eol' */
- }
- }
-}
-
-
-static int read_chars (lua_State *L, FILE *f, size_t n) {
- size_t rlen; /* how much to read */
- size_t nr; /* number of chars actually read */
- luaL_Buffer b;
- luaL_buffinit(L, &b);
- rlen = LUAL_BUFFERSIZE; /* try to read that much each time */
- do {
- char *p = luaL_prepbuffer(&b);
- if (rlen > n) rlen = n; /* cannot read more than asked */
- nr = fread(p, sizeof(char), rlen, f);
- luaL_addsize(&b, nr);
- n -= nr; /* still have to read `n' chars */
- } while (n > 0 && nr == rlen); /* until end of count or eof */
- luaL_pushresult(&b); /* close buffer */
- return (n == 0 || lua_objlen(L, -1) > 0);
-}
-
-
-static int g_read (lua_State *L, FILE *f, int first) {
- int nargs = lua_gettop(L) - 1;
- int success;
- int n;
- clearerr(f);
- if (nargs == 0) { /* no arguments? */
- success = read_line(L, f);
- n = first+1; /* to return 1 result */
- }
- else { /* ensure stack space for all results and for auxlib's buffer */
- luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
- success = 1;
- for (n = first; nargs-- && success; n++) {
- if (lua_type(L, n) == LUA_TNUMBER) {
- size_t l = (size_t)lua_tointeger(L, n);
- success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
- }
- else {
- const char *p = lua_tostring(L, n);
- luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
- switch (p[1]) {
- case 'n': /* number */
- success = read_number(L, f);
- break;
- case 'l': /* line */
- success = read_line(L, f);
- break;
- case 'a': /* file */
- read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */
- success = 1; /* always success */
- break;
- default:
- return luaL_argerror(L, n, "invalid format");
- }
- }
- }
- }
- if (ferror(f))
- return pushresult(L, 0, NULL);
- if (!success) {
- lua_pop(L, 1); /* remove last result */
- lua_pushnil(L); /* push nil instead */
- }
- return n - first;
-}
-
-
-static int io_read (lua_State *L) {
- return g_read(L, getiofile(L, IO_INPUT), 1);
-}
-
-
-static int f_read (lua_State *L) {
- return g_read(L, tofile(L), 2);
-}
-
-
-static int io_readline (lua_State *L) {
- FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1));
- int sucess;
- if (f == NULL) /* file is already closed? */
- luaL_error(L, "file is already closed");
- sucess = read_line(L, f);
- if (ferror(f))
- return luaL_error(L, "%s", strerror(errno));
- if (sucess) return 1;
- else { /* EOF */
- if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */
- lua_settop(L, 0);
- lua_pushvalue(L, lua_upvalueindex(1));
- aux_close(L); /* close it */
- }
- return 0;
- }
-}
-
-/* }====================================================== */
-
-
-static int g_write (lua_State *L, FILE *f, int arg) {
- int nargs = lua_gettop(L) - 1;
- int status = 1;
- for (; nargs--; arg++) {
- if (lua_type(L, arg) == LUA_TNUMBER) {
- /* optimization: could be done exactly as for strings */
- status = status &&
- fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
- }
- else {
- size_t l;
- const char *s = luaL_checklstring(L, arg, &l);
- status = status && (fwrite(s, sizeof(char), l, f) == l);
- }
- }
- return pushresult(L, status, NULL);
-}
-
-
-static int io_write (lua_State *L) {
- return g_write(L, getiofile(L, IO_OUTPUT), 1);
-}
-
-
-static int f_write (lua_State *L) {
- return g_write(L, tofile(L), 2);
-}
-
-
-static int f_seek (lua_State *L) {
- static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
- static const char *const modenames[] = {"set", "cur", "end", NULL};
- FILE *f = tofile(L);
- int op = luaL_checkoption(L, 2, "cur", modenames);
- long offset = luaL_optlong(L, 3, 0);
- op = fseek(f, offset, mode[op]);
- if (op)
- return pushresult(L, 0, NULL); /* error */
- else {
- lua_pushinteger(L, ftell(f));
- return 1;
- }
-}
-
-
-static int f_setvbuf (lua_State *L) {
- static const int mode[] = {_IONBF, _IOFBF, _IOLBF};
- static const char *const modenames[] = {"no", "full", "line", NULL};
- FILE *f = tofile(L);
- int op = luaL_checkoption(L, 2, NULL, modenames);
- lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
- int res = setvbuf(f, NULL, mode[op], sz);
- return pushresult(L, res == 0, NULL);
-}
-
-
-
-static int io_flush (lua_State *L) {
- return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
-}
-
-
-static int f_flush (lua_State *L) {
- return pushresult(L, fflush(tofile(L)) == 0, NULL);
-}
-
-
-static const luaL_Reg iolib[] = {
- {"close", io_close},
- {"flush", io_flush},
- {"input", io_input},
- {"lines", io_lines},
- {"open", io_open},
- {"output", io_output},
- {"popen", io_popen},
- {"read", io_read},
- {"tmpfile", io_tmpfile},
- {"type", io_type},
- {"write", io_write},
- {NULL, NULL}
-};
-
-
-static const luaL_Reg flib[] = {
- {"close", io_close},
- {"flush", f_flush},
- {"lines", f_lines},
- {"read", f_read},
- {"seek", f_seek},
- {"setvbuf", f_setvbuf},
- {"write", f_write},
- {"__gc", io_gc},
- {"__tostring", io_tostring},
- {NULL, NULL}
-};
-
-
-static void createmeta (lua_State *L) {
- luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */
- lua_pushvalue(L, -1); /* push metatable */
- lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
- luaL_register(L, NULL, flib); /* file methods */
-}
-
-
-static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) {
- *newfile(L) = f;
- if (k > 0) {
- lua_pushvalue(L, -1);
- lua_rawseti(L, LUA_ENVIRONINDEX, k);
- }
- lua_pushvalue(L, -2); /* copy environment */
- lua_setfenv(L, -2); /* set it */
- lua_setfield(L, -3, fname);
-}
-
-
-static void newfenv (lua_State *L, lua_CFunction cls) {
- lua_createtable(L, 0, 1);
- lua_pushcfunction(L, cls);
- lua_setfield(L, -2, "__close");
-}
-
-
-LUALIB_API int luaopen_io (lua_State *L) {
- createmeta(L);
- /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */
- newfenv(L, io_fclose);
- lua_replace(L, LUA_ENVIRONINDEX);
- /* open library */
- luaL_register(L, LUA_IOLIBNAME, iolib);
- /* create (and set) default files */
- newfenv(L, io_noclose); /* close function for default files */
- createstdfile(L, stdin, IO_INPUT, "stdin");
- createstdfile(L, stdout, IO_OUTPUT, "stdout");
- createstdfile(L, stderr, 0, "stderr");
- lua_pop(L, 1); /* pop environment for default files */
- lua_getfield(L, -1, "popen");
- newfenv(L, io_pclose); /* create environment for 'popen' */
- lua_setfenv(L, -2); /* set fenv for 'popen' */
- lua_pop(L, 1); /* pop 'popen' */
- return 1;
-}
-
diff --git a/src/lua/src/llex.c b/src/lua/src/llex.c
deleted file mode 100644
index 98068c1aa..000000000
--- a/src/lua/src/llex.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
-** $Id: llex.c,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $
-** Lexical Analyzer
-** See Copyright Notice in lua.h
-*/
-
-
-#include <ctype.h>
-#include <locale.h>
-#include <string.h>
-
-#define llex_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "ldo.h"
-#include "llex.h"
-#include "lobject.h"
-#include "lparser.h"
-#include "lstate.h"
-#include "lstring.h"
-#include "ltable.h"
-#include "lzio.h"
-
-
-
-#define next(ls) (ls->current = zgetc(ls->z))
-
-
-
-
-#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r')
-
-
-/* ORDER RESERVED */
-const char *const luaX_tokens [] = {
- "and", "break", "do", "else", "elseif",
- "end", "false", "for", "function", "if",
- "in", "local", "nil", "not", "or", "repeat",
- "return", "then", "true", "until", "while",
- "..", "...", "==", ">=", "<=", "~=",
- "<number>", "<name>", "<string>", "<eof>",
- NULL
-};
-
-
-#define save_and_next(ls) (save(ls, ls->current), next(ls))
-
-
-static void save (LexState *ls, int c) {
- Mbuffer *b = ls->buff;
- if (b->n + 1 > b->buffsize) {
- size_t newsize;
- if (b->buffsize >= MAX_SIZET/2)
- luaX_lexerror(ls, "lexical element too long", 0);
- newsize = b->buffsize * 2;
- luaZ_resizebuffer(ls->L, b, newsize);
- }
- b->buffer[b->n++] = cast(char, c);
-}
-
-
-void luaX_init (lua_State *L) {
- int i;
- for (i=0; i<NUM_RESERVED; i++) {
- TString *ts = luaS_new(L, luaX_tokens[i]);
- luaS_fix(ts); /* reserved words are never collected */
- lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN);
- ts->tsv.reserved = cast_byte(i+1); /* reserved word */
- }
-}
-
-
-#define MAXSRC 80
-
-
-const char *luaX_token2str (LexState *ls, int token) {
- if (token < FIRST_RESERVED) {
- lua_assert(token == cast(unsigned char, token));
- return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) :
- luaO_pushfstring(ls->L, "%c", token);
- }
- else
- return luaX_tokens[token-FIRST_RESERVED];
-}
-
-
-static const char *txtToken (LexState *ls, int token) {
- switch (token) {
- case TK_NAME:
- case TK_STRING:
- case TK_NUMBER:
- save(ls, '\0');
- return luaZ_buffer(ls->buff);
- default:
- return luaX_token2str(ls, token);
- }
-}
-
-
-void luaX_lexerror (LexState *ls, const char *msg, int token) {
- char buff[MAXSRC];
- luaO_chunkid(buff, getstr(ls->source), MAXSRC);
- msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg);
- if (token)
- luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token));
- luaD_throw(ls->L, LUA_ERRSYNTAX);
-}
-
-
-void luaX_syntaxerror (LexState *ls, const char *msg) {
- luaX_lexerror(ls, msg, ls->t.token);
-}
-
-
-TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
- lua_State *L = ls->L;
- TString *ts = luaS_newlstr(L, str, l);
- TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */
- if (ttisnil(o))
- setbvalue(o, 1); /* make sure `str' will not be collected */
- return ts;
-}
-
-
-static void inclinenumber (LexState *ls) {
- int old = ls->current;
- lua_assert(currIsNewline(ls));
- next(ls); /* skip `\n' or `\r' */
- if (currIsNewline(ls) && ls->current != old)
- next(ls); /* skip `\n\r' or `\r\n' */
- if (++ls->linenumber >= MAX_INT)
- luaX_syntaxerror(ls, "chunk has too many lines");
-}
-
-
-void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) {
- ls->decpoint = '.';
- ls->L = L;
- ls->lookahead.token = TK_EOS; /* no look-ahead token */
- ls->z = z;
- ls->fs = NULL;
- ls->linenumber = 1;
- ls->lastline = 1;
- ls->source = source;
- luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
- next(ls); /* read first char */
-}
-
-
-
-/*
-** =======================================================
-** LEXICAL ANALYZER
-** =======================================================
-*/
-
-
-
-static int check_next (LexState *ls, const char *set) {
- if (!strchr(set, ls->current))
- return 0;
- save_and_next(ls);
- return 1;
-}
-
-
-static void buffreplace (LexState *ls, char from, char to) {
- size_t n = luaZ_bufflen(ls->buff);
- char *p = luaZ_buffer(ls->buff);
- while (n--)
- if (p[n] == from) p[n] = to;
-}
-
-
-static void trydecpoint (LexState *ls, SemInfo *seminfo) {
- /* format error: try to update decimal point separator */
-#ifndef __ANDROID__
- struct lconv *cv = localeconv();
-#endif
- char old = ls->decpoint;
-#ifndef __ANDROID__
- ls->decpoint = (cv ? cv->decimal_point[0] : '.');
-#else
- ls->decpoint = '.';
-#endif
- buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */
- if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) {
- /* format error with correct decimal point: no more options */
- buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */
- luaX_lexerror(ls, "malformed number", TK_NUMBER);
- }
-}
-
-
-/* LUA_NUMBER */
-static void read_numeral (LexState *ls, SemInfo *seminfo) {
- lua_assert(isdigit(ls->current));
- do {
- save_and_next(ls);
- } while (isdigit(ls->current) || ls->current == '.');
- if (check_next(ls, "Ee")) /* `E'? */
- check_next(ls, "+-"); /* optional exponent sign */
- while (isalnum(ls->current) || ls->current == '_')
- save_and_next(ls);
- save(ls, '\0');
- buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
- if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) /* format error? */
- trydecpoint(ls, seminfo); /* try to update decimal point separator */
-}
-
-
-static int skip_sep (LexState *ls) {
- int count = 0;
- int s = ls->current;
- lua_assert(s == '[' || s == ']');
- save_and_next(ls);
- while (ls->current == '=') {
- save_and_next(ls);
- count++;
- }
- return (ls->current == s) ? count : (-count) - 1;
-}
-
-
-static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
- int cont = 0;
- (void)(cont); /* avoid warnings when `cont' is not used */
- save_and_next(ls); /* skip 2nd `[' */
- if (currIsNewline(ls)) /* string starts with a newline? */
- inclinenumber(ls); /* skip it */
- for (;;) {
- switch (ls->current) {
- case EOZ:
- luaX_lexerror(ls, (seminfo) ? "unfinished long string" :
- "unfinished long comment", TK_EOS);
- break; /* to avoid warnings */
-#if defined(LUA_COMPAT_LSTR)
- case '[': {
- if (skip_sep(ls) == sep) {
- save_and_next(ls); /* skip 2nd `[' */
- cont++;
-#if LUA_COMPAT_LSTR == 1
- if (sep == 0)
- luaX_lexerror(ls, "nesting of [[...]] is deprecated", '[');
-#endif
- }
- break;
- }
-#endif
- case ']': {
- if (skip_sep(ls) == sep) {
- save_and_next(ls); /* skip 2nd `]' */
-#if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2
- cont--;
- if (sep == 0 && cont >= 0) break;
-#endif
- goto endloop;
- }
- break;
- }
- case '\n':
- case '\r': {
- save(ls, '\n');
- inclinenumber(ls);
- if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */
- break;
- }
- default: {
- if (seminfo) save_and_next(ls);
- else next(ls);
- }
- }
- } endloop:
- if (seminfo)
- seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep),
- luaZ_bufflen(ls->buff) - 2*(2 + sep));
-}
-
-
-static void read_string (LexState *ls, int del, SemInfo *seminfo) {
- save_and_next(ls);
- while (ls->current != del) {
- switch (ls->current) {
- case EOZ:
- luaX_lexerror(ls, "unfinished string", TK_EOS);
- continue; /* to avoid warnings */
- case '\n':
- case '\r':
- luaX_lexerror(ls, "unfinished string", TK_STRING);
- continue; /* to avoid warnings */
- case '\\': {
- int c;
- next(ls); /* do not save the `\' */
- switch (ls->current) {
- case 'a': c = '\a'; break;
- case 'b': c = '\b'; break;
- case 'f': c = '\f'; break;
- case 'n': c = '\n'; break;
- case 'r': c = '\r'; break;
- case 't': c = '\t'; break;
- case 'v': c = '\v'; break;
- case '\n': /* go through */
- case '\r': save(ls, '\n'); inclinenumber(ls); continue;
- case EOZ: continue; /* will raise an error next loop */
- default: {
- if (!isdigit(ls->current))
- save_and_next(ls); /* handles \\, \", \', and \? */
- else { /* \xxx */
- int i = 0;
- c = 0;
- do {
- c = 10*c + (ls->current-'0');
- next(ls);
- } while (++i<3 && isdigit(ls->current));
- if (c > UCHAR_MAX)
- luaX_lexerror(ls, "escape sequence too large", TK_STRING);
- save(ls, c);
- }
- continue;
- }
- }
- save(ls, c);
- next(ls);
- continue;
- }
- default:
- save_and_next(ls);
- }
- }
- save_and_next(ls); /* skip delimiter */
- seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1,
- luaZ_bufflen(ls->buff) - 2);
-}
-
-
-static int llex (LexState *ls, SemInfo *seminfo) {
- luaZ_resetbuffer(ls->buff);
- for (;;) {
- switch (ls->current) {
- case '\n':
- case '\r': {
- inclinenumber(ls);
- continue;
- }
- case '-': {
- next(ls);
- if (ls->current != '-') return '-';
- /* else is a comment */
- next(ls);
- if (ls->current == '[') {
- int sep = skip_sep(ls);
- luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */
- if (sep >= 0) {
- read_long_string(ls, NULL, sep); /* long comment */
- luaZ_resetbuffer(ls->buff);
- continue;
- }
- }
- /* else short comment */
- while (!currIsNewline(ls) && ls->current != EOZ)
- next(ls);
- continue;
- }
- case '[': {
- int sep = skip_sep(ls);
- if (sep >= 0) {
- read_long_string(ls, seminfo, sep);
- return TK_STRING;
- }
- else if (sep == -1) return '[';
- else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING);
- }
- case '=': {
- next(ls);
- if (ls->current != '=') return '=';
- else { next(ls); return TK_EQ; }
- }
- case '<': {
- next(ls);
- if (ls->current != '=') return '<';
- else { next(ls); return TK_LE; }
- }
- case '>': {
- next(ls);
- if (ls->current != '=') return '>';
- else { next(ls); return TK_GE; }
- }
- case '~': {
- next(ls);
- if (ls->current != '=') return '~';
- else { next(ls); return TK_NE; }
- }
- case '"':
- case '\'': {
- read_string(ls, ls->current, seminfo);
- return TK_STRING;
- }
- case '.': {
- save_and_next(ls);
- if (check_next(ls, ".")) {
- if (check_next(ls, "."))
- return TK_DOTS; /* ... */
- else return TK_CONCAT; /* .. */
- }
- else if (!isdigit(ls->current)) return '.';
- else {
- read_numeral(ls, seminfo);
- return TK_NUMBER;
- }
- }
- case EOZ: {
- return TK_EOS;
- }
- default: {
- if (isspace(ls->current)) {
- lua_assert(!currIsNewline(ls));
- next(ls);
- continue;
- }
- else if (isdigit(ls->current)) {
- read_numeral(ls, seminfo);
- return TK_NUMBER;
- }
- else if (isalpha(ls->current) || ls->current == '_') {
- /* identifier or reserved word */
- TString *ts;
- do {
- save_and_next(ls);
- } while (isalnum(ls->current) || ls->current == '_');
- ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
- luaZ_bufflen(ls->buff));
- if (ts->tsv.reserved > 0) /* reserved word? */
- return ts->tsv.reserved - 1 + FIRST_RESERVED;
- else {
- seminfo->ts = ts;
- return TK_NAME;
- }
- }
- else {
- int c = ls->current;
- next(ls);
- return c; /* single-char tokens (+ - / ...) */
- }
- }
- }
- }
-}
-
-
-void luaX_next (LexState *ls) {
- ls->lastline = ls->linenumber;
- if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */
- ls->t = ls->lookahead; /* use this one */
- ls->lookahead.token = TK_EOS; /* and discharge it */
- }
- else
- ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */
-}
-
-
-void luaX_lookahead (LexState *ls) {
- lua_assert(ls->lookahead.token == TK_EOS);
- ls->lookahead.token = llex(ls, &ls->lookahead.seminfo);
-}
-
diff --git a/src/lua/src/llex.h b/src/lua/src/llex.h
deleted file mode 100644
index a9201cee4..000000000
--- a/src/lua/src/llex.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-** $Id: llex.h,v 1.58.1.1 2007/12/27 13:02:25 roberto Exp $
-** Lexical Analyzer
-** See Copyright Notice in lua.h
-*/
-
-#ifndef llex_h
-#define llex_h
-
-#include "lobject.h"
-#include "lzio.h"
-
-
-#define FIRST_RESERVED 257
-
-/* maximum length of a reserved word */
-#define TOKEN_LEN (sizeof("function")/sizeof(char))
-
-
-/*
-* WARNING: if you change the order of this enumeration,
-* grep "ORDER RESERVED"
-*/
-enum RESERVED {
- /* terminal symbols denoted by reserved words */
- TK_AND = FIRST_RESERVED, TK_BREAK,
- TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
- TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
- TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
- /* other terminal symbols */
- TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER,
- TK_NAME, TK_STRING, TK_EOS
-};
-
-/* number of reserved words */
-#define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1))
-
-
-/* array with token `names' */
-LUAI_DATA const char *const luaX_tokens [];
-
-
-typedef union {
- lua_Number r;
- TString *ts;
-} SemInfo; /* semantics information */
-
-
-typedef struct Token {
- int token;
- SemInfo seminfo;
-} Token;
-
-
-typedef struct LexState {
- int current; /* current character (charint) */
- int linenumber; /* input line counter */
- int lastline; /* line of last token `consumed' */
- Token t; /* current token */
- Token lookahead; /* look ahead token */
- struct FuncState *fs; /* `FuncState' is private to the parser */
- struct lua_State *L;
- ZIO *z; /* input stream */
- Mbuffer *buff; /* buffer for tokens */
- TString *source; /* current source name */
- char decpoint; /* locale decimal point */
-} LexState;
-
-
-LUAI_FUNC void luaX_init (lua_State *L);
-LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z,
- TString *source);
-LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l);
-LUAI_FUNC void luaX_next (LexState *ls);
-LUAI_FUNC void luaX_lookahead (LexState *ls);
-LUAI_FUNC void luaX_lexerror (LexState *ls, const char *msg, int token);
-LUAI_FUNC void luaX_syntaxerror (LexState *ls, const char *s);
-LUAI_FUNC const char *luaX_token2str (LexState *ls, int token);
-
-
-#endif
diff --git a/src/lua/src/llimits.h b/src/lua/src/llimits.h
deleted file mode 100644
index ca8dcb722..000000000
--- a/src/lua/src/llimits.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
-** $Id: llimits.h,v 1.69.1.1 2007/12/27 13:02:25 roberto Exp $
-** Limits, basic types, and some other `installation-dependent' definitions
-** See Copyright Notice in lua.h
-*/
-
-#ifndef llimits_h
-#define llimits_h
-
-
-#include <limits.h>
-#include <stddef.h>
-
-
-#include "lua.h"
-
-
-typedef LUAI_UINT32 lu_int32;
-
-typedef LUAI_UMEM lu_mem;
-
-typedef LUAI_MEM l_mem;
-
-
-
-/* chars used as small naturals (so that `char' is reserved for characters) */
-typedef unsigned char lu_byte;
-
-
-#define MAX_SIZET ((size_t)(~(size_t)0)-2)
-
-#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2)
-
-
-#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */
-
-/*
-** conversion of pointer to integer
-** this is for hashing only; there is no problem if the integer
-** cannot hold the whole pointer value
-*/
-#define IntPoint(p) ((unsigned int)(lu_mem)(p))
-
-
-
-/* type to ensure maximum alignment */
-typedef LUAI_USER_ALIGNMENT_T L_Umaxalign;
-
-
-/* result of a `usual argument conversion' over lua_Number */
-typedef LUAI_UACNUMBER l_uacNumber;
-
-
-/* internal assertions for in-house debugging */
-#ifdef lua_assert
-
-#define check_exp(c,e) (lua_assert(c), (e))
-#define api_check(l,e) lua_assert(e)
-
-#else
-
-#define lua_assert(c) ((void)0)
-#define check_exp(c,e) (e)
-#define api_check luai_apicheck
-
-#endif
-
-
-#ifndef UNUSED
-#define UNUSED(x) ((void)(x)) /* to avoid warnings */
-#endif
-
-
-#ifndef cast
-#define cast(t, exp) ((t)(exp))
-#endif
-
-#define cast_byte(i) cast(lu_byte, (i))
-#define cast_num(i) cast(lua_Number, (i))
-#define cast_int(i) cast(int, (i))
-
-
-
-/*
-** type for virtual-machine instructions
-** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
-*/
-typedef lu_int32 Instruction;
-
-
-
-/* maximum stack for a Lua function */
-#define MAXSTACK 250
-
-
-
-/* minimum size for the string table (must be power of 2) */
-#ifndef MINSTRTABSIZE
-#define MINSTRTABSIZE 32
-#endif
-
-
-/* minimum size for string buffer */
-#ifndef LUA_MINBUFFER
-#define LUA_MINBUFFER 32
-#endif
-
-
-#ifndef lua_lock
-#define lua_lock(L) ((void) 0)
-#define lua_unlock(L) ((void) 0)
-#endif
-
-#ifndef luai_threadyield
-#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);}
-#endif
-
-
-/*
-** macro to control inclusion of some hard tests on stack reallocation
-*/
-#ifndef HARDSTACKTESTS
-#define condhardstacktests(x) ((void)0)
-#else
-#define condhardstacktests(x) x
-#endif
-
-#endif
diff --git a/src/lua/src/lmathlib.c b/src/lua/src/lmathlib.c
deleted file mode 100644
index 441fbf736..000000000
--- a/src/lua/src/lmathlib.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
-** $Id: lmathlib.c,v 1.67.1.1 2007/12/27 13:02:25 roberto Exp $
-** Standard mathematical library
-** See Copyright Notice in lua.h
-*/
-
-
-#include <stdlib.h>
-#include <math.h>
-
-#define lmathlib_c
-#define LUA_LIB
-
-#include "lua.h"
-
-#include "lauxlib.h"
-#include "lualib.h"
-
-
-#undef PI
-#define PI (3.14159265358979323846)
-#define RADIANS_PER_DEGREE (PI/180.0)
-
-
-
-static int math_abs (lua_State *L) {
- lua_pushnumber(L, fabs(luaL_checknumber(L, 1)));
- return 1;
-}
-
-static int math_sin (lua_State *L) {
- lua_pushnumber(L, sin(luaL_checknumber(L, 1)));
- return 1;
-}
-
-static int math_sinh (lua_State *L) {
- lua_pushnumber(L, sinh(luaL_checknumber(L, 1)));
- return 1;
-}
-
-static int math_cos (lua_State *L) {
- lua_pushnumber(L, cos(luaL_checknumber(L, 1)));
- return 1;
-}
-
-static int math_cosh (lua_State *L) {
- lua_pushnumber(L, cosh(luaL_checknumber(L, 1)));
- return 1;
-}
-
-static int math_tan (lua_State *L) {
- lua_pushnumber(L, tan(luaL_checknumber(L, 1)));
- return 1;
-}
-
-static int math_tanh (lua_State *L) {
- lua_pushnumber(L, tanh(luaL_checknumber(L, 1)));
- return 1;
-}
-
-static int math_asin (lua_State *L) {
- lua_pushnumber(L, asin(luaL_checknumber(L, 1)));
- return 1;
-}
-
-static int math_acos (lua_State *L) {
- lua_pushnumber(L, acos(luaL_checknumber(L, 1)));
- return 1;
-}
-
-static int math_atan (lua_State *L) {
- lua_pushnumber(L, atan(luaL_checknumber(L, 1)));
- return 1;
-}
-
-static int math_atan2 (lua_State *L) {
- lua_pushnumber(L, atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
- return 1;
-}
-
-static int math_ceil (lua_State *L) {
- lua_pushnumber(L, ceil(luaL_checknumber(L, 1)));
- return 1;
-}
-
-static int math_floor (lua_State *L) {
- lua_pushnumber(L, floor(luaL_checknumber(L, 1)));
- return 1;
-}
-
-static int math_fmod (lua_State *L) {
- lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
- return 1;
-}
-
-static int math_modf (lua_State *L) {
- double ip;
- double fp = modf(luaL_checknumber(L, 1), &ip);
- lua_pushnumber(L, ip);
- lua_pushnumber(L, fp);
- return 2;
-}
-
-static int math_sqrt (lua_State *L) {
- lua_pushnumber(L, sqrt(luaL_checknumber(L, 1)));
- return 1;
-}
-
-static int math_pow (lua_State *L) {
- lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
- return 1;
-}
-
-static int math_log (lua_State *L) {
- lua_pushnumber(L, log(luaL_checknumber(L, 1)));
- return 1;
-}
-
-static int math_log10 (lua_State *L) {
- lua_pushnumber(L, log10(luaL_checknumber(L, 1)));
- return 1;
-}
-
-static int math_exp (lua_State *L) {
- lua_pushnumber(L, exp(luaL_checknumber(L, 1)));
- return 1;
-}
-
-static int math_deg (lua_State *L) {
- lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE);
- return 1;
-}
-
-static int math_rad (lua_State *L) {
- lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE);
- return 1;
-}
-
-static int math_frexp (lua_State *L) {
- int e;
- lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e));
- lua_pushinteger(L, e);
- return 2;
-}
-
-static int math_ldexp (lua_State *L) {
- lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2)));
- return 1;
-}
-
-
-
-static int math_min (lua_State *L) {
- int n = lua_gettop(L); /* number of arguments */
- lua_Number dmin = luaL_checknumber(L, 1);
- int i;
- for (i=2; i<=n; i++) {
- lua_Number d = luaL_checknumber(L, i);
- if (d < dmin)
- dmin = d;
- }
- lua_pushnumber(L, dmin);
- return 1;
-}
-
-
-static int math_max (lua_State *L) {
- int n = lua_gettop(L); /* number of arguments */
- lua_Number dmax = luaL_checknumber(L, 1);
- int i;
- for (i=2; i<=n; i++) {
- lua_Number d = luaL_checknumber(L, i);
- if (d > dmax)
- dmax = d;
- }
- lua_pushnumber(L, dmax);
- return 1;
-}
-
-
-static int math_random (lua_State *L) {
- /* the `%' avoids the (rare) case of r==1, and is needed also because on
- some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
- lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX;
- switch (lua_gettop(L)) { /* check number of arguments */
- case 0: { /* no arguments */
- lua_pushnumber(L, r); /* Number between 0 and 1 */
- break;
- }
- case 1: { /* only upper limit */
- int u = luaL_checkint(L, 1);
- luaL_argcheck(L, 1<=u, 1, "interval is empty");
- lua_pushnumber(L, floor(r*u)+1); /* int between 1 and `u' */
- break;
- }
- case 2: { /* lower and upper limits */
- int l = luaL_checkint(L, 1);
- int u = luaL_checkint(L, 2);
- luaL_argcheck(L, l<=u, 2, "interval is empty");
- lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */
- break;
- }
- default: return luaL_error(L, "wrong number of arguments");
- }
- return 1;
-}
-
-
-static int math_randomseed (lua_State *L) {
- srand(luaL_checkint(L, 1));
- return 0;
-}
-
-
-static const luaL_Reg mathlib[] = {
- {"abs", math_abs},
- {"acos", math_acos},
- {"asin", math_asin},
- {"atan2", math_atan2},
- {"atan", math_atan},
- {"ceil", math_ceil},
- {"cosh", math_cosh},
- {"cos", math_cos},
- {"deg", math_deg},
- {"exp", math_exp},
- {"floor", math_floor},
- {"fmod", math_fmod},
- {"frexp", math_frexp},
- {"ldexp", math_ldexp},
- {"log10", math_log10},
- {"log", math_log},
- {"max", math_max},
- {"min", math_min},
- {"modf", math_modf},
- {"pow", math_pow},
- {"rad", math_rad},
- {"random", math_random},
- {"randomseed", math_randomseed},
- {"sinh", math_sinh},
- {"sin", math_sin},
- {"sqrt", math_sqrt},
- {"tanh", math_tanh},
- {"tan", math_tan},
- {NULL, NULL}
-};
-
-
-/*
-** Open math library
-*/
-LUALIB_API int luaopen_math (lua_State *L) {
- luaL_register(L, LUA_MATHLIBNAME, mathlib);
- lua_pushnumber(L, PI);
- lua_setfield(L, -2, "pi");
- lua_pushnumber(L, HUGE_VAL);
- lua_setfield(L, -2, "huge");
-#if defined(LUA_COMPAT_MOD)
- lua_getfield(L, -1, "fmod");
- lua_setfield(L, -2, "mod");
-#endif
- return 1;
-}
-
diff --git a/src/lua/src/lmem.c b/src/lua/src/lmem.c
deleted file mode 100644
index ae7d8c965..000000000
--- a/src/lua/src/lmem.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
-** $Id: lmem.c,v 1.70.1.1 2007/12/27 13:02:25 roberto Exp $
-** Interface to Memory Manager
-** See Copyright Notice in lua.h
-*/
-
-
-#include <stddef.h>
-
-#define lmem_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "ldebug.h"
-#include "ldo.h"
-#include "lmem.h"
-#include "lobject.h"
-#include "lstate.h"
-
-
-
-/*
-** About the realloc function:
-** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
-** (`osize' is the old size, `nsize' is the new size)
-**
-** Lua ensures that (ptr == NULL) iff (osize == 0).
-**
-** * frealloc(ud, NULL, 0, x) creates a new block of size `x'
-**
-** * frealloc(ud, p, x, 0) frees the block `p'
-** (in this specific case, frealloc must return NULL).
-** particularly, frealloc(ud, NULL, 0, 0) does nothing
-** (which is equivalent to free(NULL) in ANSI C)
-**
-** frealloc returns NULL if it cannot create or reallocate the area
-** (any reallocation to an equal or smaller size cannot fail!)
-*/
-
-
-
-#define MINSIZEARRAY 4
-
-
-void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems,
- int limit, const char *errormsg) {
- void *newblock;
- int newsize;
- if (*size >= limit/2) { /* cannot double it? */
- if (*size >= limit) /* cannot grow even a little? */
- luaG_runerror(L, errormsg);
- newsize = limit; /* still have at least one free place */
- }
- else {
- newsize = (*size)*2;
- if (newsize < MINSIZEARRAY)
- newsize = MINSIZEARRAY; /* minimum size */
- }
- newblock = luaM_reallocv(L, block, *size, newsize, size_elems);
- *size = newsize; /* update only when everything else is OK */
- return newblock;
-}
-
-
-void *luaM_toobig (lua_State *L) {
- luaG_runerror(L, "memory allocation error: block too big");
- return NULL; /* to avoid warnings */
-}
-
-
-
-/*
-** generic allocation routine.
-*/
-void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
- global_State *g = G(L);
- lua_assert((osize == 0) == (block == NULL));
- block = (*g->frealloc)(g->ud, block, osize, nsize);
- if (block == NULL && nsize > 0)
- luaD_throw(L, LUA_ERRMEM);
- lua_assert((nsize == 0) == (block == NULL));
- g->totalbytes = (g->totalbytes - osize) + nsize;
- return block;
-}
-
diff --git a/src/lua/src/lmem.h b/src/lua/src/lmem.h
deleted file mode 100644
index 7c2dcb322..000000000
--- a/src/lua/src/lmem.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-** $Id: lmem.h,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $
-** Interface to Memory Manager
-** See Copyright Notice in lua.h
-*/
-
-#ifndef lmem_h
-#define lmem_h
-
-
-#include <stddef.h>
-
-#include "llimits.h"
-#include "lua.h"
-
-#define MEMERRMSG "not enough memory"
-
-
-#define luaM_reallocv(L,b,on,n,e) \
- ((cast(size_t, (n)+1) <= MAX_SIZET/(e)) ? /* +1 to avoid warnings */ \
- luaM_realloc_(L, (b), (on)*(e), (n)*(e)) : \
- luaM_toobig(L))
-
-#define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0)
-#define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0)
-#define luaM_freearray(L, b, n, t) luaM_reallocv(L, (b), n, 0, sizeof(t))
-
-#define luaM_malloc(L,t) luaM_realloc_(L, NULL, 0, (t))
-#define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t)))
-#define luaM_newvector(L,n,t) \
- cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t)))
-
-#define luaM_growvector(L,v,nelems,size,t,limit,e) \
- if ((nelems)+1 > (size)) \
- ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e)))
-
-#define luaM_reallocvector(L, v,oldn,n,t) \
- ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t))))
-
-
-LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize,
- size_t size);
-LUAI_FUNC void *luaM_toobig (lua_State *L);
-LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size,
- size_t size_elem, int limit,
- const char *errormsg);
-
-#endif
-
diff --git a/src/lua/src/loadlib.c b/src/lua/src/loadlib.c
deleted file mode 100644
index 0d401eba1..000000000
--- a/src/lua/src/loadlib.c
+++ /dev/null
@@ -1,666 +0,0 @@
-/*
-** $Id: loadlib.c,v 1.52.1.3 2008/08/06 13:29:28 roberto Exp $
-** Dynamic library loader for Lua
-** See Copyright Notice in lua.h
-**
-** This module contains an implementation of loadlib for Unix systems
-** that have dlfcn, an implementation for Darwin (Mac OS X), an
-** implementation for Windows, and a stub for other systems.
-*/
-
-
-#include <stdlib.h>
-#include <string.h>
-
-
-#define loadlib_c
-#define LUA_LIB
-
-#include "lua.h"
-
-#include "lauxlib.h"
-#include "lualib.h"
-
-
-/* prefix for open functions in C libraries */
-#define LUA_POF "luaopen_"
-
-/* separator for open functions in C libraries */
-#define LUA_OFSEP "_"
-
-
-#define LIBPREFIX "LOADLIB: "
-
-#define POF LUA_POF
-#define LIB_FAIL "open"
-
-
-/* error codes for ll_loadfunc */
-#define ERRLIB 1
-#define ERRFUNC 2
-
-#define setprogdir(L) ((void)0)
-
-
-static void ll_unloadlib (void *lib);
-static void *ll_load (lua_State *L, const char *path);
-static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym);
-
-
-
-#if defined(LUA_DL_DLOPEN)
-/*
-** {========================================================================
-** This is an implementation of loadlib based on the dlfcn interface.
-** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
-** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
-** as an emulation layer on top of native functions.
-** =========================================================================
-*/
-
-#include <dlfcn.h>
-
-static void ll_unloadlib (void *lib) {
- dlclose(lib);
-}
-
-
-static void *ll_load (lua_State *L, const char *path) {
- void *lib = dlopen(path, RTLD_NOW);
- if (lib == NULL) lua_pushstring(L, dlerror());
- return lib;
-}
-
-
-static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
- lua_CFunction f = (lua_CFunction)dlsym(lib, sym);
- if (f == NULL) lua_pushstring(L, dlerror());
- return f;
-}
-
-/* }====================================================== */
-
-
-
-#elif defined(LUA_DL_DLL)
-/*
-** {======================================================================
-** This is an implementation of loadlib for Windows using native functions.
-** =======================================================================
-*/
-
-#include <windows.h>
-
-
-#undef setprogdir
-
-static void setprogdir (lua_State *L) {
- char buff[MAX_PATH + 1];
- char *lb;
- DWORD nsize = sizeof(buff)/sizeof(char);
- DWORD n = GetModuleFileNameA(NULL, buff, nsize);
- if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL)
- luaL_error(L, "unable to get ModuleFileName");
- else {
- *lb = '\0';
- luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff);
- lua_remove(L, -2); /* remove original string */
- }
-}
-
-
-static void pusherror (lua_State *L) {
- int error = GetLastError();
- char buffer[128];
- if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, error, 0, buffer, sizeof(buffer), NULL))
- lua_pushstring(L, buffer);
- else
- lua_pushfstring(L, "system error %d\n", error);
-}
-
-static void ll_unloadlib (void *lib) {
- FreeLibrary((HINSTANCE)lib);
-}
-
-
-static void *ll_load (lua_State *L, const char *path) {
- HINSTANCE lib = LoadLibraryA(path);
- if (lib == NULL) pusherror(L);
- return lib;
-}
-
-
-static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
- lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym);
- if (f == NULL) pusherror(L);
- return f;
-}
-
-/* }====================================================== */
-
-
-
-#elif defined(LUA_DL_DYLD)
-/*
-** {======================================================================
-** Native Mac OS X / Darwin Implementation
-** =======================================================================
-*/
-
-#include <mach-o/dyld.h>
-
-
-/* Mac appends a `_' before C function names */
-#undef POF
-#define POF "_" LUA_POF
-
-
-static void pusherror (lua_State *L) {
- const char *err_str;
- const char *err_file;
- NSLinkEditErrors err;
- int err_num;
- NSLinkEditError(&err, &err_num, &err_file, &err_str);
- lua_pushstring(L, err_str);
-}
-
-
-static const char *errorfromcode (NSObjectFileImageReturnCode ret) {
- switch (ret) {
- case NSObjectFileImageInappropriateFile:
- return "file is not a bundle";
- case NSObjectFileImageArch:
- return "library is for wrong CPU type";
- case NSObjectFileImageFormat:
- return "bad format";
- case NSObjectFileImageAccess:
- return "cannot access file";
- case NSObjectFileImageFailure:
- default:
- return "unable to load library";
- }
-}
-
-
-static void ll_unloadlib (void *lib) {
- NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
-}
-
-
-static void *ll_load (lua_State *L, const char *path) {
- NSObjectFileImage img;
- NSObjectFileImageReturnCode ret;
- /* this would be a rare case, but prevents crashing if it happens */
- if(!_dyld_present()) {
- lua_pushliteral(L, "dyld not present");
- return NULL;
- }
- ret = NSCreateObjectFileImageFromFile(path, &img);
- if (ret == NSObjectFileImageSuccess) {
- NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE |
- NSLINKMODULE_OPTION_RETURN_ON_ERROR);
- NSDestroyObjectFileImage(img);
- if (mod == NULL) pusherror(L);
- return mod;
- }
- lua_pushstring(L, errorfromcode(ret));
- return NULL;
-}
-
-
-static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
- NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym);
- if (nss == NULL) {
- lua_pushfstring(L, "symbol " LUA_QS " not found", sym);
- return NULL;
- }
- return (lua_CFunction)NSAddressOfSymbol(nss);
-}
-
-/* }====================================================== */
-
-
-
-#else
-/*
-** {======================================================
-** Fallback for other systems
-** =======================================================
-*/
-
-#undef LIB_FAIL
-#define LIB_FAIL "absent"
-
-
-#define DLMSG "dynamic libraries not enabled; check your Lua installation"
-
-
-static void ll_unloadlib (void *lib) {
- (void)lib; /* to avoid warnings */
-}
-
-
-static void *ll_load (lua_State *L, const char *path) {
- (void)path; /* to avoid warnings */
- lua_pushliteral(L, DLMSG);
- return NULL;
-}
-
-
-static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
- (void)lib; (void)sym; /* to avoid warnings */
- lua_pushliteral(L, DLMSG);
- return NULL;
-}
-
-/* }====================================================== */
-#endif
-
-
-
-static void **ll_register (lua_State *L, const char *path) {
- void **plib;
- lua_pushfstring(L, "%s%s", LIBPREFIX, path);
- lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */
- if (!lua_isnil(L, -1)) /* is there an entry? */
- plib = (void **)lua_touserdata(L, -1);
- else { /* no entry yet; create one */
- lua_pop(L, 1);
- plib = (void **)lua_newuserdata(L, sizeof(const void *));
- *plib = NULL;
- luaL_getmetatable(L, "_LOADLIB");
- lua_setmetatable(L, -2);
- lua_pushfstring(L, "%s%s", LIBPREFIX, path);
- lua_pushvalue(L, -2);
- lua_settable(L, LUA_REGISTRYINDEX);
- }
- return plib;
-}
-
-
-/*
-** __gc tag method: calls library's `ll_unloadlib' function with the lib
-** handle
-*/
-static int gctm (lua_State *L) {
- void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB");
- if (*lib) ll_unloadlib(*lib);
- *lib = NULL; /* mark library as closed */
- return 0;
-}
-
-
-static int ll_loadfunc (lua_State *L, const char *path, const char *sym) {
- void **reg = ll_register(L, path);
- if (*reg == NULL) *reg = ll_load(L, path);
- if (*reg == NULL)
- return ERRLIB; /* unable to load library */
- else {
- lua_CFunction f = ll_sym(L, *reg, sym);
- if (f == NULL)
- return ERRFUNC; /* unable to find function */
- lua_pushcfunction(L, f);
- return 0; /* return function */
- }
-}
-
-
-static int ll_loadlib (lua_State *L) {
- const char *path = luaL_checkstring(L, 1);
- const char *init = luaL_checkstring(L, 2);
- int stat = ll_loadfunc(L, path, init);
- if (stat == 0) /* no errors? */
- return 1; /* return the loaded function */
- else { /* error; error message is on stack top */
- lua_pushnil(L);
- lua_insert(L, -2);
- lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init");
- return 3; /* return nil, error message, and where */
- }
-}
-
-
-
-/*
-** {======================================================
-** 'require' function
-** =======================================================
-*/
-
-
-static int readable (const char *filename) {
- FILE *f = fopen(filename, "r"); /* try to open file */
- if (f == NULL) return 0; /* open failed */
- fclose(f);
- return 1;
-}
-
-
-static const char *pushnexttemplate (lua_State *L, const char *path) {
- const char *l;
- while (*path == *LUA_PATHSEP) path++; /* skip separators */
- if (*path == '\0') return NULL; /* no more templates */
- l = strchr(path, *LUA_PATHSEP); /* find next separator */
- if (l == NULL) l = path + strlen(path);
- lua_pushlstring(L, path, l - path); /* template */
- return l;
-}
-
-
-static const char *findfile (lua_State *L, const char *name,
- const char *pname) {
- const char *path;
- name = luaL_gsub(L, name, ".", LUA_DIRSEP);
- lua_getfield(L, LUA_ENVIRONINDEX, pname);
- path = lua_tostring(L, -1);
- if (path == NULL)
- luaL_error(L, LUA_QL("package.%s") " must be a string", pname);
- lua_pushliteral(L, ""); /* error accumulator */
- while ((path = pushnexttemplate(L, path)) != NULL) {
- const char *filename;
- filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name);
- lua_remove(L, -2); /* remove path template */
- if (readable(filename)) /* does file exist and is readable? */
- return filename; /* return that file name */
- lua_pushfstring(L, "\n\tno file " LUA_QS, filename);
- lua_remove(L, -2); /* remove file name */
- lua_concat(L, 2); /* add entry to possible error message */
- }
- return NULL; /* not found */
-}
-
-
-static void loaderror (lua_State *L, const char *filename) {
- luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s",
- lua_tostring(L, 1), filename, lua_tostring(L, -1));
-}
-
-
-static int loader_Lua (lua_State *L) {
- const char *filename;
- const char *name = luaL_checkstring(L, 1);
- filename = findfile(L, name, "path");
- if (filename == NULL) return 1; /* library not found in this path */
- if (luaL_loadfile(L, filename) != 0)
- loaderror(L, filename);
- return 1; /* library loaded successfully */
-}
-
-
-static const char *mkfuncname (lua_State *L, const char *modname) {
- const char *funcname;
- const char *mark = strchr(modname, *LUA_IGMARK);
- if (mark) modname = mark + 1;
- funcname = luaL_gsub(L, modname, ".", LUA_OFSEP);
- funcname = lua_pushfstring(L, POF"%s", funcname);
- lua_remove(L, -2); /* remove 'gsub' result */
- return funcname;
-}
-
-
-static int loader_C (lua_State *L) {
- const char *funcname;
- const char *name = luaL_checkstring(L, 1);
- const char *filename = findfile(L, name, "cpath");
- if (filename == NULL) return 1; /* library not found in this path */
- funcname = mkfuncname(L, name);
- if (ll_loadfunc(L, filename, funcname) != 0)
- loaderror(L, filename);
- return 1; /* library loaded successfully */
-}
-
-
-static int loader_Croot (lua_State *L) {
- const char *funcname;
- const char *filename;
- const char *name = luaL_checkstring(L, 1);
- const char *p = strchr(name, '.');
- int stat;
- if (p == NULL) return 0; /* is root */
- lua_pushlstring(L, name, p - name);
- filename = findfile(L, lua_tostring(L, -1), "cpath");
- if (filename == NULL) return 1; /* root not found */
- funcname = mkfuncname(L, name);
- if ((stat = ll_loadfunc(L, filename, funcname)) != 0) {
- if (stat != ERRFUNC) loaderror(L, filename); /* real error */
- lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS,
- name, filename);
- return 1; /* function not found */
- }
- return 1;
-}
-
-
-static int loader_preload (lua_State *L) {
- const char *name = luaL_checkstring(L, 1);
- lua_getfield(L, LUA_ENVIRONINDEX, "preload");
- if (!lua_istable(L, -1))
- luaL_error(L, LUA_QL("package.preload") " must be a table");
- lua_getfield(L, -1, name);
- if (lua_isnil(L, -1)) /* not found? */
- lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
- return 1;
-}
-
-
-static const int sentinel_ = 0;
-#define sentinel ((void *)&sentinel_)
-
-
-static int ll_require (lua_State *L) {
- const char *name = luaL_checkstring(L, 1);
- int i;
- lua_settop(L, 1); /* _LOADED table will be at index 2 */
- lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
- lua_getfield(L, 2, name);
- if (lua_toboolean(L, -1)) { /* is it there? */
- if (lua_touserdata(L, -1) == sentinel) /* check loops */
- luaL_error(L, "loop or previous error loading module " LUA_QS, name);
- return 1; /* package is already loaded */
- }
- /* else must load it; iterate over available loaders */
- lua_getfield(L, LUA_ENVIRONINDEX, "loaders");
- if (!lua_istable(L, -1))
- luaL_error(L, LUA_QL("package.loaders") " must be a table");
- lua_pushliteral(L, ""); /* error message accumulator */
- for (i=1; ; i++) {
- lua_rawgeti(L, -2, i); /* get a loader */
- if (lua_isnil(L, -1))
- luaL_error(L, "module " LUA_QS " not found:%s",
- name, lua_tostring(L, -2));
- lua_pushstring(L, name);
- lua_call(L, 1, 1); /* call it */
- if (lua_isfunction(L, -1)) /* did it find module? */
- break; /* module loaded successfully */
- else if (lua_isstring(L, -1)) /* loader returned error message? */
- lua_concat(L, 2); /* accumulate it */
- else
- lua_pop(L, 1);
- }
- lua_pushlightuserdata(L, sentinel);
- lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */
- lua_pushstring(L, name); /* pass name as argument to module */
- lua_call(L, 1, 1); /* run loaded module */
- if (!lua_isnil(L, -1)) /* non-nil return? */
- lua_setfield(L, 2, name); /* _LOADED[name] = returned value */
- lua_getfield(L, 2, name);
- if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */
- lua_pushboolean(L, 1); /* use true as result */
- lua_pushvalue(L, -1); /* extra copy to be returned */
- lua_setfield(L, 2, name); /* _LOADED[name] = true */
- }
- return 1;
-}
-
-/* }====================================================== */
-
-
-
-/*
-** {======================================================
-** 'module' function
-** =======================================================
-*/
-
-
-static void setfenv (lua_State *L) {
- lua_Debug ar;
- if (lua_getstack(L, 1, &ar) == 0 ||
- lua_getinfo(L, "f", &ar) == 0 || /* get calling function */
- lua_iscfunction(L, -1))
- luaL_error(L, LUA_QL("module") " not called from a Lua function");
- lua_pushvalue(L, -2);
- lua_setfenv(L, -2);
- lua_pop(L, 1);
-}
-
-
-static void dooptions (lua_State *L, int n) {
- int i;
- for (i = 2; i <= n; i++) {
- lua_pushvalue(L, i); /* get option (a function) */
- lua_pushvalue(L, -2); /* module */
- lua_call(L, 1, 0);
- }
-}
-
-
-static void modinit (lua_State *L, const char *modname) {
- const char *dot;
- lua_pushvalue(L, -1);
- lua_setfield(L, -2, "_M"); /* module._M = module */
- lua_pushstring(L, modname);
- lua_setfield(L, -2, "_NAME");
- dot = strrchr(modname, '.'); /* look for last dot in module name */
- if (dot == NULL) dot = modname;
- else dot++;
- /* set _PACKAGE as package name (full module name minus last part) */
- lua_pushlstring(L, modname, dot - modname);
- lua_setfield(L, -2, "_PACKAGE");
-}
-
-
-static int ll_module (lua_State *L) {
- const char *modname = luaL_checkstring(L, 1);
- int loaded = lua_gettop(L) + 1; /* index of _LOADED table */
- lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
- lua_getfield(L, loaded, modname); /* get _LOADED[modname] */
- if (!lua_istable(L, -1)) { /* not found? */
- lua_pop(L, 1); /* remove previous result */
- /* try global variable (and create one if it does not exist) */
- if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL)
- return luaL_error(L, "name conflict for module " LUA_QS, modname);
- lua_pushvalue(L, -1);
- lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */
- }
- /* check whether table already has a _NAME field */
- lua_getfield(L, -1, "_NAME");
- if (!lua_isnil(L, -1)) /* is table an initialized module? */
- lua_pop(L, 1);
- else { /* no; initialize it */
- lua_pop(L, 1);
- modinit(L, modname);
- }
- lua_pushvalue(L, -1);
- setfenv(L);
- dooptions(L, loaded - 1);
- return 0;
-}
-
-
-static int ll_seeall (lua_State *L) {
- luaL_checktype(L, 1, LUA_TTABLE);
- if (!lua_getmetatable(L, 1)) {
- lua_createtable(L, 0, 1); /* create new metatable */
- lua_pushvalue(L, -1);
- lua_setmetatable(L, 1);
- }
- lua_pushvalue(L, LUA_GLOBALSINDEX);
- lua_setfield(L, -2, "__index"); /* mt.__index = _G */
- return 0;
-}
-
-
-/* }====================================================== */
-
-
-
-/* auxiliary mark (for internal use) */
-#define AUXMARK "\1"
-
-static void setpath (lua_State *L, const char *fieldname, const char *envname,
- const char *def) {
- const char *path = getenv(envname);
- if (path == NULL) /* no environment variable? */
- lua_pushstring(L, def); /* use default */
- else {
- /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
- path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP,
- LUA_PATHSEP AUXMARK LUA_PATHSEP);
- luaL_gsub(L, path, AUXMARK, def);
- lua_remove(L, -2);
- }
- setprogdir(L);
- lua_setfield(L, -2, fieldname);
-}
-
-
-static const luaL_Reg pk_funcs[] = {
- {"loadlib", ll_loadlib},
- {"seeall", ll_seeall},
- {NULL, NULL}
-};
-
-
-static const luaL_Reg ll_funcs[] = {
- {"module", ll_module},
- {"require", ll_require},
- {NULL, NULL}
-};
-
-
-static const lua_CFunction loaders[] =
- {loader_preload, loader_Lua, loader_C, loader_Croot, NULL};
-
-
-LUALIB_API int luaopen_package (lua_State *L) {
- int i;
- /* create new type _LOADLIB */
- luaL_newmetatable(L, "_LOADLIB");
- lua_pushcfunction(L, gctm);
- lua_setfield(L, -2, "__gc");
- /* create `package' table */
- luaL_register(L, LUA_LOADLIBNAME, pk_funcs);
-#if defined(LUA_COMPAT_LOADLIB)
- lua_getfield(L, -1, "loadlib");
- lua_setfield(L, LUA_GLOBALSINDEX, "loadlib");
-#endif
- lua_pushvalue(L, -1);
- lua_replace(L, LUA_ENVIRONINDEX);
- /* create `loaders' table */
- lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1);
- /* fill it with pre-defined loaders */
- for (i=0; loaders[i] != NULL; i++) {
- lua_pushcfunction(L, loaders[i]);
- lua_rawseti(L, -2, i+1);
- }
- lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */
- setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */
- setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */
- /* store config information */
- lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n"
- LUA_EXECDIR "\n" LUA_IGMARK);
- lua_setfield(L, -2, "config");
- /* set field `loaded' */
- luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2);
- lua_setfield(L, -2, "loaded");
- /* set field `preload' */
- lua_newtable(L);
- lua_setfield(L, -2, "preload");
- lua_pushvalue(L, LUA_GLOBALSINDEX);
- luaL_register(L, NULL, ll_funcs); /* open lib into global table */
- lua_pop(L, 1);
- return 1; /* return 'package' table */
-}
-
diff --git a/src/lua/src/lobject.c b/src/lua/src/lobject.c
deleted file mode 100644
index 4ff50732a..000000000
--- a/src/lua/src/lobject.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
-** $Id: lobject.c,v 2.22.1.1 2007/12/27 13:02:25 roberto Exp $
-** Some generic functions over Lua objects
-** See Copyright Notice in lua.h
-*/
-
-#include <ctype.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define lobject_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "ldo.h"
-#include "lmem.h"
-#include "lobject.h"
-#include "lstate.h"
-#include "lstring.h"
-#include "lvm.h"
-
-
-
-const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL};
-
-
-/*
-** converts an integer to a "floating point byte", represented as
-** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
-** eeeee != 0 and (xxx) otherwise.
-*/
-int luaO_int2fb (unsigned int x) {
- int e = 0; /* expoent */
- while (x >= 16) {
- x = (x+1) >> 1;
- e++;
- }
- if (x < 8) return x;
- else return ((e+1) << 3) | (cast_int(x) - 8);
-}
-
-
-/* converts back */
-int luaO_fb2int (int x) {
- int e = (x >> 3) & 31;
- if (e == 0) return x;
- else return ((x & 7)+8) << (e - 1);
-}
-
-
-int luaO_log2 (unsigned int x) {
- static const lu_byte log_2[256] = {
- 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
- 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
- };
- int l = -1;
- while (x >= 256) { l += 8; x >>= 8; }
- return l + log_2[x];
-
-}
-
-
-int luaO_rawequalObj (const TValue *t1, const TValue *t2) {
- if (ttype(t1) != ttype(t2)) return 0;
- else switch (ttype(t1)) {
- case LUA_TNIL:
- return 1;
- case LUA_TNUMBER:
- return luai_numeq(nvalue(t1), nvalue(t2));
- case LUA_TBOOLEAN:
- return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */
- case LUA_TLIGHTUSERDATA:
- return pvalue(t1) == pvalue(t2);
- default:
- lua_assert(iscollectable(t1));
- return gcvalue(t1) == gcvalue(t2);
- }
-}
-
-
-int luaO_str2d (const char *s, lua_Number *result) {
- char *endptr;
- *result = lua_str2number(s, &endptr);
- if (endptr == s) return 0; /* conversion failed */
- if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */
- *result = cast_num(strtoul(s, &endptr, 16));
- if (*endptr == '\0') return 1; /* most common case */
- while (isspace(cast(unsigned char, *endptr))) endptr++;
- if (*endptr != '\0') return 0; /* invalid trailing characters? */
- return 1;
-}
-
-
-
-static void pushstr (lua_State *L, const char *str) {
- setsvalue2s(L, L->top, luaS_new(L, str));
- incr_top(L);
-}
-
-
-/* this function handles only `%d', `%c', %f, %p, and `%s' formats */
-const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
- int n = 1;
- pushstr(L, "");
- for (;;) {
- const char *e = strchr(fmt, '%');
- if (e == NULL) break;
- setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt));
- incr_top(L);
- switch (*(e+1)) {
- case 's': {
- const char *s = va_arg(argp, char *);
- if (s == NULL) s = "(null)";
- pushstr(L, s);
- break;
- }
- case 'c': {
- char buff[2];
- buff[0] = cast(char, va_arg(argp, int));
- buff[1] = '\0';
- pushstr(L, buff);
- break;
- }
- case 'd': {
- setnvalue(L->top, cast_num(va_arg(argp, int)));
- incr_top(L);
- break;
- }
- case 'f': {
- setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber)));
- incr_top(L);
- break;
- }
- case 'p': {
- char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */
- sprintf(buff, "%p", va_arg(argp, void *));
- pushstr(L, buff);
- break;
- }
- case '%': {
- pushstr(L, "%");
- break;
- }
- default: {
- char buff[3];
- buff[0] = '%';
- buff[1] = *(e+1);
- buff[2] = '\0';
- pushstr(L, buff);
- break;
- }
- }
- n += 2;
- fmt = e+2;
- }
- pushstr(L, fmt);
- luaV_concat(L, n+1, cast_int(L->top - L->base) - 1);
- L->top -= n;
- return svalue(L->top - 1);
-}
-
-
-const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) {
- const char *msg;
- va_list argp;
- va_start(argp, fmt);
- msg = luaO_pushvfstring(L, fmt, argp);
- va_end(argp);
- return msg;
-}
-
-
-void luaO_chunkid (char *out, const char *source, size_t bufflen) {
- if (*source == '=') {
- strncpy(out, source+1, bufflen); /* remove first char */
- out[bufflen-1] = '\0'; /* ensures null termination */
- }
- else { /* out = "source", or "...source" */
- if (*source == '@') {
- size_t l;
- source++; /* skip the `@' */
- bufflen -= sizeof(" '...' ");
- l = strlen(source);
- strcpy(out, "");
- if (l > bufflen) {
- source += (l-bufflen); /* get last part of file name */
- strcat(out, "...");
- }
- strcat(out, source);
- }
- else { /* out = [string "string"] */
- size_t len = strcspn(source, "\n\r"); /* stop at first newline */
- bufflen -= sizeof(" [string \"...\"] ");
- if (len > bufflen) len = bufflen;
- strcpy(out, "[string \"");
- if (source[len] != '\0') { /* must truncate? */
- strncat(out, source, len);
- strcat(out, "...");
- }
- else
- strcat(out, source);
- strcat(out, "\"]");
- }
- }
-}
diff --git a/src/lua/src/lobject.h b/src/lua/src/lobject.h
deleted file mode 100644
index f1e447ef3..000000000
--- a/src/lua/src/lobject.h
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
-** $Id: lobject.h,v 2.20.1.2 2008/08/06 13:29:48 roberto Exp $
-** Type definitions for Lua objects
-** See Copyright Notice in lua.h
-*/
-
-
-#ifndef lobject_h
-#define lobject_h
-
-
-#include <stdarg.h>
-
-
-#include "llimits.h"
-#include "lua.h"
-
-
-/* tags for values visible from Lua */
-#define LAST_TAG LUA_TTHREAD
-
-#define NUM_TAGS (LAST_TAG+1)
-
-
-/*
-** Extra tags for non-values
-*/
-#define LUA_TPROTO (LAST_TAG+1)
-#define LUA_TUPVAL (LAST_TAG+2)
-#define LUA_TDEADKEY (LAST_TAG+3)
-
-
-/*
-** Union of all collectable objects
-*/
-typedef union GCObject GCObject;
-
-
-/*
-** Common Header for all collectable objects (in macro form, to be
-** included in other objects)
-*/
-#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked
-
-
-/*
-** Common header in struct form
-*/
-typedef struct GCheader {
- CommonHeader;
-} GCheader;
-
-
-
-
-/*
-** Union of all Lua values
-*/
-typedef union {
- GCObject *gc;
- void *p;
- lua_Number n;
- int b;
-} Value;
-
-
-/*
-** Tagged Values
-*/
-
-#define TValuefields Value value; int tt
-
-typedef struct lua_TValue {
- TValuefields;
-} TValue;
-
-
-/* Macros to test type */
-#define ttisnil(o) (ttype(o) == LUA_TNIL)
-#define ttisnumber(o) (ttype(o) == LUA_TNUMBER)
-#define ttisstring(o) (ttype(o) == LUA_TSTRING)
-#define ttistable(o) (ttype(o) == LUA_TTABLE)
-#define ttisfunction(o) (ttype(o) == LUA_TFUNCTION)
-#define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN)
-#define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA)
-#define ttisthread(o) (ttype(o) == LUA_TTHREAD)
-#define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA)
-
-/* Macros to access values */
-#define ttype(o) ((o)->tt)
-#define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc)
-#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p)
-#define nvalue(o) check_exp(ttisnumber(o), (o)->value.n)
-#define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts)
-#define tsvalue(o) (&rawtsvalue(o)->tsv)
-#define rawuvalue(o) check_exp(ttisuserdata(o), &(o)->value.gc->u)
-#define uvalue(o) (&rawuvalue(o)->uv)
-#define clvalue(o) check_exp(ttisfunction(o), &(o)->value.gc->cl)
-#define hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h)
-#define bvalue(o) check_exp(ttisboolean(o), (o)->value.b)
-#define thvalue(o) check_exp(ttisthread(o), &(o)->value.gc->th)
-
-#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
-
-/*
-** for internal debug only
-*/
-#define checkconsistency(obj) \
- lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt))
-
-#define checkliveness(g,obj) \
- lua_assert(!iscollectable(obj) || \
- ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc)))
-
-
-/* Macros to set values */
-#define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
-
-#define setnvalue(obj,x) \
- { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; }
-
-#define setpvalue(obj,x) \
- { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; }
-
-#define setbvalue(obj,x) \
- { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; }
-
-#define setsvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \
- checkliveness(G(L),i_o); }
-
-#define setuvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \
- checkliveness(G(L),i_o); }
-
-#define setthvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \
- checkliveness(G(L),i_o); }
-
-#define setclvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \
- checkliveness(G(L),i_o); }
-
-#define sethvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \
- checkliveness(G(L),i_o); }
-
-#define setptvalue(L,obj,x) \
- { TValue *i_o=(obj); \
- i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \
- checkliveness(G(L),i_o); }
-
-
-
-
-#define setobj(L,obj1,obj2) \
- { const TValue *o2=(obj2); TValue *o1=(obj1); \
- o1->value = o2->value; o1->tt=o2->tt; \
- checkliveness(G(L),o1); }
-
-
-/*
-** different types of sets, according to destination
-*/
-
-/* from stack to (same) stack */
-#define setobjs2s setobj
-/* to stack (not from same stack) */
-#define setobj2s setobj
-#define setsvalue2s setsvalue
-#define sethvalue2s sethvalue
-#define setptvalue2s setptvalue
-/* from table to same table */
-#define setobjt2t setobj
-/* to table */
-#define setobj2t setobj
-/* to new object */
-#define setobj2n setobj
-#define setsvalue2n setsvalue
-
-#define setttype(obj, tt) (ttype(obj) = (tt))
-
-
-#define iscollectable(o) (ttype(o) >= LUA_TSTRING)
-
-
-
-typedef TValue *StkId; /* index to stack elements */
-
-
-/*
-** String headers for string table
-*/
-typedef union TString {
- L_Umaxalign dummy; /* ensures maximum alignment for strings */
- struct {
- CommonHeader;
- lu_byte reserved;
- unsigned int hash;
- size_t len;
- } tsv;
-} TString;
-
-
-#define getstr(ts) cast(const char *, (ts) + 1)
-#define svalue(o) getstr(rawtsvalue(o))
-
-
-
-typedef union Udata {
- L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */
- struct {
- CommonHeader;
- struct Table *metatable;
- struct Table *env;
- size_t len;
- } uv;
-} Udata;
-
-
-
-
-/*
-** Function Prototypes
-*/
-typedef struct Proto {
- CommonHeader;
- TValue *k; /* constants used by the function */
- Instruction *code;
- struct Proto **p; /* functions defined inside the function */
- int *lineinfo; /* map from opcodes to source lines */
- struct LocVar *locvars; /* information about local variables */
- TString **upvalues; /* upvalue names */
- TString *source;
- int sizeupvalues;
- int sizek; /* size of `k' */
- int sizecode;
- int sizelineinfo;
- int sizep; /* size of `p' */
- int sizelocvars;
- int linedefined;
- int lastlinedefined;
- GCObject *gclist;
- lu_byte nups; /* number of upvalues */
- lu_byte numparams;
- lu_byte is_vararg;
- lu_byte maxstacksize;
-} Proto;
-
-
-/* masks for new-style vararg */
-#define VARARG_HASARG 1
-#define VARARG_ISVARARG 2
-#define VARARG_NEEDSARG 4
-
-
-typedef struct LocVar {
- TString *varname;
- int startpc; /* first point where variable is active */
- int endpc; /* first point where variable is dead */
-} LocVar;
-
-
-
-/*
-** Upvalues
-*/
-
-typedef struct UpVal {
- CommonHeader;
- TValue *v; /* points to stack or to its own value */
- union {
- TValue value; /* the value (when closed) */
- struct { /* double linked list (when open) */
- struct UpVal *prev;
- struct UpVal *next;
- } l;
- } u;
-} UpVal;
-
-
-/*
-** Closures
-*/
-
-#define ClosureHeader \
- CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \
- struct Table *env
-
-typedef struct CClosure {
- ClosureHeader;
- lua_CFunction f;
- TValue upvalue[1];
-} CClosure;
-
-
-typedef struct LClosure {
- ClosureHeader;
- struct Proto *p;
- UpVal *upvals[1];
-} LClosure;
-
-
-typedef union Closure {
- CClosure c;
- LClosure l;
-} Closure;
-
-
-#define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->c.isC)
-#define isLfunction(o) (ttype(o) == LUA_TFUNCTION && !clvalue(o)->c.isC)
-
-
-/*
-** Tables
-*/
-
-typedef union TKey {
- struct {
- TValuefields;
- struct Node *next; /* for chaining */
- } nk;
- TValue tvk;
-} TKey;
-
-
-typedef struct Node {
- TValue i_val;
- TKey i_key;
-} Node;
-
-
-typedef struct Table {
- CommonHeader;
- lu_byte flags; /* 1<<p means tagmethod(p) is not present */
- lu_byte lsizenode; /* log2 of size of `node' array */
- struct Table *metatable;
- TValue *array; /* array part */
- Node *node;
- Node *lastfree; /* any free position is before this position */
- GCObject *gclist;
- int sizearray; /* size of `array' array */
-} Table;
-
-
-
-/*
-** `module' operation for hashing (size is always a power of 2)
-*/
-#define lmod(s,size) \
- (check_exp((size&(size-1))==0, (cast(int, (s) & ((size)-1)))))
-
-
-#define twoto(x) (1<<(x))
-#define sizenode(t) (twoto((t)->lsizenode))
-
-
-#define luaO_nilobject (&luaO_nilobject_)
-
-LUAI_DATA const TValue luaO_nilobject_;
-
-#define ceillog2(x) (luaO_log2((x)-1) + 1)
-
-LUAI_FUNC int luaO_log2 (unsigned int x);
-LUAI_FUNC int luaO_int2fb (unsigned int x);
-LUAI_FUNC int luaO_fb2int (int x);
-LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2);
-LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result);
-LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
- va_list argp);
-LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...);
-LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len);
-
-
-#endif
-
diff --git a/src/lua/src/lopcodes.c b/src/lua/src/lopcodes.c
deleted file mode 100644
index 4cc745230..000000000
--- a/src/lua/src/lopcodes.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
-** $Id: lopcodes.c,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $
-** See Copyright Notice in lua.h
-*/
-
-
-#define lopcodes_c
-#define LUA_CORE
-
-
-#include "lopcodes.h"
-
-
-/* ORDER OP */
-
-const char *const luaP_opnames[NUM_OPCODES+1] = {
- "MOVE",
- "LOADK",
- "LOADBOOL",
- "LOADNIL",
- "GETUPVAL",
- "GETGLOBAL",
- "GETTABLE",
- "SETGLOBAL",
- "SETUPVAL",
- "SETTABLE",
- "NEWTABLE",
- "SELF",
- "ADD",
- "SUB",
- "MUL",
- "DIV",
- "MOD",
- "POW",
- "UNM",
- "NOT",
- "LEN",
- "CONCAT",
- "JMP",
- "EQ",
- "LT",
- "LE",
- "TEST",
- "TESTSET",
- "CALL",
- "TAILCALL",
- "RETURN",
- "FORLOOP",
- "FORPREP",
- "TFORLOOP",
- "SETLIST",
- "CLOSE",
- "CLOSURE",
- "VARARG",
- NULL
-};
-
-
-#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m))
-
-const lu_byte luaP_opmodes[NUM_OPCODES] = {
-/* T A B C mode opcode */
- opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */
- ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */
- ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */
- ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LOADNIL */
- ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */
- ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_GETGLOBAL */
- ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */
- ,opmode(0, 0, OpArgK, OpArgN, iABx) /* OP_SETGLOBAL */
- ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */
- ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */
- ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */
- ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */
- ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */
- ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */
- ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */
- ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */
- ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */
- ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */
- ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */
- ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */
- ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */
- ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */
- ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */
- ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */
- ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */
- ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */
- ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TEST */
- ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */
- ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */
- ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */
- ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */
- ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */
- ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */
- ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TFORLOOP */
- ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */
- ,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */
- ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */
- ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */
-};
-
diff --git a/src/lua/src/lopcodes.h b/src/lua/src/lopcodes.h
deleted file mode 100644
index 41224d6ee..000000000
--- a/src/lua/src/lopcodes.h
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
-** $Id: lopcodes.h,v 1.125.1.1 2007/12/27 13:02:25 roberto Exp $
-** Opcodes for Lua virtual machine
-** See Copyright Notice in lua.h
-*/
-
-#ifndef lopcodes_h
-#define lopcodes_h
-
-#include "llimits.h"
-
-
-/*===========================================================================
- We assume that instructions are unsigned numbers.
- All instructions have an opcode in the first 6 bits.
- Instructions can have the following fields:
- `A' : 8 bits
- `B' : 9 bits
- `C' : 9 bits
- `Bx' : 18 bits (`B' and `C' together)
- `sBx' : signed Bx
-
- A signed argument is represented in excess K; that is, the number
- value is the unsigned value minus K. K is exactly the maximum value
- for that argument (so that -max is represented by 0, and +max is
- represented by 2*max), which is half the maximum for the corresponding
- unsigned argument.
-===========================================================================*/
-
-
-enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */
-
-
-/*
-** size and position of opcode arguments.
-*/
-#define SIZE_C 9
-#define SIZE_B 9
-#define SIZE_Bx (SIZE_C + SIZE_B)
-#define SIZE_A 8
-
-#define SIZE_OP 6
-
-#define POS_OP 0
-#define POS_A (POS_OP + SIZE_OP)
-#define POS_C (POS_A + SIZE_A)
-#define POS_B (POS_C + SIZE_C)
-#define POS_Bx POS_C
-
-
-/*
-** limits for opcode arguments.
-** we use (signed) int to manipulate most arguments,
-** so they must fit in LUAI_BITSINT-1 bits (-1 for sign)
-*/
-#if SIZE_Bx < LUAI_BITSINT-1
-#define MAXARG_Bx ((1<<SIZE_Bx)-1)
-#define MAXARG_sBx (MAXARG_Bx>>1) /* `sBx' is signed */
-#else
-#define MAXARG_Bx MAX_INT
-#define MAXARG_sBx MAX_INT
-#endif
-
-
-#define MAXARG_A ((1<<SIZE_A)-1)
-#define MAXARG_B ((1<<SIZE_B)-1)
-#define MAXARG_C ((1<<SIZE_C)-1)
-
-
-/* creates a mask with `n' 1 bits at position `p' */
-#define MASK1(n,p) ((~((~(Instruction)0)<<n))<<p)
-
-/* creates a mask with `n' 0 bits at position `p' */
-#define MASK0(n,p) (~MASK1(n,p))
-
-/*
-** the following macros help to manipulate instructions
-*/
-
-#define GET_OPCODE(i) (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))
-#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
- ((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))
-
-#define GETARG_A(i) (cast(int, ((i)>>POS_A) & MASK1(SIZE_A,0)))
-#define SETARG_A(i,u) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \
- ((cast(Instruction, u)<<POS_A)&MASK1(SIZE_A,POS_A))))
-
-#define GETARG_B(i) (cast(int, ((i)>>POS_B) & MASK1(SIZE_B,0)))
-#define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \
- ((cast(Instruction, b)<<POS_B)&MASK1(SIZE_B,POS_B))))
-
-#define GETARG_C(i) (cast(int, ((i)>>POS_C) & MASK1(SIZE_C,0)))
-#define SETARG_C(i,b) ((i) = (((i)&MASK0(SIZE_C,POS_C)) | \
- ((cast(Instruction, b)<<POS_C)&MASK1(SIZE_C,POS_C))))
-
-#define GETARG_Bx(i) (cast(int, ((i)>>POS_Bx) & MASK1(SIZE_Bx,0)))
-#define SETARG_Bx(i,b) ((i) = (((i)&MASK0(SIZE_Bx,POS_Bx)) | \
- ((cast(Instruction, b)<<POS_Bx)&MASK1(SIZE_Bx,POS_Bx))))
-
-#define GETARG_sBx(i) (GETARG_Bx(i)-MAXARG_sBx)
-#define SETARG_sBx(i,b) SETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx))
-
-
-#define CREATE_ABC(o,a,b,c) ((cast(Instruction, o)<<POS_OP) \
- | (cast(Instruction, a)<<POS_A) \
- | (cast(Instruction, b)<<POS_B) \
- | (cast(Instruction, c)<<POS_C))
-
-#define CREATE_ABx(o,a,bc) ((cast(Instruction, o)<<POS_OP) \
- | (cast(Instruction, a)<<POS_A) \
- | (cast(Instruction, bc)<<POS_Bx))
-
-
-/*
-** Macros to operate RK indices
-*/
-
-/* this bit 1 means constant (0 means register) */
-#define BITRK (1 << (SIZE_B - 1))
-
-/* test whether value is a constant */
-#define ISK(x) ((x) & BITRK)
-
-/* gets the index of the constant */
-#define INDEXK(r) ((int)(r) & ~BITRK)
-
-#define MAXINDEXRK (BITRK - 1)
-
-/* code a constant index as a RK value */
-#define RKASK(x) ((x) | BITRK)
-
-
-/*
-** invalid register that fits in 8 bits
-*/
-#define NO_REG MAXARG_A
-
-
-/*
-** R(x) - register
-** Kst(x) - constant (in constant table)
-** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
-*/
-
-
-/*
-** grep "ORDER OP" if you change these enums
-*/
-
-typedef enum {
-/*----------------------------------------------------------------------
-name args description
-------------------------------------------------------------------------*/
-OP_MOVE,/* A B R(A) := R(B) */
-OP_LOADK,/* A Bx R(A) := Kst(Bx) */
-OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */
-OP_LOADNIL,/* A B R(A) := ... := R(B) := nil */
-OP_GETUPVAL,/* A B R(A) := UpValue[B] */
-
-OP_GETGLOBAL,/* A Bx R(A) := Gbl[Kst(Bx)] */
-OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */
-
-OP_SETGLOBAL,/* A Bx Gbl[Kst(Bx)] := R(A) */
-OP_SETUPVAL,/* A B UpValue[B] := R(A) */
-OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */
-
-OP_NEWTABLE,/* A B C R(A) := {} (size = B,C) */
-
-OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
-
-OP_ADD,/* A B C R(A) := RK(B) + RK(C) */
-OP_SUB,/* A B C R(A) := RK(B) - RK(C) */
-OP_MUL,/* A B C R(A) := RK(B) * RK(C) */
-OP_DIV,/* A B C R(A) := RK(B) / RK(C) */
-OP_MOD,/* A B C R(A) := RK(B) % RK(C) */
-OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */
-OP_UNM,/* A B R(A) := -R(B) */
-OP_NOT,/* A B R(A) := not R(B) */
-OP_LEN,/* A B R(A) := length of R(B) */
-
-OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */
-
-OP_JMP,/* sBx pc+=sBx */
-
-OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
-OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
-OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
-
-OP_TEST,/* A C if not (R(A) <=> C) then pc++ */
-OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
-
-OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
-OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
-OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */
-
-OP_FORLOOP,/* A sBx R(A)+=R(A+2);
- if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
-OP_FORPREP,/* A sBx R(A)-=R(A+2); pc+=sBx */
-
-OP_TFORLOOP,/* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
- if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++ */
-OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
-
-OP_CLOSE,/* A close all variables in the stack up to (>=) R(A)*/
-OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
-
-OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
-} OpCode;
-
-
-#define NUM_OPCODES (cast(int, OP_VARARG) + 1)
-
-
-
-/*===========================================================================
- Notes:
- (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
- and can be 0: OP_CALL then sets `top' to last_result+1, so
- next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'.
-
- (*) In OP_VARARG, if (B == 0) then use actual number of varargs and
- set top (like in OP_CALL with C == 0).
-
- (*) In OP_RETURN, if (B == 0) then return up to `top'
-
- (*) In OP_SETLIST, if (B == 0) then B = `top';
- if (C == 0) then next `instruction' is real C
-
- (*) For comparisons, A specifies what condition the test should accept
- (true or false).
-
- (*) All `skips' (pc++) assume that next instruction is a jump
-===========================================================================*/
-
-
-/*
-** masks for instruction properties. The format is:
-** bits 0-1: op mode
-** bits 2-3: C arg mode
-** bits 4-5: B arg mode
-** bit 6: instruction set register A
-** bit 7: operator is a test
-*/
-
-enum OpArgMask {
- OpArgN, /* argument is not used */
- OpArgU, /* argument is used */
- OpArgR, /* argument is a register or a jump offset */
- OpArgK /* argument is a constant or register/constant */
-};
-
-LUAI_DATA const lu_byte luaP_opmodes[NUM_OPCODES];
-
-#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3))
-#define getBMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3))
-#define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3))
-#define testAMode(m) (luaP_opmodes[m] & (1 << 6))
-#define testTMode(m) (luaP_opmodes[m] & (1 << 7))
-
-
-LUAI_DATA const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */
-
-
-/* number of list items to accumulate before a SETLIST instruction */
-#define LFIELDS_PER_FLUSH 50
-
-
-#endif
diff --git a/src/lua/src/loslib.c b/src/lua/src/loslib.c
deleted file mode 100644
index da06a572a..000000000
--- a/src/lua/src/loslib.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
-** $Id: loslib.c,v 1.19.1.3 2008/01/18 16:38:18 roberto Exp $
-** Standard Operating System library
-** See Copyright Notice in lua.h
-*/
-
-
-#include <errno.h>
-#include <locale.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#define loslib_c
-#define LUA_LIB
-
-#include "lua.h"
-
-#include "lauxlib.h"
-#include "lualib.h"
-
-
-static int os_pushresult (lua_State *L, int i, const char *filename) {
- int en = errno; /* calls to Lua API may change this value */
- if (i) {
- lua_pushboolean(L, 1);
- return 1;
- }
- else {
- lua_pushnil(L);
- lua_pushfstring(L, "%s: %s", filename, strerror(en));
- lua_pushinteger(L, en);
- return 3;
- }
-}
-
-
-static int os_execute (lua_State *L) {
- lua_pushinteger(L, system(luaL_optstring(L, 1, NULL)));
- return 1;
-}
-
-
-static int os_remove (lua_State *L) {
- const char *filename = luaL_checkstring(L, 1);
- return os_pushresult(L, remove(filename) == 0, filename);
-}
-
-
-static int os_rename (lua_State *L) {
- const char *fromname = luaL_checkstring(L, 1);
- const char *toname = luaL_checkstring(L, 2);
- return os_pushresult(L, rename(fromname, toname) == 0, fromname);
-}
-
-
-static int os_tmpname (lua_State *L) {
- char buff[LUA_TMPNAMBUFSIZE];
- int err;
- lua_tmpnam(buff, err);
- if (err)
- return luaL_error(L, "unable to generate a unique filename");
- lua_pushstring(L, buff);
- return 1;
-}
-
-
-static int os_getenv (lua_State *L) {
- lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */
- return 1;
-}
-
-
-static int os_clock (lua_State *L) {
- lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC);
- return 1;
-}
-
-
-/*
-** {======================================================
-** Time/Date operations
-** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S,
-** wday=%w+1, yday=%j, isdst=? }
-** =======================================================
-*/
-
-static void setfield (lua_State *L, const char *key, int value) {
- lua_pushinteger(L, value);
- lua_setfield(L, -2, key);
-}
-
-static void setboolfield (lua_State *L, const char *key, int value) {
- if (value < 0) /* undefined? */
- return; /* does not set field */
- lua_pushboolean(L, value);
- lua_setfield(L, -2, key);
-}
-
-static int getboolfield (lua_State *L, const char *key) {
- int res;
- lua_getfield(L, -1, key);
- res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1);
- lua_pop(L, 1);
- return res;
-}
-
-
-static int getfield (lua_State *L, const char *key, int d) {
- int res;
- lua_getfield(L, -1, key);
- if (lua_isnumber(L, -1))
- res = (int)lua_tointeger(L, -1);
- else {
- if (d < 0)
- return luaL_error(L, "field " LUA_QS " missing in date table", key);
- res = d;
- }
- lua_pop(L, 1);
- return res;
-}
-
-
-static int os_date (lua_State *L) {
- const char *s = luaL_optstring(L, 1, "%c");
- time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL));
- struct tm *stm;
- if (*s == '!') { /* UTC? */
- stm = gmtime(&t);
- s++; /* skip `!' */
- }
- else
- stm = localtime(&t);
- if (stm == NULL) /* invalid date? */
- lua_pushnil(L);
- else if (strcmp(s, "*t") == 0) {
- lua_createtable(L, 0, 9); /* 9 = number of fields */
- setfield(L, "sec", stm->tm_sec);
- setfield(L, "min", stm->tm_min);
- setfield(L, "hour", stm->tm_hour);
- setfield(L, "day", stm->tm_mday);
- setfield(L, "month", stm->tm_mon+1);
- setfield(L, "year", stm->tm_year+1900);
- setfield(L, "wday", stm->tm_wday+1);
- setfield(L, "yday", stm->tm_yday+1);
- setboolfield(L, "isdst", stm->tm_isdst);
- }
- else {
- char cc[3];
- luaL_Buffer b;
- cc[0] = '%'; cc[2] = '\0';
- luaL_buffinit(L, &b);
- for (; *s; s++) {
- if (*s != '%' || *(s + 1) == '\0') /* no conversion specifier? */
- luaL_addchar(&b, *s);
- else {
- size_t reslen;
- char buff[200]; /* should be big enough for any conversion result */
- cc[1] = *(++s);
- reslen = strftime(buff, sizeof(buff), cc, stm);
- luaL_addlstring(&b, buff, reslen);
- }
- }
- luaL_pushresult(&b);
- }
- return 1;
-}
-
-
-static int os_time (lua_State *L) {
- time_t t;
- if (lua_isnoneornil(L, 1)) /* called without args? */
- t = time(NULL); /* get current time */
- else {
- struct tm ts;
- luaL_checktype(L, 1, LUA_TTABLE);
- lua_settop(L, 1); /* make sure table is at the top */
- ts.tm_sec = getfield(L, "sec", 0);
- ts.tm_min = getfield(L, "min", 0);
- ts.tm_hour = getfield(L, "hour", 12);
- ts.tm_mday = getfield(L, "day", -1);
- ts.tm_mon = getfield(L, "month", -1) - 1;
- ts.tm_year = getfield(L, "year", -1) - 1900;
- ts.tm_isdst = getboolfield(L, "isdst");
- t = mktime(&ts);
- }
- if (t == (time_t)(-1))
- lua_pushnil(L);
- else
- lua_pushnumber(L, (lua_Number)t);
- return 1;
-}
-
-
-static int os_difftime (lua_State *L) {
- lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)),
- (time_t)(luaL_optnumber(L, 2, 0))));
- return 1;
-}
-
-/* }====================================================== */
-
-
-static int os_setlocale (lua_State *L) {
- static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY,
- LC_NUMERIC, LC_TIME};
- static const char *const catnames[] = {"all", "collate", "ctype", "monetary",
- "numeric", "time", NULL};
- const char *l = luaL_optstring(L, 1, NULL);
- int op = luaL_checkoption(L, 2, "all", catnames);
- lua_pushstring(L, setlocale(cat[op], l));
- return 1;
-}
-
-
-static int os_exit (lua_State *L) {
- exit(luaL_optint(L, 1, EXIT_SUCCESS));
-}
-
-static const luaL_Reg syslib[] = {
- {"clock", os_clock},
- {"date", os_date},
- {"difftime", os_difftime},
- {"execute", os_execute},
- {"exit", os_exit},
- {"getenv", os_getenv},
- {"remove", os_remove},
- {"rename", os_rename},
- {"setlocale", os_setlocale},
- {"time", os_time},
- {"tmpname", os_tmpname},
- {NULL, NULL}
-};
-
-/* }====================================================== */
-
-
-
-LUALIB_API int luaopen_os (lua_State *L) {
- luaL_register(L, LUA_OSLIBNAME, syslib);
- return 1;
-}
-
diff --git a/src/lua/src/lparser.c b/src/lua/src/lparser.c
deleted file mode 100644
index 1e2a9a88b..000000000
--- a/src/lua/src/lparser.c
+++ /dev/null
@@ -1,1339 +0,0 @@
-/*
-** $Id: lparser.c,v 2.42.1.3 2007/12/28 15:32:23 roberto Exp $
-** Lua Parser
-** See Copyright Notice in lua.h
-*/
-
-
-#include <string.h>
-
-#define lparser_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "lcode.h"
-#include "ldebug.h"
-#include "ldo.h"
-#include "lfunc.h"
-#include "llex.h"
-#include "lmem.h"
-#include "lobject.h"
-#include "lopcodes.h"
-#include "lparser.h"
-#include "lstate.h"
-#include "lstring.h"
-#include "ltable.h"
-
-
-
-#define hasmultret(k) ((k) == VCALL || (k) == VVARARG)
-
-#define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]])
-
-#define luaY_checklimit(fs,v,l,m) if ((v)>(l)) errorlimit(fs,l,m)
-
-
-/*
-** nodes for block list (list of active blocks)
-*/
-typedef struct BlockCnt {
- struct BlockCnt *previous; /* chain */
- int breaklist; /* list of jumps out of this loop */
- lu_byte nactvar; /* # active locals outside the breakable structure */
- lu_byte upval; /* true if some variable in the block is an upvalue */
- lu_byte isbreakable; /* true if `block' is a loop */
-} BlockCnt;
-
-
-
-/*
-** prototypes for recursive non-terminal functions
-*/
-static void chunk (LexState *ls);
-static void expr (LexState *ls, expdesc *v);
-
-
-static void anchor_token (LexState *ls) {
- if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) {
- TString *ts = ls->t.seminfo.ts;
- luaX_newstring(ls, getstr(ts), ts->tsv.len);
- }
-}
-
-
-static void error_expected (LexState *ls, int token) {
- luaX_syntaxerror(ls,
- luaO_pushfstring(ls->L, LUA_QS " expected", luaX_token2str(ls, token)));
-}
-
-
-static void errorlimit (FuncState *fs, int limit, const char *what) {
- const char *msg = (fs->f->linedefined == 0) ?
- luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) :
- luaO_pushfstring(fs->L, "function at line %d has more than %d %s",
- fs->f->linedefined, limit, what);
- luaX_lexerror(fs->ls, msg, 0);
-}
-
-
-static int testnext (LexState *ls, int c) {
- if (ls->t.token == c) {
- luaX_next(ls);
- return 1;
- }
- else return 0;
-}
-
-
-static void check (LexState *ls, int c) {
- if (ls->t.token != c)
- error_expected(ls, c);
-}
-
-static void checknext (LexState *ls, int c) {
- check(ls, c);
- luaX_next(ls);
-}
-
-
-#define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); }
-
-
-
-static void check_match (LexState *ls, int what, int who, int where) {
- if (!testnext(ls, what)) {
- if (where == ls->linenumber)
- error_expected(ls, what);
- else {
- luaX_syntaxerror(ls, luaO_pushfstring(ls->L,
- LUA_QS " expected (to close " LUA_QS " at line %d)",
- luaX_token2str(ls, what), luaX_token2str(ls, who), where));
- }
- }
-}
-
-
-static TString *str_checkname (LexState *ls) {
- TString *ts;
- check(ls, TK_NAME);
- ts = ls->t.seminfo.ts;
- luaX_next(ls);
- return ts;
-}
-
-
-static void init_exp (expdesc *e, expkind k, int i) {
- e->f = e->t = NO_JUMP;
- e->k = k;
- e->u.s.info = i;
-}
-
-
-static void codestring (LexState *ls, expdesc *e, TString *s) {
- init_exp(e, VK, luaK_stringK(ls->fs, s));
-}
-
-
-static void checkname(LexState *ls, expdesc *e) {
- codestring(ls, e, str_checkname(ls));
-}
-
-
-static int registerlocalvar (LexState *ls, TString *varname) {
- FuncState *fs = ls->fs;
- Proto *f = fs->f;
- int oldsize = f->sizelocvars;
- luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
- LocVar, SHRT_MAX, "too many local variables");
- while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;
- f->locvars[fs->nlocvars].varname = varname;
- luaC_objbarrier(ls->L, f, varname);
- return fs->nlocvars++;
-}
-
-
-#define new_localvarliteral(ls,v,n) \
- new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n)
-
-
-static void new_localvar (LexState *ls, TString *name, int n) {
- FuncState *fs = ls->fs;
- luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables");
- fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name));
-}
-
-
-static void adjustlocalvars (LexState *ls, int nvars) {
- FuncState *fs = ls->fs;
- fs->nactvar = cast_byte(fs->nactvar + nvars);
- for (; nvars; nvars--) {
- getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc;
- }
-}
-
-
-static void removevars (LexState *ls, int tolevel) {
- FuncState *fs = ls->fs;
- while (fs->nactvar > tolevel)
- getlocvar(fs, --fs->nactvar).endpc = fs->pc;
-}
-
-
-static int indexupvalue (FuncState *fs, TString *name, expdesc *v) {
- int i;
- Proto *f = fs->f;
- int oldsize = f->sizeupvalues;
- for (i=0; i<f->nups; i++) {
- if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->u.s.info) {
- lua_assert(f->upvalues[i] == name);
- return i;
- }
- }
- /* new one */
- luaY_checklimit(fs, f->nups + 1, LUAI_MAXUPVALUES, "upvalues");
- luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues,
- TString *, MAX_INT, "");
- while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL;
- f->upvalues[f->nups] = name;
- luaC_objbarrier(fs->L, f, name);
- lua_assert(v->k == VLOCAL || v->k == VUPVAL);
- fs->upvalues[f->nups].k = cast_byte(v->k);
- fs->upvalues[f->nups].info = cast_byte(v->u.s.info);
- return f->nups++;
-}
-
-
-static int searchvar (FuncState *fs, TString *n) {
- int i;
- for (i=fs->nactvar-1; i >= 0; i--) {
- if (n == getlocvar(fs, i).varname)
- return i;
- }
- return -1; /* not found */
-}
-
-
-static void markupval (FuncState *fs, int level) {
- BlockCnt *bl = fs->bl;
- while (bl && bl->nactvar > level) bl = bl->previous;
- if (bl) bl->upval = 1;
-}
-
-
-static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
- if (fs == NULL) { /* no more levels? */
- init_exp(var, VGLOBAL, NO_REG); /* default is global variable */
- return VGLOBAL;
- }
- else {
- int v = searchvar(fs, n); /* look up at current level */
- if (v >= 0) {
- init_exp(var, VLOCAL, v);
- if (!base)
- markupval(fs, v); /* local will be used as an upval */
- return VLOCAL;
- }
- else { /* not found at current level; try upper one */
- if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL)
- return VGLOBAL;
- var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */
- var->k = VUPVAL; /* upvalue in this level */
- return VUPVAL;
- }
- }
-}
-
-
-static void singlevar (LexState *ls, expdesc *var) {
- TString *varname = str_checkname(ls);
- FuncState *fs = ls->fs;
- if (singlevaraux(fs, varname, var, 1) == VGLOBAL)
- var->u.s.info = luaK_stringK(fs, varname); /* info points to global name */
-}
-
-
-static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
- FuncState *fs = ls->fs;
- int extra = nvars - nexps;
- if (hasmultret(e->k)) {
- extra++; /* includes call itself */
- if (extra < 0) extra = 0;
- luaK_setreturns(fs, e, extra); /* last exp. provides the difference */
- if (extra > 1) luaK_reserveregs(fs, extra-1);
- }
- else {
- if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */
- if (extra > 0) {
- int reg = fs->freereg;
- luaK_reserveregs(fs, extra);
- luaK_nil(fs, reg, extra);
- }
- }
-}
-
-
-static void enterlevel (LexState *ls) {
- if (++ls->L->nCcalls > LUAI_MAXCCALLS)
- luaX_lexerror(ls, "chunk has too many syntax levels", 0);
-}
-
-
-#define leavelevel(ls) ((ls)->L->nCcalls--)
-
-
-static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) {
- bl->breaklist = NO_JUMP;
- bl->isbreakable = isbreakable;
- bl->nactvar = fs->nactvar;
- bl->upval = 0;
- bl->previous = fs->bl;
- fs->bl = bl;
- lua_assert(fs->freereg == fs->nactvar);
-}
-
-
-static void leaveblock (FuncState *fs) {
- BlockCnt *bl = fs->bl;
- fs->bl = bl->previous;
- removevars(fs->ls, bl->nactvar);
- if (bl->upval)
- luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
- /* a block either controls scope or breaks (never both) */
- lua_assert(!bl->isbreakable || !bl->upval);
- lua_assert(bl->nactvar == fs->nactvar);
- fs->freereg = fs->nactvar; /* free registers */
- luaK_patchtohere(fs, bl->breaklist);
-}
-
-
-static void pushclosure (LexState *ls, FuncState *func, expdesc *v) {
- FuncState *fs = ls->fs;
- Proto *f = fs->f;
- int oldsize = f->sizep;
- int i;
- luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *,
- MAXARG_Bx, "constant table overflow");
- while (oldsize < f->sizep) f->p[oldsize++] = NULL;
- f->p[fs->np++] = func->f;
- luaC_objbarrier(ls->L, f, func->f);
- init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1));
- for (i=0; i<func->f->nups; i++) {
- OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;
- luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0);
- }
-}
-
-
-static void open_func (LexState *ls, FuncState *fs) {
- lua_State *L = ls->L;
- Proto *f = luaF_newproto(L);
- fs->f = f;
- fs->prev = ls->fs; /* linked list of funcstates */
- fs->ls = ls;
- fs->L = L;
- ls->fs = fs;
- fs->pc = 0;
- fs->lasttarget = -1;
- fs->jpc = NO_JUMP;
- fs->freereg = 0;
- fs->nk = 0;
- fs->np = 0;
- fs->nlocvars = 0;
- fs->nactvar = 0;
- fs->bl = NULL;
- f->source = ls->source;
- f->maxstacksize = 2; /* registers 0/1 are always valid */
- fs->h = luaH_new(L, 0, 0);
- /* anchor table of constants and prototype (to avoid being collected) */
- sethvalue2s(L, L->top, fs->h);
- incr_top(L);
- setptvalue2s(L, L->top, f);
- incr_top(L);
-}
-
-
-static void close_func (LexState *ls) {
- lua_State *L = ls->L;
- FuncState *fs = ls->fs;
- Proto *f = fs->f;
- removevars(ls, 0);
- luaK_ret(fs, 0, 0); /* final return */
- luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
- f->sizecode = fs->pc;
- luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
- f->sizelineinfo = fs->pc;
- luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);
- f->sizek = fs->nk;
- luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);
- f->sizep = fs->np;
- luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
- f->sizelocvars = fs->nlocvars;
- luaM_reallocvector(L, f->upvalues, f->sizeupvalues, f->nups, TString *);
- f->sizeupvalues = f->nups;
- lua_assert(luaG_checkcode(f));
- lua_assert(fs->bl == NULL);
- ls->fs = fs->prev;
- L->top -= 2; /* remove table and prototype from the stack */
- /* last token read was anchored in defunct function; must reanchor it */
- if (fs) anchor_token(ls);
-}
-
-
-Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) {
- struct LexState lexstate;
- struct FuncState funcstate;
- lexstate.buff = buff;
- luaX_setinput(L, &lexstate, z, luaS_new(L, name));
- open_func(&lexstate, &funcstate);
- funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */
- luaX_next(&lexstate); /* read first token */
- chunk(&lexstate);
- check(&lexstate, TK_EOS);
- close_func(&lexstate);
- lua_assert(funcstate.prev == NULL);
- lua_assert(funcstate.f->nups == 0);
- lua_assert(lexstate.fs == NULL);
- return funcstate.f;
-}
-
-
-
-/*============================================================*/
-/* GRAMMAR RULES */
-/*============================================================*/
-
-
-static void field (LexState *ls, expdesc *v) {
- /* field -> ['.' | ':'] NAME */
- FuncState *fs = ls->fs;
- expdesc key;
- luaK_exp2anyreg(fs, v);
- luaX_next(ls); /* skip the dot or colon */
- checkname(ls, &key);
- luaK_indexed(fs, v, &key);
-}
-
-
-static void yindex (LexState *ls, expdesc *v) {
- /* index -> '[' expr ']' */
- luaX_next(ls); /* skip the '[' */
- expr(ls, v);
- luaK_exp2val(ls->fs, v);
- checknext(ls, ']');
-}
-
-
-/*
-** {======================================================================
-** Rules for Constructors
-** =======================================================================
-*/
-
-
-struct ConsControl {
- expdesc v; /* last list item read */
- expdesc *t; /* table descriptor */
- int nh; /* total number of `record' elements */
- int na; /* total number of array elements */
- int tostore; /* number of array elements pending to be stored */
-};
-
-
-static void recfield (LexState *ls, struct ConsControl *cc) {
- /* recfield -> (NAME | `['exp1`]') = exp1 */
- FuncState *fs = ls->fs;
- int reg = ls->fs->freereg;
- expdesc key, val;
- int rkkey;
- if (ls->t.token == TK_NAME) {
- luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor");
- checkname(ls, &key);
- }
- else /* ls->t.token == '[' */
- yindex(ls, &key);
- cc->nh++;
- checknext(ls, '=');
- rkkey = luaK_exp2RK(fs, &key);
- expr(ls, &val);
- luaK_codeABC(fs, OP_SETTABLE, cc->t->u.s.info, rkkey, luaK_exp2RK(fs, &val));
- fs->freereg = reg; /* free registers */
-}
-
-
-static void closelistfield (FuncState *fs, struct ConsControl *cc) {
- if (cc->v.k == VVOID) return; /* there is no list item */
- luaK_exp2nextreg(fs, &cc->v);
- cc->v.k = VVOID;
- if (cc->tostore == LFIELDS_PER_FLUSH) {
- luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); /* flush */
- cc->tostore = 0; /* no more items pending */
- }
-}
-
-
-static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
- if (cc->tostore == 0) return;
- if (hasmultret(cc->v.k)) {
- luaK_setmultret(fs, &cc->v);
- luaK_setlist(fs, cc->t->u.s.info, cc->na, LUA_MULTRET);
- cc->na--; /* do not count last expression (unknown number of elements) */
- }
- else {
- if (cc->v.k != VVOID)
- luaK_exp2nextreg(fs, &cc->v);
- luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore);
- }
-}
-
-
-static void listfield (LexState *ls, struct ConsControl *cc) {
- expr(ls, &cc->v);
- luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor");
- cc->na++;
- cc->tostore++;
-}
-
-
-static void constructor (LexState *ls, expdesc *t) {
- /* constructor -> ?? */
- FuncState *fs = ls->fs;
- int line = ls->linenumber;
- int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
- struct ConsControl cc;
- cc.na = cc.nh = cc.tostore = 0;
- cc.t = t;
- init_exp(t, VRELOCABLE, pc);
- init_exp(&cc.v, VVOID, 0); /* no value (yet) */
- luaK_exp2nextreg(ls->fs, t); /* fix it at stack top (for gc) */
- checknext(ls, '{');
- do {
- lua_assert(cc.v.k == VVOID || cc.tostore > 0);
- if (ls->t.token == '}') break;
- closelistfield(fs, &cc);
- switch(ls->t.token) {
- case TK_NAME: { /* may be listfields or recfields */
- luaX_lookahead(ls);
- if (ls->lookahead.token != '=') /* expression? */
- listfield(ls, &cc);
- else
- recfield(ls, &cc);
- break;
- }
- case '[': { /* constructor_item -> recfield */
- recfield(ls, &cc);
- break;
- }
- default: { /* constructor_part -> listfield */
- listfield(ls, &cc);
- break;
- }
- }
- } while (testnext(ls, ',') || testnext(ls, ';'));
- check_match(ls, '}', '{', line);
- lastlistfield(fs, &cc);
- SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */
- SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */
-}
-
-/* }====================================================================== */
-
-
-
-static void parlist (LexState *ls) {
- /* parlist -> [ param { `,' param } ] */
- FuncState *fs = ls->fs;
- Proto *f = fs->f;
- int nparams = 0;
- f->is_vararg = 0;
- if (ls->t.token != ')') { /* is `parlist' not empty? */
- do {
- switch (ls->t.token) {
- case TK_NAME: { /* param -> NAME */
- new_localvar(ls, str_checkname(ls), nparams++);
- break;
- }
- case TK_DOTS: { /* param -> `...' */
- luaX_next(ls);
-#if defined(LUA_COMPAT_VARARG)
- /* use `arg' as default name */
- new_localvarliteral(ls, "arg", nparams++);
- f->is_vararg = VARARG_HASARG | VARARG_NEEDSARG;
-#endif
- f->is_vararg |= VARARG_ISVARARG;
- break;
- }
- default: luaX_syntaxerror(ls, "<name> or " LUA_QL("...") " expected");
- }
- } while (!f->is_vararg && testnext(ls, ','));
- }
- adjustlocalvars(ls, nparams);
- f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG));
- luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */
-}
-
-
-static void body (LexState *ls, expdesc *e, int needself, int line) {
- /* body -> `(' parlist `)' chunk END */
- FuncState new_fs;
- open_func(ls, &new_fs);
- new_fs.f->linedefined = line;
- checknext(ls, '(');
- if (needself) {
- new_localvarliteral(ls, "self", 0);
- adjustlocalvars(ls, 1);
- }
- parlist(ls);
- checknext(ls, ')');
- chunk(ls);
- new_fs.f->lastlinedefined = ls->linenumber;
- check_match(ls, TK_END, TK_FUNCTION, line);
- close_func(ls);
- pushclosure(ls, &new_fs, e);
-}
-
-
-static int explist1 (LexState *ls, expdesc *v) {
- /* explist1 -> expr { `,' expr } */
- int n = 1; /* at least one expression */
- expr(ls, v);
- while (testnext(ls, ',')) {
- luaK_exp2nextreg(ls->fs, v);
- expr(ls, v);
- n++;
- }
- return n;
-}
-
-
-static void funcargs (LexState *ls, expdesc *f) {
- FuncState *fs = ls->fs;
- expdesc args;
- int base, nparams;
- int line = ls->linenumber;
- switch (ls->t.token) {
- case '(': { /* funcargs -> `(' [ explist1 ] `)' */
- if (line != ls->lastline)
- luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)");
- luaX_next(ls);
- if (ls->t.token == ')') /* arg list is empty? */
- args.k = VVOID;
- else {
- explist1(ls, &args);
- luaK_setmultret(fs, &args);
- }
- check_match(ls, ')', '(', line);
- break;
- }
- case '{': { /* funcargs -> constructor */
- constructor(ls, &args);
- break;
- }
- case TK_STRING: { /* funcargs -> STRING */
- codestring(ls, &args, ls->t.seminfo.ts);
- luaX_next(ls); /* must use `seminfo' before `next' */
- break;
- }
- default: {
- luaX_syntaxerror(ls, "function arguments expected");
- return;
- }
- }
- lua_assert(f->k == VNONRELOC);
- base = f->u.s.info; /* base register for call */
- if (hasmultret(args.k))
- nparams = LUA_MULTRET; /* open call */
- else {
- if (args.k != VVOID)
- luaK_exp2nextreg(fs, &args); /* close last argument */
- nparams = fs->freereg - (base+1);
- }
- init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
- luaK_fixline(fs, line);
- fs->freereg = base+1; /* call remove function and arguments and leaves
- (unless changed) one result */
-}
-
-
-
-
-/*
-** {======================================================================
-** Expression parsing
-** =======================================================================
-*/
-
-
-static void prefixexp (LexState *ls, expdesc *v) {
- /* prefixexp -> NAME | '(' expr ')' */
- switch (ls->t.token) {
- case '(': {
- int line = ls->linenumber;
- luaX_next(ls);
- expr(ls, v);
- check_match(ls, ')', '(', line);
- luaK_dischargevars(ls->fs, v);
- return;
- }
- case TK_NAME: {
- singlevar(ls, v);
- return;
- }
- default: {
- luaX_syntaxerror(ls, "unexpected symbol");
- return;
- }
- }
-}
-
-
-static void primaryexp (LexState *ls, expdesc *v) {
- /* primaryexp ->
- prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */
- FuncState *fs = ls->fs;
- prefixexp(ls, v);
- for (;;) {
- switch (ls->t.token) {
- case '.': { /* field */
- field(ls, v);
- break;
- }
- case '[': { /* `[' exp1 `]' */
- expdesc key;
- luaK_exp2anyreg(fs, v);
- yindex(ls, &key);
- luaK_indexed(fs, v, &key);
- break;
- }
- case ':': { /* `:' NAME funcargs */
- expdesc key;
- luaX_next(ls);
- checkname(ls, &key);
- luaK_self(fs, v, &key);
- funcargs(ls, v);
- break;
- }
- case '(': case TK_STRING: case '{': { /* funcargs */
- luaK_exp2nextreg(fs, v);
- funcargs(ls, v);
- break;
- }
- default: return;
- }
- }
-}
-
-
-static void simpleexp (LexState *ls, expdesc *v) {
- /* simpleexp -> NUMBER | STRING | NIL | true | false | ... |
- constructor | FUNCTION body | primaryexp */
- switch (ls->t.token) {
- case TK_NUMBER: {
- init_exp(v, VKNUM, 0);
- v->u.nval = ls->t.seminfo.r;
- break;
- }
- case TK_STRING: {
- codestring(ls, v, ls->t.seminfo.ts);
- break;
- }
- case TK_NIL: {
- init_exp(v, VNIL, 0);
- break;
- }
- case TK_TRUE: {
- init_exp(v, VTRUE, 0);
- break;
- }
- case TK_FALSE: {
- init_exp(v, VFALSE, 0);
- break;
- }
- case TK_DOTS: { /* vararg */
- FuncState *fs = ls->fs;
- check_condition(ls, fs->f->is_vararg,
- "cannot use " LUA_QL("...") " outside a vararg function");
- fs->f->is_vararg &= ~VARARG_NEEDSARG; /* don't need 'arg' */
- init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
- break;
- }
- case '{': { /* constructor */
- constructor(ls, v);
- return;
- }
- case TK_FUNCTION: {
- luaX_next(ls);
- body(ls, v, 0, ls->linenumber);
- return;
- }
- default: {
- primaryexp(ls, v);
- return;
- }
- }
- luaX_next(ls);
-}
-
-
-static UnOpr getunopr (int op) {
- switch (op) {
- case TK_NOT: return OPR_NOT;
- case '-': return OPR_MINUS;
- case '#': return OPR_LEN;
- default: return OPR_NOUNOPR;
- }
-}
-
-
-static BinOpr getbinopr (int op) {
- switch (op) {
- case '+': return OPR_ADD;
- case '-': return OPR_SUB;
- case '*': return OPR_MUL;
- case '/': return OPR_DIV;
- case '%': return OPR_MOD;
- case '^': return OPR_POW;
- case TK_CONCAT: return OPR_CONCAT;
- case TK_NE: return OPR_NE;
- case TK_EQ: return OPR_EQ;
- case '<': return OPR_LT;
- case TK_LE: return OPR_LE;
- case '>': return OPR_GT;
- case TK_GE: return OPR_GE;
- case TK_AND: return OPR_AND;
- case TK_OR: return OPR_OR;
- default: return OPR_NOBINOPR;
- }
-}
-
-
-static const struct {
- lu_byte left; /* left priority for each binary operator */
- lu_byte right; /* right priority */
-} priority[] = { /* ORDER OPR */
- {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `/' `%' */
- {10, 9}, {5, 4}, /* power and concat (right associative) */
- {3, 3}, {3, 3}, /* equality and inequality */
- {3, 3}, {3, 3}, {3, 3}, {3, 3}, /* order */
- {2, 2}, {1, 1} /* logical (and/or) */
-};
-
-#define UNARY_PRIORITY 8 /* priority for unary operators */
-
-
-/*
-** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
-** where `binop' is any binary operator with a priority higher than `limit'
-*/
-static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) {
- BinOpr op;
- UnOpr uop;
- enterlevel(ls);
- uop = getunopr(ls->t.token);
- if (uop != OPR_NOUNOPR) {
- luaX_next(ls);
- subexpr(ls, v, UNARY_PRIORITY);
- luaK_prefix(ls->fs, uop, v);
- }
- else simpleexp(ls, v);
- /* expand while operators have priorities higher than `limit' */
- op = getbinopr(ls->t.token);
- while (op != OPR_NOBINOPR && priority[op].left > limit) {
- expdesc v2;
- BinOpr nextop;
- luaX_next(ls);
- luaK_infix(ls->fs, op, v);
- /* read sub-expression with higher priority */
- nextop = subexpr(ls, &v2, priority[op].right);
- luaK_posfix(ls->fs, op, v, &v2);
- op = nextop;
- }
- leavelevel(ls);
- return op; /* return first untreated operator */
-}
-
-
-static void expr (LexState *ls, expdesc *v) {
- subexpr(ls, v, 0);
-}
-
-/* }==================================================================== */
-
-
-
-/*
-** {======================================================================
-** Rules for Statements
-** =======================================================================
-*/
-
-
-static int block_follow (int token) {
- switch (token) {
- case TK_ELSE: case TK_ELSEIF: case TK_END:
- case TK_UNTIL: case TK_EOS:
- return 1;
- default: return 0;
- }
-}
-
-
-static void block (LexState *ls) {
- /* block -> chunk */
- FuncState *fs = ls->fs;
- BlockCnt bl;
- enterblock(fs, &bl, 0);
- chunk(ls);
- lua_assert(bl.breaklist == NO_JUMP);
- leaveblock(fs);
-}
-
-
-/*
-** structure to chain all variables in the left-hand side of an
-** assignment
-*/
-struct LHS_assign {
- struct LHS_assign *prev;
- expdesc v; /* variable (global, local, upvalue, or indexed) */
-};
-
-
-/*
-** check whether, in an assignment to a local variable, the local variable
-** is needed in a previous assignment (to a table). If so, save original
-** local value in a safe place and use this safe copy in the previous
-** assignment.
-*/
-static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
- FuncState *fs = ls->fs;
- int extra = fs->freereg; /* eventual position to save local variable */
- int conflict = 0;
- for (; lh; lh = lh->prev) {
- if (lh->v.k == VINDEXED) {
- if (lh->v.u.s.info == v->u.s.info) { /* conflict? */
- conflict = 1;
- lh->v.u.s.info = extra; /* previous assignment will use safe copy */
- }
- if (lh->v.u.s.aux == v->u.s.info) { /* conflict? */
- conflict = 1;
- lh->v.u.s.aux = extra; /* previous assignment will use safe copy */
- }
- }
- }
- if (conflict) {
- luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0); /* make copy */
- luaK_reserveregs(fs, 1);
- }
-}
-
-
-static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
- expdesc e;
- check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED,
- "syntax error");
- if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */
- struct LHS_assign nv;
- nv.prev = lh;
- primaryexp(ls, &nv.v);
- if (nv.v.k == VLOCAL)
- check_conflict(ls, lh, &nv.v);
- luaY_checklimit(ls->fs, nvars, LUAI_MAXCCALLS - ls->L->nCcalls,
- "variables in assignment");
- assignment(ls, &nv, nvars+1);
- }
- else { /* assignment -> `=' explist1 */
- int nexps;
- checknext(ls, '=');
- nexps = explist1(ls, &e);
- if (nexps != nvars) {
- adjust_assign(ls, nvars, nexps, &e);
- if (nexps > nvars)
- ls->fs->freereg -= nexps - nvars; /* remove extra values */
- }
- else {
- luaK_setoneret(ls->fs, &e); /* close last expression */
- luaK_storevar(ls->fs, &lh->v, &e);
- return; /* avoid default */
- }
- }
- init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */
- luaK_storevar(ls->fs, &lh->v, &e);
-}
-
-
-static int cond (LexState *ls) {
- /* cond -> exp */
- expdesc v;
- expr(ls, &v); /* read condition */
- if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */
- luaK_goiftrue(ls->fs, &v);
- return v.f;
-}
-
-
-static void breakstat (LexState *ls) {
- FuncState *fs = ls->fs;
- BlockCnt *bl = fs->bl;
- int upval = 0;
- while (bl && !bl->isbreakable) {
- upval |= bl->upval;
- bl = bl->previous;
- }
- if (!bl)
- luaX_syntaxerror(ls, "no loop to break");
- if (upval)
- luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
- luaK_concat(fs, &bl->breaklist, luaK_jump(fs));
-}
-
-
-static void whilestat (LexState *ls, int line) {
- /* whilestat -> WHILE cond DO block END */
- FuncState *fs = ls->fs;
- int whileinit;
- int condexit;
- BlockCnt bl;
- luaX_next(ls); /* skip WHILE */
- whileinit = luaK_getlabel(fs);
- condexit = cond(ls);
- enterblock(fs, &bl, 1);
- checknext(ls, TK_DO);
- block(ls);
- luaK_patchlist(fs, luaK_jump(fs), whileinit);
- check_match(ls, TK_END, TK_WHILE, line);
- leaveblock(fs);
- luaK_patchtohere(fs, condexit); /* false conditions finish the loop */
-}
-
-
-static void repeatstat (LexState *ls, int line) {
- /* repeatstat -> REPEAT block UNTIL cond */
- int condexit;
- FuncState *fs = ls->fs;
- int repeat_init = luaK_getlabel(fs);
- BlockCnt bl1, bl2;
- enterblock(fs, &bl1, 1); /* loop block */
- enterblock(fs, &bl2, 0); /* scope block */
- luaX_next(ls); /* skip REPEAT */
- chunk(ls);
- check_match(ls, TK_UNTIL, TK_REPEAT, line);
- condexit = cond(ls); /* read condition (inside scope block) */
- if (!bl2.upval) { /* no upvalues? */
- leaveblock(fs); /* finish scope */
- luaK_patchlist(ls->fs, condexit, repeat_init); /* close the loop */
- }
- else { /* complete semantics when there are upvalues */
- breakstat(ls); /* if condition then break */
- luaK_patchtohere(ls->fs, condexit); /* else... */
- leaveblock(fs); /* finish scope... */
- luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init); /* and repeat */
- }
- leaveblock(fs); /* finish loop */
-}
-
-
-static int exp1 (LexState *ls) {
- expdesc e;
- int k;
- expr(ls, &e);
- k = e.k;
- luaK_exp2nextreg(ls->fs, &e);
- return k;
-}
-
-
-static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
- /* forbody -> DO block */
- BlockCnt bl;
- FuncState *fs = ls->fs;
- int prep, endfor;
- adjustlocalvars(ls, 3); /* control variables */
- checknext(ls, TK_DO);
- prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs);
- enterblock(fs, &bl, 0); /* scope for declared variables */
- adjustlocalvars(ls, nvars);
- luaK_reserveregs(fs, nvars);
- block(ls);
- leaveblock(fs); /* end of scope for declared variables */
- luaK_patchtohere(fs, prep);
- endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) :
- luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars);
- luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */
- luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1);
-}
-
-
-static void fornum (LexState *ls, TString *varname, int line) {
- /* fornum -> NAME = exp1,exp1[,exp1] forbody */
- FuncState *fs = ls->fs;
- int base = fs->freereg;
- new_localvarliteral(ls, "(for index)", 0);
- new_localvarliteral(ls, "(for limit)", 1);
- new_localvarliteral(ls, "(for step)", 2);
- new_localvar(ls, varname, 3);
- checknext(ls, '=');
- exp1(ls); /* initial value */
- checknext(ls, ',');
- exp1(ls); /* limit */
- if (testnext(ls, ','))
- exp1(ls); /* optional step */
- else { /* default step = 1 */
- luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1));
- luaK_reserveregs(fs, 1);
- }
- forbody(ls, base, line, 1, 1);
-}
-
-
-static void forlist (LexState *ls, TString *indexname) {
- /* forlist -> NAME {,NAME} IN explist1 forbody */
- FuncState *fs = ls->fs;
- expdesc e;
- int nvars = 0;
- int line;
- int base = fs->freereg;
- /* create control variables */
- new_localvarliteral(ls, "(for generator)", nvars++);
- new_localvarliteral(ls, "(for state)", nvars++);
- new_localvarliteral(ls, "(for control)", nvars++);
- /* create declared variables */
- new_localvar(ls, indexname, nvars++);
- while (testnext(ls, ','))
- new_localvar(ls, str_checkname(ls), nvars++);
- checknext(ls, TK_IN);
- line = ls->linenumber;
- adjust_assign(ls, 3, explist1(ls, &e), &e);
- luaK_checkstack(fs, 3); /* extra space to call generator */
- forbody(ls, base, line, nvars - 3, 0);
-}
-
-
-static void forstat (LexState *ls, int line) {
- /* forstat -> FOR (fornum | forlist) END */
- FuncState *fs = ls->fs;
- TString *varname;
- BlockCnt bl;
- enterblock(fs, &bl, 1); /* scope for loop and control variables */
- luaX_next(ls); /* skip `for' */
- varname = str_checkname(ls); /* first variable name */
- switch (ls->t.token) {
- case '=': fornum(ls, varname, line); break;
- case ',': case TK_IN: forlist(ls, varname); break;
- default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected");
- }
- check_match(ls, TK_END, TK_FOR, line);
- leaveblock(fs); /* loop scope (`break' jumps to this point) */
-}
-
-
-static int test_then_block (LexState *ls) {
- /* test_then_block -> [IF | ELSEIF] cond THEN block */
- int condexit;
- luaX_next(ls); /* skip IF or ELSEIF */
- condexit = cond(ls);
- checknext(ls, TK_THEN);
- block(ls); /* `then' part */
- return condexit;
-}
-
-
-static void ifstat (LexState *ls, int line) {
- /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */
- FuncState *fs = ls->fs;
- int flist;
- int escapelist = NO_JUMP;
- flist = test_then_block(ls); /* IF cond THEN block */
- while (ls->t.token == TK_ELSEIF) {
- luaK_concat(fs, &escapelist, luaK_jump(fs));
- luaK_patchtohere(fs, flist);
- flist = test_then_block(ls); /* ELSEIF cond THEN block */
- }
- if (ls->t.token == TK_ELSE) {
- luaK_concat(fs, &escapelist, luaK_jump(fs));
- luaK_patchtohere(fs, flist);
- luaX_next(ls); /* skip ELSE (after patch, for correct line info) */
- block(ls); /* `else' part */
- }
- else
- luaK_concat(fs, &escapelist, flist);
- luaK_patchtohere(fs, escapelist);
- check_match(ls, TK_END, TK_IF, line);
-}
-
-
-static void localfunc (LexState *ls) {
- expdesc v, b;
- FuncState *fs = ls->fs;
- new_localvar(ls, str_checkname(ls), 0);
- init_exp(&v, VLOCAL, fs->freereg);
- luaK_reserveregs(fs, 1);
- adjustlocalvars(ls, 1);
- body(ls, &b, 0, ls->linenumber);
- luaK_storevar(fs, &v, &b);
- /* debug information will only see the variable after this point! */
- getlocvar(fs, fs->nactvar - 1).startpc = fs->pc;
-}
-
-
-static void localstat (LexState *ls) {
- /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
- int nvars = 0;
- int nexps;
- expdesc e;
- do {
- new_localvar(ls, str_checkname(ls), nvars++);
- } while (testnext(ls, ','));
- if (testnext(ls, '='))
- nexps = explist1(ls, &e);
- else {
- e.k = VVOID;
- nexps = 0;
- }
- adjust_assign(ls, nvars, nexps, &e);
- adjustlocalvars(ls, nvars);
-}
-
-
-static int funcname (LexState *ls, expdesc *v) {
- /* funcname -> NAME {field} [`:' NAME] */
- int needself = 0;
- singlevar(ls, v);
- while (ls->t.token == '.')
- field(ls, v);
- if (ls->t.token == ':') {
- needself = 1;
- field(ls, v);
- }
- return needself;
-}
-
-
-static void funcstat (LexState *ls, int line) {
- /* funcstat -> FUNCTION funcname body */
- int needself;
- expdesc v, b;
- luaX_next(ls); /* skip FUNCTION */
- needself = funcname(ls, &v);
- body(ls, &b, needself, line);
- luaK_storevar(ls->fs, &v, &b);
- luaK_fixline(ls->fs, line); /* definition `happens' in the first line */
-}
-
-
-static void exprstat (LexState *ls) {
- /* stat -> func | assignment */
- FuncState *fs = ls->fs;
- struct LHS_assign v;
- primaryexp(ls, &v.v);
- if (v.v.k == VCALL) /* stat -> func */
- SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */
- else { /* stat -> assignment */
- v.prev = NULL;
- assignment(ls, &v, 1);
- }
-}
-
-
-static void retstat (LexState *ls) {
- /* stat -> RETURN explist */
- FuncState *fs = ls->fs;
- expdesc e;
- int first, nret; /* registers with returned values */
- luaX_next(ls); /* skip RETURN */
- if (block_follow(ls->t.token) || ls->t.token == ';')
- first = nret = 0; /* return no values */
- else {
- nret = explist1(ls, &e); /* optional return values */
- if (hasmultret(e.k)) {
- luaK_setmultret(fs, &e);
- if (e.k == VCALL && nret == 1) { /* tail call? */
- SET_OPCODE(getcode(fs,&e), OP_TAILCALL);
- lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar);
- }
- first = fs->nactvar;
- nret = LUA_MULTRET; /* return all values */
- }
- else {
- if (nret == 1) /* only one single value? */
- first = luaK_exp2anyreg(fs, &e);
- else {
- luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */
- first = fs->nactvar; /* return all `active' values */
- lua_assert(nret == fs->freereg - first);
- }
- }
- }
- luaK_ret(fs, first, nret);
-}
-
-
-static int statement (LexState *ls) {
- int line = ls->linenumber; /* may be needed for error messages */
- switch (ls->t.token) {
- case TK_IF: { /* stat -> ifstat */
- ifstat(ls, line);
- return 0;
- }
- case TK_WHILE: { /* stat -> whilestat */
- whilestat(ls, line);
- return 0;
- }
- case TK_DO: { /* stat -> DO block END */
- luaX_next(ls); /* skip DO */
- block(ls);
- check_match(ls, TK_END, TK_DO, line);
- return 0;
- }
- case TK_FOR: { /* stat -> forstat */
- forstat(ls, line);
- return 0;
- }
- case TK_REPEAT: { /* stat -> repeatstat */
- repeatstat(ls, line);
- return 0;
- }
- case TK_FUNCTION: {
- funcstat(ls, line); /* stat -> funcstat */
- return 0;
- }
- case TK_LOCAL: { /* stat -> localstat */
- luaX_next(ls); /* skip LOCAL */
- if (testnext(ls, TK_FUNCTION)) /* local function? */
- localfunc(ls);
- else
- localstat(ls);
- return 0;
- }
- case TK_RETURN: { /* stat -> retstat */
- retstat(ls);
- return 1; /* must be last statement */
- }
- case TK_BREAK: { /* stat -> breakstat */
- luaX_next(ls); /* skip BREAK */
- breakstat(ls);
- return 1; /* must be last statement */
- }
- default: {
- exprstat(ls);
- return 0; /* to avoid warnings */
- }
- }
-}
-
-
-static void chunk (LexState *ls) {
- /* chunk -> { stat [`;'] } */
- int islast = 0;
- enterlevel(ls);
- while (!islast && !block_follow(ls->t.token)) {
- islast = statement(ls);
- testnext(ls, ';');
- lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
- ls->fs->freereg >= ls->fs->nactvar);
- ls->fs->freereg = ls->fs->nactvar; /* free registers */
- }
- leavelevel(ls);
-}
-
-/* }====================================================================== */
diff --git a/src/lua/src/lparser.h b/src/lua/src/lparser.h
deleted file mode 100644
index 18836afd1..000000000
--- a/src/lua/src/lparser.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-** $Id: lparser.h,v 1.57.1.1 2007/12/27 13:02:25 roberto Exp $
-** Lua Parser
-** See Copyright Notice in lua.h
-*/
-
-#ifndef lparser_h
-#define lparser_h
-
-#include "llimits.h"
-#include "lobject.h"
-#include "lzio.h"
-
-
-/*
-** Expression descriptor
-*/
-
-typedef enum {
- VVOID, /* no value */
- VNIL,
- VTRUE,
- VFALSE,
- VK, /* info = index of constant in `k' */
- VKNUM, /* nval = numerical value */
- VLOCAL, /* info = local register */
- VUPVAL, /* info = index of upvalue in `upvalues' */
- VGLOBAL, /* info = index of table; aux = index of global name in `k' */
- VINDEXED, /* info = table register; aux = index register (or `k') */
- VJMP, /* info = instruction pc */
- VRELOCABLE, /* info = instruction pc */
- VNONRELOC, /* info = result register */
- VCALL, /* info = instruction pc */
- VVARARG /* info = instruction pc */
-} expkind;
-
-typedef struct expdesc {
- expkind k;
- union {
- struct { int info, aux; } s;
- lua_Number nval;
- } u;
- int t; /* patch list of `exit when true' */
- int f; /* patch list of `exit when false' */
-} expdesc;
-
-
-typedef struct upvaldesc {
- lu_byte k;
- lu_byte info;
-} upvaldesc;
-
-
-struct BlockCnt; /* defined in lparser.c */
-
-
-/* state needed to generate code for a given function */
-typedef struct FuncState {
- Proto *f; /* current function header */
- Table *h; /* table to find (and reuse) elements in `k' */
- struct FuncState *prev; /* enclosing function */
- struct LexState *ls; /* lexical state */
- struct lua_State *L; /* copy of the Lua state */
- struct BlockCnt *bl; /* chain of current blocks */
- int pc; /* next position to code (equivalent to `ncode') */
- int lasttarget; /* `pc' of last `jump target' */
- int jpc; /* list of pending jumps to `pc' */
- int freereg; /* first free register */
- int nk; /* number of elements in `k' */
- int np; /* number of elements in `p' */
- short nlocvars; /* number of elements in `locvars' */
- lu_byte nactvar; /* number of active local variables */
- upvaldesc upvalues[LUAI_MAXUPVALUES]; /* upvalues */
- unsigned short actvar[LUAI_MAXVARS]; /* declared-variable stack */
-} FuncState;
-
-
-LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
- const char *name);
-
-
-#endif
diff --git a/src/lua/src/lstate.c b/src/lua/src/lstate.c
deleted file mode 100644
index 4313b83a0..000000000
--- a/src/lua/src/lstate.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
-** $Id: lstate.c,v 2.36.1.2 2008/01/03 15:20:39 roberto Exp $
-** Global State
-** See Copyright Notice in lua.h
-*/
-
-
-#include <stddef.h>
-
-#define lstate_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "ldebug.h"
-#include "ldo.h"
-#include "lfunc.h"
-#include "lgc.h"
-#include "llex.h"
-#include "lmem.h"
-#include "lstate.h"
-#include "lstring.h"
-#include "ltable.h"
-#include "ltm.h"
-
-
-#define state_size(x) (sizeof(x) + LUAI_EXTRASPACE)
-#define fromstate(l) (cast(lu_byte *, (l)) - LUAI_EXTRASPACE)
-#define tostate(l) (cast(lua_State *, cast(lu_byte *, l) + LUAI_EXTRASPACE))
-
-
-/*
-** Main thread combines a thread state and the global state
-*/
-typedef struct LG {
- lua_State l;
- global_State g;
-} LG;
-
-
-
-static void stack_init (lua_State *L1, lua_State *L) {
- /* initialize CallInfo array */
- L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo);
- L1->ci = L1->base_ci;
- L1->size_ci = BASIC_CI_SIZE;
- L1->end_ci = L1->base_ci + L1->size_ci - 1;
- /* initialize stack array */
- L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue);
- L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK;
- L1->top = L1->stack;
- L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1;
- /* initialize first ci */
- L1->ci->func = L1->top;
- setnilvalue(L1->top++); /* `function' entry for this `ci' */
- L1->base = L1->ci->base = L1->top;
- L1->ci->top = L1->top + LUA_MINSTACK;
-}
-
-
-static void freestack (lua_State *L, lua_State *L1) {
- luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo);
- luaM_freearray(L, L1->stack, L1->stacksize, TValue);
-}
-
-
-/*
-** open parts that may cause memory-allocation errors
-*/
-static void f_luaopen (lua_State *L, void *ud) {
- global_State *g = G(L);
- UNUSED(ud);
- stack_init(L, L); /* init stack */
- sethvalue(L, gt(L), luaH_new(L, 0, 2)); /* table of globals */
- sethvalue(L, registry(L), luaH_new(L, 0, 2)); /* registry */
- luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
- luaT_init(L);
- luaX_init(L);
- luaS_fix(luaS_newliteral(L, MEMERRMSG));
- g->GCthreshold = 4*g->totalbytes;
-}
-
-
-static void preinit_state (lua_State *L, global_State *g) {
- G(L) = g;
- L->stack = NULL;
- L->stacksize = 0;
- L->errorJmp = NULL;
- L->hook = NULL;
- L->hookmask = 0;
- L->basehookcount = 0;
- L->allowhook = 1;
- resethookcount(L);
- L->openupval = NULL;
- L->size_ci = 0;
- L->nCcalls = L->baseCcalls = 0;
- L->status = 0;
- L->base_ci = L->ci = NULL;
- L->savedpc = NULL;
- L->errfunc = 0;
- setnilvalue(gt(L));
-}
-
-
-static void close_state (lua_State *L) {
- global_State *g = G(L);
- luaF_close(L, L->stack); /* close all upvalues for this thread */
- luaC_freeall(L); /* collect all objects */
- lua_assert(g->rootgc == obj2gco(L));
- lua_assert(g->strt.nuse == 0);
- luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *);
- luaZ_freebuffer(L, &g->buff);
- freestack(L, L);
- lua_assert(g->totalbytes == sizeof(LG));
- (*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0);
-}
-
-
-lua_State *luaE_newthread (lua_State *L) {
- lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State)));
- luaC_link(L, obj2gco(L1), LUA_TTHREAD);
- preinit_state(L1, G(L));
- stack_init(L1, L); /* init stack */
- setobj2n(L, gt(L1), gt(L)); /* share table of globals */
- L1->hookmask = L->hookmask;
- L1->basehookcount = L->basehookcount;
- L1->hook = L->hook;
- resethookcount(L1);
- lua_assert(iswhite(obj2gco(L1)));
- return L1;
-}
-
-
-void luaE_freethread (lua_State *L, lua_State *L1) {
- luaF_close(L1, L1->stack); /* close all upvalues for this thread */
- lua_assert(L1->openupval == NULL);
- luai_userstatefree(L1);
- freestack(L, L1);
- luaM_freemem(L, fromstate(L1), state_size(lua_State));
-}
-
-
-LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
- int i;
- lua_State *L;
- global_State *g;
- void *l = (*f)(ud, NULL, 0, state_size(LG));
- if (l == NULL) return NULL;
- L = tostate(l);
- g = &((LG *)L)->g;
- L->next = NULL;
- L->tt = LUA_TTHREAD;
- g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT);
- L->marked = luaC_white(g);
- set2bits(L->marked, FIXEDBIT, SFIXEDBIT);
- preinit_state(L, g);
- g->frealloc = f;
- g->ud = ud;
- g->mainthread = L;
- g->uvhead.u.l.prev = &g->uvhead;
- g->uvhead.u.l.next = &g->uvhead;
- g->GCthreshold = 0; /* mark it as unfinished state */
- g->strt.size = 0;
- g->strt.nuse = 0;
- g->strt.hash = NULL;
- setnilvalue(registry(L));
- luaZ_initbuffer(L, &g->buff);
- g->panic = NULL;
- g->gcstate = GCSpause;
- g->rootgc = obj2gco(L);
- g->sweepstrgc = 0;
- g->sweepgc = &g->rootgc;
- g->gray = NULL;
- g->grayagain = NULL;
- g->weak = NULL;
- g->tmudata = NULL;
- g->totalbytes = sizeof(LG);
- g->gcpause = LUAI_GCPAUSE;
- g->gcstepmul = LUAI_GCMUL;
- g->gcdept = 0;
- for (i=0; i<NUM_TAGS; i++) g->mt[i] = NULL;
- if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) {
- /* memory allocation error: free partial state */
- close_state(L);
- L = NULL;
- }
- else
- luai_userstateopen(L);
- return L;
-}
-
-
-static void callallgcTM (lua_State *L, void *ud) {
- UNUSED(ud);
- luaC_callGCTM(L); /* call GC metamethods for all udata */
-}
-
-
-LUA_API void lua_close (lua_State *L) {
- L = G(L)->mainthread; /* only the main thread can be closed */
- lua_lock(L);
- luaF_close(L, L->stack); /* close all upvalues for this thread */
- luaC_separateudata(L, 1); /* separate udata that have GC metamethods */
- L->errfunc = 0; /* no error function during GC metamethods */
- do { /* repeat until no more errors */
- L->ci = L->base_ci;
- L->base = L->top = L->ci->base;
- L->nCcalls = L->baseCcalls = 0;
- } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0);
- lua_assert(G(L)->tmudata == NULL);
- luai_userstateclose(L);
- close_state(L);
-}
-
diff --git a/src/lua/src/lstate.h b/src/lua/src/lstate.h
deleted file mode 100644
index 3bc575b6b..000000000
--- a/src/lua/src/lstate.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
-** $Id: lstate.h,v 2.24.1.2 2008/01/03 15:20:39 roberto Exp $
-** Global State
-** See Copyright Notice in lua.h
-*/
-
-#ifndef lstate_h
-#define lstate_h
-
-#include "lua.h"
-
-#include "lobject.h"
-#include "ltm.h"
-#include "lzio.h"
-
-
-
-struct lua_longjmp; /* defined in ldo.c */
-
-
-/* table of globals */
-#define gt(L) (&L->l_gt)
-
-/* registry */
-#define registry(L) (&G(L)->l_registry)
-
-
-/* extra stack space to handle TM calls and some other extras */
-#define EXTRA_STACK 5
-
-
-#define BASIC_CI_SIZE 8
-
-#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
-
-
-
-typedef struct stringtable {
- GCObject **hash;
- lu_int32 nuse; /* number of elements */
- int size;
-} stringtable;
-
-
-/*
-** informations about a call
-*/
-typedef struct CallInfo {
- StkId base; /* base for this function */
- StkId func; /* function index in the stack */
- StkId top; /* top for this function */
- const Instruction *savedpc;
- int nresults; /* expected number of results from this function */
- int tailcalls; /* number of tail calls lost under this entry */
-} CallInfo;
-
-
-
-#define curr_func(L) (clvalue(L->ci->func))
-#define ci_func(ci) (clvalue((ci)->func))
-#define f_isLua(ci) (!ci_func(ci)->c.isC)
-#define isLua(ci) (ttisfunction((ci)->func) && f_isLua(ci))
-
-
-/*
-** `global state', shared by all threads of this state
-*/
-typedef struct global_State {
- stringtable strt; /* hash table for strings */
- lua_Alloc frealloc; /* function to reallocate memory */
- void *ud; /* auxiliary data to `frealloc' */
- lu_byte currentwhite;
- lu_byte gcstate; /* state of garbage collector */
- int sweepstrgc; /* position of sweep in `strt' */
- GCObject *rootgc; /* list of all collectable objects */
- GCObject **sweepgc; /* position of sweep in `rootgc' */
- GCObject *gray; /* list of gray objects */
- GCObject *grayagain; /* list of objects to be traversed atomically */
- GCObject *weak; /* list of weak tables (to be cleared) */
- GCObject *tmudata; /* last element of list of userdata to be GC */
- Mbuffer buff; /* temporary buffer for string concatentation */
- lu_mem GCthreshold;
- lu_mem totalbytes; /* number of bytes currently allocated */
- lu_mem estimate; /* an estimate of number of bytes actually in use */
- lu_mem gcdept; /* how much GC is `behind schedule' */
- int gcpause; /* size of pause between successive GCs */
- int gcstepmul; /* GC `granularity' */
- lua_CFunction panic; /* to be called in unprotected errors */
- TValue l_registry;
- struct lua_State *mainthread;
- UpVal uvhead; /* head of double-linked list of all open upvalues */
- struct Table *mt[NUM_TAGS]; /* metatables for basic types */
- TString *tmname[TM_N]; /* array with tag-method names */
-} global_State;
-
-
-/*
-** `per thread' state
-*/
-struct lua_State {
- CommonHeader;
- lu_byte status;
- StkId top; /* first free slot in the stack */
- StkId base; /* base of current function */
- global_State *l_G;
- CallInfo *ci; /* call info for current function */
- const Instruction *savedpc; /* `savedpc' of current function */
- StkId stack_last; /* last free slot in the stack */
- StkId stack; /* stack base */
- CallInfo *end_ci; /* points after end of ci array*/
- CallInfo *base_ci; /* array of CallInfo's */
- int stacksize;
- int size_ci; /* size of array `base_ci' */
- unsigned short nCcalls; /* number of nested C calls */
- unsigned short baseCcalls; /* nested C calls when resuming coroutine */
- lu_byte hookmask;
- lu_byte allowhook;
- int basehookcount;
- int hookcount;
- lua_Hook hook;
- TValue l_gt; /* table of globals */
- TValue env; /* temporary place for environments */
- GCObject *openupval; /* list of open upvalues in this stack */
- GCObject *gclist;
- struct lua_longjmp *errorJmp; /* current error recover point */
- ptrdiff_t errfunc; /* current error handling function (stack index) */
-};
-
-
-#define G(L) (L->l_G)
-
-
-/*
-** Union of all collectable objects
-*/
-union GCObject {
- GCheader gch;
- union TString ts;
- union Udata u;
- union Closure cl;
- struct Table h;
- struct Proto p;
- struct UpVal uv;
- struct lua_State th; /* thread */
-};
-
-
-/* macros to convert a GCObject into a specific value */
-#define rawgco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts))
-#define gco2ts(o) (&rawgco2ts(o)->tsv)
-#define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u))
-#define gco2u(o) (&rawgco2u(o)->uv)
-#define gco2cl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl))
-#define gco2h(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h))
-#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p))
-#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv))
-#define ngcotouv(o) \
- check_exp((o) == NULL || (o)->gch.tt == LUA_TUPVAL, &((o)->uv))
-#define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th))
-
-/* macro to convert any Lua object into a GCObject */
-#define obj2gco(v) (cast(GCObject *, (v)))
-
-
-LUAI_FUNC lua_State *luaE_newthread (lua_State *L);
-LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
-
-#endif
-
diff --git a/src/lua/src/lstring.c b/src/lua/src/lstring.c
deleted file mode 100644
index 49113151c..000000000
--- a/src/lua/src/lstring.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
-** $Id: lstring.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
-** String table (keeps all strings handled by Lua)
-** See Copyright Notice in lua.h
-*/
-
-
-#include <string.h>
-
-#define lstring_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "lmem.h"
-#include "lobject.h"
-#include "lstate.h"
-#include "lstring.h"
-
-
-
-void luaS_resize (lua_State *L, int newsize) {
- GCObject **newhash;
- stringtable *tb;
- int i;
- if (G(L)->gcstate == GCSsweepstring)
- return; /* cannot resize during GC traverse */
- newhash = luaM_newvector(L, newsize, GCObject *);
- tb = &G(L)->strt;
- for (i=0; i<newsize; i++) newhash[i] = NULL;
- /* rehash */
- for (i=0; i<tb->size; i++) {
- GCObject *p = tb->hash[i];
- while (p) { /* for each node in the list */
- GCObject *next = p->gch.next; /* save next */
- unsigned int h = gco2ts(p)->hash;
- int h1 = lmod(h, newsize); /* new position */
- lua_assert(cast_int(h%newsize) == lmod(h, newsize));
- p->gch.next = newhash[h1]; /* chain it */
- newhash[h1] = p;
- p = next;
- }
- }
- luaM_freearray(L, tb->hash, tb->size, TString *);
- tb->size = newsize;
- tb->hash = newhash;
-}
-
-
-static TString *newlstr (lua_State *L, const char *str, size_t l,
- unsigned int h) {
- TString *ts;
- stringtable *tb;
- if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char))
- luaM_toobig(L);
- ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString)));
- ts->tsv.len = l;
- ts->tsv.hash = h;
- ts->tsv.marked = luaC_white(G(L));
- ts->tsv.tt = LUA_TSTRING;
- ts->tsv.reserved = 0;
- memcpy(ts+1, str, l*sizeof(char));
- ((char *)(ts+1))[l] = '\0'; /* ending 0 */
- tb = &G(L)->strt;
- h = lmod(h, tb->size);
- ts->tsv.next = tb->hash[h]; /* chain new entry */
- tb->hash[h] = obj2gco(ts);
- tb->nuse++;
- if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
- luaS_resize(L, tb->size*2); /* too crowded */
- return ts;
-}
-
-
-TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
- GCObject *o;
- unsigned int h = cast(unsigned int, l); /* seed */
- size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */
- size_t l1;
- for (l1=l; l1>=step; l1-=step) /* compute hash */
- h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1]));
- for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)];
- o != NULL;
- o = o->gch.next) {
- TString *ts = rawgco2ts(o);
- if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) {
- /* string may be dead */
- if (isdead(G(L), o)) changewhite(o);
- return ts;
- }
- }
- return newlstr(L, str, l, h); /* not found */
-}
-
-
-Udata *luaS_newudata (lua_State *L, size_t s, Table *e) {
- Udata *u;
- if (s > MAX_SIZET - sizeof(Udata))
- luaM_toobig(L);
- u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata)));
- u->uv.marked = luaC_white(G(L)); /* is not finalized */
- u->uv.tt = LUA_TUSERDATA;
- u->uv.len = s;
- u->uv.metatable = NULL;
- u->uv.env = e;
- /* chain it on udata list (after main thread) */
- u->uv.next = G(L)->mainthread->next;
- G(L)->mainthread->next = obj2gco(u);
- return u;
-}
-
diff --git a/src/lua/src/lstring.h b/src/lua/src/lstring.h
deleted file mode 100644
index 73a2ff8b3..000000000
--- a/src/lua/src/lstring.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
-** $Id: lstring.h,v 1.43.1.1 2007/12/27 13:02:25 roberto Exp $
-** String table (keep all strings handled by Lua)
-** See Copyright Notice in lua.h
-*/
-
-#ifndef lstring_h
-#define lstring_h
-
-
-#include "lgc.h"
-#include "lobject.h"
-#include "lstate.h"
-
-
-#define sizestring(s) (sizeof(union TString)+((s)->len+1)*sizeof(char))
-
-#define sizeudata(u) (sizeof(union Udata)+(u)->len)
-
-#define luaS_new(L, s) (luaS_newlstr(L, s, strlen(s)))
-#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \
- (sizeof(s)/sizeof(char))-1))
-
-#define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT)
-
-LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
-LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e);
-LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
-
-
-#endif
diff --git a/src/lua/src/lstrlib.c b/src/lua/src/lstrlib.c
deleted file mode 100644
index 1b4763d4e..000000000
--- a/src/lua/src/lstrlib.c
+++ /dev/null
@@ -1,869 +0,0 @@
-/*
-** $Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp $
-** Standard library for string operations and pattern-matching
-** See Copyright Notice in lua.h
-*/
-
-
-#include <ctype.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define lstrlib_c
-#define LUA_LIB
-
-#include "lua.h"
-
-#include "lauxlib.h"
-#include "lualib.h"
-
-
-/* macro to `unsign' a character */
-#define uchar(c) ((unsigned char)(c))
-
-
-
-static int str_len (lua_State *L) {
- size_t l;
- luaL_checklstring(L, 1, &l);
- lua_pushinteger(L, l);
- return 1;
-}
-
-
-static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) {
- /* relative string position: negative means back from end */
- if (pos < 0) pos += (ptrdiff_t)len + 1;
- return (pos >= 0) ? pos : 0;
-}
-
-
-static int str_sub (lua_State *L) {
- size_t l;
- const char *s = luaL_checklstring(L, 1, &l);
- ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l);
- ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l);
- if (start < 1) start = 1;
- if (end > (ptrdiff_t)l) end = (ptrdiff_t)l;
- if (start <= end)
- lua_pushlstring(L, s+start-1, end-start+1);
- else lua_pushliteral(L, "");
- return 1;
-}
-
-
-static int str_reverse (lua_State *L) {
- size_t l;
- luaL_Buffer b;
- const char *s = luaL_checklstring(L, 1, &l);
- luaL_buffinit(L, &b);
- while (l--) luaL_addchar(&b, s[l]);
- luaL_pushresult(&b);
- return 1;
-}
-
-
-static int str_lower (lua_State *L) {
- size_t l;
- size_t i;
- luaL_Buffer b;
- const char *s = luaL_checklstring(L, 1, &l);
- luaL_buffinit(L, &b);
- for (i=0; i<l; i++)
- luaL_addchar(&b, tolower(uchar(s[i])));
- luaL_pushresult(&b);
- return 1;
-}
-
-
-static int str_upper (lua_State *L) {
- size_t l;
- size_t i;
- luaL_Buffer b;
- const char *s = luaL_checklstring(L, 1, &l);
- luaL_buffinit(L, &b);
- for (i=0; i<l; i++)
- luaL_addchar(&b, toupper(uchar(s[i])));
- luaL_pushresult(&b);
- return 1;
-}
-
-static int str_rep (lua_State *L) {
- size_t l;
- luaL_Buffer b;
- const char *s = luaL_checklstring(L, 1, &l);
- int n = luaL_checkint(L, 2);
- luaL_buffinit(L, &b);
- while (n-- > 0)
- luaL_addlstring(&b, s, l);
- luaL_pushresult(&b);
- return 1;
-}
-
-
-static int str_byte (lua_State *L) {
- size_t l;
- const char *s = luaL_checklstring(L, 1, &l);
- ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l);
- ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l);
- int n, i;
- if (posi <= 0) posi = 1;
- if ((size_t)pose > l) pose = l;
- if (posi > pose) return 0; /* empty interval; return no values */
- n = (int)(pose - posi + 1);
- if (posi + n <= pose) /* overflow? */
- luaL_error(L, "string slice too long");
- luaL_checkstack(L, n, "string slice too long");
- for (i=0; i<n; i++)
- lua_pushinteger(L, uchar(s[posi+i-1]));
- return n;
-}
-
-
-static int str_char (lua_State *L) {
- int n = lua_gettop(L); /* number of arguments */
- int i;
- luaL_Buffer b;
- luaL_buffinit(L, &b);
- for (i=1; i<=n; i++) {
- int c = luaL_checkint(L, i);
- luaL_argcheck(L, uchar(c) == c, i, "invalid value");
- luaL_addchar(&b, uchar(c));
- }
- luaL_pushresult(&b);
- return 1;
-}
-
-
-static int writer (lua_State *L, const void* b, size_t size, void* B) {
- (void)L;
- luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);
- return 0;
-}
-
-
-static int str_dump (lua_State *L) {
- luaL_Buffer b;
- luaL_checktype(L, 1, LUA_TFUNCTION);
- lua_settop(L, 1);
- luaL_buffinit(L,&b);
- if (lua_dump(L, writer, &b) != 0)
- luaL_error(L, "unable to dump given function");
- luaL_pushresult(&b);
- return 1;
-}
-
-
-
-/*
-** {======================================================
-** PATTERN MATCHING
-** =======================================================
-*/
-
-
-#define CAP_UNFINISHED (-1)
-#define CAP_POSITION (-2)
-
-typedef struct MatchState {
- const char *src_init; /* init of source string */
- const char *src_end; /* end (`\0') of source string */
- lua_State *L;
- int level; /* total number of captures (finished or unfinished) */
- struct {
- const char *init;
- ptrdiff_t len;
- } capture[LUA_MAXCAPTURES];
-} MatchState;
-
-
-#define L_ESC '%'
-#define SPECIALS "^$*+?.([%-"
-
-
-static int check_capture (MatchState *ms, int l) {
- l -= '1';
- if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
- return luaL_error(ms->L, "invalid capture index");
- return l;
-}
-
-
-static int capture_to_close (MatchState *ms) {
- int level = ms->level;
- for (level--; level>=0; level--)
- if (ms->capture[level].len == CAP_UNFINISHED) return level;
- return luaL_error(ms->L, "invalid pattern capture");
-}
-
-
-static const char *classend (MatchState *ms, const char *p) {
- switch (*p++) {
- case L_ESC: {
- if (*p == '\0')
- luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")");
- return p+1;
- }
- case '[': {
- if (*p == '^') p++;
- do { /* look for a `]' */
- if (*p == '\0')
- luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")");
- if (*(p++) == L_ESC && *p != '\0')
- p++; /* skip escapes (e.g. `%]') */
- } while (*p != ']');
- return p+1;
- }
- default: {
- return p;
- }
- }
-}
-
-
-static int match_class (int c, int cl) {
- int res;
- switch (tolower(cl)) {
- case 'a' : res = isalpha(c); break;
- case 'c' : res = iscntrl(c); break;
- case 'd' : res = isdigit(c); break;
- case 'l' : res = islower(c); break;
- case 'p' : res = ispunct(c); break;
- case 's' : res = isspace(c); break;
- case 'u' : res = isupper(c); break;
- case 'w' : res = isalnum(c); break;
- case 'x' : res = isxdigit(c); break;
- case 'z' : res = (c == 0); break;
- default: return (cl == c);
- }
- return (islower(cl) ? res : !res);
-}
-
-
-static int matchbracketclass (int c, const char *p, const char *ec) {
- int sig = 1;
- if (*(p+1) == '^') {
- sig = 0;
- p++; /* skip the `^' */
- }
- while (++p < ec) {
- if (*p == L_ESC) {
- p++;
- if (match_class(c, uchar(*p)))
- return sig;
- }
- else if ((*(p+1) == '-') && (p+2 < ec)) {
- p+=2;
- if (uchar(*(p-2)) <= c && c <= uchar(*p))
- return sig;
- }
- else if (uchar(*p) == c) return sig;
- }
- return !sig;
-}
-
-
-static int singlematch (int c, const char *p, const char *ep) {
- switch (*p) {
- case '.': return 1; /* matches any char */
- case L_ESC: return match_class(c, uchar(*(p+1)));
- case '[': return matchbracketclass(c, p, ep-1);
- default: return (uchar(*p) == c);
- }
-}
-
-
-static const char *match (MatchState *ms, const char *s, const char *p);
-
-
-static const char *matchbalance (MatchState *ms, const char *s,
- const char *p) {
- if (*p == 0 || *(p+1) == 0)
- luaL_error(ms->L, "unbalanced pattern");
- if (*s != *p) return NULL;
- else {
- int b = *p;
- int e = *(p+1);
- int cont = 1;
- while (++s < ms->src_end) {
- if (*s == e) {
- if (--cont == 0) return s+1;
- }
- else if (*s == b) cont++;
- }
- }
- return NULL; /* string ends out of balance */
-}
-
-
-static const char *max_expand (MatchState *ms, const char *s,
- const char *p, const char *ep) {
- ptrdiff_t i = 0; /* counts maximum expand for item */
- while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep))
- i++;
- /* keeps trying to match with the maximum repetitions */
- while (i>=0) {
- const char *res = match(ms, (s+i), ep+1);
- if (res) return res;
- i--; /* else didn't match; reduce 1 repetition to try again */
- }
- return NULL;
-}
-
-
-static const char *min_expand (MatchState *ms, const char *s,
- const char *p, const char *ep) {
- for (;;) {
- const char *res = match(ms, s, ep+1);
- if (res != NULL)
- return res;
- else if (s<ms->src_end && singlematch(uchar(*s), p, ep))
- s++; /* try with one more repetition */
- else return NULL;
- }
-}
-
-
-static const char *start_capture (MatchState *ms, const char *s,
- const char *p, int what) {
- const char *res;
- int level = ms->level;
- if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures");
- ms->capture[level].init = s;
- ms->capture[level].len = what;
- ms->level = level+1;
- if ((res=match(ms, s, p)) == NULL) /* match failed? */
- ms->level--; /* undo capture */
- return res;
-}
-
-
-static const char *end_capture (MatchState *ms, const char *s,
- const char *p) {
- int l = capture_to_close(ms);
- const char *res;
- ms->capture[l].len = s - ms->capture[l].init; /* close capture */
- if ((res = match(ms, s, p)) == NULL) /* match failed? */
- ms->capture[l].len = CAP_UNFINISHED; /* undo capture */
- return res;
-}
-
-
-static const char *match_capture (MatchState *ms, const char *s, int l) {
- size_t len;
- l = check_capture(ms, l);
- len = ms->capture[l].len;
- if ((size_t)(ms->src_end-s) >= len &&
- memcmp(ms->capture[l].init, s, len) == 0)
- return s+len;
- else return NULL;
-}
-
-
-static const char *match (MatchState *ms, const char *s, const char *p) {
- init: /* using goto's to optimize tail recursion */
- switch (*p) {
- case '(': { /* start capture */
- if (*(p+1) == ')') /* position capture? */
- return start_capture(ms, s, p+2, CAP_POSITION);
- else
- return start_capture(ms, s, p+1, CAP_UNFINISHED);
- }
- case ')': { /* end capture */
- return end_capture(ms, s, p+1);
- }
- case L_ESC: {
- switch (*(p+1)) {
- case 'b': { /* balanced string? */
- s = matchbalance(ms, s, p+2);
- if (s == NULL) return NULL;
- p+=4; goto init; /* else return match(ms, s, p+4); */
- }
- case 'f': { /* frontier? */
- const char *ep; char previous;
- p += 2;
- if (*p != '[')
- luaL_error(ms->L, "missing " LUA_QL("[") " after "
- LUA_QL("%%f") " in pattern");
- ep = classend(ms, p); /* points to what is next */
- previous = (s == ms->src_init) ? '\0' : *(s-1);
- if (matchbracketclass(uchar(previous), p, ep-1) ||
- !matchbracketclass(uchar(*s), p, ep-1)) return NULL;
- p=ep; goto init; /* else return match(ms, s, ep); */
- }
- default: {
- if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */
- s = match_capture(ms, s, uchar(*(p+1)));
- if (s == NULL) return NULL;
- p+=2; goto init; /* else return match(ms, s, p+2) */
- }
- goto dflt; /* case default */
- }
- }
- }
- case '\0': { /* end of pattern */
- return s; /* match succeeded */
- }
- case '$': {
- if (*(p+1) == '\0') /* is the `$' the last char in pattern? */
- return (s == ms->src_end) ? s : NULL; /* check end of string */
- else goto dflt;
- }
- default: dflt: { /* it is a pattern item */
- const char *ep = classend(ms, p); /* points to what is next */
- int m = s<ms->src_end && singlematch(uchar(*s), p, ep);
- switch (*ep) {
- case '?': { /* optional */
- const char *res;
- if (m && ((res=match(ms, s+1, ep+1)) != NULL))
- return res;
- p=ep+1; goto init; /* else return match(ms, s, ep+1); */
- }
- case '*': { /* 0 or more repetitions */
- return max_expand(ms, s, p, ep);
- }
- case '+': { /* 1 or more repetitions */
- return (m ? max_expand(ms, s+1, p, ep) : NULL);
- }
- case '-': { /* 0 or more repetitions (minimum) */
- return min_expand(ms, s, p, ep);
- }
- default: {
- if (!m) return NULL;
- s++; p=ep; goto init; /* else return match(ms, s+1, ep); */
- }
- }
- }
- }
-}
-
-
-
-static const char *lmemfind (const char *s1, size_t l1,
- const char *s2, size_t l2) {
- if (l2 == 0) return s1; /* empty strings are everywhere */
- else if (l2 > l1) return NULL; /* avoids a negative `l1' */
- else {
- const char *init; /* to search for a `*s2' inside `s1' */
- l2--; /* 1st char will be checked by `memchr' */
- l1 = l1-l2; /* `s2' cannot be found after that */
- while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
- init++; /* 1st char is already checked */
- if (memcmp(init, s2+1, l2) == 0)
- return init-1;
- else { /* correct `l1' and `s1' to try again */
- l1 -= init-s1;
- s1 = init;
- }
- }
- return NULL; /* not found */
- }
-}
-
-
-static void push_onecapture (MatchState *ms, int i, const char *s,
- const char *e) {
- if (i >= ms->level) {
- if (i == 0) /* ms->level == 0, too */
- lua_pushlstring(ms->L, s, e - s); /* add whole match */
- else
- luaL_error(ms->L, "invalid capture index");
- }
- else {
- ptrdiff_t l = ms->capture[i].len;
- if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
- if (l == CAP_POSITION)
- lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
- else
- lua_pushlstring(ms->L, ms->capture[i].init, l);
- }
-}
-
-
-static int push_captures (MatchState *ms, const char *s, const char *e) {
- int i;
- int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
- luaL_checkstack(ms->L, nlevels, "too many captures");
- for (i = 0; i < nlevels; i++)
- push_onecapture(ms, i, s, e);
- return nlevels; /* number of strings pushed */
-}
-
-
-static int str_find_aux (lua_State *L, int find) {
- size_t l1, l2;
- const char *s = luaL_checklstring(L, 1, &l1);
- const char *p = luaL_checklstring(L, 2, &l2);
- ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1;
- if (init < 0) init = 0;
- else if ((size_t)(init) > l1) init = (ptrdiff_t)l1;
- if (find && (lua_toboolean(L, 4) || /* explicit request? */
- strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */
- /* do a plain search */
- const char *s2 = lmemfind(s+init, l1-init, p, l2);
- if (s2) {
- lua_pushinteger(L, s2-s+1);
- lua_pushinteger(L, s2-s+l2);
- return 2;
- }
- }
- else {
- MatchState ms;
- int anchor = (*p == '^') ? (p++, 1) : 0;
- const char *s1=s+init;
- ms.L = L;
- ms.src_init = s;
- ms.src_end = s+l1;
- do {
- const char *res;
- ms.level = 0;
- if ((res=match(&ms, s1, p)) != NULL) {
- if (find) {
- lua_pushinteger(L, s1-s+1); /* start */
- lua_pushinteger(L, res-s); /* end */
- return push_captures(&ms, NULL, 0) + 2;
- }
- else
- return push_captures(&ms, s1, res);
- }
- } while (s1++ < ms.src_end && !anchor);
- }
- lua_pushnil(L); /* not found */
- return 1;
-}
-
-
-static int str_find (lua_State *L) {
- return str_find_aux(L, 1);
-}
-
-
-static int str_match (lua_State *L) {
- return str_find_aux(L, 0);
-}
-
-
-static int gmatch_aux (lua_State *L) {
- MatchState ms;
- size_t ls;
- const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
- const char *p = lua_tostring(L, lua_upvalueindex(2));
- const char *src;
- ms.L = L;
- ms.src_init = s;
- ms.src_end = s+ls;
- for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3));
- src <= ms.src_end;
- src++) {
- const char *e;
- ms.level = 0;
- if ((e = match(&ms, src, p)) != NULL) {
- lua_Integer newstart = e-s;
- if (e == src) newstart++; /* empty match? go at least one position */
- lua_pushinteger(L, newstart);
- lua_replace(L, lua_upvalueindex(3));
- return push_captures(&ms, src, e);
- }
- }
- return 0; /* not found */
-}
-
-
-static int gmatch (lua_State *L) {
- luaL_checkstring(L, 1);
- luaL_checkstring(L, 2);
- lua_settop(L, 2);
- lua_pushinteger(L, 0);
- lua_pushcclosure(L, gmatch_aux, 3);
- return 1;
-}
-
-
-static int gfind_nodef (lua_State *L) {
- return luaL_error(L, LUA_QL("string.gfind") " was renamed to "
- LUA_QL("string.gmatch"));
-}
-
-
-static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
- const char *e) {
- size_t l, i;
- const char *news = lua_tolstring(ms->L, 3, &l);
- for (i = 0; i < l; i++) {
- if (news[i] != L_ESC)
- luaL_addchar(b, news[i]);
- else {
- i++; /* skip ESC */
- if (!isdigit(uchar(news[i])))
- luaL_addchar(b, news[i]);
- else if (news[i] == '0')
- luaL_addlstring(b, s, e - s);
- else {
- push_onecapture(ms, news[i] - '1', s, e);
- luaL_addvalue(b); /* add capture to accumulated result */
- }
- }
- }
-}
-
-
-static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
- const char *e) {
- lua_State *L = ms->L;
- switch (lua_type(L, 3)) {
- case LUA_TNUMBER:
- case LUA_TSTRING: {
- add_s(ms, b, s, e);
- return;
- }
- case LUA_TFUNCTION: {
- int n;
- lua_pushvalue(L, 3);
- n = push_captures(ms, s, e);
- lua_call(L, n, 1);
- break;
- }
- case LUA_TTABLE: {
- push_onecapture(ms, 0, s, e);
- lua_gettable(L, 3);
- break;
- }
- }
- if (!lua_toboolean(L, -1)) { /* nil or false? */
- lua_pop(L, 1);
- lua_pushlstring(L, s, e - s); /* keep original text */
- }
- else if (!lua_isstring(L, -1))
- luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1));
- luaL_addvalue(b); /* add result to accumulator */
-}
-
-
-static int str_gsub (lua_State *L) {
- size_t srcl;
- const char *src = luaL_checklstring(L, 1, &srcl);
- const char *p = luaL_checkstring(L, 2);
- int tr = lua_type(L, 3);
- int max_s = luaL_optint(L, 4, srcl+1);
- int anchor = (*p == '^') ? (p++, 1) : 0;
- int n = 0;
- MatchState ms;
- luaL_Buffer b;
- luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
- tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
- "string/function/table expected");
- luaL_buffinit(L, &b);
- ms.L = L;
- ms.src_init = src;
- ms.src_end = src+srcl;
- while (n < max_s) {
- const char *e;
- ms.level = 0;
- e = match(&ms, src, p);
- if (e) {
- n++;
- add_value(&ms, &b, src, e);
- }
- if (e && e>src) /* non empty match? */
- src = e; /* skip it */
- else if (src < ms.src_end)
- luaL_addchar(&b, *src++);
- else break;
- if (anchor) break;
- }
- luaL_addlstring(&b, src, ms.src_end-src);
- luaL_pushresult(&b);
- lua_pushinteger(L, n); /* number of substitutions */
- return 2;
-}
-
-/* }====================================================== */
-
-
-/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
-#define MAX_ITEM 512
-/* valid flags in a format specification */
-#define FLAGS "-+ #0"
-/*
-** maximum size of each format specification (such as '%-099.99d')
-** (+10 accounts for %99.99x plus margin of error)
-*/
-#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10)
-
-
-static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
- size_t l;
- const char *s = luaL_checklstring(L, arg, &l);
- luaL_addchar(b, '"');
- while (l--) {
- switch (*s) {
- case '"': case '\\': case '\n': {
- luaL_addchar(b, '\\');
- luaL_addchar(b, *s);
- break;
- }
- case '\r': {
- luaL_addlstring(b, "\\r", 2);
- break;
- }
- case '\0': {
- luaL_addlstring(b, "\\000", 4);
- break;
- }
- default: {
- luaL_addchar(b, *s);
- break;
- }
- }
- s++;
- }
- luaL_addchar(b, '"');
-}
-
-static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
- const char *p = strfrmt;
- while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */
- if ((size_t)(p - strfrmt) >= sizeof(FLAGS))
- luaL_error(L, "invalid format (repeated flags)");
- if (isdigit(uchar(*p))) p++; /* skip width */
- if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
- if (*p == '.') {
- p++;
- if (isdigit(uchar(*p))) p++; /* skip precision */
- if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
- }
- if (isdigit(uchar(*p)))
- luaL_error(L, "invalid format (width or precision too long)");
- *(form++) = '%';
- strncpy(form, strfrmt, p - strfrmt + 1);
- form += p - strfrmt + 1;
- *form = '\0';
- return p;
-}
-
-
-static void addintlen (char *form) {
- size_t l = strlen(form);
- char spec = form[l - 1];
- strcpy(form + l - 1, LUA_INTFRMLEN);
- form[l + sizeof(LUA_INTFRMLEN) - 2] = spec;
- form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0';
-}
-
-
-static int str_format (lua_State *L) {
- int arg = 1;
- size_t sfl;
- const char *strfrmt = luaL_checklstring(L, arg, &sfl);
- const char *strfrmt_end = strfrmt+sfl;
- luaL_Buffer b;
- luaL_buffinit(L, &b);
- while (strfrmt < strfrmt_end) {
- if (*strfrmt != L_ESC)
- luaL_addchar(&b, *strfrmt++);
- else if (*++strfrmt == L_ESC)
- luaL_addchar(&b, *strfrmt++); /* %% */
- else { /* format item */
- char form[MAX_FORMAT]; /* to store the format (`%...') */
- char buff[MAX_ITEM]; /* to store the formatted item */
- arg++;
- strfrmt = scanformat(L, strfrmt, form);
- switch (*strfrmt++) {
- case 'c': {
- sprintf(buff, form, (int)luaL_checknumber(L, arg));
- break;
- }
- case 'd': case 'i': {
- addintlen(form);
- sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg));
- break;
- }
- case 'o': case 'u': case 'x': case 'X': {
- addintlen(form);
- sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg));
- break;
- }
- case 'e': case 'E': case 'f':
- case 'g': case 'G': {
- sprintf(buff, form, (double)luaL_checknumber(L, arg));
- break;
- }
- case 'q': {
- addquoted(L, &b, arg);
- continue; /* skip the 'addsize' at the end */
- }
- case 's': {
- size_t l;
- const char *s = luaL_checklstring(L, arg, &l);
- if (!strchr(form, '.') && l >= 100) {
- /* no precision and string is too long to be formatted;
- keep original string */
- lua_pushvalue(L, arg);
- luaL_addvalue(&b);
- continue; /* skip the `addsize' at the end */
- }
- else {
- sprintf(buff, form, s);
- break;
- }
- }
- default: { /* also treat cases `pnLlh' */
- return luaL_error(L, "invalid option " LUA_QL("%%%c") " to "
- LUA_QL("format"), *(strfrmt - 1));
- }
- }
- luaL_addlstring(&b, buff, strlen(buff));
- }
- }
- luaL_pushresult(&b);
- return 1;
-}
-
-
-static const luaL_Reg strlib[] = {
- {"byte", str_byte},
- {"char", str_char},
- {"dump", str_dump},
- {"find", str_find},
- {"format", str_format},
- {"gfind", gfind_nodef},
- {"gmatch", gmatch},
- {"gsub", str_gsub},
- {"len", str_len},
- {"lower", str_lower},
- {"match", str_match},
- {"rep", str_rep},
- {"reverse", str_reverse},
- {"sub", str_sub},
- {"upper", str_upper},
- {NULL, NULL}
-};
-
-
-static void createmetatable (lua_State *L) {
- lua_createtable(L, 0, 1); /* create metatable for strings */
- lua_pushliteral(L, ""); /* dummy string */
- lua_pushvalue(L, -2);
- lua_setmetatable(L, -2); /* set string metatable */
- lua_pop(L, 1); /* pop dummy string */
- lua_pushvalue(L, -2); /* string library... */
- lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */
- lua_pop(L, 1); /* pop metatable */
-}
-
-
-/*
-** Open string library
-*/
-LUALIB_API int luaopen_string (lua_State *L) {
- luaL_register(L, LUA_STRLIBNAME, strlib);
-#if defined(LUA_COMPAT_GFIND)
- lua_getfield(L, -1, "gmatch");
- lua_setfield(L, -2, "gfind");
-#endif
- createmetatable(L);
- return 1;
-}
-
diff --git a/src/lua/src/ltable.c b/src/lua/src/ltable.c
deleted file mode 100644
index ec84f4fab..000000000
--- a/src/lua/src/ltable.c
+++ /dev/null
@@ -1,588 +0,0 @@
-/*
-** $Id: ltable.c,v 2.32.1.2 2007/12/28 15:32:23 roberto Exp $
-** Lua tables (hash)
-** See Copyright Notice in lua.h
-*/
-
-
-/*
-** Implementation of tables (aka arrays, objects, or hash tables).
-** Tables keep its elements in two parts: an array part and a hash part.
-** Non-negative integer keys are all candidates to be kept in the array
-** part. The actual size of the array is the largest `n' such that at
-** least half the slots between 0 and n are in use.
-** Hash uses a mix of chained scatter table with Brent's variation.
-** A main invariant of these tables is that, if an element is not
-** in its main position (i.e. the `original' position that its hash gives
-** to it), then the colliding element is in its own main position.
-** Hence even when the load factor reaches 100%, performance remains good.
-*/
-
-#include <math.h>
-#include <string.h>
-
-#define ltable_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "ldebug.h"
-#include "ldo.h"
-#include "lgc.h"
-#include "lmem.h"
-#include "lobject.h"
-#include "lstate.h"
-#include "ltable.h"
-
-
-/*
-** max size of array part is 2^MAXBITS
-*/
-#if LUAI_BITSINT > 26
-#define MAXBITS 26
-#else
-#define MAXBITS (LUAI_BITSINT-2)
-#endif
-
-#define MAXASIZE (1 << MAXBITS)
-
-
-#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
-
-#define hashstr(t,str) hashpow2(t, (str)->tsv.hash)
-#define hashboolean(t,p) hashpow2(t, p)
-
-
-/*
-** for some types, it is better to avoid modulus by power of 2, as
-** they tend to have many 2 factors.
-*/
-#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
-
-
-#define hashpointer(t,p) hashmod(t, IntPoint(p))
-
-
-/*
-** number of ints inside a lua_Number
-*/
-#define numints cast_int(sizeof(lua_Number)/sizeof(int))
-
-
-
-#define dummynode (&dummynode_)
-
-static const Node dummynode_ = {
- {{NULL}, LUA_TNIL}, /* value */
- {{{NULL}, LUA_TNIL, NULL}} /* key */
-};
-
-
-/*
-** hash for lua_Numbers
-*/
-static Node *hashnum (const Table *t, lua_Number n) {
- unsigned int a[numints];
- int i;
- if (luai_numeq(n, 0)) /* avoid problems with -0 */
- return gnode(t, 0);
- memcpy(a, &n, sizeof(a));
- for (i = 1; i < numints; i++) a[0] += a[i];
- return hashmod(t, a[0]);
-}
-
-
-
-/*
-** returns the `main' position of an element in a table (that is, the index
-** of its hash value)
-*/
-static Node *mainposition (const Table *t, const TValue *key) {
- switch (ttype(key)) {
- case LUA_TNUMBER:
- return hashnum(t, nvalue(key));
- case LUA_TSTRING:
- return hashstr(t, rawtsvalue(key));
- case LUA_TBOOLEAN:
- return hashboolean(t, bvalue(key));
- case LUA_TLIGHTUSERDATA:
- return hashpointer(t, pvalue(key));
- default:
- return hashpointer(t, gcvalue(key));
- }
-}
-
-
-/*
-** returns the index for `key' if `key' is an appropriate key to live in
-** the array part of the table, -1 otherwise.
-*/
-static int arrayindex (const TValue *key) {
- if (ttisnumber(key)) {
- lua_Number n = nvalue(key);
- int k;
- lua_number2int(k, n);
- if (luai_numeq(cast_num(k), n))
- return k;
- }
- return -1; /* `key' did not match some condition */
-}
-
-
-/*
-** returns the index of a `key' for table traversals. First goes all
-** elements in the array part, then elements in the hash part. The
-** beginning of a traversal is signalled by -1.
-*/
-static int findindex (lua_State *L, Table *t, StkId key) {
- int i;
- if (ttisnil(key)) return -1; /* first iteration */
- i = arrayindex(key);
- if (0 < i && i <= t->sizearray) /* is `key' inside array part? */
- return i-1; /* yes; that's the index (corrected to C) */
- else {
- Node *n = mainposition(t, key);
- do { /* check whether `key' is somewhere in the chain */
- /* key may be dead already, but it is ok to use it in `next' */
- if (luaO_rawequalObj(key2tval(n), key) ||
- (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) &&
- gcvalue(gkey(n)) == gcvalue(key))) {
- i = cast_int(n - gnode(t, 0)); /* key index in hash table */
- /* hash elements are numbered after array ones */
- return i + t->sizearray;
- }
- else n = gnext(n);
- } while (n);
- luaG_runerror(L, "invalid key to " LUA_QL("next")); /* key not found */
- return 0; /* to avoid warnings */
- }
-}
-
-
-int luaH_next (lua_State *L, Table *t, StkId key) {
- int i = findindex(L, t, key); /* find original element */
- for (i++; i < t->sizearray; i++) { /* try first array part */
- if (!ttisnil(&t->array[i])) { /* a non-nil value? */
- setnvalue(key, cast_num(i+1));
- setobj2s(L, key+1, &t->array[i]);
- return 1;
- }
- }
- for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */
- if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */
- setobj2s(L, key, key2tval(gnode(t, i)));
- setobj2s(L, key+1, gval(gnode(t, i)));
- return 1;
- }
- }
- return 0; /* no more elements */
-}
-
-
-/*
-** {=============================================================
-** Rehash
-** ==============================================================
-*/
-
-
-static int computesizes (int nums[], int *narray) {
- int i;
- int twotoi; /* 2^i */
- int a = 0; /* number of elements smaller than 2^i */
- int na = 0; /* number of elements to go to array part */
- int n = 0; /* optimal size for array part */
- for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) {
- if (nums[i] > 0) {
- a += nums[i];
- if (a > twotoi/2) { /* more than half elements present? */
- n = twotoi; /* optimal size (till now) */
- na = a; /* all elements smaller than n will go to array part */
- }
- }
- if (a == *narray) break; /* all elements already counted */
- }
- *narray = n;
- lua_assert(*narray/2 <= na && na <= *narray);
- return na;
-}
-
-
-static int countint (const TValue *key, int *nums) {
- int k = arrayindex(key);
- if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */
- nums[ceillog2(k)]++; /* count as such */
- return 1;
- }
- else
- return 0;
-}
-
-
-static int numusearray (const Table *t, int *nums) {
- int lg;
- int ttlg; /* 2^lg */
- int ause = 0; /* summation of `nums' */
- int i = 1; /* count to traverse all array keys */
- for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) { /* for each slice */
- int lc = 0; /* counter */
- int lim = ttlg;
- if (lim > t->sizearray) {
- lim = t->sizearray; /* adjust upper limit */
- if (i > lim)
- break; /* no more elements to count */
- }
- /* count elements in range (2^(lg-1), 2^lg] */
- for (; i <= lim; i++) {
- if (!ttisnil(&t->array[i-1]))
- lc++;
- }
- nums[lg] += lc;
- ause += lc;
- }
- return ause;
-}
-
-
-static int numusehash (const Table *t, int *nums, int *pnasize) {
- int totaluse = 0; /* total number of elements */
- int ause = 0; /* summation of `nums' */
- int i = sizenode(t);
- while (i--) {
- Node *n = &t->node[i];
- if (!ttisnil(gval(n))) {
- ause += countint(key2tval(n), nums);
- totaluse++;
- }
- }
- *pnasize += ause;
- return totaluse;
-}
-
-
-static void setarrayvector (lua_State *L, Table *t, int size) {
- int i;
- luaM_reallocvector(L, t->array, t->sizearray, size, TValue);
- for (i=t->sizearray; i<size; i++)
- setnilvalue(&t->array[i]);
- t->sizearray = size;
-}
-
-
-static void setnodevector (lua_State *L, Table *t, int size) {
- int lsize;
- if (size == 0) { /* no elements to hash part? */
- t->node = cast(Node *, dummynode); /* use common `dummynode' */
- lsize = 0;
- }
- else {
- int i;
- lsize = ceillog2(size);
- if (lsize > MAXBITS)
- luaG_runerror(L, "table overflow");
- size = twoto(lsize);
- t->node = luaM_newvector(L, size, Node);
- for (i=0; i<size; i++) {
- Node *n = gnode(t, i);
- gnext(n) = NULL;
- setnilvalue(gkey(n));
- setnilvalue(gval(n));
- }
- }
- t->lsizenode = cast_byte(lsize);
- t->lastfree = gnode(t, size); /* all positions are free */
-}
-
-
-static void resize (lua_State *L, Table *t, int nasize, int nhsize) {
- int i;
- int oldasize = t->sizearray;
- int oldhsize = t->lsizenode;
- Node *nold = t->node; /* save old hash ... */
- if (nasize > oldasize) /* array part must grow? */
- setarrayvector(L, t, nasize);
- /* create new hash part with appropriate size */
- setnodevector(L, t, nhsize);
- if (nasize < oldasize) { /* array part must shrink? */
- t->sizearray = nasize;
- /* re-insert elements from vanishing slice */
- for (i=nasize; i<oldasize; i++) {
- if (!ttisnil(&t->array[i]))
- setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]);
- }
- /* shrink array */
- luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
- }
- /* re-insert elements from hash part */
- for (i = twoto(oldhsize) - 1; i >= 0; i--) {
- Node *old = nold+i;
- if (!ttisnil(gval(old)))
- setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old));
- }
- if (nold != dummynode)
- luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */
-}
-
-
-void luaH_resizearray (lua_State *L, Table *t, int nasize) {
- int nsize = (t->node == dummynode) ? 0 : sizenode(t);
- resize(L, t, nasize, nsize);
-}
-
-
-static void rehash (lua_State *L, Table *t, const TValue *ek) {
- int nasize, na;
- int nums[MAXBITS+1]; /* nums[i] = number of keys between 2^(i-1) and 2^i */
- int i;
- int totaluse;
- for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */
- nasize = numusearray(t, nums); /* count keys in array part */
- totaluse = nasize; /* all those keys are integer keys */
- totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */
- /* count extra key */
- nasize += countint(ek, nums);
- totaluse++;
- /* compute new size for array part */
- na = computesizes(nums, &nasize);
- /* resize the table to new computed sizes */
- resize(L, t, nasize, totaluse - na);
-}
-
-
-
-/*
-** }=============================================================
-*/
-
-
-Table *luaH_new (lua_State *L, int narray, int nhash) {
- Table *t = luaM_new(L, Table);
- luaC_link(L, obj2gco(t), LUA_TTABLE);
- t->metatable = NULL;
- t->flags = cast_byte(~0);
- /* temporary values (kept only if some malloc fails) */
- t->array = NULL;
- t->sizearray = 0;
- t->lsizenode = 0;
- t->node = cast(Node *, dummynode);
- setarrayvector(L, t, narray);
- setnodevector(L, t, nhash);
- return t;
-}
-
-
-void luaH_free (lua_State *L, Table *t) {
- if (t->node != dummynode)
- luaM_freearray(L, t->node, sizenode(t), Node);
- luaM_freearray(L, t->array, t->sizearray, TValue);
- luaM_free(L, t);
-}
-
-
-static Node *getfreepos (Table *t) {
- while (t->lastfree-- > t->node) {
- if (ttisnil(gkey(t->lastfree)))
- return t->lastfree;
- }
- return NULL; /* could not find a free place */
-}
-
-
-
-/*
-** inserts a new key into a hash table; first, check whether key's main
-** position is free. If not, check whether colliding node is in its main
-** position or not: if it is not, move colliding node to an empty place and
-** put new key in its main position; otherwise (colliding node is in its main
-** position), new key goes to an empty position.
-*/
-static TValue *newkey (lua_State *L, Table *t, const TValue *key) {
- Node *mp = mainposition(t, key);
- if (!ttisnil(gval(mp)) || mp == dummynode) {
- Node *othern;
- Node *n = getfreepos(t); /* get a free place */
- if (n == NULL) { /* cannot find a free place? */
- rehash(L, t, key); /* grow table */
- return luaH_set(L, t, key); /* re-insert key into grown table */
- }
- lua_assert(n != dummynode);
- othern = mainposition(t, key2tval(mp));
- if (othern != mp) { /* is colliding node out of its main position? */
- /* yes; move colliding node into free position */
- while (gnext(othern) != mp) othern = gnext(othern); /* find previous */
- gnext(othern) = n; /* redo the chain with `n' in place of `mp' */
- *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */
- gnext(mp) = NULL; /* now `mp' is free */
- setnilvalue(gval(mp));
- }
- else { /* colliding node is in its own main position */
- /* new node will go into free position */
- gnext(n) = gnext(mp); /* chain new position */
- gnext(mp) = n;
- mp = n;
- }
- }
- gkey(mp)->value = key->value; gkey(mp)->tt = key->tt;
- luaC_barriert(L, t, key);
- lua_assert(ttisnil(gval(mp)));
- return gval(mp);
-}
-
-
-/*
-** search function for integers
-*/
-const TValue *luaH_getnum (Table *t, int key) {
- /* (1 <= key && key <= t->sizearray) */
- if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray))
- return &t->array[key-1];
- else {
- lua_Number nk = cast_num(key);
- Node *n = hashnum(t, nk);
- do { /* check whether `key' is somewhere in the chain */
- if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk))
- return gval(n); /* that's it */
- else n = gnext(n);
- } while (n);
- return luaO_nilobject;
- }
-}
-
-
-/*
-** search function for strings
-*/
-const TValue *luaH_getstr (Table *t, TString *key) {
- Node *n = hashstr(t, key);
- do { /* check whether `key' is somewhere in the chain */
- if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key)
- return gval(n); /* that's it */
- else n = gnext(n);
- } while (n);
- return luaO_nilobject;
-}
-
-
-/*
-** main search function
-*/
-const TValue *luaH_get (Table *t, const TValue *key) {
- switch (ttype(key)) {
- case LUA_TNIL: return luaO_nilobject;
- case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key));
- case LUA_TNUMBER: {
- int k;
- lua_Number n = nvalue(key);
- lua_number2int(k, n);
- if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */
- return luaH_getnum(t, k); /* use specialized version */
- /* else go through */
- }
- default: {
- Node *n = mainposition(t, key);
- do { /* check whether `key' is somewhere in the chain */
- if (luaO_rawequalObj(key2tval(n), key))
- return gval(n); /* that's it */
- else n = gnext(n);
- } while (n);
- return luaO_nilobject;
- }
- }
-}
-
-
-TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
- const TValue *p = luaH_get(t, key);
- t->flags = 0;
- if (p != luaO_nilobject)
- return cast(TValue *, p);
- else {
- if (ttisnil(key)) luaG_runerror(L, "table index is nil");
- else if (ttisnumber(key) && luai_numisnan(nvalue(key)))
- luaG_runerror(L, "table index is NaN");
- return newkey(L, t, key);
- }
-}
-
-
-TValue *luaH_setnum (lua_State *L, Table *t, int key) {
- const TValue *p = luaH_getnum(t, key);
- if (p != luaO_nilobject)
- return cast(TValue *, p);
- else {
- TValue k;
- setnvalue(&k, cast_num(key));
- return newkey(L, t, &k);
- }
-}
-
-
-TValue *luaH_setstr (lua_State *L, Table *t, TString *key) {
- const TValue *p = luaH_getstr(t, key);
- if (p != luaO_nilobject)
- return cast(TValue *, p);
- else {
- TValue k;
- setsvalue(L, &k, key);
- return newkey(L, t, &k);
- }
-}
-
-
-static int unbound_search (Table *t, unsigned int j) {
- unsigned int i = j; /* i is zero or a present index */
- j++;
- /* find `i' and `j' such that i is present and j is not */
- while (!ttisnil(luaH_getnum(t, j))) {
- i = j;
- j *= 2;
- if (j > cast(unsigned int, MAX_INT)) { /* overflow? */
- /* table was built with bad purposes: resort to linear search */
- i = 1;
- while (!ttisnil(luaH_getnum(t, i))) i++;
- return i - 1;
- }
- }
- /* now do a binary search between them */
- while (j - i > 1) {
- unsigned int m = (i+j)/2;
- if (ttisnil(luaH_getnum(t, m))) j = m;
- else i = m;
- }
- return i;
-}
-
-
-/*
-** Try to find a boundary in table `t'. A `boundary' is an integer index
-** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
-*/
-int luaH_getn (Table *t) {
- unsigned int j = t->sizearray;
- if (j > 0 && ttisnil(&t->array[j - 1])) {
- /* there is a boundary in the array part: (binary) search for it */
- unsigned int i = 0;
- while (j - i > 1) {
- unsigned int m = (i+j)/2;
- if (ttisnil(&t->array[m - 1])) j = m;
- else i = m;
- }
- return i;
- }
- /* else must find a boundary in hash part */
- else if (t->node == dummynode) /* hash part is empty? */
- return j; /* that is easy... */
- else return unbound_search(t, j);
-}
-
-
-
-#if defined(LUA_DEBUG)
-
-Node *luaH_mainposition (const Table *t, const TValue *key) {
- return mainposition(t, key);
-}
-
-int luaH_isdummy (Node *n) { return n == dummynode; }
-
-#endif
diff --git a/src/lua/src/ltable.h b/src/lua/src/ltable.h
deleted file mode 100644
index f5b9d5ead..000000000
--- a/src/lua/src/ltable.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-** $Id: ltable.h,v 2.10.1.1 2007/12/27 13:02:25 roberto Exp $
-** Lua tables (hash)
-** See Copyright Notice in lua.h
-*/
-
-#ifndef ltable_h
-#define ltable_h
-
-#include "lobject.h"
-
-
-#define gnode(t,i) (&(t)->node[i])
-#define gkey(n) (&(n)->i_key.nk)
-#define gval(n) (&(n)->i_val)
-#define gnext(n) ((n)->i_key.nk.next)
-
-#define key2tval(n) (&(n)->i_key.tvk)
-
-
-LUAI_FUNC const TValue *luaH_getnum (Table *t, int key);
-LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key);
-LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
-LUAI_FUNC TValue *luaH_setstr (lua_State *L, Table *t, TString *key);
-LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
-LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key);
-LUAI_FUNC Table *luaH_new (lua_State *L, int narray, int lnhash);
-LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize);
-LUAI_FUNC void luaH_free (lua_State *L, Table *t);
-LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key);
-LUAI_FUNC int luaH_getn (Table *t);
-
-
-#if defined(LUA_DEBUG)
-LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
-LUAI_FUNC int luaH_isdummy (Node *n);
-#endif
-
-
-#endif
diff --git a/src/lua/src/ltablib.c b/src/lua/src/ltablib.c
deleted file mode 100644
index b6d9cb4ac..000000000
--- a/src/lua/src/ltablib.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
-** $Id: ltablib.c,v 1.38.1.3 2008/02/14 16:46:58 roberto Exp $
-** Library for Table Manipulation
-** See Copyright Notice in lua.h
-*/
-
-
-#include <stddef.h>
-
-#define ltablib_c
-#define LUA_LIB
-
-#include "lua.h"
-
-#include "lauxlib.h"
-#include "lualib.h"
-
-
-#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n))
-
-
-static int foreachi (lua_State *L) {
- int i;
- int n = aux_getn(L, 1);
- luaL_checktype(L, 2, LUA_TFUNCTION);
- for (i=1; i <= n; i++) {
- lua_pushvalue(L, 2); /* function */
- lua_pushinteger(L, i); /* 1st argument */
- lua_rawgeti(L, 1, i); /* 2nd argument */
- lua_call(L, 2, 1);
- if (!lua_isnil(L, -1))
- return 1;
- lua_pop(L, 1); /* remove nil result */
- }
- return 0;
-}
-
-
-static int foreach (lua_State *L) {
- luaL_checktype(L, 1, LUA_TTABLE);
- luaL_checktype(L, 2, LUA_TFUNCTION);
- lua_pushnil(L); /* first key */
- while (lua_next(L, 1)) {
- lua_pushvalue(L, 2); /* function */
- lua_pushvalue(L, -3); /* key */
- lua_pushvalue(L, -3); /* value */
- lua_call(L, 2, 1);
- if (!lua_isnil(L, -1))
- return 1;
- lua_pop(L, 2); /* remove value and result */
- }
- return 0;
-}
-
-
-static int maxn (lua_State *L) {
- lua_Number max = 0;
- luaL_checktype(L, 1, LUA_TTABLE);
- lua_pushnil(L); /* first key */
- while (lua_next(L, 1)) {
- lua_pop(L, 1); /* remove value */
- if (lua_type(L, -1) == LUA_TNUMBER) {
- lua_Number v = lua_tonumber(L, -1);
- if (v > max) max = v;
- }
- }
- lua_pushnumber(L, max);
- return 1;
-}
-
-
-static int getn (lua_State *L) {
- lua_pushinteger(L, aux_getn(L, 1));
- return 1;
-}
-
-
-static int setn (lua_State *L) {
- luaL_checktype(L, 1, LUA_TTABLE);
-#ifndef luaL_setn
- luaL_setn(L, 1, luaL_checkint(L, 2));
-#else
- luaL_error(L, LUA_QL("setn") " is obsolete");
-#endif
- lua_pushvalue(L, 1);
- return 1;
-}
-
-
-static int tinsert (lua_State *L) {
- int e = aux_getn(L, 1) + 1; /* first empty element */
- int pos; /* where to insert new element */
- switch (lua_gettop(L)) {
- case 2: { /* called with only 2 arguments */
- pos = e; /* insert new element at the end */
- break;
- }
- case 3: {
- int i;
- pos = luaL_checkint(L, 2); /* 2nd argument is the position */
- if (pos > e) e = pos; /* `grow' array if necessary */
- for (i = e; i > pos; i--) { /* move up elements */
- lua_rawgeti(L, 1, i-1);
- lua_rawseti(L, 1, i); /* t[i] = t[i-1] */
- }
- break;
- }
- default: {
- return luaL_error(L, "wrong number of arguments to " LUA_QL("insert"));
- }
- }
- luaL_setn(L, 1, e); /* new size */
- lua_rawseti(L, 1, pos); /* t[pos] = v */
- return 0;
-}
-
-
-static int tremove (lua_State *L) {
- int e = aux_getn(L, 1);
- int pos = luaL_optint(L, 2, e);
- if (!(1 <= pos && pos <= e)) /* position is outside bounds? */
- return 0; /* nothing to remove */
- luaL_setn(L, 1, e - 1); /* t.n = n-1 */
- lua_rawgeti(L, 1, pos); /* result = t[pos] */
- for ( ;pos<e; pos++) {
- lua_rawgeti(L, 1, pos+1);
- lua_rawseti(L, 1, pos); /* t[pos] = t[pos+1] */
- }
- lua_pushnil(L);
- lua_rawseti(L, 1, e); /* t[e] = nil */
- return 1;
-}
-
-
-static void addfield (lua_State *L, luaL_Buffer *b, int i) {
- lua_rawgeti(L, 1, i);
- if (!lua_isstring(L, -1))
- luaL_error(L, "invalid value (%s) at index %d in table for "
- LUA_QL("concat"), luaL_typename(L, -1), i);
- luaL_addvalue(b);
-}
-
-
-static int tconcat (lua_State *L) {
- luaL_Buffer b;
- size_t lsep;
- int i, last;
- const char *sep = luaL_optlstring(L, 2, "", &lsep);
- luaL_checktype(L, 1, LUA_TTABLE);
- i = luaL_optint(L, 3, 1);
- last = luaL_opt(L, luaL_checkint, 4, luaL_getn(L, 1));
- luaL_buffinit(L, &b);
- for (; i < last; i++) {
- addfield(L, &b, i);
- luaL_addlstring(&b, sep, lsep);
- }
- if (i == last) /* add last value (if interval was not empty) */
- addfield(L, &b, i);
- luaL_pushresult(&b);
- return 1;
-}
-
-
-
-/*
-** {======================================================
-** Quicksort
-** (based on `Algorithms in MODULA-3', Robert Sedgewick;
-** Addison-Wesley, 1993.)
-*/
-
-
-static void set2 (lua_State *L, int i, int j) {
- lua_rawseti(L, 1, i);
- lua_rawseti(L, 1, j);
-}
-
-static int sort_comp (lua_State *L, int a, int b) {
- if (!lua_isnil(L, 2)) { /* function? */
- int res;
- lua_pushvalue(L, 2);
- lua_pushvalue(L, a-1); /* -1 to compensate function */
- lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */
- lua_call(L, 2, 1);
- res = lua_toboolean(L, -1);
- lua_pop(L, 1);
- return res;
- }
- else /* a < b? */
- return lua_lessthan(L, a, b);
-}
-
-static void auxsort (lua_State *L, int l, int u) {
- while (l < u) { /* for tail recursion */
- int i, j;
- /* sort elements a[l], a[(l+u)/2] and a[u] */
- lua_rawgeti(L, 1, l);
- lua_rawgeti(L, 1, u);
- if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */
- set2(L, l, u); /* swap a[l] - a[u] */
- else
- lua_pop(L, 2);
- if (u-l == 1) break; /* only 2 elements */
- i = (l+u)/2;
- lua_rawgeti(L, 1, i);
- lua_rawgeti(L, 1, l);
- if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */
- set2(L, i, l);
- else {
- lua_pop(L, 1); /* remove a[l] */
- lua_rawgeti(L, 1, u);
- if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */
- set2(L, i, u);
- else
- lua_pop(L, 2);
- }
- if (u-l == 2) break; /* only 3 elements */
- lua_rawgeti(L, 1, i); /* Pivot */
- lua_pushvalue(L, -1);
- lua_rawgeti(L, 1, u-1);
- set2(L, i, u-1);
- /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
- i = l; j = u-1;
- for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */
- /* repeat ++i until a[i] >= P */
- while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) {
- if (i>u) luaL_error(L, "invalid order function for sorting");
- lua_pop(L, 1); /* remove a[i] */
- }
- /* repeat --j until a[j] <= P */
- while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) {
- if (j<l) luaL_error(L, "invalid order function for sorting");
- lua_pop(L, 1); /* remove a[j] */
- }
- if (j<i) {
- lua_pop(L, 3); /* pop pivot, a[i], a[j] */
- break;
- }
- set2(L, i, j);
- }
- lua_rawgeti(L, 1, u-1);
- lua_rawgeti(L, 1, i);
- set2(L, u-1, i); /* swap pivot (a[u-1]) with a[i] */
- /* a[l..i-1] <= a[i] == P <= a[i+1..u] */
- /* adjust so that smaller half is in [j..i] and larger one in [l..u] */
- if (i-l < u-i) {
- j=l; i=i-1; l=i+2;
- }
- else {
- j=i+1; i=u; u=j-2;
- }
- auxsort(L, j, i); /* call recursively the smaller one */
- } /* repeat the routine for the larger one */
-}
-
-static int sort (lua_State *L) {
- int n = aux_getn(L, 1);
- luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */
- if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
- luaL_checktype(L, 2, LUA_TFUNCTION);
- lua_settop(L, 2); /* make sure there is two arguments */
- auxsort(L, 1, n);
- return 0;
-}
-
-/* }====================================================== */
-
-
-static const luaL_Reg tab_funcs[] = {
- {"concat", tconcat},
- {"foreach", foreach},
- {"foreachi", foreachi},
- {"getn", getn},
- {"maxn", maxn},
- {"insert", tinsert},
- {"remove", tremove},
- {"setn", setn},
- {"sort", sort},
- {NULL, NULL}
-};
-
-
-LUALIB_API int luaopen_table (lua_State *L) {
- luaL_register(L, LUA_TABLIBNAME, tab_funcs);
- return 1;
-}
-
diff --git a/src/lua/src/ltm.c b/src/lua/src/ltm.c
deleted file mode 100644
index c27f0f6fa..000000000
--- a/src/lua/src/ltm.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
-** $Id: ltm.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
-** Tag methods
-** See Copyright Notice in lua.h
-*/
-
-
-#include <string.h>
-
-#define ltm_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "lobject.h"
-#include "lstate.h"
-#include "lstring.h"
-#include "ltable.h"
-#include "ltm.h"
-
-
-
-const char *const luaT_typenames[] = {
- "nil", "boolean", "userdata", "number",
- "string", "table", "function", "userdata", "thread",
- "proto", "upval"
-};
-
-
-void luaT_init (lua_State *L) {
- static const char *const luaT_eventname[] = { /* ORDER TM */
- "__index", "__newindex",
- "__gc", "__mode", "__eq",
- "__add", "__sub", "__mul", "__div", "__mod",
- "__pow", "__unm", "__len", "__lt", "__le",
- "__concat", "__call"
- };
- int i;
- for (i=0; i<TM_N; i++) {
- G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]);
- luaS_fix(G(L)->tmname[i]); /* never collect these names */
- }
-}
-
-
-/*
-** function to be used with macro "fasttm": optimized for absence of
-** tag methods
-*/
-const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
- const TValue *tm = luaH_getstr(events, ename);
- lua_assert(event <= TM_EQ);
- if (ttisnil(tm)) { /* no tag method? */
- events->flags |= cast_byte(1u<<event); /* cache this fact */
- return NULL;
- }
- else return tm;
-}
-
-
-const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
- Table *mt;
- switch (ttype(o)) {
- case LUA_TTABLE:
- mt = hvalue(o)->metatable;
- break;
- case LUA_TUSERDATA:
- mt = uvalue(o)->metatable;
- break;
- default:
- mt = G(L)->mt[ttype(o)];
- }
- return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject);
-}
-
diff --git a/src/lua/src/ltm.h b/src/lua/src/ltm.h
deleted file mode 100644
index 64343b781..000000000
--- a/src/lua/src/ltm.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-** $Id: ltm.h,v 2.6.1.1 2007/12/27 13:02:25 roberto Exp $
-** Tag methods
-** See Copyright Notice in lua.h
-*/
-
-#ifndef ltm_h
-#define ltm_h
-
-
-#include "lobject.h"
-
-
-/*
-* WARNING: if you change the order of this enumeration,
-* grep "ORDER TM"
-*/
-typedef enum {
- TM_INDEX,
- TM_NEWINDEX,
- TM_GC,
- TM_MODE,
- TM_EQ, /* last tag method with `fast' access */
- TM_ADD,
- TM_SUB,
- TM_MUL,
- TM_DIV,
- TM_MOD,
- TM_POW,
- TM_UNM,
- TM_LEN,
- TM_LT,
- TM_LE,
- TM_CONCAT,
- TM_CALL,
- TM_N /* number of elements in the enum */
-} TMS;
-
-
-
-#define gfasttm(g,et,e) ((et) == NULL ? NULL : \
- ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e]))
-
-#define fasttm(l,et,e) gfasttm(G(l), et, e)
-
-LUAI_DATA const char *const luaT_typenames[];
-
-
-LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename);
-LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,
- TMS event);
-LUAI_FUNC void luaT_init (lua_State *L);
-
-#endif
diff --git a/src/lua/src/lua.c b/src/lua/src/lua.c
deleted file mode 100644
index 3a4660932..000000000
--- a/src/lua/src/lua.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
-** $Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 roberto Exp $
-** Lua stand-alone interpreter
-** See Copyright Notice in lua.h
-*/
-
-
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define lua_c
-
-#include "lua.h"
-
-#include "lauxlib.h"
-#include "lualib.h"
-
-
-
-static lua_State *globalL = NULL;
-
-static const char *progname = LUA_PROGNAME;
-
-
-
-static void lstop (lua_State *L, lua_Debug *ar) {
- (void)ar; /* unused arg. */
- lua_sethook(L, NULL, 0, 0);
- luaL_error(L, "interrupted!");
-}
-
-
-static void laction (int i) {
- signal(i, SIG_DFL); /* if another SIGINT happens before lstop,
- terminate process (default action) */
- lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
-}
-
-
-static void print_usage (void) {
- fprintf(stderr,
- "usage: %s [options] [script [args]].\n"
- "Available options are:\n"
- " -e stat execute string " LUA_QL("stat") "\n"
- " -l name require library " LUA_QL("name") "\n"
- " -i enter interactive mode after executing " LUA_QL("script") "\n"
- " -v show version information\n"
- " -- stop handling options\n"
- " - execute stdin and stop handling options\n"
- ,
- progname);
- fflush(stderr);
-}
-
-
-static void l_message (const char *pname, const char *msg) {
- if (pname) fprintf(stderr, "%s: ", pname);
- fprintf(stderr, "%s\n", msg);
- fflush(stderr);
-}
-
-
-static int report (lua_State *L, int status) {
- if (status && !lua_isnil(L, -1)) {
- const char *msg = lua_tostring(L, -1);
- if (msg == NULL) msg = "(error object is not a string)";
- l_message(progname, msg);
- lua_pop(L, 1);
- }
- return status;
-}
-
-
-static int traceback (lua_State *L) {
- if (!lua_isstring(L, 1)) /* 'message' not a string? */
- return 1; /* keep it intact */
- lua_getfield(L, LUA_GLOBALSINDEX, "debug");
- if (!lua_istable(L, -1)) {
- lua_pop(L, 1);
- return 1;
- }
- lua_getfield(L, -1, "traceback");
- if (!lua_isfunction(L, -1)) {
- lua_pop(L, 2);
- return 1;
- }
- lua_pushvalue(L, 1); /* pass error message */
- lua_pushinteger(L, 2); /* skip this function and traceback */
- lua_call(L, 2, 1); /* call debug.traceback */
- return 1;
-}
-
-
-static int docall (lua_State *L, int narg, int clear) {
- int status;
- int base = lua_gettop(L) - narg; /* function index */
- lua_pushcfunction(L, traceback); /* push traceback function */
- lua_insert(L, base); /* put it under chunk and args */
- signal(SIGINT, laction);
- status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
- signal(SIGINT, SIG_DFL);
- lua_remove(L, base); /* remove traceback function */
- /* force a complete garbage collection in case of errors */
- if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
- return status;
-}
-
-
-static void print_version (void) {
- l_message(NULL, LUA_RELEASE " " LUA_COPYRIGHT);
-}
-
-
-static int getargs (lua_State *L, char **argv, int n) {
- int narg;
- int i;
- int argc = 0;
- while (argv[argc]) argc++; /* count total number of arguments */
- narg = argc - (n + 1); /* number of arguments to the script */
- luaL_checkstack(L, narg + 3, "too many arguments to script");
- for (i=n+1; i < argc; i++)
- lua_pushstring(L, argv[i]);
- lua_createtable(L, narg, n + 1);
- for (i=0; i < argc; i++) {
- lua_pushstring(L, argv[i]);
- lua_rawseti(L, -2, i - n);
- }
- return narg;
-}
-
-
-static int dofile (lua_State *L, const char *name) {
- int status = luaL_loadfile(L, name) || docall(L, 0, 1);
- return report(L, status);
-}
-
-
-static int dostring (lua_State *L, const char *s, const char *name) {
- int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1);
- return report(L, status);
-}
-
-
-static int dolibrary (lua_State *L, const char *name) {
- lua_getglobal(L, "require");
- lua_pushstring(L, name);
- return report(L, docall(L, 1, 1));
-}
-
-
-static const char *get_prompt (lua_State *L, int firstline) {
- const char *p;
- lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
- p = lua_tostring(L, -1);
- if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
- lua_pop(L, 1); /* remove global */
- return p;
-}
-
-
-static int incomplete (lua_State *L, int status) {
- if (status == LUA_ERRSYNTAX) {
- size_t lmsg;
- const char *msg = lua_tolstring(L, -1, &lmsg);
- const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
- if (strstr(msg, LUA_QL("<eof>")) == tp) {
- lua_pop(L, 1);
- return 1;
- }
- }
- return 0; /* else... */
-}
-
-
-static int pushline (lua_State *L, int firstline) {
- char buffer[LUA_MAXINPUT];
- char *b = buffer;
- size_t l;
- const char *prmt = get_prompt(L, firstline);
- if (lua_readline(L, b, prmt) == 0)
- return 0; /* no input */
- l = strlen(b);
- if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
- b[l-1] = '\0'; /* remove it */
- if (firstline && b[0] == '=') /* first line starts with `=' ? */
- lua_pushfstring(L, "return %s", b+1); /* change it to `return' */
- else
- lua_pushstring(L, b);
- lua_freeline(L, b);
- return 1;
-}
-
-
-static int loadline (lua_State *L) {
- int status;
- lua_settop(L, 0);
- if (!pushline(L, 1))
- return -1; /* no input */
- for (;;) { /* repeat until gets a complete line */
- status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
- if (!incomplete(L, status)) break; /* cannot try to add lines? */
- if (!pushline(L, 0)) /* no more input? */
- return -1;
- lua_pushliteral(L, "\n"); /* add a new line... */
- lua_insert(L, -2); /* ...between the two lines */
- lua_concat(L, 3); /* join them */
- }
- lua_saveline(L, 1);
- lua_remove(L, 1); /* remove line */
- return status;
-}
-
-
-static void dotty (lua_State *L) {
- int status;
- const char *oldprogname = progname;
- progname = NULL;
- while ((status = loadline(L)) != -1) {
- if (status == 0) status = docall(L, 0, 0);
- report(L, status);
- if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */
- lua_getglobal(L, "print");
- lua_insert(L, 1);
- if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
- l_message(progname, lua_pushfstring(L,
- "error calling " LUA_QL("print") " (%s)",
- lua_tostring(L, -1)));
- }
- }
- lua_settop(L, 0); /* clear stack */
- fputs("\n", stdout);
- fflush(stdout);
- progname = oldprogname;
-}
-
-
-static int handle_script (lua_State *L, char **argv, int n) {
- int status;
- const char *fname;
- int narg = getargs(L, argv, n); /* collect arguments */
- lua_setglobal(L, "arg");
- fname = argv[n];
- if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0)
- fname = NULL; /* stdin */
- status = luaL_loadfile(L, fname);
- lua_insert(L, -(narg+1));
- if (status == 0)
- status = docall(L, narg, 0);
- else
- lua_pop(L, narg);
- return report(L, status);
-}
-
-
-/* check that argument has no extra characters at the end */
-#define notail(x) {if ((x)[2] != '\0') return -1;}
-
-
-static int collectargs (char **argv, int *pi, int *pv, int *pe) {
- int i;
- for (i = 1; argv[i] != NULL; i++) {
- if (argv[i][0] != '-') /* not an option? */
- return i;
- switch (argv[i][1]) { /* option */
- case '-':
- notail(argv[i]);
- return (argv[i+1] != NULL ? i+1 : 0);
- case '\0':
- return i;
- case 'i':
- notail(argv[i]);
- *pi = 1; /* go through */
- case 'v':
- notail(argv[i]);
- *pv = 1;
- break;
- case 'e':
- *pe = 1; /* go through */
- case 'l':
- if (argv[i][2] == '\0') {
- i++;
- if (argv[i] == NULL) return -1;
- }
- break;
- default: return -1; /* invalid option */
- }
- }
- return 0;
-}
-
-
-static int runargs (lua_State *L, char **argv, int n) {
- int i;
- for (i = 1; i < n; i++) {
- if (argv[i] == NULL) continue;
- lua_assert(argv[i][0] == '-');
- switch (argv[i][1]) { /* option */
- case 'e': {
- const char *chunk = argv[i] + 2;
- if (*chunk == '\0') chunk = argv[++i];
- lua_assert(chunk != NULL);
- if (dostring(L, chunk, "=(command line)") != 0)
- return 1;
- break;
- }
- case 'l': {
- const char *filename = argv[i] + 2;
- if (*filename == '\0') filename = argv[++i];
- lua_assert(filename != NULL);
- if (dolibrary(L, filename))
- return 1; /* stop if file fails */
- break;
- }
- default: break;
- }
- }
- return 0;
-}
-
-
-static int handle_luainit (lua_State *L) {
- const char *init = getenv(LUA_INIT);
- if (init == NULL) return 0; /* status OK */
- else if (init[0] == '@')
- return dofile(L, init+1);
- else
- return dostring(L, init, "=" LUA_INIT);
-}
-
-
-struct Smain {
- int argc;
- char **argv;
- int status;
-};
-
-
-static int pmain (lua_State *L) {
- struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
- char **argv = s->argv;
- int script;
- int has_i = 0, has_v = 0, has_e = 0;
- globalL = L;
- if (argv[0] && argv[0][0]) progname = argv[0];
- lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */
- luaL_openlibs(L); /* open libraries */
- lua_gc(L, LUA_GCRESTART, 0);
- s->status = handle_luainit(L);
- if (s->status != 0) return 0;
- script = collectargs(argv, &has_i, &has_v, &has_e);
- if (script < 0) { /* invalid args? */
- print_usage();
- s->status = 1;
- return 0;
- }
- if (has_v) print_version();
- s->status = runargs(L, argv, (script > 0) ? script : s->argc);
- if (s->status != 0) return 0;
- if (script)
- s->status = handle_script(L, argv, script);
- if (s->status != 0) return 0;
- if (has_i)
- dotty(L);
- else if (script == 0 && !has_e && !has_v) {
- if (lua_stdin_is_tty()) {
- print_version();
- dotty(L);
- }
- else dofile(L, NULL); /* executes stdin as a file */
- }
- return 0;
-}
-
-
-int main (int argc, char **argv) {
- int status;
- struct Smain s;
- lua_State *L = lua_open(); /* create state */
- if (L == NULL) {
- l_message(argv[0], "cannot create state: not enough memory");
- return EXIT_FAILURE;
- }
- s.argc = argc;
- s.argv = argv;
- status = lua_cpcall(L, &pmain, &s);
- report(L, status);
- lua_close(L);
- return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
-}
-
diff --git a/src/lua/src/lua.h b/src/lua/src/lua.h
deleted file mode 100644
index e4bdfd3b9..000000000
--- a/src/lua/src/lua.h
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
-** $Id: lua.h,v 1.218.1.5 2008/08/06 13:30:12 roberto Exp $
-** Lua - An Extensible Extension Language
-** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
-** See Copyright Notice at the end of this file
-*/
-
-
-#ifndef lua_h
-#define lua_h
-
-#include <stdarg.h>
-#include <stddef.h>
-
-
-#include "luaconf.h"
-
-
-#define LUA_VERSION "Lua 5.1"
-#define LUA_RELEASE "Lua 5.1.4"
-#define LUA_VERSION_NUM 501
-#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio"
-#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
-
-
-/* mark for precompiled code (`<esc>Lua') */
-#define LUA_SIGNATURE "\033Lua"
-
-/* option for multiple returns in `lua_pcall' and `lua_call' */
-#define LUA_MULTRET (-1)
-
-
-/*
-** pseudo-indices
-*/
-#define LUA_REGISTRYINDEX (-10000)
-#define LUA_ENVIRONINDEX (-10001)
-#define LUA_GLOBALSINDEX (-10002)
-#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i))
-
-
-/* thread status; 0 is OK */
-#define LUA_YIELD 1
-#define LUA_ERRRUN 2
-#define LUA_ERRSYNTAX 3
-#define LUA_ERRMEM 4
-#define LUA_ERRERR 5
-
-
-typedef struct lua_State lua_State;
-
-typedef int (*lua_CFunction) (lua_State *L);
-
-
-/*
-** functions that read/write blocks when loading/dumping Lua chunks
-*/
-typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
-
-typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud);
-
-
-/*
-** prototype for memory-allocation functions
-*/
-typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
-
-
-/*
-** basic types
-*/
-#define LUA_TNONE (-1)
-
-#define LUA_TNIL 0
-#define LUA_TBOOLEAN 1
-#define LUA_TLIGHTUSERDATA 2
-#define LUA_TNUMBER 3
-#define LUA_TSTRING 4
-#define LUA_TTABLE 5
-#define LUA_TFUNCTION 6
-#define LUA_TUSERDATA 7
-#define LUA_TTHREAD 8
-
-
-
-/* minimum Lua stack available to a C function */
-#define LUA_MINSTACK 20
-
-
-/*
-** generic extra include file
-*/
-#if defined(LUA_USER_H)
-#include LUA_USER_H
-#endif
-
-
-/* type of numbers in Lua */
-typedef LUA_NUMBER lua_Number;
-
-
-/* type for integer functions */
-typedef LUA_INTEGER lua_Integer;
-
-
-
-/*
-** state manipulation
-*/
-LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
-LUA_API void (lua_close) (lua_State *L);
-LUA_API lua_State *(lua_newthread) (lua_State *L);
-
-LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
-
-
-/*
-** basic stack manipulation
-*/
-LUA_API int (lua_gettop) (lua_State *L);
-LUA_API void (lua_settop) (lua_State *L, int idx);
-LUA_API void (lua_pushvalue) (lua_State *L, int idx);
-LUA_API void (lua_remove) (lua_State *L, int idx);
-LUA_API void (lua_insert) (lua_State *L, int idx);
-LUA_API void (lua_replace) (lua_State *L, int idx);
-LUA_API int (lua_checkstack) (lua_State *L, int sz);
-
-LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n);
-
-
-/*
-** access functions (stack -> C)
-*/
-
-LUA_API int (lua_isnumber) (lua_State *L, int idx);
-LUA_API int (lua_isstring) (lua_State *L, int idx);
-LUA_API int (lua_iscfunction) (lua_State *L, int idx);
-LUA_API int (lua_isuserdata) (lua_State *L, int idx);
-LUA_API int (lua_type) (lua_State *L, int idx);
-LUA_API const char *(lua_typename) (lua_State *L, int tp);
-
-LUA_API int (lua_equal) (lua_State *L, int idx1, int idx2);
-LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2);
-LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2);
-
-LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx);
-LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx);
-LUA_API int (lua_toboolean) (lua_State *L, int idx);
-LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
-LUA_API size_t (lua_objlen) (lua_State *L, int idx);
-LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);
-LUA_API void *(lua_touserdata) (lua_State *L, int idx);
-LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);
-LUA_API const void *(lua_topointer) (lua_State *L, int idx);
-
-
-/*
-** push functions (C -> stack)
-*/
-LUA_API void (lua_pushnil) (lua_State *L);
-LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
-LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
-LUA_API void (lua_pushlstring) (lua_State *L, const char *s, size_t l);
-LUA_API void (lua_pushstring) (lua_State *L, const char *s);
-LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
- va_list argp);
-LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
-LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
-LUA_API void (lua_pushboolean) (lua_State *L, int b);
-LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
-LUA_API int (lua_pushthread) (lua_State *L);
-
-
-/*
-** get functions (Lua -> stack)
-*/
-LUA_API void (lua_gettable) (lua_State *L, int idx);
-LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k);
-LUA_API void (lua_rawget) (lua_State *L, int idx);
-LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n);
-LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
-LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
-LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
-LUA_API void (lua_getfenv) (lua_State *L, int idx);
-
-
-/*
-** set functions (stack -> Lua)
-*/
-LUA_API void (lua_settable) (lua_State *L, int idx);
-LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
-LUA_API void (lua_rawset) (lua_State *L, int idx);
-LUA_API void (lua_rawseti) (lua_State *L, int idx, int n);
-LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
-LUA_API int (lua_setfenv) (lua_State *L, int idx);
-
-
-/*
-** `load' and `call' functions (load and run Lua code)
-*/
-LUA_API void (lua_call) (lua_State *L, int nargs, int nresults);
-LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);
-LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud);
-LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
- const char *chunkname);
-
-LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data);
-
-
-/*
-** coroutine functions
-*/
-LUA_API int (lua_yield) (lua_State *L, int nresults);
-LUA_API int (lua_resume) (lua_State *L, int narg);
-LUA_API int (lua_status) (lua_State *L);
-
-/*
-** garbage-collection function and options
-*/
-
-#define LUA_GCSTOP 0
-#define LUA_GCRESTART 1
-#define LUA_GCCOLLECT 2
-#define LUA_GCCOUNT 3
-#define LUA_GCCOUNTB 4
-#define LUA_GCSTEP 5
-#define LUA_GCSETPAUSE 6
-#define LUA_GCSETSTEPMUL 7
-
-LUA_API int (lua_gc) (lua_State *L, int what, int data);
-
-
-/*
-** miscellaneous functions
-*/
-
-LUA_API int (lua_error) (lua_State *L);
-
-LUA_API int (lua_next) (lua_State *L, int idx);
-
-LUA_API void (lua_concat) (lua_State *L, int n);
-
-LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
-LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
-
-
-
-/*
-** ===============================================================
-** some useful macros
-** ===============================================================
-*/
-
-#define lua_pop(L,n) lua_settop(L, -(n)-1)
-
-#define lua_newtable(L) lua_createtable(L, 0, 0)
-
-#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
-
-#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
-
-#define lua_strlen(L,i) lua_objlen(L, (i))
-
-#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
-#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
-#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
-#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL)
-#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN)
-#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD)
-#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
-#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
-
-#define lua_pushliteral(L, s) \
- lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)
-
-#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s))
-#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s))
-
-#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
-
-
-
-/*
-** compatibility macros and functions
-*/
-
-#define lua_open() luaL_newstate()
-
-#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX)
-
-#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0)
-
-#define lua_Chunkreader lua_Reader
-#define lua_Chunkwriter lua_Writer
-
-
-/* hack */
-LUA_API void lua_setlevel (lua_State *from, lua_State *to);
-
-
-/*
-** {======================================================================
-** Debug API
-** =======================================================================
-*/
-
-
-/*
-** Event codes
-*/
-#define LUA_HOOKCALL 0
-#define LUA_HOOKRET 1
-#define LUA_HOOKLINE 2
-#define LUA_HOOKCOUNT 3
-#define LUA_HOOKTAILRET 4
-
-
-/*
-** Event masks
-*/
-#define LUA_MASKCALL (1 << LUA_HOOKCALL)
-#define LUA_MASKRET (1 << LUA_HOOKRET)
-#define LUA_MASKLINE (1 << LUA_HOOKLINE)
-#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
-
-typedef struct lua_Debug lua_Debug; /* activation record */
-
-
-/* Functions to be called by the debuger in specific events */
-typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
-
-
-LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar);
-LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
-LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
-LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
-LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n);
-LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n);
-
-LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
-LUA_API lua_Hook lua_gethook (lua_State *L);
-LUA_API int lua_gethookmask (lua_State *L);
-LUA_API int lua_gethookcount (lua_State *L);
-
-
-struct lua_Debug {
- int event;
- const char *name; /* (n) */
- const char *namewhat; /* (n) `global', `local', `field', `method' */
- const char *what; /* (S) `Lua', `C', `main', `tail' */
- const char *source; /* (S) */
- int currentline; /* (l) */
- int nups; /* (u) number of upvalues */
- int linedefined; /* (S) */
- int lastlinedefined; /* (S) */
- char short_src[LUA_IDSIZE]; /* (S) */
- /* private part */
- int i_ci; /* active function */
-};
-
-/* }====================================================================== */
-
-
-/******************************************************************************
-* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
-*
-* 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.
-******************************************************************************/
-
-
-#endif
diff --git a/src/lua/src/luac.c b/src/lua/src/luac.c
deleted file mode 100644
index d07017391..000000000
--- a/src/lua/src/luac.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
-** $Id: luac.c,v 1.54 2006/06/02 17:37:11 lhf Exp $
-** Lua compiler (saves bytecodes to files; also list bytecodes)
-** See Copyright Notice in lua.h
-*/
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define luac_c
-#define LUA_CORE
-
-#include "lua.h"
-#include "lauxlib.h"
-
-#include "ldo.h"
-#include "lfunc.h"
-#include "lmem.h"
-#include "lobject.h"
-#include "lopcodes.h"
-#include "lstring.h"
-#include "lundump.h"
-
-#define PROGNAME "luac" /* default program name */
-#define OUTPUT PROGNAME ".out" /* default output file */
-
-static int listing=0; /* list bytecodes? */
-static int dumping=1; /* dump bytecodes? */
-static int stripping=0; /* strip debug information? */
-static char Output[]={ OUTPUT }; /* default output file name */
-static const char* output=Output; /* actual output file name */
-static const char* progname=PROGNAME; /* actual program name */
-
-static void fatal(const char* message)
-{
- fprintf(stderr,"%s: %s\n",progname,message);
- exit(EXIT_FAILURE);
-}
-
-static void cannot(const char* what)
-{
- fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno));
- exit(EXIT_FAILURE);
-}
-
-static void usage(const char* message)
-{
- if (*message=='-')
- fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message);
- else
- fprintf(stderr,"%s: %s\n",progname,message);
- fprintf(stderr,
- "usage: %s [options] [filenames].\n"
- "Available options are:\n"
- " - process stdin\n"
- " -l list\n"
- " -o name output to file " LUA_QL("name") " (default is \"%s\")\n"
- " -p parse only\n"
- " -s strip debug information\n"
- " -v show version information\n"
- " -- stop handling options\n",
- progname,Output);
- exit(EXIT_FAILURE);
-}
-
-#define IS(s) (strcmp(argv[i],s)==0)
-
-static int doargs(int argc, char* argv[])
-{
- int i;
- int version=0;
- if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0];
- for (i=1; i<argc; i++)
- {
- if (*argv[i]!='-') /* end of options; keep it */
- break;
- else if (IS("--")) /* end of options; skip it */
- {
- ++i;
- if (version) ++version;
- break;
- }
- else if (IS("-")) /* end of options; use stdin */
- break;
- else if (IS("-l")) /* list */
- ++listing;
- else if (IS("-o")) /* output file */
- {
- output=argv[++i];
- if (output==NULL || *output==0) usage(LUA_QL("-o") " needs argument");
- if (IS("-")) output=NULL;
- }
- else if (IS("-p")) /* parse only */
- dumping=0;
- else if (IS("-s")) /* strip debug information */
- stripping=1;
- else if (IS("-v")) /* show version */
- ++version;
- else /* unknown option */
- usage(argv[i]);
- }
- if (i==argc && (listing || !dumping))
- {
- dumping=0;
- argv[--i]=Output;
- }
- if (version)
- {
- printf("%s %s\n",LUA_RELEASE,LUA_COPYRIGHT);
- if (version==argc-1) exit(EXIT_SUCCESS);
- }
- return i;
-}
-
-#define toproto(L,i) (clvalue(L->top+(i))->l.p)
-
-static const Proto* combine(lua_State* L, int n)
-{
- if (n==1)
- return toproto(L,-1);
- else
- {
- int i,pc;
- Proto* f=luaF_newproto(L);
- setptvalue2s(L,L->top,f); incr_top(L);
- f->source=luaS_newliteral(L,"=(" PROGNAME ")");
- f->maxstacksize=1;
- pc=2*n+1;
- f->code=luaM_newvector(L,pc,Instruction);
- f->sizecode=pc;
- f->p=luaM_newvector(L,n,Proto*);
- f->sizep=n;
- pc=0;
- for (i=0; i<n; i++)
- {
- f->p[i]=toproto(L,i-n-1);
- f->code[pc++]=CREATE_ABx(OP_CLOSURE,0,i);
- f->code[pc++]=CREATE_ABC(OP_CALL,0,1,1);
- }
- f->code[pc++]=CREATE_ABC(OP_RETURN,0,1,0);
- return f;
- }
-}
-
-static int writer(lua_State* L, const void* p, size_t size, void* u)
-{
- UNUSED(L);
- return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0);
-}
-
-struct Smain {
- int argc;
- char** argv;
-};
-
-static int pmain(lua_State* L)
-{
- struct Smain* s = (struct Smain*)lua_touserdata(L, 1);
- int argc=s->argc;
- char** argv=s->argv;
- const Proto* f;
- int i;
- if (!lua_checkstack(L,argc)) fatal("too many input files");
- for (i=0; i<argc; i++)
- {
- const char* filename=IS("-") ? NULL : argv[i];
- if (luaL_loadfile(L,filename)!=0) fatal(lua_tostring(L,-1));
- }
- f=combine(L,argc);
- if (listing) luaU_print(f,listing>1);
- if (dumping)
- {
- FILE* D= (output==NULL) ? stdout : fopen(output,"wb");
- if (D==NULL) cannot("open");
- lua_lock(L);
- luaU_dump(L,f,writer,D,stripping);
- lua_unlock(L);
- if (ferror(D)) cannot("write");
- if (fclose(D)) cannot("close");
- }
- return 0;
-}
-
-int main(int argc, char* argv[])
-{
- lua_State* L;
- struct Smain s;
- int i=doargs(argc,argv);
- argc-=i; argv+=i;
- if (argc<=0) usage("no input files given");
- L=lua_open();
- if (L==NULL) fatal("not enough memory for state");
- s.argc=argc;
- s.argv=argv;
- if (lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1));
- lua_close(L);
- return EXIT_SUCCESS;
-}
diff --git a/src/lua/src/luaconf.h b/src/lua/src/luaconf.h
deleted file mode 100644
index e2cb26163..000000000
--- a/src/lua/src/luaconf.h
+++ /dev/null
@@ -1,763 +0,0 @@
-/*
-** $Id: luaconf.h,v 1.82.1.7 2008/02/11 16:25:08 roberto Exp $
-** Configuration file for Lua
-** See Copyright Notice in lua.h
-*/
-
-
-#ifndef lconfig_h
-#define lconfig_h
-
-#include <limits.h>
-#include <stddef.h>
-
-
-/*
-** ==================================================================
-** Search for "@@" to find all configurable definitions.
-** ===================================================================
-*/
-
-
-/*
-@@ LUA_ANSI controls the use of non-ansi features.
-** CHANGE it (define it) if you want Lua to avoid the use of any
-** non-ansi feature or library.
-*/
-#if defined(__STRICT_ANSI__)
-#define LUA_ANSI
-#endif
-
-
-#if !defined(LUA_ANSI) && defined(_WIN32)
-#define LUA_WIN
-#endif
-
-#if defined(LUA_USE_LINUX)
-#define LUA_USE_POSIX
-#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
-#define LUA_USE_READLINE /* needs some extra libraries */
-#endif
-
-#if defined(LUA_USE_MACOSX)
-#define LUA_USE_POSIX
-#define LUA_DL_DYLD /* does not need extra library */
-#endif
-
-
-
-/*
-@@ LUA_USE_POSIX includes all functionallity listed as X/Open System
-@* Interfaces Extension (XSI).
-** CHANGE it (define it) if your system is XSI compatible.
-*/
-#if defined(LUA_USE_POSIX)
-#define LUA_USE_MKSTEMP
-#define LUA_USE_ISATTY
-#define LUA_USE_POPEN
-#define LUA_USE_ULONGJMP
-#endif
-
-
-/*
-@@ LUA_PATH and LUA_CPATH are the names of the environment variables that
-@* Lua check to set its paths.
-@@ LUA_INIT is the name of the environment variable that Lua
-@* checks for initialization code.
-** CHANGE them if you want different names.
-*/
-#define LUA_PATH "LUA_PATH"
-#define LUA_CPATH "LUA_CPATH"
-#define LUA_INIT "LUA_INIT"
-
-
-/*
-@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
-@* Lua libraries.
-@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for
-@* C libraries.
-** CHANGE them if your machine has a non-conventional directory
-** hierarchy or if you want to install your libraries in
-** non-conventional directories.
-*/
-#if defined(_WIN32)
-/*
-** In Windows, any exclamation mark ('!') in the path is replaced by the
-** path of the directory of the executable file of the current process.
-*/
-#define LUA_LDIR "!\\lua\\"
-#define LUA_CDIR "!\\"
-#define LUA_PATH_DEFAULT \
- ".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
- LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua"
-#define LUA_CPATH_DEFAULT \
- ".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll"
-
-#else
-#define LUA_ROOT "/usr/local/"
-#define LUA_LDIR LUA_ROOT "share/lua/5.1/"
-#define LUA_CDIR LUA_ROOT "lib/lua/5.1/"
-#define LUA_PATH_DEFAULT \
- "./?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
- LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua"
-#define LUA_CPATH_DEFAULT \
- "./?.so;" LUA_CDIR"?.so;" LUA_CDIR"loadall.so"
-#endif
-
-
-/*
-@@ LUA_DIRSEP is the directory separator (for submodules).
-** CHANGE it if your machine does not use "/" as the directory separator
-** and is not Windows. (On Windows Lua automatically uses "\".)
-*/
-#if defined(_WIN32)
-#define LUA_DIRSEP "\\"
-#else
-#define LUA_DIRSEP "/"
-#endif
-
-
-/*
-@@ LUA_PATHSEP is the character that separates templates in a path.
-@@ LUA_PATH_MARK is the string that marks the substitution points in a
-@* template.
-@@ LUA_EXECDIR in a Windows path is replaced by the executable's
-@* directory.
-@@ LUA_IGMARK is a mark to ignore all before it when bulding the
-@* luaopen_ function name.
-** CHANGE them if for some reason your system cannot use those
-** characters. (E.g., if one of those characters is a common character
-** in file/directory names.) Probably you do not need to change them.
-*/
-#define LUA_PATHSEP ";"
-#define LUA_PATH_MARK "?"
-#define LUA_EXECDIR "!"
-#define LUA_IGMARK "-"
-
-
-/*
-@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger.
-** CHANGE that if ptrdiff_t is not adequate on your machine. (On most
-** machines, ptrdiff_t gives a good choice between int or long.)
-*/
-#define LUA_INTEGER ptrdiff_t
-
-
-/*
-@@ LUA_API is a mark for all core API functions.
-@@ LUALIB_API is a mark for all standard library functions.
-** CHANGE them if you need to define those functions in some special way.
-** For instance, if you want to create one Windows DLL with the core and
-** the libraries, you may want to use the following definition (define
-** LUA_BUILD_AS_DLL to get it).
-*/
-#if defined(LUA_BUILD_AS_DLL)
-
-#if defined(LUA_CORE) || defined(LUA_LIB)
-#define LUA_API __declspec(dllexport)
-#else
-#define LUA_API __declspec(dllimport)
-#endif
-
-#else
-
-#define LUA_API extern
-
-#endif
-
-/* more often than not the libs go together with the core */
-#define LUALIB_API LUA_API
-
-
-/*
-@@ LUAI_FUNC is a mark for all extern functions that are not to be
-@* exported to outside modules.
-@@ LUAI_DATA is a mark for all extern (const) variables that are not to
-@* be exported to outside modules.
-** CHANGE them if you need to mark them in some special way. Elf/gcc
-** (versions 3.2 and later) mark them as "hidden" to optimize access
-** when Lua is compiled as a shared library.
-*/
-#if defined(luaall_c)
-#define LUAI_FUNC static
-#define LUAI_DATA /* empty */
-
-#elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
- defined(__ELF__)
-#define LUAI_FUNC __attribute__((visibility("hidden"))) extern
-#define LUAI_DATA LUAI_FUNC
-
-#else
-#define LUAI_FUNC extern
-#define LUAI_DATA extern
-#endif
-
-
-
-/*
-@@ LUA_QL describes how error messages quote program elements.
-** CHANGE it if you want a different appearance.
-*/
-#define LUA_QL(x) "'" x "'"
-#define LUA_QS LUA_QL("%s")
-
-
-/*
-@@ LUA_IDSIZE gives the maximum size for the description of the source
-@* of a function in debug information.
-** CHANGE it if you want a different size.
-*/
-#define LUA_IDSIZE 60
-
-
-/*
-** {==================================================================
-** Stand-alone configuration
-** ===================================================================
-*/
-
-#if defined(lua_c) || defined(luaall_c)
-
-/*
-@@ lua_stdin_is_tty detects whether the standard input is a 'tty' (that
-@* is, whether we're running lua interactively).
-** CHANGE it if you have a better definition for non-POSIX/non-Windows
-** systems.
-*/
-#if defined(LUA_USE_ISATTY)
-#include <unistd.h>
-#define lua_stdin_is_tty() isatty(0)
-#elif defined(LUA_WIN)
-#include <io.h>
-#include <stdio.h>
-#define lua_stdin_is_tty() _isatty(_fileno(stdin))
-#else
-#define lua_stdin_is_tty() 1 /* assume stdin is a tty */
-#endif
-
-
-/*
-@@ LUA_PROMPT is the default prompt used by stand-alone Lua.
-@@ LUA_PROMPT2 is the default continuation prompt used by stand-alone Lua.
-** CHANGE them if you want different prompts. (You can also change the
-** prompts dynamically, assigning to globals _PROMPT/_PROMPT2.)
-*/
-#define LUA_PROMPT "> "
-#define LUA_PROMPT2 ">> "
-
-
-/*
-@@ LUA_PROGNAME is the default name for the stand-alone Lua program.
-** CHANGE it if your stand-alone interpreter has a different name and
-** your system is not able to detect that name automatically.
-*/
-#define LUA_PROGNAME "lua"
-
-
-/*
-@@ LUA_MAXINPUT is the maximum length for an input line in the
-@* stand-alone interpreter.
-** CHANGE it if you need longer lines.
-*/
-#define LUA_MAXINPUT 512
-
-
-/*
-@@ lua_readline defines how to show a prompt and then read a line from
-@* the standard input.
-@@ lua_saveline defines how to "save" a read line in a "history".
-@@ lua_freeline defines how to free a line read by lua_readline.
-** CHANGE them if you want to improve this functionality (e.g., by using
-** GNU readline and history facilities).
-*/
-#if defined(LUA_USE_READLINE)
-#include <stdio.h>
-#include <readline/readline.h>
-#include <readline/history.h>
-#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL)
-#define lua_saveline(L,idx) \
- if (lua_strlen(L,idx) > 0) /* non-empty line? */ \
- add_history(lua_tostring(L, idx)); /* add it to history */
-#define lua_freeline(L,b) ((void)L, free(b))
-#else
-#define lua_readline(L,b,p) \
- ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \
- fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */
-#define lua_saveline(L,idx) { (void)L; (void)idx; }
-#define lua_freeline(L,b) { (void)L; (void)b; }
-#endif
-
-#endif
-
-/* }================================================================== */
-
-
-/*
-@@ LUAI_GCPAUSE defines the default pause between garbage-collector cycles
-@* as a percentage.
-** CHANGE it if you want the GC to run faster or slower (higher values
-** mean larger pauses which mean slower collection.) You can also change
-** this value dynamically.
-*/
-#define LUAI_GCPAUSE 200 /* 200% (wait memory to double before next GC) */
-
-
-/*
-@@ LUAI_GCMUL defines the default speed of garbage collection relative to
-@* memory allocation as a percentage.
-** CHANGE it if you want to change the granularity of the garbage
-** collection. (Higher values mean coarser collections. 0 represents
-** infinity, where each step performs a full collection.) You can also
-** change this value dynamically.
-*/
-#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */
-
-
-
-/*
-@@ LUA_COMPAT_GETN controls compatibility with old getn behavior.
-** CHANGE it (define it) if you want exact compatibility with the
-** behavior of setn/getn in Lua 5.0.
-*/
-#undef LUA_COMPAT_GETN
-
-/*
-@@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib.
-** CHANGE it to undefined as soon as you do not need a global 'loadlib'
-** function (the function is still available as 'package.loadlib').
-*/
-#undef LUA_COMPAT_LOADLIB
-
-/*
-@@ LUA_COMPAT_VARARG controls compatibility with old vararg feature.
-** CHANGE it to undefined as soon as your programs use only '...' to
-** access vararg parameters (instead of the old 'arg' table).
-*/
-#define LUA_COMPAT_VARARG
-
-/*
-@@ LUA_COMPAT_MOD controls compatibility with old math.mod function.
-** CHANGE it to undefined as soon as your programs use 'math.fmod' or
-** the new '%' operator instead of 'math.mod'.
-*/
-#define LUA_COMPAT_MOD
-
-/*
-@@ LUA_COMPAT_LSTR controls compatibility with old long string nesting
-@* facility.
-** CHANGE it to 2 if you want the old behaviour, or undefine it to turn
-** off the advisory error when nesting [[...]].
-*/
-#define LUA_COMPAT_LSTR 1
-
-/*
-@@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name.
-** CHANGE it to undefined as soon as you rename 'string.gfind' to
-** 'string.gmatch'.
-*/
-#define LUA_COMPAT_GFIND
-
-/*
-@@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib'
-@* behavior.
-** CHANGE it to undefined as soon as you replace to 'luaL_register'
-** your uses of 'luaL_openlib'
-*/
-#define LUA_COMPAT_OPENLIB
-
-
-
-/*
-@@ luai_apicheck is the assert macro used by the Lua-C API.
-** CHANGE luai_apicheck if you want Lua to perform some checks in the
-** parameters it gets from API calls. This may slow down the interpreter
-** a bit, but may be quite useful when debugging C code that interfaces
-** with Lua. A useful redefinition is to use assert.h.
-*/
-#if defined(LUA_USE_APICHECK)
-#include <assert.h>
-#define luai_apicheck(L,o) { (void)L; assert(o); }
-#else
-#define luai_apicheck(L,o) { (void)L; }
-#endif
-
-
-/*
-@@ LUAI_BITSINT defines the number of bits in an int.
-** CHANGE here if Lua cannot automatically detect the number of bits of
-** your machine. Probably you do not need to change this.
-*/
-/* avoid overflows in comparison */
-#if INT_MAX-20 < 32760
-#define LUAI_BITSINT 16
-#elif INT_MAX > 2147483640L
-/* int has at least 32 bits */
-#define LUAI_BITSINT 32
-#else
-#error "you must define LUA_BITSINT with number of bits in an integer"
-#endif
-
-
-/*
-@@ LUAI_UINT32 is an unsigned integer with at least 32 bits.
-@@ LUAI_INT32 is an signed integer with at least 32 bits.
-@@ LUAI_UMEM is an unsigned integer big enough to count the total
-@* memory used by Lua.
-@@ LUAI_MEM is a signed integer big enough to count the total memory
-@* used by Lua.
-** CHANGE here if for some weird reason the default definitions are not
-** good enough for your machine. (The definitions in the 'else'
-** part always works, but may waste space on machines with 64-bit
-** longs.) Probably you do not need to change this.
-*/
-#if LUAI_BITSINT >= 32
-#define LUAI_UINT32 unsigned int
-#define LUAI_INT32 int
-#define LUAI_MAXINT32 INT_MAX
-#define LUAI_UMEM size_t
-#define LUAI_MEM ptrdiff_t
-#else
-/* 16-bit ints */
-#define LUAI_UINT32 unsigned long
-#define LUAI_INT32 long
-#define LUAI_MAXINT32 LONG_MAX
-#define LUAI_UMEM unsigned long
-#define LUAI_MEM long
-#endif
-
-
-/*
-@@ LUAI_MAXCALLS limits the number of nested calls.
-** CHANGE it if you need really deep recursive calls. This limit is
-** arbitrary; its only purpose is to stop infinite recursion before
-** exhausting memory.
-*/
-#define LUAI_MAXCALLS 20000
-
-
-/*
-@@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function
-@* can use.
-** CHANGE it if you need lots of (Lua) stack space for your C
-** functions. This limit is arbitrary; its only purpose is to stop C
-** functions to consume unlimited stack space. (must be smaller than
-** -LUA_REGISTRYINDEX)
-*/
-#define LUAI_MAXCSTACK 8000
-
-
-
-/*
-** {==================================================================
-** CHANGE (to smaller values) the following definitions if your system
-** has a small C stack. (Or you may want to change them to larger
-** values if your system has a large C stack and these limits are
-** too rigid for you.) Some of these constants control the size of
-** stack-allocated arrays used by the compiler or the interpreter, while
-** others limit the maximum number of recursive calls that the compiler
-** or the interpreter can perform. Values too large may cause a C stack
-** overflow for some forms of deep constructs.
-** ===================================================================
-*/
-
-
-/*
-@@ LUAI_MAXCCALLS is the maximum depth for nested C calls (short) and
-@* syntactical nested non-terminals in a program.
-*/
-#define LUAI_MAXCCALLS 200
-
-
-/*
-@@ LUAI_MAXVARS is the maximum number of local variables per function
-@* (must be smaller than 250).
-*/
-#define LUAI_MAXVARS 200
-
-
-/*
-@@ LUAI_MAXUPVALUES is the maximum number of upvalues per function
-@* (must be smaller than 250).
-*/
-#define LUAI_MAXUPVALUES 60
-
-
-/*
-@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
-*/
-#define LUAL_BUFFERSIZE BUFSIZ
-
-/* }================================================================== */
-
-
-
-
-/*
-** {==================================================================
-@@ LUA_NUMBER is the type of numbers in Lua.
-** CHANGE the following definitions only if you want to build Lua
-** with a number type different from double. You may also need to
-** change lua_number2int & lua_number2integer.
-** ===================================================================
-*/
-
-#define LUA_NUMBER_DOUBLE
-#define LUA_NUMBER double
-
-/*
-@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
-@* over a number.
-*/
-#define LUAI_UACNUMBER double
-
-
-/*
-@@ LUA_NUMBER_SCAN is the format for reading numbers.
-@@ LUA_NUMBER_FMT is the format for writing numbers.
-@@ lua_number2str converts a number to a string.
-@@ LUAI_MAXNUMBER2STR is maximum size of previous conversion.
-@@ lua_str2number converts a string to a number.
-*/
-#define LUA_NUMBER_SCAN "%lf"
-#define LUA_NUMBER_FMT "%.14g"
-#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n))
-#define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */
-#define lua_str2number(s,p) strtod((s), (p))
-
-
-/*
-@@ The luai_num* macros define the primitive operations over numbers.
-*/
-#if defined(LUA_CORE)
-#include <math.h>
-#define luai_numadd(a,b) ((a)+(b))
-#define luai_numsub(a,b) ((a)-(b))
-#define luai_nummul(a,b) ((a)*(b))
-#define luai_numdiv(a,b) ((a)/(b))
-#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b))
-#define luai_numpow(a,b) (pow(a,b))
-#define luai_numunm(a) (-(a))
-#define luai_numeq(a,b) ((a)==(b))
-#define luai_numlt(a,b) ((a)<(b))
-#define luai_numle(a,b) ((a)<=(b))
-#define luai_numisnan(a) (!luai_numeq((a), (a)))
-#endif
-
-
-/*
-@@ lua_number2int is a macro to convert lua_Number to int.
-@@ lua_number2integer is a macro to convert lua_Number to lua_Integer.
-** CHANGE them if you know a faster way to convert a lua_Number to
-** int (with any rounding method and without throwing errors) in your
-** system. In Pentium machines, a naive typecast from double to int
-** in C is extremely slow, so any alternative is worth trying.
-*/
-
-/* On a Pentium, resort to a trick */
-#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \
- (defined(__i386) || defined (_M_IX86) || defined(__i386__))
-
-/* On a Microsoft compiler, use assembler */
-#if defined(_MSC_VER)
-
-#define lua_number2int(i,d) __asm fld d __asm fistp i
-#define lua_number2integer(i,n) lua_number2int(i, n)
-
-/* the next trick should work on any Pentium, but sometimes clashes
- with a DirectX idiosyncrasy */
-#else
-
-union luai_Cast { double l_d; long l_l; };
-#define lua_number2int(i,d) \
- { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; }
-#define lua_number2integer(i,n) lua_number2int(i, n)
-
-#endif
-
-
-/* this option always works, but may be slow */
-#else
-#define lua_number2int(i,d) ((i)=(int)(d))
-#define lua_number2integer(i,d) ((i)=(lua_Integer)(d))
-
-#endif
-
-/* }================================================================== */
-
-
-/*
-@@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment.
-** CHANGE it if your system requires alignments larger than double. (For
-** instance, if your system supports long doubles and they must be
-** aligned in 16-byte boundaries, then you should add long double in the
-** union.) Probably you do not need to change this.
-*/
-#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; }
-
-
-/*
-@@ LUAI_THROW/LUAI_TRY define how Lua does exception handling.
-** CHANGE them if you prefer to use longjmp/setjmp even with C++
-** or if want/don't to use _longjmp/_setjmp instead of regular
-** longjmp/setjmp. By default, Lua handles errors with exceptions when
-** compiling as C++ code, with _longjmp/_setjmp when asked to use them,
-** and with longjmp/setjmp otherwise.
-*/
-#if defined(__cplusplus)
-/* C++ exceptions */
-#define LUAI_THROW(L,c) throw(c)
-#define LUAI_TRY(L,c,a) try { a } catch(...) \
- { if ((c)->status == 0) (c)->status = -1; }
-#define luai_jmpbuf int /* dummy variable */
-
-#elif defined(LUA_USE_ULONGJMP)
-/* in Unix, try _longjmp/_setjmp (more efficient) */
-#define LUAI_THROW(L,c) _longjmp((c)->b, 1)
-#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a }
-#define luai_jmpbuf jmp_buf
-
-#else
-/* default handling with long jumps */
-#define LUAI_THROW(L,c) longjmp((c)->b, 1)
-#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a }
-#define luai_jmpbuf jmp_buf
-
-#endif
-
-
-/*
-@@ LUA_MAXCAPTURES is the maximum number of captures that a pattern
-@* can do during pattern-matching.
-** CHANGE it if you need more captures. This limit is arbitrary.
-*/
-#define LUA_MAXCAPTURES 32
-
-
-/*
-@@ lua_tmpnam is the function that the OS library uses to create a
-@* temporary name.
-@@ LUA_TMPNAMBUFSIZE is the maximum size of a name created by lua_tmpnam.
-** CHANGE them if you have an alternative to tmpnam (which is considered
-** insecure) or if you want the original tmpnam anyway. By default, Lua
-** uses tmpnam except when POSIX is available, where it uses mkstemp.
-*/
-#if defined(loslib_c) || defined(luaall_c)
-
-#if defined(LUA_USE_MKSTEMP)
-#include <unistd.h>
-#define LUA_TMPNAMBUFSIZE 32
-#define lua_tmpnam(b,e) { \
- strcpy(b, "/tmp/lua_XXXXXX"); \
- e = mkstemp(b); \
- if (e != -1) close(e); \
- e = (e == -1); }
-
-#else
-#define LUA_TMPNAMBUFSIZE L_tmpnam
-#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); }
-#endif
-
-#endif
-
-
-/*
-@@ lua_popen spawns a new process connected to the current one through
-@* the file streams.
-** CHANGE it if you have a way to implement it in your system.
-*/
-#if defined(LUA_USE_POPEN)
-
-#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m))
-#define lua_pclose(L,file) ((void)L, (pclose(file) != -1))
-
-#elif defined(LUA_WIN)
-
-#define lua_popen(L,c,m) ((void)L, _popen(c,m))
-#define lua_pclose(L,file) ((void)L, (_pclose(file) != -1))
-
-#else
-
-#define lua_popen(L,c,m) ((void)((void)c, m), \
- luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0)
-#define lua_pclose(L,file) ((void)((void)L, file), 0)
-
-#endif
-
-/*
-@@ LUA_DL_* define which dynamic-library system Lua should use.
-** CHANGE here if Lua has problems choosing the appropriate
-** dynamic-library system for your platform (either Windows' DLL, Mac's
-** dyld, or Unix's dlopen). If your system is some kind of Unix, there
-** is a good chance that it has dlopen, so LUA_DL_DLOPEN will work for
-** it. To use dlopen you also need to adapt the src/Makefile (probably
-** adding -ldl to the linker options), so Lua does not select it
-** automatically. (When you change the makefile to add -ldl, you must
-** also add -DLUA_USE_DLOPEN.)
-** If you do not want any kind of dynamic library, undefine all these
-** options.
-** By default, _WIN32 gets LUA_DL_DLL and MAC OS X gets LUA_DL_DYLD.
-*/
-#if defined(LUA_USE_DLOPEN)
-#define LUA_DL_DLOPEN
-#endif
-
-#if defined(LUA_WIN)
-#define LUA_DL_DLL
-#endif
-
-
-/*
-@@ LUAI_EXTRASPACE allows you to add user-specific data in a lua_State
-@* (the data goes just *before* the lua_State pointer).
-** CHANGE (define) this if you really need that. This value must be
-** a multiple of the maximum alignment required for your machine.
-*/
-#define LUAI_EXTRASPACE 0
-
-
-/*
-@@ luai_userstate* allow user-specific actions on threads.
-** CHANGE them if you defined LUAI_EXTRASPACE and need to do something
-** extra when a thread is created/deleted/resumed/yielded.
-*/
-#define luai_userstateopen(L) ((void)L)
-#define luai_userstateclose(L) ((void)L)
-#define luai_userstatethread(L,L1) ((void)L)
-#define luai_userstatefree(L) ((void)L)
-#define luai_userstateresume(L,n) ((void)L)
-#define luai_userstateyield(L,n) ((void)L)
-
-
-/*
-@@ LUA_INTFRMLEN is the length modifier for integer conversions
-@* in 'string.format'.
-@@ LUA_INTFRM_T is the integer type correspoding to the previous length
-@* modifier.
-** CHANGE them if your system supports long long or does not support long.
-*/
-
-#if defined(LUA_USELONGLONG)
-
-#define LUA_INTFRMLEN "ll"
-#define LUA_INTFRM_T long long
-
-#else
-
-#define LUA_INTFRMLEN "l"
-#define LUA_INTFRM_T long
-
-#endif
-
-
-
-/* =================================================================== */
-
-/*
-** Local configuration. You can use this space to add your redefinitions
-** without modifying the main part of the file.
-*/
-
-
-
-#endif
-
diff --git a/src/lua/src/lualib.h b/src/lua/src/lualib.h
deleted file mode 100644
index 469417f67..000000000
--- a/src/lua/src/lualib.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-** $Id: lualib.h,v 1.36.1.1 2007/12/27 13:02:25 roberto Exp $
-** Lua standard libraries
-** See Copyright Notice in lua.h
-*/
-
-
-#ifndef lualib_h
-#define lualib_h
-
-#include "lua.h"
-
-
-/* Key to file-handle type */
-#define LUA_FILEHANDLE "FILE*"
-
-
-#define LUA_COLIBNAME "coroutine"
-LUALIB_API int (luaopen_base) (lua_State *L);
-
-#define LUA_TABLIBNAME "table"
-LUALIB_API int (luaopen_table) (lua_State *L);
-
-#define LUA_IOLIBNAME "io"
-LUALIB_API int (luaopen_io) (lua_State *L);
-
-#define LUA_OSLIBNAME "os"
-LUALIB_API int (luaopen_os) (lua_State *L);
-
-#define LUA_STRLIBNAME "string"
-LUALIB_API int (luaopen_string) (lua_State *L);
-
-#define LUA_MATHLIBNAME "math"
-LUALIB_API int (luaopen_math) (lua_State *L);
-
-#define LUA_DBLIBNAME "debug"
-LUALIB_API int (luaopen_debug) (lua_State *L);
-
-#define LUA_LOADLIBNAME "package"
-LUALIB_API int (luaopen_package) (lua_State *L);
-
-
-/* open all previous libraries */
-LUALIB_API void (luaL_openlibs) (lua_State *L);
-
-
-
-#ifndef lua_assert
-#define lua_assert(x) ((void)0)
-#endif
-
-
-#endif
diff --git a/src/lua/src/lundump.c b/src/lua/src/lundump.c
deleted file mode 100644
index 8010a4579..000000000
--- a/src/lua/src/lundump.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
-** $Id: lundump.c,v 2.7.1.4 2008/04/04 19:51:41 roberto Exp $
-** load precompiled Lua chunks
-** See Copyright Notice in lua.h
-*/
-
-#include <string.h>
-
-#define lundump_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "ldebug.h"
-#include "ldo.h"
-#include "lfunc.h"
-#include "lmem.h"
-#include "lobject.h"
-#include "lstring.h"
-#include "lundump.h"
-#include "lzio.h"
-
-typedef struct {
- lua_State* L;
- ZIO* Z;
- Mbuffer* b;
- const char* name;
-} LoadState;
-
-#ifdef LUAC_TRUST_BINARIES
-#define IF(c,s)
-#define error(S,s)
-#else
-#define IF(c,s) if (c) error(S,s)
-
-static void error(LoadState* S, const char* why)
-{
- luaO_pushfstring(S->L,"%s: %s in precompiled chunk",S->name,why);
- luaD_throw(S->L,LUA_ERRSYNTAX);
-}
-#endif
-
-#define LoadMem(S,b,n,size) LoadBlock(S,b,(n)*(size))
-#define LoadByte(S) (lu_byte)LoadChar(S)
-#define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x))
-#define LoadVector(S,b,n,size) LoadMem(S,b,n,size)
-
-static void LoadBlock(LoadState* S, void* b, size_t size)
-{
- size_t r=luaZ_read(S->Z,b,size);
- IF (r!=0, "unexpected end");
-}
-
-static int LoadChar(LoadState* S)
-{
- char x;
- LoadVar(S,x);
- return x;
-}
-
-static int LoadInt(LoadState* S)
-{
- int x;
- LoadVar(S,x);
- IF (x<0, "bad integer");
- return x;
-}
-
-static lua_Number LoadNumber(LoadState* S)
-{
- lua_Number x;
- LoadVar(S,x);
- return x;
-}
-
-static TString* LoadString(LoadState* S)
-{
- size_t size;
- LoadVar(S,size);
- if (size==0)
- return NULL;
- else
- {
- char* s=luaZ_openspace(S->L,S->b,size);
- LoadBlock(S,s,size);
- return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */
- }
-}
-
-static void LoadCode(LoadState* S, Proto* f)
-{
- int n=LoadInt(S);
- f->code=luaM_newvector(S->L,n,Instruction);
- f->sizecode=n;
- LoadVector(S,f->code,n,sizeof(Instruction));
-}
-
-static Proto* LoadFunction(LoadState* S, TString* p);
-
-static void LoadConstants(LoadState* S, Proto* f)
-{
- int i,n;
- n=LoadInt(S);
- f->k=luaM_newvector(S->L,n,TValue);
- f->sizek=n;
- for (i=0; i<n; i++) setnilvalue(&f->k[i]);
- for (i=0; i<n; i++)
- {
- TValue* o=&f->k[i];
- int t=LoadChar(S);
- switch (t)
- {
- case LUA_TNIL:
- setnilvalue(o);
- break;
- case LUA_TBOOLEAN:
- setbvalue(o,LoadChar(S)!=0);
- break;
- case LUA_TNUMBER:
- setnvalue(o,LoadNumber(S));
- break;
- case LUA_TSTRING:
- setsvalue2n(S->L,o,LoadString(S));
- break;
- default:
- error(S,"bad constant");
- break;
- }
- }
- n=LoadInt(S);
- f->p=luaM_newvector(S->L,n,Proto*);
- f->sizep=n;
- for (i=0; i<n; i++) f->p[i]=NULL;
- for (i=0; i<n; i++) f->p[i]=LoadFunction(S,f->source);
-}
-
-static void LoadDebug(LoadState* S, Proto* f)
-{
- int i,n;
- n=LoadInt(S);
- f->lineinfo=luaM_newvector(S->L,n,int);
- f->sizelineinfo=n;
- LoadVector(S,f->lineinfo,n,sizeof(int));
- n=LoadInt(S);
- f->locvars=luaM_newvector(S->L,n,LocVar);
- f->sizelocvars=n;
- for (i=0; i<n; i++) f->locvars[i].varname=NULL;
- for (i=0; i<n; i++)
- {
- f->locvars[i].varname=LoadString(S);
- f->locvars[i].startpc=LoadInt(S);
- f->locvars[i].endpc=LoadInt(S);
- }
- n=LoadInt(S);
- f->upvalues=luaM_newvector(S->L,n,TString*);
- f->sizeupvalues=n;
- for (i=0; i<n; i++) f->upvalues[i]=NULL;
- for (i=0; i<n; i++) f->upvalues[i]=LoadString(S);
-}
-
-static Proto* LoadFunction(LoadState* S, TString* p)
-{
- Proto* f;
- if (++S->L->nCcalls > LUAI_MAXCCALLS) error(S,"code too deep");
- f=luaF_newproto(S->L);
- setptvalue2s(S->L,S->L->top,f); incr_top(S->L);
- f->source=LoadString(S); if (f->source==NULL) f->source=p;
- f->linedefined=LoadInt(S);
- f->lastlinedefined=LoadInt(S);
- f->nups=LoadByte(S);
- f->numparams=LoadByte(S);
- f->is_vararg=LoadByte(S);
- f->maxstacksize=LoadByte(S);
- LoadCode(S,f);
- LoadConstants(S,f);
- LoadDebug(S,f);
- IF (!luaG_checkcode(f), "bad code");
- S->L->top--;
- S->L->nCcalls--;
- return f;
-}
-
-static void LoadHeader(LoadState* S)
-{
- char h[LUAC_HEADERSIZE];
- char s[LUAC_HEADERSIZE];
- luaU_header(h);
- LoadBlock(S,s,LUAC_HEADERSIZE);
- IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header");
-}
-
-/*
-** load precompiled chunk
-*/
-Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name)
-{
- LoadState S;
- if (*name=='@' || *name=='=')
- S.name=name+1;
- else if (*name==LUA_SIGNATURE[0])
- S.name="binary string";
- else
- S.name=name;
- S.L=L;
- S.Z=Z;
- S.b=buff;
- LoadHeader(&S);
- return LoadFunction(&S,luaS_newliteral(L,"=?"));
-}
-
-/*
-* make header
-*/
-void luaU_header (char* h)
-{
- int x=1;
- memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1);
- h+=sizeof(LUA_SIGNATURE)-1;
- *h++=(char)LUAC_VERSION;
- *h++=(char)LUAC_FORMAT;
- *h++=(char)*(char*)&x; /* endianness */
- *h++=(char)sizeof(int);
- *h++=(char)sizeof(size_t);
- *h++=(char)sizeof(Instruction);
- *h++=(char)sizeof(lua_Number);
- *h++=(char)(((lua_Number)0.5)==0); /* is lua_Number integral? */
-}
diff --git a/src/lua/src/lundump.h b/src/lua/src/lundump.h
deleted file mode 100644
index c80189dbf..000000000
--- a/src/lua/src/lundump.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-** $Id: lundump.h,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $
-** load precompiled Lua chunks
-** See Copyright Notice in lua.h
-*/
-
-#ifndef lundump_h
-#define lundump_h
-
-#include "lobject.h"
-#include "lzio.h"
-
-/* load one chunk; from lundump.c */
-LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name);
-
-/* make header; from lundump.c */
-LUAI_FUNC void luaU_header (char* h);
-
-/* dump one chunk; from ldump.c */
-LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip);
-
-#ifdef luac_c
-/* print one chunk; from print.c */
-LUAI_FUNC void luaU_print (const Proto* f, int full);
-#endif
-
-/* for header of binary files -- this is Lua 5.1 */
-#define LUAC_VERSION 0x51
-
-/* for header of binary files -- this is the official format */
-#define LUAC_FORMAT 0
-
-/* size of header of binary files */
-#define LUAC_HEADERSIZE 12
-
-#endif
diff --git a/src/lua/src/lvm.c b/src/lua/src/lvm.c
deleted file mode 100644
index ee3256ab9..000000000
--- a/src/lua/src/lvm.c
+++ /dev/null
@@ -1,763 +0,0 @@
-/*
-** $Id: lvm.c,v 2.63.1.3 2007/12/28 15:32:23 roberto Exp $
-** Lua virtual machine
-** See Copyright Notice in lua.h
-*/
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define lvm_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "ldebug.h"
-#include "ldo.h"
-#include "lfunc.h"
-#include "lgc.h"
-#include "lobject.h"
-#include "lopcodes.h"
-#include "lstate.h"
-#include "lstring.h"
-#include "ltable.h"
-#include "ltm.h"
-#include "lvm.h"
-
-
-
-/* limit for table tag-method chains (to avoid loops) */
-#define MAXTAGLOOP 100
-
-
-const TValue *luaV_tonumber (const TValue *obj, TValue *n) {
- lua_Number num;
- if (ttisnumber(obj)) return obj;
- if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) {
- setnvalue(n, num);
- return n;
- }
- else
- return NULL;
-}
-
-
-int luaV_tostring (lua_State *L, StkId obj) {
- if (!ttisnumber(obj))
- return 0;
- else {
- char s[LUAI_MAXNUMBER2STR];
- lua_Number n = nvalue(obj);
- lua_number2str(s, n);
- setsvalue2s(L, obj, luaS_new(L, s));
- return 1;
- }
-}
-
-
-static void traceexec (lua_State *L, const Instruction *pc) {
- lu_byte mask = L->hookmask;
- const Instruction *oldpc = L->savedpc;
- L->savedpc = pc;
- if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) {
- resethookcount(L);
- luaD_callhook(L, LUA_HOOKCOUNT, -1);
- }
- if (mask & LUA_MASKLINE) {
- Proto *p = ci_func(L->ci)->l.p;
- int npc = pcRel(pc, p);
- int newline = getline(p, npc);
- /* call linehook when enter a new function, when jump back (loop),
- or when enter a new line */
- if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p)))
- luaD_callhook(L, LUA_HOOKLINE, newline);
- }
-}
-
-
-static void callTMres (lua_State *L, StkId res, const TValue *f,
- const TValue *p1, const TValue *p2) {
- ptrdiff_t result = savestack(L, res);
- setobj2s(L, L->top, f); /* push function */
- setobj2s(L, L->top+1, p1); /* 1st argument */
- setobj2s(L, L->top+2, p2); /* 2nd argument */
- luaD_checkstack(L, 3);
- L->top += 3;
- luaD_call(L, L->top - 3, 1);
- res = restorestack(L, result);
- L->top--;
- setobjs2s(L, res, L->top);
-}
-
-
-
-static void callTM (lua_State *L, const TValue *f, const TValue *p1,
- const TValue *p2, const TValue *p3) {
- setobj2s(L, L->top, f); /* push function */
- setobj2s(L, L->top+1, p1); /* 1st argument */
- setobj2s(L, L->top+2, p2); /* 2nd argument */
- setobj2s(L, L->top+3, p3); /* 3th argument */
- luaD_checkstack(L, 4);
- L->top += 4;
- luaD_call(L, L->top - 4, 0);
-}
-
-
-void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
- int loop;
- for (loop = 0; loop < MAXTAGLOOP; loop++) {
- const TValue *tm;
- if (ttistable(t)) { /* `t' is a table? */
- Table *h = hvalue(t);
- const TValue *res = luaH_get(h, key); /* do a primitive get */
- if (!ttisnil(res) || /* result is no nil? */
- (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */
- setobj2s(L, val, res);
- return;
- }
- /* else will try the tag method */
- }
- else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))
- luaG_typeerror(L, t, "index");
- if (ttisfunction(tm)) {
- callTMres(L, val, tm, t, key);
- return;
- }
- t = tm; /* else repeat with `tm' */
- }
- luaG_runerror(L, "loop in gettable");
-}
-
-
-void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
- int loop;
- for (loop = 0; loop < MAXTAGLOOP; loop++) {
- const TValue *tm;
- if (ttistable(t)) { /* `t' is a table? */
- Table *h = hvalue(t);
- TValue *oldval = luaH_set(L, h, key); /* do a primitive set */
- if (!ttisnil(oldval) || /* result is no nil? */
- (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */
- setobj2t(L, oldval, val);
- luaC_barriert(L, h, val);
- return;
- }
- /* else will try the tag method */
- }
- else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
- luaG_typeerror(L, t, "index");
- if (ttisfunction(tm)) {
- callTM(L, tm, t, key, val);
- return;
- }
- t = tm; /* else repeat with `tm' */
- }
- luaG_runerror(L, "loop in settable");
-}
-
-
-static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2,
- StkId res, TMS event) {
- const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */
- if (ttisnil(tm))
- tm = luaT_gettmbyobj(L, p2, event); /* try second operand */
- if (ttisnil(tm)) return 0;
- callTMres(L, res, tm, p1, p2);
- return 1;
-}
-
-
-static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2,
- TMS event) {
- const TValue *tm1 = fasttm(L, mt1, event);
- const TValue *tm2;
- if (tm1 == NULL) return NULL; /* no metamethod */
- if (mt1 == mt2) return tm1; /* same metatables => same metamethods */
- tm2 = fasttm(L, mt2, event);
- if (tm2 == NULL) return NULL; /* no metamethod */
- if (luaO_rawequalObj(tm1, tm2)) /* same metamethods? */
- return tm1;
- return NULL;
-}
-
-
-static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2,
- TMS event) {
- const TValue *tm1 = luaT_gettmbyobj(L, p1, event);
- const TValue *tm2;
- if (ttisnil(tm1)) return -1; /* no metamethod? */
- tm2 = luaT_gettmbyobj(L, p2, event);
- if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */
- return -1;
- callTMres(L, L->top, tm1, p1, p2);
- return !l_isfalse(L->top);
-}
-
-
-static int l_strcmp (const TString *ls, const TString *rs) {
- const char *l = getstr(ls);
- size_t ll = ls->tsv.len;
- const char *r = getstr(rs);
- size_t lr = rs->tsv.len;
- for (;;) {
- int temp = strcoll(l, r);
- if (temp != 0) return temp;
- else { /* strings are equal up to a `\0' */
- size_t len = strlen(l); /* index of first `\0' in both strings */
- if (len == lr) /* r is finished? */
- return (len == ll) ? 0 : 1;
- else if (len == ll) /* l is finished? */
- return -1; /* l is smaller than r (because r is not finished) */
- /* both strings longer than `len'; go on comparing (after the `\0') */
- len++;
- l += len; ll -= len; r += len; lr -= len;
- }
- }
-}
-
-
-int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
- int res;
- if (ttype(l) != ttype(r))
- return luaG_ordererror(L, l, r);
- else if (ttisnumber(l))
- return luai_numlt(nvalue(l), nvalue(r));
- else if (ttisstring(l))
- return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0;
- else if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
- return res;
- return luaG_ordererror(L, l, r);
-}
-
-
-static int lessequal (lua_State *L, const TValue *l, const TValue *r) {
- int res;
- if (ttype(l) != ttype(r))
- return luaG_ordererror(L, l, r);
- else if (ttisnumber(l))
- return luai_numle(nvalue(l), nvalue(r));
- else if (ttisstring(l))
- return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0;
- else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */
- return res;
- else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */
- return !res;
- return luaG_ordererror(L, l, r);
-}
-
-
-int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) {
- const TValue *tm;
- lua_assert(ttype(t1) == ttype(t2));
- switch (ttype(t1)) {
- case LUA_TNIL: return 1;
- case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2));
- case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */
- case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
- case LUA_TUSERDATA: {
- if (uvalue(t1) == uvalue(t2)) return 1;
- tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable,
- TM_EQ);
- break; /* will try TM */
- }
- case LUA_TTABLE: {
- if (hvalue(t1) == hvalue(t2)) return 1;
- tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ);
- break; /* will try TM */
- }
- default: return gcvalue(t1) == gcvalue(t2);
- }
- if (tm == NULL) return 0; /* no TM? */
- callTMres(L, L->top, tm, t1, t2); /* call TM */
- return !l_isfalse(L->top);
-}
-
-
-void luaV_concat (lua_State *L, int total, int last) {
- do {
- StkId top = L->base + last + 1;
- int n = 2; /* number of elements handled in this pass (at least 2) */
- if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) {
- if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))
- luaG_concaterror(L, top-2, top-1);
- } else if (tsvalue(top-1)->len == 0) /* second op is empty? */
- (void)tostring(L, top - 2); /* result is first op (as string) */
- else {
- /* at least two string values; get as many as possible */
- size_t tl = tsvalue(top-1)->len;
- char *buffer;
- int i;
- /* collect total length */
- for (n = 1; n < total && tostring(L, top-n-1); n++) {
- size_t l = tsvalue(top-n-1)->len;
- if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
- tl += l;
- }
- buffer = luaZ_openspace(L, &G(L)->buff, tl);
- tl = 0;
- for (i=n; i>0; i--) { /* concat all strings */
- size_t l = tsvalue(top-i)->len;
- memcpy(buffer+tl, svalue(top-i), l);
- tl += l;
- }
- setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
- }
- total -= n-1; /* got `n' strings to create 1 new */
- last -= n-1;
- } while (total > 1); /* repeat until only 1 result left */
-}
-
-
-static void Arith (lua_State *L, StkId ra, const TValue *rb,
- const TValue *rc, TMS op) {
- TValue tempb, tempc;
- const TValue *b, *c;
- if ((b = luaV_tonumber(rb, &tempb)) != NULL &&
- (c = luaV_tonumber(rc, &tempc)) != NULL) {
- lua_Number nb = nvalue(b), nc = nvalue(c);
- switch (op) {
- case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break;
- case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break;
- case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break;
- case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break;
- case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break;
- case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break;
- case TM_UNM: setnvalue(ra, luai_numunm(nb)); break;
- default: lua_assert(0); break;
- }
- }
- else if (!call_binTM(L, rb, rc, ra, op))
- luaG_aritherror(L, rb, rc);
-}
-
-
-
-/*
-** some macros for common tasks in `luaV_execute'
-*/
-
-#define runtime_check(L, c) { if (!(c)) break; }
-
-#define RA(i) (base+GETARG_A(i))
-/* to be used after possible stack reallocation */
-#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i))
-#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i))
-#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \
- ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i))
-#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \
- ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i))
-#define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i))
-
-
-#define dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);}
-
-
-#define Protect(x) { L->savedpc = pc; {x;}; base = L->base; }
-
-
-#define arith_op(op,tm) { \
- TValue *rb = RKB(i); \
- TValue *rc = RKC(i); \
- if (ttisnumber(rb) && ttisnumber(rc)) { \
- lua_Number nb = nvalue(rb), nc = nvalue(rc); \
- setnvalue(ra, op(nb, nc)); \
- } \
- else \
- Protect(Arith(L, ra, rb, rc, tm)); \
- }
-
-
-
-void luaV_execute (lua_State *L, int nexeccalls) {
- LClosure *cl;
- StkId base;
- TValue *k;
- const Instruction *pc;
- reentry: /* entry point */
- lua_assert(isLua(L->ci));
- pc = L->savedpc;
- cl = &clvalue(L->ci->func)->l;
- base = L->base;
- k = cl->p->k;
- /* main loop of interpreter */
- for (;;) {
- const Instruction i = *pc++;
- StkId ra;
- if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
- (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
- traceexec(L, pc);
- if (L->status == LUA_YIELD) { /* did hook yield? */
- L->savedpc = pc - 1;
- return;
- }
- base = L->base;
- }
- /* warning!! several calls may realloc the stack and invalidate `ra' */
- ra = RA(i);
- lua_assert(base == L->base && L->base == L->ci->base);
- lua_assert(base <= L->top && L->top <= L->stack + L->stacksize);
- lua_assert(L->top == L->ci->top || luaG_checkopenop(i));
- switch (GET_OPCODE(i)) {
- case OP_MOVE: {
- setobjs2s(L, ra, RB(i));
- continue;
- }
- case OP_LOADK: {
- setobj2s(L, ra, KBx(i));
- continue;
- }
- case OP_LOADBOOL: {
- setbvalue(ra, GETARG_B(i));
- if (GETARG_C(i)) pc++; /* skip next instruction (if C) */
- continue;
- }
- case OP_LOADNIL: {
- TValue *rb = RB(i);
- do {
- setnilvalue(rb--);
- } while (rb >= ra);
- continue;
- }
- case OP_GETUPVAL: {
- int b = GETARG_B(i);
- setobj2s(L, ra, cl->upvals[b]->v);
- continue;
- }
- case OP_GETGLOBAL: {
- TValue g;
- TValue *rb = KBx(i);
- sethvalue(L, &g, cl->env);
- lua_assert(ttisstring(rb));
- Protect(luaV_gettable(L, &g, rb, ra));
- continue;
- }
- case OP_GETTABLE: {
- Protect(luaV_gettable(L, RB(i), RKC(i), ra));
- continue;
- }
- case OP_SETGLOBAL: {
- TValue g;
- sethvalue(L, &g, cl->env);
- lua_assert(ttisstring(KBx(i)));
- Protect(luaV_settable(L, &g, KBx(i), ra));
- continue;
- }
- case OP_SETUPVAL: {
- UpVal *uv = cl->upvals[GETARG_B(i)];
- setobj(L, uv->v, ra);
- luaC_barrier(L, uv, ra);
- continue;
- }
- case OP_SETTABLE: {
- Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
- continue;
- }
- case OP_NEWTABLE: {
- int b = GETARG_B(i);
- int c = GETARG_C(i);
- sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
- Protect(luaC_checkGC(L));
- continue;
- }
- case OP_SELF: {
- StkId rb = RB(i);
- setobjs2s(L, ra+1, rb);
- Protect(luaV_gettable(L, rb, RKC(i), ra));
- continue;
- }
- case OP_ADD: {
- arith_op(luai_numadd, TM_ADD);
- continue;
- }
- case OP_SUB: {
- arith_op(luai_numsub, TM_SUB);
- continue;
- }
- case OP_MUL: {
- arith_op(luai_nummul, TM_MUL);
- continue;
- }
- case OP_DIV: {
- arith_op(luai_numdiv, TM_DIV);
- continue;
- }
- case OP_MOD: {
- arith_op(luai_nummod, TM_MOD);
- continue;
- }
- case OP_POW: {
- arith_op(luai_numpow, TM_POW);
- continue;
- }
- case OP_UNM: {
- TValue *rb = RB(i);
- if (ttisnumber(rb)) {
- lua_Number nb = nvalue(rb);
- setnvalue(ra, luai_numunm(nb));
- }
- else {
- Protect(Arith(L, ra, rb, rb, TM_UNM));
- }
- continue;
- }
- case OP_NOT: {
- int res = l_isfalse(RB(i)); /* next assignment may change this value */
- setbvalue(ra, res);
- continue;
- }
- case OP_LEN: {
- const TValue *rb = RB(i);
- switch (ttype(rb)) {
- case LUA_TTABLE: {
- setnvalue(ra, cast_num(luaH_getn(hvalue(rb))));
- break;
- }
- case LUA_TSTRING: {
- setnvalue(ra, cast_num(tsvalue(rb)->len));
- break;
- }
- default: { /* try metamethod */
- Protect(
- if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN))
- luaG_typeerror(L, rb, "get length of");
- )
- }
- }
- continue;
- }
- case OP_CONCAT: {
- int b = GETARG_B(i);
- int c = GETARG_C(i);
- Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L));
- setobjs2s(L, RA(i), base+b);
- continue;
- }
- case OP_JMP: {
- dojump(L, pc, GETARG_sBx(i));
- continue;
- }
- case OP_EQ: {
- TValue *rb = RKB(i);
- TValue *rc = RKC(i);
- Protect(
- if (equalobj(L, rb, rc) == GETARG_A(i))
- dojump(L, pc, GETARG_sBx(*pc));
- )
- pc++;
- continue;
- }
- case OP_LT: {
- Protect(
- if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i))
- dojump(L, pc, GETARG_sBx(*pc));
- )
- pc++;
- continue;
- }
- case OP_LE: {
- Protect(
- if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i))
- dojump(L, pc, GETARG_sBx(*pc));
- )
- pc++;
- continue;
- }
- case OP_TEST: {
- if (l_isfalse(ra) != GETARG_C(i))
- dojump(L, pc, GETARG_sBx(*pc));
- pc++;
- continue;
- }
- case OP_TESTSET: {
- TValue *rb = RB(i);
- if (l_isfalse(rb) != GETARG_C(i)) {
- setobjs2s(L, ra, rb);
- dojump(L, pc, GETARG_sBx(*pc));
- }
- pc++;
- continue;
- }
- case OP_CALL: {
- int b = GETARG_B(i);
- int nresults = GETARG_C(i) - 1;
- if (b != 0) L->top = ra+b; /* else previous instruction set top */
- L->savedpc = pc;
- switch (luaD_precall(L, ra, nresults)) {
- case PCRLUA: {
- nexeccalls++;
- goto reentry; /* restart luaV_execute over new Lua function */
- }
- case PCRC: {
- /* it was a C function (`precall' called it); adjust results */
- if (nresults >= 0) L->top = L->ci->top;
- base = L->base;
- continue;
- }
- default: {
- return; /* yield */
- }
- }
- }
- case OP_TAILCALL: {
- int b = GETARG_B(i);
- if (b != 0) L->top = ra+b; /* else previous instruction set top */
- L->savedpc = pc;
- lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
- switch (luaD_precall(L, ra, LUA_MULTRET)) {
- case PCRLUA: {
- /* tail call: put new frame in place of previous one */
- CallInfo *ci = L->ci - 1; /* previous frame */
- int aux;
- StkId func = ci->func;
- StkId pfunc = (ci+1)->func; /* previous function index */
- if (L->openupval) luaF_close(L, ci->base);
- L->base = ci->base = ci->func + ((ci+1)->base - pfunc);
- for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */
- setobjs2s(L, func+aux, pfunc+aux);
- ci->top = L->top = func+aux; /* correct top */
- lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize);
- ci->savedpc = L->savedpc;
- ci->tailcalls++; /* one more call lost */
- L->ci--; /* remove new frame */
- goto reentry;
- }
- case PCRC: { /* it was a C function (`precall' called it) */
- base = L->base;
- continue;
- }
- default: {
- return; /* yield */
- }
- }
- }
- case OP_RETURN: {
- int b = GETARG_B(i);
- if (b != 0) L->top = ra+b-1;
- if (L->openupval) luaF_close(L, base);
- L->savedpc = pc;
- b = luaD_poscall(L, ra);
- if (--nexeccalls == 0) /* was previous function running `here'? */
- return; /* no: return */
- else { /* yes: continue its execution */
- if (b) L->top = L->ci->top;
- lua_assert(isLua(L->ci));
- lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL);
- goto reentry;
- }
- }
- case OP_FORLOOP: {
- lua_Number step = nvalue(ra+2);
- lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */
- lua_Number limit = nvalue(ra+1);
- if (luai_numlt(0, step) ? luai_numle(idx, limit)
- : luai_numle(limit, idx)) {
- dojump(L, pc, GETARG_sBx(i)); /* jump back */
- setnvalue(ra, idx); /* update internal index... */
- setnvalue(ra+3, idx); /* ...and external index */
- }
- continue;
- }
- case OP_FORPREP: {
- const TValue *init = ra;
- const TValue *plimit = ra+1;
- const TValue *pstep = ra+2;
- L->savedpc = pc; /* next steps may throw errors */
- if (!tonumber(init, ra))
- luaG_runerror(L, LUA_QL("for") " initial value must be a number");
- else if (!tonumber(plimit, ra+1))
- luaG_runerror(L, LUA_QL("for") " limit must be a number");
- else if (!tonumber(pstep, ra+2))
- luaG_runerror(L, LUA_QL("for") " step must be a number");
- setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
- dojump(L, pc, GETARG_sBx(i));
- continue;
- }
- case OP_TFORLOOP: {
- StkId cb = ra + 3; /* call base */
- setobjs2s(L, cb+2, ra+2);
- setobjs2s(L, cb+1, ra+1);
- setobjs2s(L, cb, ra);
- L->top = cb+3; /* func. + 2 args (state and index) */
- Protect(luaD_call(L, cb, GETARG_C(i)));
- L->top = L->ci->top;
- cb = RA(i) + 3; /* previous call may change the stack */
- if (!ttisnil(cb)) { /* continue loop? */
- setobjs2s(L, cb-1, cb); /* save control variable */
- dojump(L, pc, GETARG_sBx(*pc)); /* jump back */
- }
- pc++;
- continue;
- }
- case OP_SETLIST: {
- int n = GETARG_B(i);
- int c = GETARG_C(i);
- int last;
- Table *h;
- if (n == 0) {
- n = cast_int(L->top - ra) - 1;
- L->top = L->ci->top;
- }
- if (c == 0) c = cast_int(*pc++);
- runtime_check(L, ttistable(ra));
- h = hvalue(ra);
- last = ((c-1)*LFIELDS_PER_FLUSH) + n;
- if (last > h->sizearray) /* needs more space? */
- luaH_resizearray(L, h, last); /* pre-alloc it at once */
- for (; n > 0; n--) {
- TValue *val = ra+n;
- setobj2t(L, luaH_setnum(L, h, last--), val);
- luaC_barriert(L, h, val);
- }
- continue;
- }
- case OP_CLOSE: {
- luaF_close(L, ra);
- continue;
- }
- case OP_CLOSURE: {
- Proto *p;
- Closure *ncl;
- int nup, j;
- p = cl->p->p[GETARG_Bx(i)];
- nup = p->nups;
- ncl = luaF_newLclosure(L, nup, cl->env);
- ncl->l.p = p;
- for (j=0; j<nup; j++, pc++) {
- if (GET_OPCODE(*pc) == OP_GETUPVAL)
- ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)];
- else {
- lua_assert(GET_OPCODE(*pc) == OP_MOVE);
- ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc));
- }
- }
- setclvalue(L, ra, ncl);
- Protect(luaC_checkGC(L));
- continue;
- }
- case OP_VARARG: {
- int b = GETARG_B(i) - 1;
- int j;
- CallInfo *ci = L->ci;
- int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1;
- if (b == LUA_MULTRET) {
- Protect(luaD_checkstack(L, n));
- ra = RA(i); /* previous call may change the stack */
- b = n;
- L->top = ra + n;
- }
- for (j = 0; j < b; j++) {
- if (j < n) {
- setobjs2s(L, ra + j, ci->base - n + j);
- }
- else {
- setnilvalue(ra + j);
- }
- }
- continue;
- }
- }
- }
-}
-
diff --git a/src/lua/src/lvm.h b/src/lua/src/lvm.h
deleted file mode 100644
index bfe4f5678..000000000
--- a/src/lua/src/lvm.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-** $Id: lvm.h,v 2.5.1.1 2007/12/27 13:02:25 roberto Exp $
-** Lua virtual machine
-** See Copyright Notice in lua.h
-*/
-
-#ifndef lvm_h
-#define lvm_h
-
-
-#include "ldo.h"
-#include "lobject.h"
-#include "ltm.h"
-
-
-#define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o)))
-
-#define tonumber(o,n) (ttype(o) == LUA_TNUMBER || \
- (((o) = luaV_tonumber(o,n)) != NULL))
-
-#define equalobj(L,o1,o2) \
- (ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2))
-
-
-LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
-LUAI_FUNC int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2);
-LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n);
-LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj);
-LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key,
- StkId val);
-LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key,
- StkId val);
-LUAI_FUNC void luaV_execute (lua_State *L, int nexeccalls);
-LUAI_FUNC void luaV_concat (lua_State *L, int total, int last);
-
-#endif
diff --git a/src/lua/src/lzio.c b/src/lua/src/lzio.c
deleted file mode 100644
index 293edd59b..000000000
--- a/src/lua/src/lzio.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-** $Id: lzio.c,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $
-** a generic input stream interface
-** See Copyright Notice in lua.h
-*/
-
-
-#include <string.h>
-
-#define lzio_c
-#define LUA_CORE
-
-#include "lua.h"
-
-#include "llimits.h"
-#include "lmem.h"
-#include "lstate.h"
-#include "lzio.h"
-
-
-int luaZ_fill (ZIO *z) {
- size_t size;
- lua_State *L = z->L;
- const char *buff;
- lua_unlock(L);
- buff = z->reader(L, z->data, &size);
- lua_lock(L);
- if (buff == NULL || size == 0) return EOZ;
- z->n = size - 1;
- z->p = buff;
- return char2int(*(z->p++));
-}
-
-
-int luaZ_lookahead (ZIO *z) {
- if (z->n == 0) {
- if (luaZ_fill(z) == EOZ)
- return EOZ;
- else {
- z->n++; /* luaZ_fill removed first byte; put back it */
- z->p--;
- }
- }
- return char2int(*z->p);
-}
-
-
-void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) {
- z->L = L;
- z->reader = reader;
- z->data = data;
- z->n = 0;
- z->p = NULL;
-}
-
-
-/* --------------------------------------------------------------- read --- */
-size_t luaZ_read (ZIO *z, void *b, size_t n) {
- while (n) {
- size_t m;
- if (luaZ_lookahead(z) == EOZ)
- return n; /* return number of missing bytes */
- m = (n <= z->n) ? n : z->n; /* min. between n and z->n */
- memcpy(b, z->p, m);
- z->n -= m;
- z->p += m;
- b = (char *)b + m;
- n -= m;
- }
- return 0;
-}
-
-/* ------------------------------------------------------------------------ */
-char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) {
- if (n > buff->buffsize) {
- if (n < LUA_MINBUFFER) n = LUA_MINBUFFER;
- luaZ_resizebuffer(L, buff, n);
- }
- return buff->buffer;
-}
-
-
diff --git a/src/lua/src/lzio.h b/src/lua/src/lzio.h
deleted file mode 100644
index 51d695d8c..000000000
--- a/src/lua/src/lzio.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-** $Id: lzio.h,v 1.21.1.1 2007/12/27 13:02:25 roberto Exp $
-** Buffered streams
-** See Copyright Notice in lua.h
-*/
-
-
-#ifndef lzio_h
-#define lzio_h
-
-#include "lua.h"
-
-#include "lmem.h"
-
-
-#define EOZ (-1) /* end of stream */
-
-typedef struct Zio ZIO;
-
-#define char2int(c) cast(int, cast(unsigned char, (c)))
-
-#define zgetc(z) (((z)->n--)>0 ? char2int(*(z)->p++) : luaZ_fill(z))
-
-typedef struct Mbuffer {
- char *buffer;
- size_t n;
- size_t buffsize;
-} Mbuffer;
-
-#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0)
-
-#define luaZ_buffer(buff) ((buff)->buffer)
-#define luaZ_sizebuffer(buff) ((buff)->buffsize)
-#define luaZ_bufflen(buff) ((buff)->n)
-
-#define luaZ_resetbuffer(buff) ((buff)->n = 0)
-
-
-#define luaZ_resizebuffer(L, buff, size) \
- (luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \
- (buff)->buffsize = size)
-
-#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0)
-
-
-LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n);
-LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader,
- void *data);
-LUAI_FUNC size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */
-LUAI_FUNC int luaZ_lookahead (ZIO *z);
-
-
-
-/* --------- Private Part ------------------ */
-
-struct Zio {
- size_t n; /* bytes still unread */
- const char *p; /* current position in buffer */
- lua_Reader reader;
- void* data; /* additional data */
- lua_State *L; /* Lua state (for reader) */
-};
-
-
-LUAI_FUNC int luaZ_fill (ZIO *z);
-
-#endif
diff --git a/src/lua/src/print.c b/src/lua/src/print.c
deleted file mode 100644
index e240cfc3c..000000000
--- a/src/lua/src/print.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
-** $Id: print.c,v 1.55a 2006/05/31 13:30:05 lhf Exp $
-** print bytecodes
-** See Copyright Notice in lua.h
-*/
-
-#include <ctype.h>
-#include <stdio.h>
-
-#define luac_c
-#define LUA_CORE
-
-#include "ldebug.h"
-#include "lobject.h"
-#include "lopcodes.h"
-#include "lundump.h"
-
-#define PrintFunction luaU_print
-
-#define Sizeof(x) ((int)sizeof(x))
-#define VOID(p) ((const void*)(p))
-
-static void PrintString(const TString* ts)
-{
- const char* s=getstr(ts);
- size_t i,n=ts->tsv.len;
- putchar('"');
- for (i=0; i<n; i++)
- {
- int c=s[i];
- switch (c)
- {
- case '"': printf("\\\""); break;
- case '\\': printf("\\\\"); break;
- case '\a': printf("\\a"); break;
- case '\b': printf("\\b"); break;
- case '\f': printf("\\f"); break;
- case '\n': printf("\\n"); break;
- case '\r': printf("\\r"); break;
- case '\t': printf("\\t"); break;
- case '\v': printf("\\v"); break;
- default: if (isprint((unsigned char)c))
- putchar(c);
- else
- printf("\\%03u",(unsigned char)c);
- }
- }
- putchar('"');
-}
-
-static void PrintConstant(const Proto* f, int i)
-{
- const TValue* o=&f->k[i];
- switch (ttype(o))
- {
- case LUA_TNIL:
- printf("nil");
- break;
- case LUA_TBOOLEAN:
- printf(bvalue(o) ? "true" : "false");
- break;
- case LUA_TNUMBER:
- printf(LUA_NUMBER_FMT,nvalue(o));
- break;
- case LUA_TSTRING:
- PrintString(rawtsvalue(o));
- break;
- default: /* cannot happen */
- printf("? type=%d",ttype(o));
- break;
- }
-}
-
-static void PrintCode(const Proto* f)
-{
- const Instruction* code=f->code;
- int pc,n=f->sizecode;
- for (pc=0; pc<n; pc++)
- {
- Instruction i=code[pc];
- OpCode o=GET_OPCODE(i);
- int a=GETARG_A(i);
- int b=GETARG_B(i);
- int c=GETARG_C(i);
- int bx=GETARG_Bx(i);
- int sbx=GETARG_sBx(i);
- int line=getline(f,pc);
- printf("\t%d\t",pc+1);
- if (line>0) printf("[%d]\t",line); else printf("[-]\t");
- printf("%-9s\t",luaP_opnames[o]);
- switch (getOpMode(o))
- {
- case iABC:
- printf("%d",a);
- if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (-1-INDEXK(b)) : b);
- if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c);
- break;
- case iABx:
- if (getBMode(o)==OpArgK) printf("%d %d",a,-1-bx); else printf("%d %d",a,bx);
- break;
- case iAsBx:
- if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx);
- break;
- }
- switch (o)
- {
- case OP_LOADK:
- printf("\t; "); PrintConstant(f,bx);
- break;
- case OP_GETUPVAL:
- case OP_SETUPVAL:
- printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b]) : "-");
- break;
- case OP_GETGLOBAL:
- case OP_SETGLOBAL:
- printf("\t; %s",svalue(&f->k[bx]));
- break;
- case OP_GETTABLE:
- case OP_SELF:
- if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); }
- break;
- case OP_SETTABLE:
- case OP_ADD:
- case OP_SUB:
- case OP_MUL:
- case OP_DIV:
- case OP_POW:
- case OP_EQ:
- case OP_LT:
- case OP_LE:
- if (ISK(b) || ISK(c))
- {
- printf("\t; ");
- if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-");
- printf(" ");
- if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-");
- }
- break;
- case OP_JMP:
- case OP_FORLOOP:
- case OP_FORPREP:
- printf("\t; to %d",sbx+pc+2);
- break;
- case OP_CLOSURE:
- printf("\t; %p",VOID(f->p[bx]));
- break;
- case OP_SETLIST:
- if (c==0) printf("\t; %d",(int)code[++pc]);
- else printf("\t; %d",c);
- break;
- default:
- break;
- }
- printf("\n");
- }
-}
-
-#define SS(x) (x==1)?"":"s"
-#define S(x) x,SS(x)
-
-static void PrintHeader(const Proto* f)
-{
- const char* s=getstr(f->source);
- if (*s=='@' || *s=='=')
- s++;
- else if (*s==LUA_SIGNATURE[0])
- s="(bstring)";
- else
- s="(string)";
- printf("\n%s <%s:%d,%d> (%d instruction%s, %d bytes at %p)\n",
- (f->linedefined==0)?"main":"function",s,
- f->linedefined,f->lastlinedefined,
- S(f->sizecode),f->sizecode*Sizeof(Instruction),VOID(f));
- printf("%d%s param%s, %d slot%s, %d upvalue%s, ",
- f->numparams,f->is_vararg?"+":"",SS(f->numparams),
- S(f->maxstacksize),S(f->nups));
- printf("%d local%s, %d constant%s, %d function%s\n",
- S(f->sizelocvars),S(f->sizek),S(f->sizep));
-}
-
-static void PrintConstants(const Proto* f)
-{
- int i,n=f->sizek;
- printf("constants (%d) for %p:\n",n,VOID(f));
- for (i=0; i<n; i++)
- {
- printf("\t%d\t",i+1);
- PrintConstant(f,i);
- printf("\n");
- }
-}
-
-static void PrintLocals(const Proto* f)
-{
- int i,n=f->sizelocvars;
- printf("locals (%d) for %p:\n",n,VOID(f));
- for (i=0; i<n; i++)
- {
- printf("\t%d\t%s\t%d\t%d\n",
- i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1);
- }
-}
-
-static void PrintUpvalues(const Proto* f)
-{
- int i,n=f->sizeupvalues;
- printf("upvalues (%d) for %p:\n",n,VOID(f));
- if (f->upvalues==NULL) return;
- for (i=0; i<n; i++)
- {
- printf("\t%d\t%s\n",i,getstr(f->upvalues[i]));
- }
-}
-
-void PrintFunction(const Proto* f, int full)
-{
- int i,n=f->sizep;
- PrintHeader(f);
- PrintCode(f);
- if (full)
- {
- PrintConstants(f);
- PrintLocals(f);
- PrintUpvalues(f);
- }
- for (i=0; i<n; i++) PrintFunction(f->p[i],full);
-}
diff --git a/src/main.cpp b/src/main.cpp
index a54454653..6a2e89f7a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -17,9 +17,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-// This would get rid of the console window
-//#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
-
#include "irrlicht.h" // createDevice
#include "mainmenumanager.h"
@@ -44,11 +41,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gameparams.h"
#include "database.h"
#include "config.h"
+#include "porting.h"
#if USE_CURSES
#include "terminal_chat_console.h"
#endif
#ifndef SERVER
#include "client/clientlauncher.h"
+
#endif
#ifdef HAVE_TOUCHSCREENGUI
@@ -104,28 +103,10 @@ static bool get_game_from_cmdline(GameParams *game_params, const Settings &cmd_a
static bool determine_subgame(GameParams *game_params);
static bool run_dedicated_server(const GameParams &game_params, const Settings &cmd_args);
-static bool migrate_database(const GameParams &game_params, const Settings &cmd_args);
+static bool migrate_map_database(const GameParams &game_params, const Settings &cmd_args);
/**********************************************************************/
-/*
- gettime.h implementation
-*/
-
-#ifdef SERVER
-
-u32 getTimeMs()
-{
- /* Use imprecise system calls directly (from porting.h) */
- return porting::getTime(PRECISION_MILLI);
-}
-
-u32 getTime(TimePrecision prec)
-{
- return porting::getTime(prec);
-}
-
-#endif
FileLogOutput file_log_output;
@@ -134,7 +115,6 @@ static OptionList allowed_options;
int main(int argc, char *argv[])
{
int retval;
-
debug_set_exception_handler();
g_logger.registerThread("Main");
@@ -145,11 +125,15 @@ int main(int argc, char *argv[])
if (!cmd_args_ok
|| cmd_args.getFlag("help")
|| cmd_args.exists("nonopt1")) {
+ porting::attachOrCreateConsole();
print_help(allowed_options);
return cmd_args_ok ? 0 : 1;
}
+ if (cmd_args.getFlag("console"))
+ porting::attachOrCreateConsole();
if (cmd_args.getFlag("version")) {
+ porting::attachOrCreateConsole();
print_version();
return 0;
}
@@ -191,6 +175,9 @@ int main(int argc, char *argv[])
if (!init_common(cmd_args, argc, argv))
return 1;
+ if (g_settings->getBool("enable_console"))
+ porting::attachOrCreateConsole();
+
#ifndef __ANDROID__
// Run unit tests
if (cmd_args.getFlag("run-unittests")) {
@@ -200,9 +187,13 @@ int main(int argc, char *argv[])
GameParams game_params;
#ifdef SERVER
+ porting::attachOrCreateConsole();
game_params.is_dedicated_server = true;
#else
- game_params.is_dedicated_server = cmd_args.getFlag("server");
+ const bool isServer = cmd_args.getFlag("server");
+ if (isServer)
+ porting::attachOrCreateConsole();
+ game_params.is_dedicated_server = isServer;
#endif
if (!game_configure(&game_params, cmd_args))
@@ -213,10 +204,6 @@ int main(int argc, char *argv[])
infostream << "Using commanded world path ["
<< game_params.world_path << "]" << std::endl;
- //Run dedicated server if asked to or no other option
- g_settings->set("server_dedicated",
- game_params.is_dedicated_server ? "true" : "false");
-
if (game_params.is_dedicated_server)
return run_dedicated_server(game_params, cmd_args) ? 0 : 1;
@@ -288,6 +275,8 @@ static void set_allowed_options(OptionList *allowed_options)
_("Set gameid (\"--gameid list\" prints available ones)"))));
allowed_options->insert(std::make_pair("migrate", ValueSpec(VALUETYPE_STRING,
_("Migrate from current map backend to another (Only works when using minetestserver or with --server)"))));
+ allowed_options->insert(std::make_pair("migrate-players", ValueSpec(VALUETYPE_STRING,
+ _("Migrate from current players backend to another (Only works when using minetestserver or with --server)"))));
allowed_options->insert(std::make_pair("terminal", ValueSpec(VALUETYPE_FLAG,
_("Feature an interactive terminal (Only works when using minetestserver or with --server)"))));
#ifndef SERVER
@@ -307,6 +296,8 @@ static void set_allowed_options(OptionList *allowed_options)
_("Set password"))));
allowed_options->insert(std::make_pair("go", ValueSpec(VALUETYPE_FLAG,
_("Disable main menu"))));
+ allowed_options->insert(std::make_pair("console", ValueSpec(VALUETYPE_FLAG,
+ _("Starts with the console (Windows only)"))));
#endif
}
@@ -326,7 +317,7 @@ static void print_allowed_options(const OptionList &allowed_options)
if (i->second.type != VALUETYPE_FLAG)
os1 << _(" <value>");
- std::cout << padStringRight(os1.str(), 24);
+ std::cout << padStringRight(os1.str(), 30);
if (i->second.help != NULL)
std::cout << i->second.help;
@@ -822,7 +813,9 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings &
// Database migration
if (cmd_args.exists("migrate"))
- return migrate_database(game_params, cmd_args);
+ return migrate_map_database(game_params, cmd_args);
+ else if (cmd_args.exists("migrate-players"))
+ return ServerEnvironment::migratePlayersDatabase(game_params, cmd_args);
if (cmd_args.exists("terminal")) {
#if USE_CURSES
@@ -852,8 +845,8 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings &
try {
// Create server
- Server server(game_params.world_path,
- game_params.game_spec, false, bind_addr.isIPv6(), &iface);
+ Server server(game_params.world_path, game_params.game_spec,
+ false, bind_addr.isIPv6(), true, &iface);
g_term_console.setup(&iface, &kill, admin_nick);
@@ -887,7 +880,7 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings &
try {
// Create server
Server server(game_params.world_path, game_params.game_spec, false,
- bind_addr.isIPv6());
+ bind_addr.isIPv6(), true);
server.start(bind_addr);
// Run server
@@ -906,7 +899,7 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings &
return true;
}
-static bool migrate_database(const GameParams &game_params, const Settings &cmd_args)
+static bool migrate_map_database(const GameParams &game_params, const Settings &cmd_args)
{
std::string migrate_to = cmd_args.get("migrate");
Settings world_mt;
@@ -915,20 +908,23 @@ static bool migrate_database(const GameParams &game_params, const Settings &cmd_
errorstream << "Cannot read world.mt!" << std::endl;
return false;
}
+
if (!world_mt.exists("backend")) {
errorstream << "Please specify your current backend in world.mt:"
<< std::endl
- << " backend = {sqlite3|leveldb|redis|dummy}"
+ << " backend = {sqlite3|leveldb|redis|dummy|postgresql}"
<< std::endl;
return false;
}
+
std::string backend = world_mt.get("backend");
if (backend == migrate_to) {
errorstream << "Cannot migrate: new backend is same"
<< " as the old one" << std::endl;
return false;
}
- Database *old_db = ServerMap::createDatabase(backend, game_params.world_path, world_mt),
+
+ MapDatabase *old_db = ServerMap::createDatabase(backend, game_params.world_path, world_mt),
*new_db = ServerMap::createDatabase(migrate_to, game_params.world_path, world_mt);
u32 count = 0;
@@ -970,4 +966,3 @@ static bool migrate_database(const GameParams &game_params, const Settings &cmd_
return true;
}
-
diff --git a/src/mainmenumanager.h b/src/mainmenumanager.h
index 17133b164..fb715ca9b 100644
--- a/src/mainmenumanager.h
+++ b/src/mainmenumanager.h
@@ -83,7 +83,7 @@ public:
/*core::list<GUIModalMenu*>::Iterator i = m_stack.getLast();
assert(*i == menu);
m_stack.erase(i);*/
-
+
if(!m_stack.empty())
m_stack.back()->setVisible(true);
}
@@ -119,7 +119,7 @@ public:
extern MainMenuManager g_menumgr;
-extern bool noMenuActive();
+extern bool isMenuActive();
class MainGameCallback : public IGameCallback
{
@@ -168,7 +168,7 @@ public:
keyconfig_changed = true;
}
-
+
bool disconnect_requested;
bool changepassword_requested;
bool changevolume_requested;
diff --git a/src/map.cpp b/src/map.cpp
index 7bb8c4a13..3b02ac02f 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -32,7 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodedef.h"
#include "gamedef.h"
#include "util/directiontables.h"
-#include "util/mathconstants.h"
+#include "util/basic_macros.h"
#include "rollback_interface.h"
#include "environment.h"
#include "reflowscan.h"
@@ -44,6 +44,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "database.h"
#include "database-dummy.h"
#include "database-sqlite3.h"
+#include "script/scripting_server.h"
#include <deque>
#include <queue>
#if USE_LEVELDB
@@ -56,8 +57,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "database-postgresql.h"
#endif
-#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
-
/*
Map
@@ -67,6 +66,7 @@ Map::Map(std::ostream &dout, IGameDef *gamedef):
m_dout(dout),
m_gamedef(gamedef),
m_sector_cache(NULL),
+ m_nodedef(gamedef->ndef()),
m_transforming_liquid_loop_count_multiplier(1.0f),
m_unprocessed_count(0),
m_inc_trending_up_start_time(0),
@@ -228,7 +228,7 @@ void Map::setNode(v3s16 p, MapNode & n)
bool temp_bool;
errorstream<<"Map::setNode(): Not allowing to place CONTENT_IGNORE"
<<" while trying to replace \""
- <<m_gamedef->ndef()->get(block->getNodeNoCheck(relpos, &temp_bool)).name
+ <<m_nodedef->get(block->getNodeNoCheck(relpos, &temp_bool)).name
<<"\" at "<<PP(p)<<" (block "<<PP(blockpos)<<")"<<std::endl;
debug_stacks_print_to(infostream);
return;
@@ -236,583 +236,10 @@ void Map::setNode(v3s16 p, MapNode & n)
block->setNodeNoCheck(relpos, n);
}
-/*
- Goes recursively through the neighbours of the node.
-
- Alters only transparent nodes.
-
- If the lighting of the neighbour is lower than the lighting of
- the node was (before changing it to 0 at the step before), the
- lighting of the neighbour is set to 0 and then the same stuff
- repeats for the neighbour.
-
- The ending nodes of the routine are stored in light_sources.
- This is useful when a light is removed. In such case, this
- routine can be called for the light node and then again for
- light_sources to re-light the area without the removed light.
-
- values of from_nodes are lighting values.
-*/
-void Map::unspreadLight(enum LightBank bank,
- std::map<v3s16, u8> & from_nodes,
- std::set<v3s16> & light_sources,
- std::map<v3s16, MapBlock*> & modified_blocks)
-{
- INodeDefManager *nodemgr = m_gamedef->ndef();
-
- v3s16 dirs[6] = {
- v3s16(0,0,1), // back
- v3s16(0,1,0), // top
- v3s16(1,0,0), // right
- v3s16(0,0,-1), // front
- v3s16(0,-1,0), // bottom
- v3s16(-1,0,0), // left
- };
-
- if(from_nodes.empty())
- return;
-
- u32 blockchangecount = 0;
-
- std::map<v3s16, u8> unlighted_nodes;
-
- /*
- Initialize block cache
- */
- v3s16 blockpos_last;
- MapBlock *block = NULL;
- // Cache this a bit, too
- bool block_checked_in_modified = false;
-
- for(std::map<v3s16, u8>::iterator j = from_nodes.begin();
- j != from_nodes.end(); ++j)
- {
- v3s16 pos = j->first;
- v3s16 blockpos = getNodeBlockPos(pos);
-
- // Only fetch a new block if the block position has changed
- try{
- if(block == NULL || blockpos != blockpos_last){
- block = getBlockNoCreate(blockpos);
- blockpos_last = blockpos;
-
- block_checked_in_modified = false;
- blockchangecount++;
- }
- }
- catch(InvalidPositionException &e)
- {
- continue;
- }
-
- if(block->isDummy())
- continue;
-
- // Calculate relative position in block
- //v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
-
- // Get node straight from the block
- //MapNode n = block->getNode(relpos);
-
- u8 oldlight = j->second;
-
- // Loop through 6 neighbors
- for(u16 i=0; i<6; i++)
- {
- // Get the position of the neighbor node
- v3s16 n2pos = pos + dirs[i];
-
- // Get the block where the node is located
- v3s16 blockpos, relpos;
- getNodeBlockPosWithOffset(n2pos, blockpos, relpos);
-
- // Only fetch a new block if the block position has changed
- try {
- if(block == NULL || blockpos != blockpos_last){
- block = getBlockNoCreate(blockpos);
- blockpos_last = blockpos;
-
- block_checked_in_modified = false;
- blockchangecount++;
- }
- }
- catch(InvalidPositionException &e) {
- continue;
- }
-
- // Get node straight from the block
- bool is_valid_position;
- MapNode n2 = block->getNode(relpos, &is_valid_position);
- if (!is_valid_position)
- continue;
-
- bool changed = false;
-
- //TODO: Optimize output by optimizing light_sources?
-
- /*
- If the neighbor is dimmer than what was specified
- as oldlight (the light of the previous node)
- */
- if(n2.getLight(bank, nodemgr) < oldlight)
- {
- /*
- And the neighbor is transparent and it has some light
- */
- if(nodemgr->get(n2).light_propagates
- && n2.getLight(bank, nodemgr) != 0)
- {
- /*
- Set light to 0 and add to queue
- */
-
- u8 current_light = n2.getLight(bank, nodemgr);
- n2.setLight(bank, 0, nodemgr);
- block->setNode(relpos, n2);
-
- unlighted_nodes[n2pos] = current_light;
- changed = true;
-
- /*
- Remove from light_sources if it is there
- NOTE: This doesn't happen nearly at all
- */
- /*if(light_sources.find(n2pos))
- {
- infostream<<"Removed from light_sources"<<std::endl;
- light_sources.remove(n2pos);
- }*/
- }
-
- /*// DEBUG
- if(light_sources.find(n2pos) != NULL)
- light_sources.remove(n2pos);*/
- }
- else{
- light_sources.insert(n2pos);
- }
-
- // Add to modified_blocks
- if(changed == true && block_checked_in_modified == false)
- {
- // If the block is not found in modified_blocks, add.
- if(modified_blocks.find(blockpos) == modified_blocks.end())
- {
- modified_blocks[blockpos] = block;
- }
- block_checked_in_modified = true;
- }
- }
- }
-
- /*infostream<<"unspreadLight(): Changed block "
- <<blockchangecount<<" times"
- <<" for "<<from_nodes.size()<<" nodes"
- <<std::endl;*/
-
- if(!unlighted_nodes.empty())
- unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks);
-}
-
-/*
- Lights neighbors of from_nodes, collects all them and then
- goes on recursively.
-*/
-void Map::spreadLight(enum LightBank bank,
- std::set<v3s16> & from_nodes,
- std::map<v3s16, MapBlock*> & modified_blocks)
-{
- INodeDefManager *nodemgr = m_gamedef->ndef();
-
- const v3s16 dirs[6] = {
- v3s16(0,0,1), // back
- v3s16(0,1,0), // top
- v3s16(1,0,0), // right
- v3s16(0,0,-1), // front
- v3s16(0,-1,0), // bottom
- v3s16(-1,0,0), // left
- };
-
- if(from_nodes.empty())
- return;
-
- u32 blockchangecount = 0;
-
- std::set<v3s16> lighted_nodes;
-
- /*
- Initialize block cache
- */
- v3s16 blockpos_last;
- MapBlock *block = NULL;
- // Cache this a bit, too
- bool block_checked_in_modified = false;
-
- for(std::set<v3s16>::iterator j = from_nodes.begin();
- j != from_nodes.end(); ++j)
- {
- v3s16 pos = *j;
- v3s16 blockpos, relpos;
-
- getNodeBlockPosWithOffset(pos, blockpos, relpos);
-
- // Only fetch a new block if the block position has changed
- try {
- if(block == NULL || blockpos != blockpos_last){
- block = getBlockNoCreate(blockpos);
- blockpos_last = blockpos;
-
- block_checked_in_modified = false;
- blockchangecount++;
- }
- }
- catch(InvalidPositionException &e) {
- continue;
- }
-
- if(block->isDummy())
- continue;
-
- // Get node straight from the block
- bool is_valid_position;
- MapNode n = block->getNode(relpos, &is_valid_position);
-
- u8 oldlight = is_valid_position ? n.getLight(bank, nodemgr) : 0;
- u8 newlight = diminish_light(oldlight);
-
- // Loop through 6 neighbors
- for(u16 i=0; i<6; i++){
- // Get the position of the neighbor node
- v3s16 n2pos = pos + dirs[i];
-
- // Get the block where the node is located
- v3s16 blockpos, relpos;
- getNodeBlockPosWithOffset(n2pos, blockpos, relpos);
-
- // Only fetch a new block if the block position has changed
- try {
- if(block == NULL || blockpos != blockpos_last){
- block = getBlockNoCreate(blockpos);
- blockpos_last = blockpos;
-
- block_checked_in_modified = false;
- blockchangecount++;
- }
- }
- catch(InvalidPositionException &e) {
- continue;
- }
-
- // Get node straight from the block
- MapNode n2 = block->getNode(relpos, &is_valid_position);
- if (!is_valid_position)
- continue;
-
- bool changed = false;
- /*
- If the neighbor is brighter than the current node,
- add to list (it will light up this node on its turn)
- */
- if(n2.getLight(bank, nodemgr) > undiminish_light(oldlight))
- {
- lighted_nodes.insert(n2pos);
- changed = true;
- }
- /*
- If the neighbor is dimmer than how much light this node
- would spread on it, add to list
- */
- if(n2.getLight(bank, nodemgr) < newlight)
- {
- if(nodemgr->get(n2).light_propagates)
- {
- n2.setLight(bank, newlight, nodemgr);
- block->setNode(relpos, n2);
- lighted_nodes.insert(n2pos);
- changed = true;
- }
- }
-
- // Add to modified_blocks
- if(changed == true && block_checked_in_modified == false)
- {
- // If the block is not found in modified_blocks, add.
- if(modified_blocks.find(blockpos) == modified_blocks.end())
- {
- modified_blocks[blockpos] = block;
- }
- block_checked_in_modified = true;
- }
- }
- }
-
- /*infostream<<"spreadLight(): Changed block "
- <<blockchangecount<<" times"
- <<" for "<<from_nodes.size()<<" nodes"
- <<std::endl;*/
-
- if(!lighted_nodes.empty())
- spreadLight(bank, lighted_nodes, modified_blocks);
-}
-
-void Map::updateLighting(enum LightBank bank,
- std::map<v3s16, MapBlock*> & a_blocks,
- std::map<v3s16, MapBlock*> & modified_blocks)
-{
- INodeDefManager *nodemgr = m_gamedef->ndef();
-
- /*m_dout<<"Map::updateLighting(): "
- <<a_blocks.size()<<" blocks."<<std::endl;*/
-
- //TimeTaker timer("updateLighting");
-
- // For debugging
- //bool debug=true;
- //u32 count_was = modified_blocks.size();
-
- //std::map<v3s16, MapBlock*> blocks_to_update;
-
- std::set<v3s16> light_sources;
-
- std::map<v3s16, u8> unlight_from;
-
- int num_bottom_invalid = 0;
-
- {
- //TimeTaker t("first stuff");
-
- for(std::map<v3s16, MapBlock*>::iterator i = a_blocks.begin();
- i != a_blocks.end(); ++i)
- {
- MapBlock *block = i->second;
-
- for(;;)
- {
- // Don't bother with dummy blocks.
- if(block->isDummy())
- break;
-
- v3s16 pos = block->getPos();
- v3s16 posnodes = block->getPosRelative();
- modified_blocks[pos] = block;
- //blocks_to_update[pos] = block;
-
- /*
- Clear all light from block
- */
- for(s16 z=0; z<MAP_BLOCKSIZE; z++)
- for(s16 x=0; x<MAP_BLOCKSIZE; x++)
- for(s16 y=0; y<MAP_BLOCKSIZE; y++)
- {
- v3s16 p(x,y,z);
- bool is_valid_position;
- MapNode n = block->getNode(p, &is_valid_position);
- if (!is_valid_position) {
- /* This would happen when dealing with a
- dummy block.
- */
- infostream<<"updateLighting(): InvalidPositionException"
- <<std::endl;
- continue;
- }
- u8 oldlight = n.getLight(bank, nodemgr);
- n.setLight(bank, 0, nodemgr);
- block->setNode(p, n);
-
- // If node sources light, add to list
- u8 source = nodemgr->get(n).light_source;
- if(source != 0)
- light_sources.insert(p + posnodes);
-
- // Collect borders for unlighting
- if((x==0 || x == MAP_BLOCKSIZE-1
- || y==0 || y == MAP_BLOCKSIZE-1
- || z==0 || z == MAP_BLOCKSIZE-1)
- && oldlight != 0)
- {
- v3s16 p_map = p + posnodes;
- unlight_from[p_map] = oldlight;
- }
-
-
- }
-
- if(bank == LIGHTBANK_DAY)
- {
- bool bottom_valid = block->propagateSunlight(light_sources);
-
- if(!bottom_valid)
- num_bottom_invalid++;
-
- // If bottom is valid, we're done.
- if(bottom_valid)
- break;
- }
- else if(bank == LIGHTBANK_NIGHT)
- {
- // For night lighting, sunlight is not propagated
- break;
- }
- else
- {
- assert("Invalid lighting bank" == NULL);
- }
-
- /*infostream<<"Bottom for sunlight-propagated block ("
- <<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid"
- <<std::endl;*/
-
- // Bottom sunlight is not valid; get the block and loop to it
-
- pos.Y--;
- try{
- block = getBlockNoCreate(pos);
- }
- catch(InvalidPositionException &e)
- {
- FATAL_ERROR("Invalid position");
- }
-
- }
- }
-
- }
-
- /*
- Enable this to disable proper lighting for speeding up map
- generation for testing or whatever
- */
-#if 0
- //if(g_settings->get(""))
- {
- core::map<v3s16, MapBlock*>::Iterator i;
- i = blocks_to_update.getIterator();
- for(; i.atEnd() == false; i++)
- {
- MapBlock *block = i.getNode()->getValue();
- v3s16 p = block->getPos();
- block->setLightingExpired(false);
- }
- return;
- }
-#endif
-
-#if 1
- {
- //TimeTaker timer("unspreadLight");
- unspreadLight(bank, unlight_from, light_sources, modified_blocks);
- }
-
- /*if(debug)
- {
- u32 diff = modified_blocks.size() - count_was;
- count_was = modified_blocks.size();
- infostream<<"unspreadLight modified "<<diff<<std::endl;
- }*/
-
- {
- //TimeTaker timer("spreadLight");
- spreadLight(bank, light_sources, modified_blocks);
- }
-
- /*if(debug)
- {
- u32 diff = modified_blocks.size() - count_was;
- count_was = modified_blocks.size();
- infostream<<"spreadLight modified "<<diff<<std::endl;
- }*/
-#endif
-
-#if 0
- {
- //MapVoxelManipulator vmanip(this);
-
- // Make a manual voxel manipulator and load all the blocks
- // that touch the requested blocks
- ManualMapVoxelManipulator vmanip(this);
-
- {
- //TimeTaker timer("initialEmerge");
-
- core::map<v3s16, MapBlock*>::Iterator i;
- i = blocks_to_update.getIterator();
- for(; i.atEnd() == false; i++)
- {
- MapBlock *block = i.getNode()->getValue();
- v3s16 p = block->getPos();
-
- // Add all surrounding blocks
- vmanip.initialEmerge(p - v3s16(1,1,1), p + v3s16(1,1,1));
-
- /*
- Add all surrounding blocks that have up-to-date lighting
- NOTE: This doesn't quite do the job (not everything
- appropriate is lighted)
- */
- /*for(s16 z=-1; z<=1; z++)
- for(s16 y=-1; y<=1; y++)
- for(s16 x=-1; x<=1; x++)
- {
- v3s16 p2 = p + v3s16(x,y,z);
- MapBlock *block = getBlockNoCreateNoEx(p2);
- if(block == NULL)
- continue;
- if(block->isDummy())
- continue;
- if(block->getLightingExpired())
- continue;
- vmanip.initialEmerge(p2, p2);
- }*/
-
- // Lighting of block will be updated completely
- block->setLightingExpired(false);
- }
- }
-
- {
- //TimeTaker timer("unSpreadLight");
- vmanip.unspreadLight(bank, unlight_from, light_sources, nodemgr);
- }
- {
- //TimeTaker timer("spreadLight");
- vmanip.spreadLight(bank, light_sources, nodemgr);
- }
- {
- //TimeTaker timer("blitBack");
- vmanip.blitBack(modified_blocks);
- }
- /*infostream<<"emerge_time="<<emerge_time<<std::endl;
- emerge_time = 0;*/
- }
-#endif
-
- //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
-}
-
-void Map::updateLighting(std::map<v3s16, MapBlock*> & a_blocks,
- std::map<v3s16, MapBlock*> & modified_blocks)
-{
- updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
- updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
-
- /*
- Update information about whether day and night light differ
- */
- for(std::map<v3s16, MapBlock*>::iterator
- i = modified_blocks.begin();
- i != modified_blocks.end(); ++i)
- {
- MapBlock *block = i->second;
- block->expireDayNightDiff();
- }
-}
-
void Map::addNodeAndUpdate(v3s16 p, MapNode n,
std::map<v3s16, MapBlock*> &modified_blocks,
bool remove_metadata)
{
- INodeDefManager *ndef = m_gamedef->ndef();
-
// Collect old node for rollback
RollbackNode rollback_oldnode(this, p, m_gamedef);
@@ -826,14 +253,14 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
// Set the node on the map
// Ignore light (because calling voxalgo::update_lighting_nodes)
- n.setLight(LIGHTBANK_DAY, 0, ndef);
- n.setLight(LIGHTBANK_NIGHT, 0, ndef);
+ n.setLight(LIGHTBANK_DAY, 0, m_nodedef);
+ n.setLight(LIGHTBANK_NIGHT, 0, m_nodedef);
setNode(p, n);
// Update lighting
std::vector<std::pair<v3s16, MapNode> > oldnodes;
oldnodes.push_back(std::pair<v3s16, MapNode>(p, oldnode));
- voxalgo::update_lighting_nodes(this, ndef, oldnodes, modified_blocks);
+ voxalgo::update_lighting_nodes(this, oldnodes, modified_blocks);
for(std::map<v3s16, MapBlock*>::iterator
i = modified_blocks.begin();
@@ -870,11 +297,10 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
bool is_valid_position;
MapNode n2 = getNodeNoEx(p2, &is_valid_position);
- if(is_valid_position
- && (ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR))
- {
+ if(is_valid_position &&
+ (m_nodedef->get(n2).isLiquid() ||
+ n2.getContent() == CONTENT_AIR))
m_transforming_liquid.push_back(p2);
- }
}
}
@@ -1212,11 +638,9 @@ s32 Map::transforming_liquid_size() {
return m_transforming_liquid.size();
}
-void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
+void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks,
+ ServerEnvironment *env)
{
-
- INodeDefManager *nodemgr = m_gamedef->ndef();
-
DSTACK(FUNCTION_NAME);
//TimeTaker timer("transformLiquids()");
@@ -1276,12 +700,12 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
// The node which will be placed there if liquid
// can't flow into this node.
content_t floodable_node = CONTENT_AIR;
- const ContentFeatures &cf = nodemgr->get(n0);
+ const ContentFeatures &cf = m_nodedef->get(n0);
LiquidType liquid_type = cf.liquid_type;
switch (liquid_type) {
case LIQUID_SOURCE:
liquid_level = LIQUID_LEVEL_SOURCE;
- liquid_kind = nodemgr->getId(cf.liquid_alternative_flowing);
+ liquid_kind = m_nodedef->getId(cf.liquid_alternative_flowing);
break;
case LIQUID_FLOWING:
liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
@@ -1323,8 +747,8 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
}
v3s16 npos = p0 + dirs[i];
NodeNeighbor nb(getNodeNoEx(npos), nt, npos);
- const ContentFeatures &cfnb = nodemgr->get(nb.n);
- switch (nodemgr->get(nb.n.getContent()).liquid_type) {
+ const ContentFeatures &cfnb = m_nodedef->get(nb.n);
+ switch (m_nodedef->get(nb.n.getContent()).liquid_type) {
case LIQUID_NONE:
if (cfnb.floodable) {
airs[num_airs++] = nb;
@@ -1352,8 +776,8 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
case LIQUID_SOURCE:
// if this node is not (yet) of a liquid type, choose the first liquid type we encounter
if (liquid_kind == CONTENT_AIR)
- liquid_kind = nodemgr->getId(cfnb.liquid_alternative_flowing);
- if (nodemgr->getId(cfnb.liquid_alternative_flowing) != liquid_kind) {
+ liquid_kind = m_nodedef->getId(cfnb.liquid_alternative_flowing);
+ if (m_nodedef->getId(cfnb.liquid_alternative_flowing) != liquid_kind) {
neutrals[num_neutrals++] = nb;
} else {
// Do not count bottom source, it will screw things up
@@ -1364,8 +788,8 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
case LIQUID_FLOWING:
// if this node is not (yet) of a liquid type, choose the first liquid type we encounter
if (liquid_kind == CONTENT_AIR)
- liquid_kind = nodemgr->getId(cfnb.liquid_alternative_flowing);
- if (nodemgr->getId(cfnb.liquid_alternative_flowing) != liquid_kind) {
+ liquid_kind = m_nodedef->getId(cfnb.liquid_alternative_flowing);
+ if (m_nodedef->getId(cfnb.liquid_alternative_flowing) != liquid_kind) {
neutrals[num_neutrals++] = nb;
} else {
flows[num_flows++] = nb;
@@ -1383,15 +807,15 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
s8 new_node_level = -1;
s8 max_node_level = -1;
- u8 range = nodemgr->get(liquid_kind).liquid_range;
+ u8 range = m_nodedef->get(liquid_kind).liquid_range;
if (range > LIQUID_LEVEL_MAX + 1)
range = LIQUID_LEVEL_MAX + 1;
- if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
+ if ((num_sources >= 2 && m_nodedef->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
// liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
// or the flowing alternative of the first of the surrounding sources (if it's air), so
// it's perfectly safe to use liquid_kind here to determine the new node content.
- new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source);
+ new_node_content = m_nodedef->getId(m_nodedef->get(liquid_kind).liquid_alternative_source);
} else if (num_sources >= 1 && sources[0].t != NEIGHBOR_LOWER) {
// liquid_kind is set properly, see above
max_node_level = new_node_level = LIQUID_LEVEL_MAX;
@@ -1428,7 +852,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
}
}
- u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
+ u8 viscosity = m_nodedef->get(liquid_kind).liquid_viscosity;
if (viscosity > 1 && max_node_level != liquid_level) {
// amount to gain, limited by viscosity
// must be at least 1 in absolute value
@@ -1456,7 +880,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
check if anything has changed. if not, just continue with the next node.
*/
if (new_node_content == n0.getContent() &&
- (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
+ (m_nodedef->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
== flowing_down)))
@@ -1468,18 +892,26 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
*/
MapNode n00 = n0;
//bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
- if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
+ if (m_nodedef->get(new_node_content).liquid_type == LIQUID_FLOWING) {
// set level to last 3 bits, flowing down bit to 4th bit
n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
} else {
// set the liquid level and flow bit to 0
n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
}
+
+ // change the node.
n0.setContent(new_node_content);
+ // on_flood() the node
+ if (floodable_node != CONTENT_AIR) {
+ if (env->getScriptIface()->node_on_flood(p0, n00, n0))
+ continue;
+ }
+
// Ignore light (because calling voxalgo::update_lighting_nodes)
- n0.setLight(LIGHTBANK_DAY, 0, nodemgr);
- n0.setLight(LIGHTBANK_NIGHT, 0, nodemgr);
+ n0.setLight(LIGHTBANK_DAY, 0, m_nodedef);
+ n0.setLight(LIGHTBANK_NIGHT, 0, m_nodedef);
// Find out whether there is a suspect for this action
std::string suspect;
@@ -1513,7 +945,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
/*
enqueue neighbors for update if neccessary
*/
- switch (nodemgr->get(n0.getContent()).liquid_type) {
+ switch (m_nodedef->get(n0.getContent()).liquid_type) {
case LIQUID_SOURCE:
case LIQUID_FLOWING:
// make sure source flows into all neighboring nodes
@@ -1536,7 +968,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
for (std::deque<v3s16>::iterator iter = must_reflow.begin(); iter != must_reflow.end(); ++iter)
m_transforming_liquid.push_back(*iter);
- voxalgo::update_lighting_nodes(this, nodemgr, changed_nodes, modified_blocks);
+ voxalgo::update_lighting_nodes(this, changed_nodes, modified_blocks);
/* ----------------------------------------------------------------------
@@ -1549,7 +981,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
time_until_purge *= 1000; // seconds -> milliseconds
- u32 curr_time = getTime(PRECISION_MILLI);
+ u64 curr_time = porting::getTimeMs();
u32 prev_unprocessed = m_unprocessed_count;
m_unprocessed_count = m_transforming_liquid.size();
@@ -1735,10 +1167,77 @@ void Map::removeNodeTimer(v3s16 p)
block->m_node_timers.remove(p_rel);
}
+bool Map::isOccluded(v3s16 p0, v3s16 p1, float step, float stepfac,
+ float start_off, float end_off, u32 needed_count)
+{
+ float d0 = (float)BS * p0.getDistanceFrom(p1);
+ v3s16 u0 = p1 - p0;
+ v3f uf = v3f(u0.X, u0.Y, u0.Z) * BS;
+ uf.normalize();
+ v3f p0f = v3f(p0.X, p0.Y, p0.Z) * BS;
+ u32 count = 0;
+ for(float s=start_off; s<d0+end_off; s+=step){
+ v3f pf = p0f + uf * s;
+ v3s16 p = floatToInt(pf, BS);
+ MapNode n = getNodeNoEx(p);
+ const ContentFeatures &f = m_nodedef->get(n);
+ if(f.drawtype == NDT_NORMAL){
+ // not transparent, see ContentFeature::updateTextures
+ count++;
+ if(count >= needed_count)
+ return true;
+ }
+ step *= stepfac;
+ }
+ return false;
+}
+
+bool Map::isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes) {
+ v3s16 cpn = block->getPos() * MAP_BLOCKSIZE;
+ cpn += v3s16(MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2);
+ float step = BS * 1;
+ float stepfac = 1.1;
+ float startoff = BS * 1;
+ // The occlusion search of 'isOccluded()' must stop short of the target
+ // point by distance 'endoff' (end offset) to not enter the target mapblock.
+ // For the 8 mapblock corners 'endoff' must therefore be the maximum diagonal
+ // of a mapblock, because we must consider all view angles.
+ // sqrt(1^2 + 1^2 + 1^2) = 1.732
+ float endoff = -BS * MAP_BLOCKSIZE * 1.732050807569;
+ v3s16 spn = cam_pos_nodes;
+ s16 bs2 = MAP_BLOCKSIZE / 2 + 1;
+ // to reduce the likelihood of falsely occluded blocks
+ // require at least two solid blocks
+ // this is a HACK, we should think of a more precise algorithm
+ u32 needed_count = 2;
+
+ return (
+ // For the central point of the mapblock 'endoff' can be halved
+ isOccluded(spn, cpn,
+ step, stepfac, startoff, endoff / 2.0f, needed_count) &&
+ isOccluded(spn, cpn + v3s16(bs2,bs2,bs2),
+ step, stepfac, startoff, endoff, needed_count) &&
+ isOccluded(spn, cpn + v3s16(bs2,bs2,-bs2),
+ step, stepfac, startoff, endoff, needed_count) &&
+ isOccluded(spn, cpn + v3s16(bs2,-bs2,bs2),
+ step, stepfac, startoff, endoff, needed_count) &&
+ isOccluded(spn, cpn + v3s16(bs2,-bs2,-bs2),
+ step, stepfac, startoff, endoff, needed_count) &&
+ isOccluded(spn, cpn + v3s16(-bs2,bs2,bs2),
+ step, stepfac, startoff, endoff, needed_count) &&
+ isOccluded(spn, cpn + v3s16(-bs2,bs2,-bs2),
+ step, stepfac, startoff, endoff, needed_count) &&
+ isOccluded(spn, cpn + v3s16(-bs2,-bs2,bs2),
+ step, stepfac, startoff, endoff, needed_count) &&
+ isOccluded(spn, cpn + v3s16(-bs2,-bs2,-bs2),
+ step, stepfac, startoff, endoff, needed_count));
+}
+
/*
ServerMap
*/
-ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
+ServerMap::ServerMap(const std::string &savedir, IGameDef *gamedef,
+ EmergeManager *emerge):
Map(dout_server, gamedef),
settings_mgr(g_settings, savedir + DIR_DELIM + "map_meta.txt"),
m_emerge(emerge),
@@ -1879,6 +1378,24 @@ s16 ServerMap::getWaterLevel()
return getMapgenParams()->water_level;
}
+bool ServerMap::saoPositionOverLimit(const v3f &p)
+{
+ return getMapgenParams()->saoPosOverLimit(p);
+}
+
+bool ServerMap::blockpos_over_mapgen_limit(v3s16 p)
+{
+ const s16 mapgen_limit_bp = rangelim(
+ getMapgenParams()->mapgen_limit, 0, MAX_MAP_GENERATION_LIMIT) /
+ MAP_BLOCKSIZE;
+ return p.X < -mapgen_limit_bp ||
+ p.X > mapgen_limit_bp ||
+ p.Y < -mapgen_limit_bp ||
+ p.Y > mapgen_limit_bp ||
+ p.Z < -mapgen_limit_bp ||
+ p.Z > mapgen_limit_bp;
+}
+
bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
{
s16 csize = getMapgenParams()->chunksize;
@@ -1892,16 +1409,16 @@ bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
v3s16 full_bpmin = bpmin - extra_borders;
v3s16 full_bpmax = bpmax + extra_borders;
- // Do nothing if not inside limits (+-1 because of neighbors)
- if (blockpos_over_limit(full_bpmin) ||
- blockpos_over_limit(full_bpmax))
+ // Do nothing if not inside mapgen limits (+-1 because of neighbors)
+ if (blockpos_over_mapgen_limit(full_bpmin) ||
+ blockpos_over_mapgen_limit(full_bpmax))
return false;
data->seed = getSeed();
data->blockpos_min = bpmin;
data->blockpos_max = bpmax;
data->blockpos_requested = blockpos;
- data->nodedef = m_gamedef->ndef();
+ data->nodedef = m_nodedef;
/*
Create the whole area of this and the neighboring blocks
@@ -1968,28 +1485,11 @@ void ServerMap::finishBlockMake(BlockMakeData *data,
v3s16 bpmax = data->blockpos_max;
v3s16 extra_borders(1, 1, 1);
- v3s16 full_bpmin = bpmin - extra_borders;
- v3s16 full_bpmax = bpmax + extra_borders;
bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
EMERGE_DBG_OUT("finishBlockMake(): " PP(bpmin) " - " PP(bpmax));
/*
- Set lighting to non-expired state in all of them.
- This is cheating, but it is not fast enough if all of them
- would actually be updated.
- */
- for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++)
- for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++)
- for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) {
- MapBlock *block = emergeBlock(v3s16(x, y, z), false);
- if (!block)
- continue;
-
- block->setLightingExpired(false);
- }
-
- /*
Blit generated stuff to map
NOTE: blitBackAll adds nearly everything to changed_blocks
*/
@@ -2076,16 +1576,16 @@ ServerMapSector *ServerMap::createSector(v2s16 p2d)
return sector;
}
#endif
+
/*
- Do not create over-limit
+ Do not create over max mapgen limit
*/
- const static u16 map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
- g_settings->getU16("map_generation_limit"));
- if(p2d.X < -map_gen_limit / MAP_BLOCKSIZE
- || p2d.X > map_gen_limit / MAP_BLOCKSIZE
- || p2d.Y < -map_gen_limit / MAP_BLOCKSIZE
- || p2d.Y > map_gen_limit / MAP_BLOCKSIZE)
- throw InvalidPositionException("createSector(): pos. over limit");
+ const s16 max_limit_bp = MAX_MAP_GENERATION_LIMIT / MAP_BLOCKSIZE;
+ if (p2d.X < -max_limit_bp ||
+ p2d.X > max_limit_bp ||
+ p2d.Y < -max_limit_bp ||
+ p2d.Y > max_limit_bp)
+ throw InvalidPositionException("createSector(): pos. over max mapgen limit");
/*
Generate blank sector
@@ -2226,10 +1726,10 @@ MapBlock * ServerMap::createBlock(v3s16 p)
FUNCTION_NAME, p.X, p.Y, p.Z);
/*
- Do not create over-limit
+ Do not create over max mapgen limit
*/
- if (blockpos_over_limit(p))
- throw InvalidPositionException("createBlock(): pos. over limit");
+ if (blockpos_over_max_limit(p))
+ throw InvalidPositionException("createBlock(): pos. over max mapgen limit");
v2s16 p2d(p.X, p.Z);
s16 block_y = p.Y;
@@ -2343,9 +1843,6 @@ MapBlock *ServerMap::getBlockOrEmerge(v3s16 p3d)
return block;
}
-void ServerMap::prepareBlock(MapBlock *block) {
-}
-
// N.B. This requires no synchronization, since data will not be modified unless
// the VoxelManipulator being updated belongs to the same thread.
void ServerMap::updateVManip(v3s16 pos)
@@ -2452,7 +1949,7 @@ std::string ServerMap::getSectorDir(v2s16 pos, int layout)
}
}
-v2s16 ServerMap::getSectorPos(std::string dirname)
+v2s16 ServerMap::getSectorPos(const std::string &dirname)
{
unsigned int x = 0, y = 0;
int r;
@@ -2482,7 +1979,7 @@ v2s16 ServerMap::getSectorPos(std::string dirname)
return pos;
}
-v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
+v3s16 ServerMap::getBlockPos(const std::string &sectordir, const std::string &blockfile)
{
v2s16 p2d = getSectorPos(sectordir);
@@ -2791,13 +2288,13 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
}
#endif
-Database *ServerMap::createDatabase(
+MapDatabase *ServerMap::createDatabase(
const std::string &name,
const std::string &savedir,
Settings &conf)
{
if (name == "sqlite3")
- return new Database_SQLite3(savedir);
+ return new MapDatabaseSQLite3(savedir);
if (name == "dummy")
return new Database_Dummy();
#if USE_LEVELDB
@@ -2809,8 +2306,11 @@ Database *ServerMap::createDatabase(
return new Database_Redis(conf);
#endif
#if USE_POSTGRESQL
- else if (name == "postgresql")
- return new Database_PostgreSQL(conf);
+ else if (name == "postgresql") {
+ std::string connect_string = "";
+ conf.getNoEx("pgsql_connection", connect_string);
+ return new MapDatabasePostgreSQL(connect_string);
+ }
#endif
else
throw BaseException(std::string("Database backend ") + name + " not supported.");
@@ -2831,7 +2331,7 @@ bool ServerMap::saveBlock(MapBlock *block)
return saveBlock(block, dbase);
}
-bool ServerMap::saveBlock(MapBlock *block, Database *db)
+bool ServerMap::saveBlock(MapBlock *block, MapDatabase *db)
{
v3s16 p3d = block->getPos();
@@ -2862,16 +2362,15 @@ bool ServerMap::saveBlock(MapBlock *block, Database *db)
return ret;
}
-void ServerMap::loadBlock(std::string sectordir, std::string blockfile,
+void ServerMap::loadBlock(const std::string &sectordir, const std::string &blockfile,
MapSector *sector, bool save_after_load)
{
DSTACK(FUNCTION_NAME);
std::string fullpath = sectordir + DIR_DELIM + blockfile;
try {
-
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
- if(is.good() == false)
+ if (!is.good())
throw FileNotGoodException("Cannot open block file");
v3s16 p3d = getBlockPos(sectordir, blockfile);
@@ -2956,13 +2455,6 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool
throw SerializationError("ServerMap::loadBlock(): Failed"
" to read MapBlock version");
- /*u32 block_size = MapBlock::serializedLength(version);
- SharedBuffer<u8> data(block_size);
- is.read((char*)*data, block_size);*/
-
- // This will always return a sector because we're the server
- //MapSector *sector = emergeSector(p2d);
-
MapBlock *block = NULL;
bool created_new = false;
block = sector->getBlockNoCreateNoEx(p3d.Y);
@@ -2993,7 +2485,6 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool
// We just loaded it from, so it's up-to-date.
block->resetModified();
-
}
catch(SerializationError &e)
{
@@ -3017,71 +2508,80 @@ MapBlock* ServerMap::loadBlock(v3s16 blockpos)
{
DSTACK(FUNCTION_NAME);
+ bool created_new = (getBlockNoCreateNoEx(blockpos) == NULL);
+
v2s16 p2d(blockpos.X, blockpos.Z);
std::string ret;
dbase->loadBlock(blockpos, &ret);
if (ret != "") {
loadBlock(&ret, blockpos, createSector(p2d), false);
- return getBlockNoCreateNoEx(blockpos);
- }
- // Not found in database, try the files
-
- // The directory layout we're going to load from.
- // 1 - original sectors/xxxxzzzz/
- // 2 - new sectors2/xxx/zzz/
- // If we load from anything but the latest structure, we will
- // immediately save to the new one, and remove the old.
- int loadlayout = 1;
- std::string sectordir1 = getSectorDir(p2d, 1);
- std::string sectordir;
- if(fs::PathExists(sectordir1))
- {
- sectordir = sectordir1;
- }
- else
- {
- loadlayout = 2;
- sectordir = getSectorDir(p2d, 2);
- }
+ } else {
+ // Not found in database, try the files
+
+ // The directory layout we're going to load from.
+ // 1 - original sectors/xxxxzzzz/
+ // 2 - new sectors2/xxx/zzz/
+ // If we load from anything but the latest structure, we will
+ // immediately save to the new one, and remove the old.
+ int loadlayout = 1;
+ std::string sectordir1 = getSectorDir(p2d, 1);
+ std::string sectordir;
+ if (fs::PathExists(sectordir1)) {
+ sectordir = sectordir1;
+ } else {
+ loadlayout = 2;
+ sectordir = getSectorDir(p2d, 2);
+ }
- /*
+ /*
Make sure sector is loaded
- */
+ */
- MapSector *sector = getSectorNoGenerateNoEx(p2d);
- if(sector == NULL)
- {
- try{
- sector = loadSectorMeta(sectordir, loadlayout != 2);
- }
- catch(InvalidFilenameException &e)
- {
- return NULL;
- }
- catch(FileNotGoodException &e)
- {
- return NULL;
- }
- catch(std::exception &e)
- {
- return NULL;
+ MapSector *sector = getSectorNoGenerateNoEx(p2d);
+ if (sector == NULL) {
+ try {
+ sector = loadSectorMeta(sectordir, loadlayout != 2);
+ } catch(InvalidFilenameException &e) {
+ return NULL;
+ } catch(FileNotGoodException &e) {
+ return NULL;
+ } catch(std::exception &e) {
+ return NULL;
+ }
}
- }
- /*
+
+ /*
Make sure file exists
- */
+ */
- std::string blockfilename = getBlockFilename(blockpos);
- if(fs::PathExists(sectordir + DIR_DELIM + blockfilename) == false)
- return NULL;
+ std::string blockfilename = getBlockFilename(blockpos);
+ if (fs::PathExists(sectordir + DIR_DELIM + blockfilename) == false)
+ return NULL;
- /*
+ /*
Load block and save it to the database
- */
- loadBlock(sectordir, blockfilename, sector, true);
- return getBlockNoCreateNoEx(blockpos);
+ */
+ loadBlock(sectordir, blockfilename, sector, true);
+ }
+ MapBlock *block = getBlockNoCreateNoEx(blockpos);
+ if (created_new && (block != NULL)) {
+ std::map<v3s16, MapBlock*> modified_blocks;
+ // Fix lighting if necessary
+ voxalgo::update_block_border_lighting(this, block, modified_blocks);
+ if (!modified_blocks.empty()) {
+ //Modified lighting, send event
+ MapEditEvent event;
+ event.type = MEET_OTHER;
+ std::map<v3s16, MapBlock *>::iterator it;
+ for (it = modified_blocks.begin();
+ it != modified_blocks.end(); ++it)
+ event.modified_blocks.insert(it->first);
+ dispatchEvent(&event);
+ }
+ }
+ return block;
}
bool ServerMap::deleteBlock(v3s16 blockpos)
@@ -3106,6 +2606,16 @@ void ServerMap::PrintInfo(std::ostream &out)
out<<"ServerMap: ";
}
+bool ServerMap::repairBlockLight(v3s16 blockpos,
+ std::map<v3s16, MapBlock *> *modified_blocks)
+{
+ MapBlock *block = emergeBlock(blockpos, false);
+ if (!block || !block->isGenerated())
+ return false;
+ voxalgo::repair_block_light(this, block, modified_blocks);
+ return true;
+}
+
MMVManip::MMVManip(Map *map):
VoxelManipulator(),
m_is_dirty(false),
@@ -3172,7 +2682,7 @@ void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
if(block_data_inexistent)
{
- if (load_if_inexistent) {
+ if (load_if_inexistent && !blockpos_over_max_limit(p)) {
ServerMap *svrmap = (ServerMap *)m_map;
block = svrmap->emergeBlock(p, false);
if (block == NULL)
diff --git a/src/map.h b/src/map.h
index e8d40e982..4b6e08f96 100644
--- a/src/map.h
+++ b/src/map.h
@@ -37,7 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map_settings_manager.h"
class Settings;
-class Database;
+class MapDatabase;
class ClientMap;
class MapSector;
class ServerMapSector;
@@ -193,6 +193,8 @@ public:
virtual MapBlock * emergeBlock(v3s16 p, bool create_blank=true)
{ return getBlockNoCreateNoEx(p); }
+ inline INodeDefManager * getNodeDefManager() { return m_nodedef; }
+
// Returns InvalidPositionException if not found
bool isNodeUnderground(v3s16 p);
@@ -206,22 +208,6 @@ public:
// position is valid, otherwise false
MapNode getNodeNoEx(v3s16 p, bool *is_valid_position = NULL);
- void unspreadLight(enum LightBank bank,
- std::map<v3s16, u8> & from_nodes,
- std::set<v3s16> & light_sources,
- std::map<v3s16, MapBlock*> & modified_blocks);
-
- void spreadLight(enum LightBank bank,
- std::set<v3s16> & from_nodes,
- std::map<v3s16, MapBlock*> & modified_blocks);
-
- void updateLighting(enum LightBank bank,
- std::map<v3s16, MapBlock*> & a_blocks,
- std::map<v3s16, MapBlock*> & modified_blocks);
-
- void updateLighting(std::map<v3s16, MapBlock*> & a_blocks,
- std::map<v3s16, MapBlock*> & modified_blocks);
-
/*
These handle lighting but not faces.
*/
@@ -280,7 +266,8 @@ public:
// For debug printing. Prints "Map: ", "ServerMap: " or "ClientMap: "
virtual void PrintInfo(std::ostream &out);
- void transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks);
+ void transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks,
+ ServerEnvironment *env);
/*
Node metadata
@@ -328,6 +315,7 @@ public:
void transforming_liquid_add(v3s16 p);
s32 transforming_liquid_size();
+ bool isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes);
protected:
friend class LuaVoxelManip;
@@ -346,10 +334,16 @@ protected:
// Queued transforming water nodes
UniqueQueue<v3s16> m_transforming_liquid;
+ // This stores the properties of the nodes on the map.
+ INodeDefManager *m_nodedef;
+
+ bool isOccluded(v3s16 p0, v3s16 p1, float step, float stepfac,
+ float start_off, float end_off, u32 needed_count);
+
private:
f32 m_transforming_liquid_loop_count_multiplier;
u32 m_unprocessed_count;
- u32 m_inc_trending_up_start_time; // milliseconds
+ u64 m_inc_trending_up_start_time; // milliseconds
bool m_queue_size_timer_started;
DISABLE_CLASS_COPY(Map);
@@ -367,7 +361,7 @@ public:
/*
savedir: directory to which map data should be saved
*/
- ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge);
+ ServerMap(const std::string &savedir, IGameDef *gamedef, EmergeManager *emerge);
~ServerMap();
s32 mapType() const
@@ -383,9 +377,12 @@ public:
*/
ServerMapSector *createSector(v2s16 p);
+ bool saoPositionOverLimit(const v3f &p);
+
/*
Blocks are generated by using these and makeBlock().
*/
+ bool blockpos_over_mapgen_limit(v3s16 p);
bool initBlockMake(v3s16 blockpos, BlockMakeData *data);
void finishBlockMake(BlockMakeData *data,
std::map<v3s16, MapBlock*> *changed_blocks);
@@ -414,9 +411,6 @@ public:
*/
MapBlock *getBlockOrEmerge(v3s16 p3d);
- // Carries out any initialization necessary before block is sent
- void prepareBlock(MapBlock *block);
-
// Helper for placing objects on ground level
s16 findGroundLevel(v2s16 p2d);
@@ -428,16 +422,14 @@ public:
// returns something like "map/sectors/xxxxxxxx"
std::string getSectorDir(v2s16 pos, int layout = 2);
// dirname: final directory name
- v2s16 getSectorPos(std::string dirname);
- v3s16 getBlockPos(std::string sectordir, std::string blockfile);
+ v2s16 getSectorPos(const std::string &dirname);
+ v3s16 getBlockPos(const std::string &sectordir, const std::string &blockfile);
static std::string getBlockFilename(v3s16 p);
/*
Database functions
*/
- static Database *createDatabase(const std::string &name, const std::string &savedir, Settings &conf);
- // Verify we can read/write to the database
- void verifyDatabase();
+ static MapDatabase *createDatabase(const std::string &name, const std::string &savedir, Settings &conf);
// Returns true if the database file does not exist
bool loadFromFolders();
@@ -464,17 +456,11 @@ public:
MapSector* loadSectorMeta(std::string dirname, bool save_after_load);
bool loadSectorMeta(v2s16 p2d);
- // Full load of a sector including all blocks.
- // returns true on success, false on failure.
- bool loadSectorFull(v2s16 p2d);
- // If sector is not found in memory, try to load it from disk.
- // Returns true if sector now resides in memory
- //bool deFlushSector(v2s16 p2d);
-
bool saveBlock(MapBlock *block);
- static bool saveBlock(MapBlock *block, Database *db);
+ static bool saveBlock(MapBlock *block, MapDatabase *db);
// This will generate a sector with getSector if not found.
- void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load=false);
+ void loadBlock(const std::string &sectordir, const std::string &blockfile,
+ MapSector *sector, bool save_after_load=false);
MapBlock* loadBlock(v3s16 p);
// Database version
void loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load=false);
@@ -491,6 +477,16 @@ public:
u64 getSeed();
s16 getWaterLevel();
+ /*!
+ * Fixes lighting in one map block.
+ * May modify other blocks as well, as light can spread
+ * out of the specified block.
+ * Returns false if the block is not generated (so nothing
+ * changed), true otherwise.
+ */
+ bool repairBlockLight(v3s16 blockpos,
+ std::map<v3s16, MapBlock *> *modified_blocks);
+
MapSettingsManager settings_mgr;
private:
@@ -513,7 +509,7 @@ private:
This is reset to false when written on disk.
*/
bool m_map_metadata_changed;
- Database *dbase;
+ MapDatabase *dbase;
};
diff --git a/src/map_settings_manager.cpp b/src/map_settings_manager.cpp
index 53d17125c..52f88778c 100644
--- a/src/map_settings_manager.cpp
+++ b/src/map_settings_manager.cpp
@@ -25,14 +25,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map_settings_manager.h"
-MapSettingsManager::MapSettingsManager(
- Settings *user_settings, const std::string &map_meta_path)
+MapSettingsManager::MapSettingsManager(Settings *user_settings,
+ const std::string &map_meta_path):
+ mapgen_params(NULL),
+ m_map_meta_path(map_meta_path),
+ m_map_settings(new Settings()),
+ m_user_settings(user_settings)
{
- m_map_meta_path = map_meta_path;
- m_user_settings = user_settings;
- m_map_settings = new Settings;
- mapgen_params = NULL;
-
assert(m_user_settings != NULL);
}
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index f8747f52b..ec10a49bb 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -35,8 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#endif
#include "util/string.h"
#include "util/serialize.h"
-
-#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
+#include "util/basic_macros.h"
static const char *modified_reason_strings[] = {
"initial",
@@ -74,7 +73,7 @@ MapBlock::MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy):
m_modified(MOD_STATE_WRITE_NEEDED),
m_modified_reason(MOD_REASON_INITIAL),
is_underground(false),
- m_lighting_expired(true),
+ m_lighting_complete(0xFFFF),
m_day_night_differs(false),
m_day_night_differs_expired(true),
m_generated(false),
@@ -572,11 +571,12 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
flags |= 0x01;
if(getDayNightDiff())
flags |= 0x02;
- if(m_lighting_expired)
- flags |= 0x04;
if(m_generated == false)
flags |= 0x08;
writeU8(os, flags);
+ if (version >= 27) {
+ writeU16(os, m_lighting_complete);
+ }
/*
Bulk node data
@@ -611,7 +611,7 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
Node metadata
*/
std::ostringstream oss(std::ios_base::binary);
- m_node_metadata.serialize(oss);
+ m_node_metadata.serialize(oss, version, disk);
compressZlib(oss.str(), os);
/*
@@ -640,19 +640,15 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
}
}
-void MapBlock::serializeNetworkSpecific(std::ostream &os, u16 net_proto_version)
+void MapBlock::serializeNetworkSpecific(std::ostream &os)
{
- if(data == NULL)
- {
+ if (!data) {
throw SerializationError("ERROR: Not writing dummy block.");
}
- if(net_proto_version >= 21){
- int version = 1;
- writeU8(os, version);
- writeF1000(os, 0); // deprecated heat
- writeF1000(os, 0); // deprecated humidity
- }
+ writeU8(os, 1); // version
+ writeF1000(os, 0); // deprecated heat
+ writeF1000(os, 0); // deprecated humidity
}
void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
@@ -673,7 +669,10 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
u8 flags = readU8(is);
is_underground = (flags & 0x01) ? true : false;
m_day_night_differs = (flags & 0x02) ? true : false;
- m_lighting_expired = (flags & 0x04) ? true : false;
+ if (version < 27)
+ m_lighting_complete = 0xFFFF;
+ else
+ m_lighting_complete = readU16(is);
m_generated = (flags & 0x08) ? false : true;
/*
@@ -784,7 +783,7 @@ void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk)
// Initialize default flags
is_underground = false;
m_day_night_differs = false;
- m_lighting_expired = false;
+ m_lighting_complete = 0xFFFF;
m_generated = true;
// Make a temporary buffer
@@ -850,7 +849,6 @@ void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk)
is.read((char*)&flags, 1);
is_underground = (flags & 0x01) ? true : false;
m_day_night_differs = (flags & 0x02) ? true : false;
- m_lighting_expired = (flags & 0x04) ? true : false;
if(version >= 18)
m_generated = (flags & 0x08) ? false : true;
@@ -1028,10 +1026,7 @@ std::string analyze_block(MapBlock *block)
else
desc<<"is_ug [ ], ";
- if(block->getLightingExpired())
- desc<<"lighting_exp [X], ";
- else
- desc<<"lighting_exp [ ], ";
+ desc<<"lighting_complete: "<<block->getLightingComplete()<<", ";
if(block->isDummy())
{
diff --git a/src/mapblock.h b/src/mapblock.h
index 5adfcf3fb..8816dc817 100644
--- a/src/mapblock.h
+++ b/src/mapblock.h
@@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "modifiedstate.h"
#include "util/numeric.h" // getContainerPos
#include "settings.h"
+#include "mapgen.h"
class Map;
class NodeMetadataList;
@@ -105,7 +106,7 @@ public:
#define MOD_REASON_INITIAL (1 << 0)
#define MOD_REASON_REALLOCATE (1 << 1)
#define MOD_REASON_SET_IS_UNDERGROUND (1 << 2)
-#define MOD_REASON_SET_LIGHTING_EXPIRED (1 << 3)
+#define MOD_REASON_SET_LIGHTING_COMPLETE (1 << 3)
#define MOD_REASON_SET_GENERATED (1 << 4)
#define MOD_REASON_SET_NODE (1 << 5)
#define MOD_REASON_SET_NODE_NO_CHECK (1 << 6)
@@ -153,6 +154,11 @@ public:
raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_REALLOCATE);
}
+ MapNode* getData()
+ {
+ return data;
+ }
+
////
//// Modification tracking methods
////
@@ -213,17 +219,42 @@ public:
raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_IS_UNDERGROUND);
}
- inline void setLightingExpired(bool expired)
+ inline void setLightingComplete(u16 newflags)
{
- if (expired != m_lighting_expired){
- m_lighting_expired = expired;
- raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_LIGHTING_EXPIRED);
+ if (newflags != m_lighting_complete) {
+ m_lighting_complete = newflags;
+ raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_LIGHTING_COMPLETE);
}
}
- inline bool getLightingExpired()
+ inline u16 getLightingComplete()
+ {
+ return m_lighting_complete;
+ }
+
+ inline void setLightingComplete(LightBank bank, u8 direction,
+ bool is_complete)
{
- return m_lighting_expired;
+ assert(direction >= 0 && direction <= 5);
+ if (bank == LIGHTBANK_NIGHT) {
+ direction += 6;
+ }
+ u16 newflags = m_lighting_complete;
+ if (is_complete) {
+ newflags |= 1 << direction;
+ } else {
+ newflags &= ~(1 << direction);
+ }
+ setLightingComplete(newflags);
+ }
+
+ inline bool isLightingComplete(LightBank bank, u8 direction)
+ {
+ assert(direction >= 0 && direction <= 5);
+ if (bank == LIGHTBANK_NIGHT) {
+ direction += 6;
+ }
+ return (m_lighting_complete & (1 << direction)) != 0;
}
inline bool isGenerated()
@@ -239,15 +270,6 @@ public:
}
}
- inline bool isValid()
- {
- if (m_lighting_expired)
- return false;
- if (data == NULL)
- return false;
- return true;
- }
-
////
//// Position stuff
////
@@ -305,8 +327,7 @@ public:
inline MapNode getNodeNoEx(v3s16 p)
{
bool is_valid;
- MapNode node = getNode(p.X, p.Y, p.Z, &is_valid);
- return is_valid ? node : MapNode(CONTENT_IGNORE);
+ return getNode(p.X, p.Y, p.Z, &is_valid);
}
inline void setNode(s16 x, s16 y, s16 z, MapNode & n)
@@ -341,6 +362,22 @@ public:
return getNodeNoCheck(p.X, p.Y, p.Z, valid_position);
}
+ ////
+ //// Non-checking, unsafe variants of the above
+ //// MapBlock must be loaded by another function in the same scope/function
+ //// Caller must ensure that this is not a dummy block (by calling isDummy())
+ ////
+
+ inline const MapNode &getNodeUnsafe(s16 x, s16 y, s16 z)
+ {
+ return data[z * zstride + y * ystride + x];
+ }
+
+ inline const MapNode &getNodeUnsafe(v3s16 &p)
+ {
+ return getNodeUnsafe(p.X, p.Y, p.Z);
+ }
+
inline void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
{
if (data == NULL)
@@ -510,9 +547,8 @@ public:
// unknown blocks from id-name mapping to wndef
void deSerialize(std::istream &is, u8 version, bool disk);
- void serializeNetworkSpecific(std::ostream &os, u16 net_proto_version);
+ void serializeNetworkSpecific(std::ostream &os);
void deSerializeNetworkSpecific(std::istream &is);
-
private:
/*
Private methods
@@ -599,14 +635,15 @@ private:
*/
bool is_underground;
- /*
- Set to true if changes has been made that make the old lighting
- values wrong but the lighting hasn't been actually updated.
-
- If this is false, lighting is exactly right.
- If this is true, lighting might be wrong or right.
+ /*!
+ * Each bit indicates if light spreading was finished
+ * in a direction. (Because the neighbor could also be unloaded.)
+ * Bits (most significant first):
+ * nothing, nothing, nothing, nothing,
+ * night X-, night Y-, night Z-, night Z+, night Y+, night X+,
+ * day X-, day Y-, day Z-, day Z+, day Y+, day X+.
*/
- bool m_lighting_expired;
+ u16 m_lighting_complete;
// Whether day and night lighting differs
bool m_day_night_differs;
@@ -639,26 +676,24 @@ typedef std::vector<MapBlock*> MapBlockVect;
inline bool objectpos_over_limit(v3f p)
{
- const static float map_gen_limit_bs = MYMIN(MAX_MAP_GENERATION_LIMIT,
- g_settings->getU16("map_generation_limit")) * BS;
- return (p.X < -map_gen_limit_bs
- || p.X > map_gen_limit_bs
- || p.Y < -map_gen_limit_bs
- || p.Y > map_gen_limit_bs
- || p.Z < -map_gen_limit_bs
- || p.Z > map_gen_limit_bs);
+ const float max_limit_bs = MAX_MAP_GENERATION_LIMIT * BS;
+ return p.X < -max_limit_bs ||
+ p.X > max_limit_bs ||
+ p.Y < -max_limit_bs ||
+ p.Y > max_limit_bs ||
+ p.Z < -max_limit_bs ||
+ p.Z > max_limit_bs;
}
-inline bool blockpos_over_limit(v3s16 p)
+inline bool blockpos_over_max_limit(v3s16 p)
{
- const static u16 map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
- g_settings->getU16("map_generation_limit"));
- return (p.X < -map_gen_limit / MAP_BLOCKSIZE
- || p.X > map_gen_limit / MAP_BLOCKSIZE
- || p.Y < -map_gen_limit / MAP_BLOCKSIZE
- || p.Y > map_gen_limit / MAP_BLOCKSIZE
- || p.Z < -map_gen_limit / MAP_BLOCKSIZE
- || p.Z > map_gen_limit / MAP_BLOCKSIZE);
+ const s16 max_limit_bp = MAX_MAP_GENERATION_LIMIT / MAP_BLOCKSIZE;
+ return p.X < -max_limit_bp ||
+ p.X > max_limit_bp ||
+ p.Y < -max_limit_bp ||
+ p.Y > max_limit_bp ||
+ p.Z < -max_limit_bp ||
+ p.Z > max_limit_bp;
}
/*
diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp
index 00f83e7ab..6781f21af 100644
--- a/src/mapblock_mesh.cpp
+++ b/src/mapblock_mesh.cpp
@@ -23,7 +23,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h"
#include "profiler.h"
#include "nodedef.h"
-#include "gamedef.h"
#include "mesh.h"
#include "minimap.h"
#include "content_mapblock.h"
@@ -33,71 +32,59 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/directiontables.h"
#include <IMeshManipulator.h>
-static void applyFacesShading(video::SColor &color, const float factor)
-{
- color.setRed(core::clamp(core::round32(color.getRed() * factor), 0, 255));
- color.setGreen(core::clamp(core::round32(color.getGreen() * factor), 0, 255));
-}
-
/*
MeshMakeData
*/
-MeshMakeData::MeshMakeData(IGameDef *gamedef, bool use_shaders,
+MeshMakeData::MeshMakeData(Client *client, bool use_shaders,
bool use_tangent_vertices):
m_vmanip(),
m_blockpos(-1337,-1337,-1337),
m_crack_pos_relative(-1337, -1337, -1337),
m_smooth_lighting(false),
m_show_hud(false),
- m_gamedef(gamedef),
+ m_client(client),
m_use_shaders(use_shaders),
m_use_tangent_vertices(use_tangent_vertices)
{}
-void MeshMakeData::fill(MapBlock *block)
+void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
{
- m_blockpos = block->getPos();
+ m_blockpos = blockpos;
v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
- /*
- Copy data
- */
-
- // Allocate this block + neighbors
m_vmanip.clear();
VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE,
blockpos_nodes + v3s16(1,1,1) * MAP_BLOCKSIZE*2-v3s16(1,1,1));
m_vmanip.addArea(voxel_area);
+}
- {
- //TimeTaker timer("copy central block data");
- // 0ms
+void MeshMakeData::fillBlockData(const v3s16 &block_offset, MapNode *data)
+{
+ v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
+ VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
- // Copy our data
- block->copyTo(m_vmanip);
- }
- {
- //TimeTaker timer("copy neighbor block data");
- // 0ms
+ v3s16 bp = m_blockpos + block_offset;
+ v3s16 blockpos_nodes = bp * MAP_BLOCKSIZE;
+ m_vmanip.copyFrom(data, data_area, v3s16(0,0,0), blockpos_nodes, data_size);
+}
- /*
- Copy neighbors. This is lightning fast.
- Copying only the borders would be *very* slow.
- */
+void MeshMakeData::fill(MapBlock *block)
+{
+ fillBlockDataBegin(block->getPos());
- // Get map
- Map *map = block->getParent();
+ fillBlockData(v3s16(0,0,0), block->getData());
- for(u16 i=0; i<26; i++)
- {
- const v3s16 &dir = g_26dirs[i];
- v3s16 bp = m_blockpos + dir;
- MapBlock *b = map->getBlockNoCreateNoEx(bp);
- if(b)
- b->copyTo(m_vmanip);
- }
+ // Get map for reading neigbhor blocks
+ Map *map = block->getParent();
+
+ for (u16 i=0; i<26; i++) {
+ const v3s16 &dir = g_26dirs[i];
+ v3s16 bp = m_blockpos + dir;
+ MapBlock *b = map->getBlockNoCreateNoEx(bp);
+ if(b)
+ fillBlockData(dir, b->getData());
}
}
@@ -233,7 +220,7 @@ static u16 getSmoothLightCombined(v3s16 p, MeshMakeData *data)
v3s16(1,1,1),
};
- INodeDefManager *ndef = data->m_gamedef->ndef();
+ INodeDefManager *ndef = data->m_client->ndef();
u16 ambient_occlusion = 0;
u16 light_count = 0;
@@ -243,7 +230,7 @@ static u16 getSmoothLightCombined(v3s16 p, MeshMakeData *data)
for (u32 i = 0; i < 8; i++)
{
- const MapNode &n = data->m_vmanip.getNodeRefUnsafeCheckFlags(p - dirs8[i]);
+ MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p - dirs8[i]);
// if it's CONTENT_IGNORE we can't do any light calculations
if (n.getContent() == CONTENT_IGNORE) {
@@ -322,19 +309,34 @@ u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
return getSmoothLightCombined(p, data);
}
-/*
- Converts from day + night color values (0..255)
- and a given daynight_ratio to the final SColor shown on screen.
-*/
-void finalColorBlend(video::SColor& result,
- u8 day, u8 night, u32 daynight_ratio)
+void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){
+ f32 rg = daynight_ratio / 1000.0f - 0.04f;
+ f32 b = (0.98f * daynight_ratio) / 1000.0f + 0.078f;
+ sunlight->r = rg;
+ sunlight->g = rg;
+ sunlight->b = b;
+}
+
+void final_color_blend(video::SColor *result,
+ u16 light, u32 daynight_ratio)
{
- s32 rg = (day * daynight_ratio + night * (1000-daynight_ratio)) / 1000;
- s32 b = rg;
+ video::SColorf dayLight;
+ get_sunlight_color(&dayLight, daynight_ratio);
+ final_color_blend(result,
+ encode_light(light, 0), dayLight);
+}
- // Moonlight is blue
- b += (day - night) / 13;
- rg -= (day - night) / 23;
+void final_color_blend(video::SColor *result,
+ const video::SColor &data, const video::SColorf &dayLight)
+{
+ static const video::SColorf artificialColor(1.04f, 1.04f, 1.04f);
+
+ video::SColorf c(data);
+ f32 n = 1 - c.a;
+
+ f32 r = c.r * (c.a * dayLight.r + n * artificialColor.r) * 2.0f;
+ f32 g = c.g * (c.a * dayLight.g + n * artificialColor.g) * 2.0f;
+ f32 b = c.b * (c.a * dayLight.b + n * artificialColor.b) * 2.0f;
// Emphase blue a bit in darker places
// Each entry of this array represents a range of 8 blue levels
@@ -342,19 +344,13 @@ void finalColorBlend(video::SColor& result,
1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
- b += emphase_blue_when_dark[irr::core::clamp(b, 0, 255) / 8];
- b = irr::core::clamp(b, 0, 255);
- // Artificial light is yellow-ish
- static const u8 emphase_yellow_when_artificial[16] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 10, 15, 15, 15
- };
- rg += emphase_yellow_when_artificial[night/16];
- rg = irr::core::clamp(rg, 0, 255);
+ b += emphase_blue_when_dark[irr::core::clamp((s32) ((r + g + b) / 3 * 255),
+ 0, 255) / 8] / 255.0f;
- result.setRed(rg);
- result.setGreen(rg);
- result.setBlue(b);
+ result->setRed(core::clamp((s32) (r * 255.0f), 0, 255));
+ result->setGreen(core::clamp((s32) (g * 255.0f), 0, 255));
+ result->setBlue(core::clamp((s32) (b * 255.0f), 0, 255));
}
/*
@@ -426,12 +422,19 @@ static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
struct FastFace
{
- TileSpec tile;
+ TileLayer layer;
video::S3DVertex vertices[4]; // Precalculated vertices
+ /*!
+ * The face is divided into two triangles. If this is true,
+ * vertices 0 and 2 are connected, othervise vertices 1 and 3
+ * are connected.
+ */
+ bool vertex_0_2_connected;
+ u8 layernum;
};
-static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
- v3f p, v3s16 dir, v3f scale, u8 light_source, std::vector<FastFace> &dest)
+static void makeFastFace(const TileSpec &tile, u16 li0, u16 li1, u16 li2, u16 li3,
+ v3f p, v3s16 dir, v3f scale, std::vector<FastFace> &dest)
{
// Position is at the center of the cube.
v3f pos = p * BS;
@@ -581,26 +584,50 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
v3f normal(dir.X, dir.Y, dir.Z);
- u8 alpha = tile.alpha;
+ u16 li[4] = { li0, li1, li2, li3 };
+ u16 day[4];
+ u16 night[4];
+
+ for (u8 i = 0; i < 4; i++) {
+ day[i] = li[i] >> 8;
+ night[i] = li[i] & 0xFF;
+ }
+
+ bool vertex_0_2_connected = abs(day[0] - day[2]) + abs(night[0] - night[2])
+ < abs(day[1] - day[3]) + abs(night[1] - night[3]);
+
+ v2f32 f[4] = {
+ core::vector2d<f32>(x0 + w * abs_scale, y0 + h),
+ core::vector2d<f32>(x0, y0 + h),
+ core::vector2d<f32>(x0, y0),
+ core::vector2d<f32>(x0 + w * abs_scale, y0) };
- dest.push_back(FastFace());
+ for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
+ const TileLayer *layer = &tile.layers[layernum];
+ if (layer->texture_id == 0)
+ continue;
+
+ dest.push_back(FastFace());
+ FastFace& face = *dest.rbegin();
- FastFace& face = *dest.rbegin();
+ for (u8 i = 0; i < 4; i++) {
+ video::SColor c = encode_light(li[i], tile.emissive_light);
+ if (!tile.emissive_light)
+ applyFacesShading(c, normal);
- face.vertices[0] = video::S3DVertex(vertex_pos[0], normal,
- MapBlock_LightColor(alpha, li0, light_source),
- core::vector2d<f32>(x0+w*abs_scale, y0+h));
- face.vertices[1] = video::S3DVertex(vertex_pos[1], normal,
- MapBlock_LightColor(alpha, li1, light_source),
- core::vector2d<f32>(x0, y0+h));
- face.vertices[2] = video::S3DVertex(vertex_pos[2], normal,
- MapBlock_LightColor(alpha, li2, light_source),
- core::vector2d<f32>(x0, y0));
- face.vertices[3] = video::S3DVertex(vertex_pos[3], normal,
- MapBlock_LightColor(alpha, li3, light_source),
- core::vector2d<f32>(x0+w*abs_scale, y0));
+ face.vertices[i] = video::S3DVertex(vertex_pos[i], normal, c, f[i]);
+ }
- face.tile = tile;
+ /*
+ Revert triangles for nicer looking gradient if the
+ brightness of vertices 1 and 3 differ less than
+ the brightness of vertices 0 and 2.
+ */
+ face.vertex_0_2_connected = vertex_0_2_connected;
+
+ face.layer = *layer;
+ face.layernum = layernum;
+ }
}
/*
@@ -662,22 +689,31 @@ static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
/*
Gets nth node tile (0 <= n <= 5).
*/
-TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data)
+void getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data, TileSpec &tile)
{
- INodeDefManager *ndef = data->m_gamedef->ndef();
- TileSpec spec = ndef->get(mn).tiles[tileindex];
+ INodeDefManager *ndef = data->m_client->ndef();
+ const ContentFeatures &f = ndef->get(mn);
+ tile = f.tiles[tileindex];
+ TileLayer *top_layer = NULL;
+ for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
+ TileLayer *layer = &tile.layers[layernum];
+ if (layer->texture_id == 0)
+ continue;
+ top_layer = layer;
+ if (!layer->has_color)
+ mn.getColor(f, &(layer->color));
+ }
// Apply temporary crack
if (p == data->m_crack_pos_relative)
- spec.material_flags |= MATERIAL_FLAG_CRACK;
- return spec;
+ top_layer->material_flags |= MATERIAL_FLAG_CRACK;
}
/*
Gets node tile given a face direction.
*/
-TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
+void getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data, TileSpec &tile)
{
- INodeDefManager *ndef = data->m_gamedef->ndef();
+ INodeDefManager *ndef = data->m_client->ndef();
// Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
// (0,0,1), (0,0,-1) or (0,0,0)
@@ -732,10 +768,8 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
};
u16 tile_index=facedir*16 + dir_i;
- TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data);
- spec.rotation=dir_to_tile[tile_index + 1];
- spec.texture = data->m_gamedef->tsrc()->getTexture(spec.texture_id);
- return spec;
+ getNodeTileN(mn, p, dir_to_tile[tile_index], data, tile);
+ tile.rotation = dir_to_tile[tile_index + 1];
}
static void getTileInfo(
@@ -748,15 +782,14 @@ static void getTileInfo(
v3s16 &p_corrected,
v3s16 &face_dir_corrected,
u16 *lights,
- TileSpec &tile,
- u8 &light_source
+ TileSpec &tile
)
{
VoxelManipulator &vmanip = data->m_vmanip;
- INodeDefManager *ndef = data->m_gamedef->ndef();
+ INodeDefManager *ndef = data->m_client->ndef();
v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
- MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
+ const MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
// Don't even try to get n1 if n0 is already CONTENT_IGNORE
if (n0.getContent() == CONTENT_IGNORE) {
@@ -776,51 +809,48 @@ static void getTileInfo(
u8 mf = face_contents(n0.getContent(), n1.getContent(),
&equivalent, ndef);
- if(mf == 0)
- {
+ if (mf == 0) {
makes_face = false;
return;
}
makes_face = true;
- if(mf == 1)
- {
- tile = getNodeTile(n0, p, face_dir, data);
+ MapNode n = n0;
+
+ if (mf == 1) {
p_corrected = p;
face_dir_corrected = face_dir;
- light_source = ndef->get(n0).light_source;
- }
- else
- {
- tile = getNodeTile(n1, p + face_dir, -face_dir, data);
+ } else {
+ n = n1;
p_corrected = p + face_dir;
face_dir_corrected = -face_dir;
- light_source = ndef->get(n1).light_source;
}
+ getNodeTile(n, p_corrected, face_dir_corrected, data, tile);
+ const ContentFeatures &f = ndef->get(n);
+ tile.emissive_light = f.light_source;
+
// eg. water and glass
- if(equivalent)
- tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
+ if (equivalent) {
+ for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++)
+ tile.layers[layernum].material_flags |=
+ MATERIAL_FLAG_BACKFACE_CULLING;
+ }
- if(data->m_smooth_lighting == false)
- {
+ if (!data->m_smooth_lighting) {
lights[0] = lights[1] = lights[2] = lights[3] =
getFaceLight(n0, n1, face_dir, ndef);
}
- else
- {
+ else {
v3s16 vertex_dirs[4];
getNodeVertexDirs(face_dir_corrected, vertex_dirs);
- for(u16 i=0; i<4; i++)
- {
- lights[i] = getSmoothLight(
- blockpos_nodes + p_corrected,
- vertex_dirs[i], data);
+
+ v3s16 light_p = blockpos_nodes + p_corrected;
+ for (u16 i = 0; i < 4; i++) {
+ lights[i] = getSmoothLight(light_p, vertex_dirs[i], data);
}
}
-
- return;
}
/*
@@ -846,13 +876,13 @@ static void updateFastFaceRow(
v3s16 face_dir_corrected;
u16 lights[4] = {0,0,0,0};
TileSpec tile;
- u8 light_source = 0;
getTileInfo(data, p, face_dir,
makes_face, p_corrected, face_dir_corrected,
- lights, tile, light_source);
+ lights, tile);
- for(u16 j=0; j<MAP_BLOCKSIZE; j++)
- {
+ // Unroll this variable which has a significant build cost
+ TileSpec next_tile;
+ for (u16 j = 0; j < MAP_BLOCKSIZE; j++) {
// If tiling can be done, this is set to false in the next step
bool next_is_different = true;
@@ -862,70 +892,38 @@ static void updateFastFaceRow(
v3s16 next_p_corrected;
v3s16 next_face_dir_corrected;
u16 next_lights[4] = {0,0,0,0};
- TileSpec next_tile;
- u8 next_light_source = 0;
+
// If at last position, there is nothing to compare to and
// the face must be drawn anyway
- if(j != MAP_BLOCKSIZE - 1)
- {
+ if (j != MAP_BLOCKSIZE - 1) {
p_next = p + translate_dir;
getTileInfo(data, p_next, face_dir,
next_makes_face, next_p_corrected,
next_face_dir_corrected, next_lights,
- next_tile, next_light_source);
+ next_tile);
- if(next_makes_face == makes_face
+ if (next_makes_face == makes_face
&& next_p_corrected == p_corrected + translate_dir
&& next_face_dir_corrected == face_dir_corrected
- && next_lights[0] == lights[0]
- && next_lights[1] == lights[1]
- && next_lights[2] == lights[2]
- && next_lights[3] == lights[3]
- && next_tile == tile
- && tile.rotation == 0
- && next_light_source == light_source
- && (tile.material_flags & MATERIAL_FLAG_TILEABLE_HORIZONTAL)
- && (tile.material_flags & MATERIAL_FLAG_TILEABLE_VERTICAL)) {
+ && memcmp(next_lights, lights, ARRLEN(lights) * sizeof(u16)) == 0
+ && next_tile.isTileable(tile)) {
next_is_different = false;
continuous_tiles_count++;
- } 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);*/
}
- if(next_is_different)
- {
+ if (next_is_different) {
/*
Create a face if there should be one
*/
- if(makes_face)
- {
+ if (makes_face) {
// Floating point conversion of the position vector
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 - 0.5) * translate_dir_f;
+ v3f sp = pf -
+ ((f32)continuous_tiles_count / 2.0f - 0.5f) * translate_dir_f;
v3f scale(1,1,1);
if(translate_dir.X != 0) {
@@ -939,8 +937,7 @@ static void updateFastFaceRow(
}
makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
- sp, face_dir_corrected, scale, light_source,
- dest);
+ sp, face_dir_corrected, scale, dest);
g_profiler->avg("Meshgen: faces drawn by tiling", 0);
for(int i = 1; i < continuous_tiles_count; i++){
@@ -954,12 +951,9 @@ static void updateFastFaceRow(
makes_face = next_makes_face;
p_corrected = next_p_corrected;
face_dir_corrected = next_face_dir_corrected;
- lights[0] = next_lights[0];
- lights[1] = next_lights[1];
- lights[2] = next_lights[2];
- lights[3] = next_lights[3];
- tile = next_tile;
- light_source = next_light_source;
+ std::memcpy(lights, next_lights, ARRLEN(lights) * sizeof(u16));
+ if (next_is_different)
+ tile = next_tile;
p = p_next;
}
}
@@ -1018,18 +1012,19 @@ static void updateAllFastFaceRows(MeshMakeData *data,
*/
MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
- m_mesh(new scene::SMesh()),
m_minimap_mapblock(NULL),
- m_gamedef(data->m_gamedef),
- m_driver(m_gamedef->tsrc()->getDevice()->getVideoDriver()),
- m_tsrc(m_gamedef->getTextureSource()),
- m_shdrsrc(m_gamedef->getShaderSource()),
+ m_client(data->m_client),
+ m_driver(m_client->tsrc()->getDevice()->getVideoDriver()),
+ m_tsrc(m_client->getTextureSource()),
+ m_shdrsrc(m_client->getShaderSource()),
m_animation_force_timer(0), // force initial animation
m_last_crack(-1),
m_crack_materials(),
m_last_daynight_ratio((u32) -1),
m_daynight_diffs()
{
+ for (int m = 0; m < MAX_TILE_LAYERS; m++)
+ m_mesh[m] = new scene::SMesh();
m_enable_shaders = data->m_use_shaders;
m_use_tangent_vertices = data->m_use_tangent_vertices;
m_enable_vbo = g_settings->getBool("enable_vbo");
@@ -1078,21 +1073,14 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
const u16 indices[] = {0,1,2,2,3,0};
const u16 indices_alternate[] = {0,1,3,2,3,1};
- if(f.tile.texture == NULL)
+ if (f.layer.texture == NULL)
continue;
- const u16 *indices_p = indices;
-
- /*
- Revert triangles for nicer looking gradient if vertices
- 1 and 3 have same color or 0 and 2 have different color.
- getRed() is the day color.
- */
- if(f.vertices[0].Color.getRed() != f.vertices[2].Color.getRed()
- || f.vertices[1].Color.getRed() == f.vertices[3].Color.getRed())
- indices_p = indices_alternate;
+ const u16 *indices_p =
+ f.vertex_0_2_connected ? indices : indices_alternate;
- collector.append(f.tile, f.vertices, 4, indices_p, 6);
+ collector.append(f.layer, f.vertices, 4, indices_p, 6,
+ f.layernum);
}
}
@@ -1104,162 +1092,155 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
- whatever
*/
- mapblock_mesh_generate_special(data, collector);
+ {
+ MapblockMeshGenerator generator(data, &collector);
+ generator.generate();
+ }
+
+ collector.applyTileColors();
/*
Convert MeshCollector to SMesh
*/
- for(u32 i = 0; i < collector.prebuffers.size(); i++)
- {
- PreMeshBuffer &p = collector.prebuffers[i];
-
- // Generate animation data
- // - Cracks
- if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
+ for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
+ for(u32 i = 0; i < collector.prebuffers[layer].size(); i++)
{
- // Find the texture name plus ^[crack:N:
- std::ostringstream os(std::ios::binary);
- os<<m_tsrc->getTextureName(p.tile.texture_id)<<"^[crack";
- if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
- os<<"o"; // use ^[cracko
- os<<":"<<(u32)p.tile.animation_frame_count<<":";
- m_crack_materials.insert(std::make_pair(i, os.str()));
- // Replace tile texture with the cracked one
- p.tile.texture = m_tsrc->getTextureForMesh(
- os.str()+"0",
- &p.tile.texture_id);
- }
- // - Texture animation
- if(p.tile.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
- {
- // Add to MapBlockMesh in order to animate these tiles
- m_animation_tiles[i] = p.tile;
- m_animation_frames[i] = 0;
- if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
- // Get starting position from noise
- m_animation_frame_offsets[i] = 100000 * (2.0 + noise3d(
- data->m_blockpos.X, data->m_blockpos.Y,
- data->m_blockpos.Z, 0));
- } else {
- // Play all synchronized
- m_animation_frame_offsets[i] = 0;
- }
- // Replace tile texture with the first animation frame
- FrameSpec animation_frame = p.tile.frames[0];
- p.tile.texture = animation_frame.texture;
- }
+ PreMeshBuffer &p = collector.prebuffers[layer][i];
- u32 vertex_count = m_use_tangent_vertices ?
- p.tangent_vertices.size() : p.vertices.size();
- for (u32 j = 0; j < vertex_count; j++) {
- v3f *Normal;
- video::SColor *vc;
- if (m_use_tangent_vertices) {
- vc = &p.tangent_vertices[j].Color;
- Normal = &p.tangent_vertices[j].Normal;
- } else {
- vc = &p.vertices[j].Color;
- Normal = &p.vertices[j].Normal;
+ // Generate animation data
+ // - Cracks
+ if(p.layer.material_flags & MATERIAL_FLAG_CRACK)
+ {
+ // Find the texture name plus ^[crack:N:
+ std::ostringstream os(std::ios::binary);
+ os<<m_tsrc->getTextureName(p.layer.texture_id)<<"^[crack";
+ if(p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
+ os<<"o"; // use ^[cracko
+ os<<":"<<(u32)p.layer.animation_frame_count<<":";
+ m_crack_materials.insert(std::make_pair(std::pair<u8, u32>(layer, i), os.str()));
+ // Replace tile texture with the cracked one
+ p.layer.texture = m_tsrc->getTextureForMesh(
+ os.str()+"0",
+ &p.layer.texture_id);
}
- // Note applyFacesShading second parameter is precalculated sqrt
- // value for speed improvement
- // Skip it for lightsources and top faces.
- if (!vc->getBlue()) {
- if (Normal->Y < -0.5) {
- applyFacesShading(*vc, 0.447213);
- } else if (Normal->X > 0.5) {
- applyFacesShading(*vc, 0.670820);
- } else if (Normal->X < -0.5) {
- applyFacesShading(*vc, 0.670820);
- } else if (Normal->Z > 0.5) {
- applyFacesShading(*vc, 0.836660);
- } else if (Normal->Z < -0.5) {
- applyFacesShading(*vc, 0.836660);
+ // - Texture animation
+ if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
+ // Add to MapBlockMesh in order to animate these tiles
+ m_animation_tiles[std::pair<u8, u32>(layer, i)] = p.layer;
+ m_animation_frames[std::pair<u8, u32>(layer, i)] = 0;
+ if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
+ // Get starting position from noise
+ m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 100000 * (2.0 + noise3d(
+ data->m_blockpos.X, data->m_blockpos.Y,
+ data->m_blockpos.Z, 0));
+ } else {
+ // Play all synchronized
+ m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 0;
}
+ // Replace tile texture with the first animation frame
+ p.layer.texture = p.layer.frames[0].texture;
}
+
if (!m_enable_shaders) {
- // - Classic lighting (shaders handle this by themselves)
- // Set initial real color and store for later updates
- u8 day = vc->getRed();
- u8 night = vc->getGreen();
- finalColorBlend(*vc, day, night, 1000);
- if (day != night) {
- m_daynight_diffs[i][j] = std::make_pair(day, night);
+ // Extract colors for day-night animation
+ // Dummy sunlight to handle non-sunlit areas
+ video::SColorf sunlight;
+ get_sunlight_color(&sunlight, 0);
+ u32 vertex_count =
+ m_use_tangent_vertices ?
+ p.tangent_vertices.size() : p.vertices.size();
+ for (u32 j = 0; j < vertex_count; j++) {
+ video::SColor *vc;
+ if (m_use_tangent_vertices) {
+ vc = &p.tangent_vertices[j].Color;
+ } else {
+ vc = &p.vertices[j].Color;
+ }
+ video::SColor copy(*vc);
+ if (vc->getAlpha() == 0) // No sunlight - no need to animate
+ final_color_blend(vc, copy, sunlight); // Finalize color
+ else // Record color to animate
+ m_daynight_diffs[std::pair<u8, u32>(layer, i)][j] = copy;
+
+ // The sunlight ratio has been stored,
+ // delete alpha (for the final rendering).
+ vc->setAlpha(255);
}
}
- }
- // Create material
- 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.setTexture(0, p.tile.texture);
+ // Create material
+ 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.setTexture(0, p.layer.texture);
+
+ if (m_enable_shaders) {
+ material.MaterialType = m_shdrsrc->getShaderInfo(p.layer.shader_id).material;
+ p.layer.applyMaterialOptionsWithShaders(material);
+ if (p.layer.normal_texture) {
+ material.setTexture(1, p.layer.normal_texture);
+ }
+ material.setTexture(2, p.layer.flags_texture);
+ } else {
+ p.layer.applyMaterialOptions(material);
+ }
- if (m_enable_shaders) {
- material.MaterialType = m_shdrsrc->getShaderInfo(p.tile.shader_id).material;
- p.tile.applyMaterialOptionsWithShaders(material);
- if (p.tile.normal_texture) {
- material.setTexture(1, p.tile.normal_texture);
+ scene::SMesh *mesh = (scene::SMesh *)m_mesh[layer];
+
+ // Create meshbuffer, add to mesh
+ if (m_use_tangent_vertices) {
+ scene::SMeshBufferTangents *buf = new scene::SMeshBufferTangents();
+ // Set material
+ buf->Material = material;
+ // Add to mesh
+ mesh->addMeshBuffer(buf);
+ // Mesh grabbed it
+ buf->drop();
+ buf->append(&p.tangent_vertices[0], p.tangent_vertices.size(),
+ &p.indices[0], p.indices.size());
+ } else {
+ scene::SMeshBuffer *buf = new scene::SMeshBuffer();
+ // Set material
+ buf->Material = material;
+ // Add to mesh
+ mesh->addMeshBuffer(buf);
+ // Mesh grabbed it
+ buf->drop();
+ buf->append(&p.vertices[0], p.vertices.size(),
+ &p.indices[0], p.indices.size());
}
- material.setTexture(2, p.tile.flags_texture);
- } else {
- p.tile.applyMaterialOptions(material);
}
- scene::SMesh *mesh = (scene::SMesh *)m_mesh;
- // Create meshbuffer, add to mesh
+ /*
+ Do some stuff to the mesh
+ */
+ m_camera_offset = camera_offset;
+ translateMesh(m_mesh[layer],
+ intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
+
if (m_use_tangent_vertices) {
- scene::SMeshBufferTangents *buf = new scene::SMeshBufferTangents();
- // Set material
- buf->Material = material;
- // Add to mesh
- mesh->addMeshBuffer(buf);
- // Mesh grabbed it
- buf->drop();
- buf->append(&p.tangent_vertices[0], p.tangent_vertices.size(),
- &p.indices[0], p.indices.size());
- } else {
- scene::SMeshBuffer *buf = new scene::SMeshBuffer();
- // Set material
- buf->Material = material;
- // Add to mesh
- mesh->addMeshBuffer(buf);
- // Mesh grabbed it
- buf->drop();
- buf->append(&p.vertices[0], p.vertices.size(),
- &p.indices[0], p.indices.size());
+ scene::IMeshManipulator* meshmanip =
+ m_client->getSceneManager()->getMeshManipulator();
+ meshmanip->recalculateTangents(m_mesh[layer], true, false, false);
}
- }
- /*
- Do some stuff to the mesh
- */
- m_camera_offset = camera_offset;
- translateMesh(m_mesh,
- intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
-
- if (m_use_tangent_vertices) {
- scene::IMeshManipulator* meshmanip =
- m_gamedef->getSceneManager()->getMeshManipulator();
- meshmanip->recalculateTangents(m_mesh, true, false, false);
- }
-
- if (m_mesh)
- {
+ if (m_mesh[layer])
+ {
#if 0
- // Usually 1-700 faces and 1-7 materials
- std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
- <<"and uses "<<m_mesh->getMeshBufferCount()
- <<" materials (meshbuffers)"<<std::endl;
+ // Usually 1-700 faces and 1-7 materials
+ std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
+ <<"and uses "<<m_mesh[layer]->getMeshBufferCount()
+ <<" materials (meshbuffers)"<<std::endl;
#endif
- // Use VBO for mesh (this just would set this for ever buffer)
- if (m_enable_vbo) {
- m_mesh->setHardwareMappingHint(scene::EHM_STATIC);
+ // Use VBO for mesh (this just would set this for ever buffer)
+ if (m_enable_vbo) {
+ m_mesh[layer]->setHardwareMappingHint(scene::EHM_STATIC);
+ }
}
}
@@ -1274,14 +1255,15 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
MapBlockMesh::~MapBlockMesh()
{
- if (m_enable_vbo && m_mesh) {
- for (u32 i = 0; i < m_mesh->getMeshBufferCount(); i++) {
- scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i);
- m_driver->removeHardwareBuffer(buf);
- }
+ for (int m = 0; m < MAX_TILE_LAYERS; m++) {
+ if (m_enable_vbo && m_mesh[m])
+ for (u32 i = 0; i < m_mesh[m]->getMeshBufferCount(); i++) {
+ scene::IMeshBuffer *buf = m_mesh[m]->getMeshBuffer(i);
+ m_driver->removeHardwareBuffer(buf);
+ }
+ m_mesh[m]->drop();
+ m_mesh[m] = NULL;
}
- m_mesh->drop();
- m_mesh = NULL;
delete m_minimap_mapblock;
}
@@ -1298,9 +1280,10 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
// Cracks
if(crack != m_last_crack)
{
- for (UNORDERED_MAP<u32, std::string>::iterator i = m_crack_materials.begin();
- i != m_crack_materials.end(); ++i) {
- scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
+ for (std::map<std::pair<u8, u32>, std::string>::iterator i =
+ m_crack_materials.begin(); i != m_crack_materials.end(); ++i) {
+ scene::IMeshBuffer *buf = m_mesh[i->first.first]->
+ getMeshBuffer(i->first.second);
std::string basename = i->second;
// Create new texture name from original
@@ -1313,10 +1296,10 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
// If the current material is also animated,
// update animation info
- UNORDERED_MAP<u32, TileSpec>::iterator anim_iter =
- m_animation_tiles.find(i->first);
+ std::map<std::pair<u8, u32>, TileLayer>::iterator anim_iter =
+ m_animation_tiles.find(i->first);
if (anim_iter != m_animation_tiles.end()){
- TileSpec &tile = anim_iter->second;
+ TileLayer &tile = anim_iter->second;
tile.texture = new_texture;
tile.texture_id = new_texture_id;
// force animation update
@@ -1328,9 +1311,9 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
}
// Texture animation
- for (UNORDERED_MAP<u32, TileSpec>::iterator i = m_animation_tiles.begin();
- i != m_animation_tiles.end(); ++i) {
- const TileSpec &tile = i->second;
+ for (std::map<std::pair<u8, u32>, TileLayer>::iterator i =
+ m_animation_tiles.begin(); i != m_animation_tiles.end(); ++i) {
+ const TileLayer &tile = i->second;
// Figure out current frame
int frameoffset = m_animation_frame_offsets[i->first];
int frame = (int)(time * 1000 / tile.animation_frame_length_ms
@@ -1341,9 +1324,10 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
m_animation_frames[i->first] = frame;
- scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
+ scene::IMeshBuffer *buf = m_mesh[i->first.first]->
+ getMeshBuffer(i->first.second);
- FrameSpec animation_frame = tile.frames[frame];
+ const FrameSpec &animation_frame = tile.frames[frame];
buf->getMaterial().setTexture(0, animation_frame.texture);
if (m_enable_shaders) {
if (animation_frame.normal_texture) {
@@ -1357,22 +1341,24 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
if(!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio))
{
// Force reload mesh to VBO
- if (m_enable_vbo) {
- m_mesh->setDirty();
- }
- for(std::map<u32, std::map<u32, std::pair<u8, u8> > >::iterator
+ if (m_enable_vbo)
+ for (int m = 0; m < MAX_TILE_LAYERS; m++)
+ m_mesh[m]->setDirty();
+ video::SColorf day_color;
+ get_sunlight_color(&day_color, daynight_ratio);
+ for(std::map<std::pair<u8, u32>, std::map<u32, video::SColor > >::iterator
i = m_daynight_diffs.begin();
i != m_daynight_diffs.end(); ++i)
{
- scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
+ scene::IMeshBuffer *buf = m_mesh[i->first.first]->
+ getMeshBuffer(i->first.second);
video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
- for(std::map<u32, std::pair<u8, u8 > >::iterator
+ for(std::map<u32, video::SColor >::iterator
j = i->second.begin();
j != i->second.end(); ++j)
{
- u8 day = j->second.first;
- u8 night = j->second.second;
- finalColorBlend(vertices[j->first].Color, day, night, daynight_ratio);
+ final_color_blend(&(vertices[j->first].Color),
+ j->second, day_color);
}
}
m_last_daynight_ratio = daynight_ratio;
@@ -1384,9 +1370,12 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
{
if (camera_offset != m_camera_offset) {
- translateMesh(m_mesh, intToFloat(m_camera_offset-camera_offset, BS));
- if (m_enable_vbo) {
- m_mesh->setDirty();
+ for (u8 layer = 0; layer < 2; layer++) {
+ translateMesh(m_mesh[layer],
+ intToFloat(m_camera_offset - camera_offset, BS));
+ if (m_enable_vbo) {
+ m_mesh[layer]->setDirty();
+ }
}
m_camera_offset = camera_offset;
}
@@ -1400,15 +1389,29 @@ void MeshCollector::append(const TileSpec &tile,
const video::S3DVertex *vertices, u32 numVertices,
const u16 *indices, u32 numIndices)
{
+ for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
+ const TileLayer *layer = &tile.layers[layernum];
+ if (layer->texture_id == 0)
+ continue;
+ append(*layer, vertices, numVertices, indices, numIndices,
+ layernum);
+ }
+}
+
+void MeshCollector::append(const TileLayer &layer,
+ const video::S3DVertex *vertices, u32 numVertices,
+ const u16 *indices, u32 numIndices, u8 layernum)
+{
if (numIndices > 65535) {
dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
return;
}
+ std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
PreMeshBuffer *p = NULL;
- for (u32 i = 0; i < prebuffers.size(); i++) {
- PreMeshBuffer &pp = prebuffers[i];
- if (pp.tile != tile)
+ for (u32 i = 0; i < buffers->size(); i++) {
+ PreMeshBuffer &pp = (*buffers)[i];
+ if (pp.layer != layer)
continue;
if (pp.indices.size() + numIndices > 65535)
continue;
@@ -1419,9 +1422,9 @@ void MeshCollector::append(const TileSpec &tile,
if (p == NULL) {
PreMeshBuffer pp;
- pp.tile = tile;
- prebuffers.push_back(pp);
- p = &prebuffers[prebuffers.size() - 1];
+ pp.layer = layer;
+ buffers->push_back(pp);
+ p = &(*buffers)[buffers->size() - 1];
}
u32 vertex_count;
@@ -1454,17 +1457,32 @@ void MeshCollector::append(const TileSpec &tile,
void MeshCollector::append(const TileSpec &tile,
const video::S3DVertex *vertices, u32 numVertices,
const u16 *indices, u32 numIndices,
- v3f pos, video::SColor c)
+ v3f pos, video::SColor c, u8 light_source)
+{
+ for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
+ const TileLayer *layer = &tile.layers[layernum];
+ if (layer->texture_id == 0)
+ continue;
+ append(*layer, vertices, numVertices, indices, numIndices, pos,
+ c, light_source, layernum);
+ }
+}
+
+void MeshCollector::append(const TileLayer &layer,
+ const video::S3DVertex *vertices, u32 numVertices,
+ const u16 *indices, u32 numIndices,
+ v3f pos, video::SColor c, u8 light_source, u8 layernum)
{
if (numIndices > 65535) {
dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
return;
}
+ std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
PreMeshBuffer *p = NULL;
- for (u32 i = 0; i < prebuffers.size(); i++) {
- PreMeshBuffer &pp = prebuffers[i];
- if(pp.tile != tile)
+ for (u32 i = 0; i < buffers->size(); i++) {
+ PreMeshBuffer &pp = (*buffers)[i];
+ if(pp.layer != layer)
continue;
if(pp.indices.size() + numIndices > 65535)
continue;
@@ -1475,15 +1493,20 @@ void MeshCollector::append(const TileSpec &tile,
if (p == NULL) {
PreMeshBuffer pp;
- pp.tile = tile;
- prebuffers.push_back(pp);
- p = &prebuffers[prebuffers.size() - 1];
+ pp.layer = layer;
+ buffers->push_back(pp);
+ p = &(*buffers)[buffers->size() - 1];
}
+ video::SColor original_c = c;
u32 vertex_count;
if (m_use_tangent_vertices) {
vertex_count = p->tangent_vertices.size();
for (u32 i = 0; i < numVertices; i++) {
+ if (!light_source) {
+ c = original_c;
+ applyFacesShading(c, vertices[i].Normal);
+ }
video::S3DVertexTangents vert(vertices[i].Pos + pos,
vertices[i].Normal, c, vertices[i].TCoords);
p->tangent_vertices.push_back(vert);
@@ -1491,8 +1514,12 @@ void MeshCollector::append(const TileSpec &tile,
} else {
vertex_count = p->vertices.size();
for (u32 i = 0; i < numVertices; i++) {
- video::S3DVertex vert(vertices[i].Pos + pos,
- vertices[i].Normal, c, vertices[i].TCoords);
+ if (!light_source) {
+ c = original_c;
+ applyFacesShading(c, vertices[i].Normal);
+ }
+ video::S3DVertex vert(vertices[i].Pos + pos, vertices[i].Normal, c,
+ vertices[i].TCoords);
p->vertices.push_back(vert);
}
}
@@ -1502,3 +1529,67 @@ void MeshCollector::append(const TileSpec &tile,
p->indices.push_back(j);
}
}
+
+void MeshCollector::applyTileColors()
+{
+ if (m_use_tangent_vertices)
+ for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
+ std::vector<PreMeshBuffer> *p = &prebuffers[layer];
+ for (std::vector<PreMeshBuffer>::iterator it = p->begin();
+ it != p->end(); ++it) {
+ video::SColor tc = it->layer.color;
+ if (tc == video::SColor(0xFFFFFFFF))
+ continue;
+ for (u32 index = 0; index < it->tangent_vertices.size(); index++) {
+ video::SColor *c = &it->tangent_vertices[index].Color;
+ c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
+ c->getGreen() * tc.getGreen() / 255,
+ c->getBlue() * tc.getBlue() / 255);
+ }
+ }
+ }
+ else
+ for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
+ std::vector<PreMeshBuffer> *p = &prebuffers[layer];
+ for (std::vector<PreMeshBuffer>::iterator it = p->begin();
+ it != p->end(); ++it) {
+ video::SColor tc = it->layer.color;
+ if (tc == video::SColor(0xFFFFFFFF))
+ continue;
+ for (u32 index = 0; index < it->vertices.size(); index++) {
+ video::SColor *c = &it->vertices[index].Color;
+ c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
+ c->getGreen() * tc.getGreen() / 255,
+ c->getBlue() * tc.getBlue() / 255);
+ }
+ }
+ }
+}
+
+video::SColor encode_light(u16 light, u8 emissive_light)
+{
+ // Get components
+ u32 day = (light & 0xff);
+ u32 night = (light >> 8);
+ // Add emissive light
+ night += emissive_light * 2.5f;
+ if (night > 255)
+ night = 255;
+ // Since we don't know if the day light is sunlight or
+ // artificial light, assume it is artificial when the night
+ // light bank is also lit.
+ if (day < night)
+ day = 0;
+ else
+ day = day - night;
+ u32 sum = day + night;
+ // Ratio of sunlight:
+ u32 r;
+ if (sum > 0)
+ r = day * 255 / sum;
+ else
+ r = 0;
+ // Average light:
+ float b = (day + night) / 2;
+ return video::SColor(r, b, b, b);
+}
diff --git a/src/mapblock_mesh.h b/src/mapblock_mesh.h
index 8376468da..93d932a7b 100644
--- a/src/mapblock_mesh.h
+++ b/src/mapblock_mesh.h
@@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/cpp11_container.h"
#include <map>
-class IGameDef;
+class Client;
class IShaderSource;
/*
@@ -45,14 +45,20 @@ struct MeshMakeData
bool m_smooth_lighting;
bool m_show_hud;
- IGameDef *m_gamedef;
+ Client *m_client;
bool m_use_shaders;
bool m_use_tangent_vertices;
- MeshMakeData(IGameDef *gamedef, bool use_shaders,
+ MeshMakeData(Client *client, bool use_shaders,
bool use_tangent_vertices = false);
/*
+ Copy block data manually (to allow optimizations by the caller)
+ */
+ void fillBlockDataBegin(const v3s16 &blockpos);
+ void fillBlockData(const v3s16 &block_offset, MapNode *data);
+
+ /*
Copy central data directly from block, and other data from
parent of block.
*/
@@ -102,7 +108,12 @@ public:
scene::IMesh *getMesh()
{
- return m_mesh;
+ return m_mesh[0];
+ }
+
+ scene::IMesh *getMesh(u8 layer)
+ {
+ return m_mesh[layer];
}
MinimapMapblock *moveMinimapMapblock()
@@ -126,9 +137,9 @@ public:
void updateCameraOffset(v3s16 camera_offset);
private:
- scene::IMesh *m_mesh;
+ scene::IMesh *m_mesh[MAX_TILE_LAYERS];
MinimapMapblock *m_minimap_mapblock;
- IGameDef *m_gamedef;
+ Client *m_client;
video::IVideoDriver *m_driver;
ITextureSource *m_tsrc;
IShaderSource *m_shdrsrc;
@@ -144,20 +155,23 @@ private:
// Animation info: cracks
// Last crack value passed to animate()
int m_last_crack;
- // Maps mesh buffer (i.e. material) indices to base texture names
- UNORDERED_MAP<u32, std::string> m_crack_materials;
+ // Maps mesh and mesh buffer (i.e. material) indices to base texture names
+ std::map<std::pair<u8, u32>, std::string> m_crack_materials;
// Animation info: texture animationi
- // Maps meshbuffers to TileSpecs
- UNORDERED_MAP<u32, TileSpec> m_animation_tiles;
- UNORDERED_MAP<u32, int> m_animation_frames; // last animation frame
- UNORDERED_MAP<u32, int> m_animation_frame_offsets;
+ // Maps mesh and mesh buffer indices to TileSpecs
+ // Keys are pairs of (mesh index, buffer index in the mesh)
+ std::map<std::pair<u8, u32>, TileLayer> m_animation_tiles;
+ std::map<std::pair<u8, u32>, int> m_animation_frames; // last animation frame
+ std::map<std::pair<u8, u32>, int> m_animation_frame_offsets;
// Animation info: day/night transitions
// Last daynight_ratio value passed to animate()
u32 m_last_daynight_ratio;
- // For each meshbuffer, maps vertex indices to (day,night) pairs
- std::map<u32, std::map<u32, std::pair<u8, u8> > > m_daynight_diffs;
+ // For each mesh and mesh buffer, stores pre-baked colors
+ // of sunlit vertices
+ // Keys are pairs of (mesh index, buffer index in the mesh)
+ std::map<std::pair<u8, u32>, std::map<u32, video::SColor > > m_daynight_diffs;
// Camera offset info -> do we have to translate the mesh?
v3s16 m_camera_offset;
@@ -170,7 +184,7 @@ private:
*/
struct PreMeshBuffer
{
- TileSpec tile;
+ TileLayer layer;
std::vector<u16> indices;
std::vector<video::S3DVertex> vertices;
std::vector<video::S3DVertexTangents> tangent_vertices;
@@ -178,7 +192,7 @@ struct PreMeshBuffer
struct MeshCollector
{
- std::vector<PreMeshBuffer> prebuffers;
+ std::vector<PreMeshBuffer> prebuffers[MAX_TILE_LAYERS];
bool m_use_tangent_vertices;
MeshCollector(bool use_tangent_vertices):
@@ -187,38 +201,76 @@ struct MeshCollector
}
void append(const TileSpec &material,
+ const video::S3DVertex *vertices, u32 numVertices,
+ const u16 *indices, u32 numIndices);
+ void append(const TileLayer &material,
const video::S3DVertex *vertices, u32 numVertices,
- const u16 *indices, u32 numIndices);
+ const u16 *indices, u32 numIndices, u8 layernum);
void append(const TileSpec &material,
+ const video::S3DVertex *vertices, u32 numVertices,
+ const u16 *indices, u32 numIndices, v3f pos,
+ video::SColor c, u8 light_source);
+ void append(const TileLayer &material,
const video::S3DVertex *vertices, u32 numVertices,
- const u16 *indices, u32 numIndices,
- v3f pos, video::SColor c);
+ const u16 *indices, u32 numIndices, v3f pos,
+ video::SColor c, u8 light_source, u8 layernum);
+ /*!
+ * Colorizes all vertices in the collector.
+ */
+ void applyTileColors();
};
-// This encodes
-// alpha in the A channel of the returned SColor
-// day light (0-255) in the R channel of the returned SColor
-// night light (0-255) in the G channel of the returned SColor
-// light source (0-255) in the B channel of the returned SColor
-inline video::SColor MapBlock_LightColor(u8 alpha, u16 light, u8 light_source=0)
-{
- return video::SColor(alpha, (light & 0xff), (light >> 8), light_source);
-}
+/*!
+ * Encodes light of a node.
+ * The result is not the final color, but a
+ * half-baked vertex color.
+ * You have to multiply the resulting color
+ * with the node's color.
+ *
+ * \param light the first 8 bits are day light,
+ * the last 8 bits are night light
+ * \param emissive_light amount of light the surface emits,
+ * from 0 to LIGHT_SUN.
+ */
+video::SColor encode_light(u16 light, u8 emissive_light);
// Compute light at node
u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef);
u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef);
u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data);
-// Converts from day + night color values (0..255)
-// and a given daynight_ratio to the final SColor shown on screen.
-void finalColorBlend(video::SColor& result,
- u8 day, u8 night, u32 daynight_ratio);
+/*!
+ * Returns the sunlight's color from the current
+ * day-night ratio.
+ */
+void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio);
+
+/*!
+ * Gives the final SColor shown on screen.
+ *
+ * \param result output color
+ * \param light first 8 bits are day light, second 8 bits are
+ * night light
+ */
+void final_color_blend(video::SColor *result,
+ u16 light, u32 daynight_ratio);
+
+/*!
+ * Gives the final SColor shown on screen.
+ *
+ * \param result output color
+ * \param data the half-baked vertex color
+ * \param dayLight color of the sunlight
+ */
+void final_color_blend(video::SColor *result,
+ const video::SColor &data, const video::SColorf &dayLight);
// Retrieves the TileSpec of a face of a node
// Adds MATERIAL_FLAG_CRACK if the node is cracked
-TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data);
-TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data);
+// TileSpec should be passed as reference due to the underlying TileFrame and its vector
+// TileFrame vector copy cost very much to client
+void getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data, TileSpec &tile);
+void getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data, TileSpec &tile);
#endif
diff --git a/src/mapgen.cpp b/src/mapgen.cpp
index fd4f5858f..1f7f98621 100644
--- a/src/mapgen.cpp
+++ b/src/mapgen.cpp
@@ -1,7 +1,8 @@
/*
Minetest
-Copyright (C) 2010-2015 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
Copyright (C) 2010-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2013-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2015-2017 paramat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -84,7 +85,7 @@ static MapgenDesc g_reg_mapgens[] = {
{"flat", true},
{"fractal", true},
{"valleys", true},
- {"singlenode", false},
+ {"singlenode", true},
};
STATIC_ASSERT(
@@ -97,11 +98,12 @@ STATIC_ASSERT(
Mapgen::Mapgen()
{
- generating = false;
- id = -1;
- seed = 0;
- water_level = 0;
- flags = 0;
+ generating = false;
+ id = -1;
+ seed = 0;
+ water_level = 0;
+ mapgen_limit = 0;
+ flags = 0;
vm = NULL;
ndef = NULL;
@@ -114,11 +116,12 @@ Mapgen::Mapgen()
Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge) :
gennotify(emerge->gen_notify_on, &emerge->gen_notify_on_deco_ids)
{
- generating = false;
- id = mapgenid;
- water_level = params->water_level;
- flags = params->flags;
- csize = v3s16(1, 1, 1) * (params->chunksize * MAP_BLOCKSIZE);
+ generating = false;
+ id = mapgenid;
+ water_level = params->water_level;
+ mapgen_limit = params->mapgen_limit;
+ flags = params->flags;
+ csize = v3s16(1, 1, 1) * (params->chunksize * MAP_BLOCKSIZE);
/*
We are losing half our entropy by doing this, but it is necessary to
@@ -314,7 +317,6 @@ void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax)
heightmap[index] = y;
}
}
- //printf("updateHeightmap: %dus\n", t.stop());
}
inline bool Mapgen::isLiquidHorizontallyFlowable(u32 vi, v3s16 em)
@@ -587,35 +589,39 @@ MapgenBasic::MapgenBasic(int mapgenid, MapgenParams *params, EmergeManager *emer
//// Look up some commonly used content
c_stone = ndef->getId("mapgen_stone");
- c_water_source = ndef->getId("mapgen_water_source");
c_desert_stone = ndef->getId("mapgen_desert_stone");
c_sandstone = ndef->getId("mapgen_sandstone");
+ c_water_source = ndef->getId("mapgen_water_source");
c_river_water_source = ndef->getId("mapgen_river_water_source");
+ c_lava_source = ndef->getId("mapgen_lava_source");
// Fall back to more basic content if not defined
+ // river_water_source cannot fallback to water_source because river water
+ // needs to be non-renewable and have a short flow range.
if (c_desert_stone == CONTENT_IGNORE)
c_desert_stone = c_stone;
if (c_sandstone == CONTENT_IGNORE)
c_sandstone = c_stone;
- if (c_river_water_source == CONTENT_IGNORE)
- c_river_water_source = c_water_source;
//// Content used for dungeon generation
- c_cobble = ndef->getId("mapgen_cobble");
- c_stair_cobble = ndef->getId("mapgen_stair_cobble");
- c_mossycobble = ndef->getId("mapgen_mossycobble");
- c_sandstonebrick = ndef->getId("mapgen_sandstonebrick");
- c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");
+ c_cobble = ndef->getId("mapgen_cobble");
+ c_mossycobble = ndef->getId("mapgen_mossycobble");
+ c_stair_cobble = ndef->getId("mapgen_stair_cobble");
+ c_stair_desert_stone = ndef->getId("mapgen_stair_desert_stone");
+ c_sandstonebrick = ndef->getId("mapgen_sandstonebrick");
+ c_stair_sandstone_block = ndef->getId("mapgen_stair_sandstone_block");
// Fall back to more basic content if not defined
if (c_mossycobble == CONTENT_IGNORE)
c_mossycobble = c_cobble;
if (c_stair_cobble == CONTENT_IGNORE)
c_stair_cobble = c_cobble;
+ if (c_stair_desert_stone == CONTENT_IGNORE)
+ c_stair_desert_stone = c_desert_stone;
if (c_sandstonebrick == CONTENT_IGNORE)
c_sandstonebrick = c_sandstone;
- if (c_stair_sandstonebrick == CONTENT_IGNORE)
- c_stair_sandstonebrick = c_sandstone;
+ if (c_stair_sandstone_block == CONTENT_IGNORE)
+ c_stair_sandstone_block = c_sandstonebrick;
}
@@ -835,6 +841,18 @@ void MapgenBasic::generateCaves(s16 max_stone_y, s16 large_cave_depth)
}
+bool MapgenBasic::generateCaverns(s16 max_stone_y)
+{
+ if (node_min.Y > max_stone_y || node_min.Y > cavern_limit)
+ return false;
+
+ CavernsNoise caverns_noise(ndef, csize, &np_cavern,
+ seed, cavern_limit, cavern_taper, cavern_threshold);
+
+ return caverns_noise.generateCaverns(vm, node_min, node_max);
+}
+
+
void MapgenBasic::generateDungeons(s16 max_stone_y, MgStoneType stone_type)
{
if (max_stone_y < node_min.Y)
@@ -842,47 +860,61 @@ void MapgenBasic::generateDungeons(s16 max_stone_y, MgStoneType stone_type)
DungeonParams dp;
- dp.seed = seed;
- dp.c_water = c_water_source;
- dp.c_river_water = c_river_water_source;
- dp.rooms_min = 2;
- dp.rooms_max = 16;
- dp.y_min = -MAX_MAP_GENERATION_LIMIT;
- dp.y_max = MAX_MAP_GENERATION_LIMIT;
- dp.np_density = nparams_dungeon_density;
- dp.np_alt_wall = nparams_dungeon_alt_wall;
+ dp.seed = seed;
+ dp.c_water = c_water_source;
+ dp.c_river_water = c_river_water_source;
+
+ dp.only_in_ground = true;
+ dp.corridor_len_min = 1;
+ dp.corridor_len_max = 13;
+ dp.rooms_min = 2;
+ dp.rooms_max = 16;
+ dp.y_min = -MAX_MAP_GENERATION_LIMIT;
+ dp.y_max = MAX_MAP_GENERATION_LIMIT;
+
+ dp.np_density = nparams_dungeon_density;
+ dp.np_alt_wall = nparams_dungeon_alt_wall;
switch (stone_type) {
default:
case MGSTONE_STONE:
- dp.c_wall = c_cobble;
- dp.c_alt_wall = c_mossycobble;
- dp.c_stair = c_stair_cobble;
-
- dp.diagonal_dirs = false;
- dp.holesize = v3s16(1, 2, 1);
- dp.roomsize = v3s16(0, 0, 0);
- dp.notifytype = GENNOTIFY_DUNGEON;
+ dp.c_wall = c_cobble;
+ dp.c_alt_wall = c_mossycobble;
+ dp.c_stair = c_stair_cobble;
+
+ dp.diagonal_dirs = false;
+ dp.holesize = v3s16(1, 2, 1);
+ dp.room_size_min = v3s16(4, 4, 4);
+ dp.room_size_max = v3s16(8, 6, 8);
+ dp.room_size_large_min = v3s16(8, 8, 8);
+ dp.room_size_large_max = v3s16(16, 16, 16);
+ dp.notifytype = GENNOTIFY_DUNGEON;
break;
case MGSTONE_DESERT_STONE:
- dp.c_wall = c_desert_stone;
- dp.c_alt_wall = CONTENT_IGNORE;
- dp.c_stair = c_desert_stone;
-
- dp.diagonal_dirs = true;
- dp.holesize = v3s16(2, 3, 2);
- dp.roomsize = v3s16(2, 5, 2);
- dp.notifytype = GENNOTIFY_TEMPLE;
+ dp.c_wall = c_desert_stone;
+ dp.c_alt_wall = CONTENT_IGNORE;
+ dp.c_stair = c_stair_desert_stone;
+
+ dp.diagonal_dirs = true;
+ dp.holesize = v3s16(2, 3, 2);
+ dp.room_size_min = v3s16(6, 9, 6);
+ dp.room_size_max = v3s16(10, 11, 10);
+ dp.room_size_large_min = v3s16(10, 13, 10);
+ dp.room_size_large_max = v3s16(18, 21, 18);
+ dp.notifytype = GENNOTIFY_TEMPLE;
break;
case MGSTONE_SANDSTONE:
- dp.c_wall = c_sandstonebrick;
- dp.c_alt_wall = CONTENT_IGNORE;
- dp.c_stair = c_sandstonebrick;
-
- dp.diagonal_dirs = false;
- dp.holesize = v3s16(2, 2, 2);
- dp.roomsize = v3s16(2, 0, 2);
- dp.notifytype = GENNOTIFY_DUNGEON;
+ dp.c_wall = c_sandstonebrick;
+ dp.c_alt_wall = CONTENT_IGNORE;
+ dp.c_stair = c_stair_sandstone_block;
+
+ dp.diagonal_dirs = false;
+ dp.holesize = v3s16(2, 2, 2);
+ dp.room_size_min = v3s16(6, 4, 6);
+ dp.room_size_max = v3s16(10, 6, 10);
+ dp.room_size_large_min = v3s16(10, 8, 10);
+ dp.room_size_large_max = v3s16(18, 16, 18);
+ dp.notifytype = GENNOTIFY_DUNGEON;
break;
}
@@ -984,10 +1016,14 @@ void MapgenParams::readParams(const Settings *settings)
}
std::string mg_name;
- if (settings->getNoEx("mg_name", mg_name))
- this->mgtype = Mapgen::getMapgenType(mg_name);
+ if (settings->getNoEx("mg_name", mg_name)) {
+ mgtype = Mapgen::getMapgenType(mg_name);
+ if (mgtype == MAPGEN_INVALID)
+ mgtype = MAPGEN_DEFAULT;
+ }
settings->getS16NoEx("water_level", water_level);
+ settings->getS16NoEx("mapgen_limit", mapgen_limit);
settings->getS16NoEx("chunksize", chunksize);
settings->getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
@@ -1005,9 +1041,61 @@ void MapgenParams::writeParams(Settings *settings) const
settings->set("mg_name", Mapgen::getMapgenName(mgtype));
settings->setU64("seed", seed);
settings->setS16("water_level", water_level);
+ settings->setS16("mapgen_limit", mapgen_limit);
settings->setS16("chunksize", chunksize);
settings->setFlagStr("mg_flags", flags, flagdesc_mapgen, U32_MAX);
if (bparams)
bparams->writeParams(settings);
}
+
+// Calculate edges of outermost generated mapchunks (less than
+// 'mapgen_limit'), and corresponding exact limits for SAO entities.
+void MapgenParams::calcMapgenEdges()
+{
+ // Central chunk offset, in blocks
+ s16 ccoff_b = -chunksize / 2;
+
+ // Chunksize, in nodes
+ s32 csize_n = chunksize * MAP_BLOCKSIZE;
+
+ // Minp/maxp of central chunk, in nodes
+ s16 ccmin = ccoff_b * MAP_BLOCKSIZE;
+ s16 ccmax = ccmin + csize_n - 1;
+ // Fullminp/fullmaxp of central chunk, in nodes
+ s16 ccfmin = ccmin - MAP_BLOCKSIZE;
+ s16 ccfmax = ccmax + MAP_BLOCKSIZE;
+ // Effective mapgen limit, in blocks
+ // Uses same calculation as ServerMap::blockpos_over_mapgen_limit(v3s16 p)
+ s16 mapgen_limit_b = rangelim(mapgen_limit,
+ 0, MAX_MAP_GENERATION_LIMIT) / MAP_BLOCKSIZE;
+ // Effective mapgen limits, in nodes
+ s16 mapgen_limit_min = -mapgen_limit_b * MAP_BLOCKSIZE;
+ s16 mapgen_limit_max = (mapgen_limit_b + 1) * MAP_BLOCKSIZE - 1;
+ // Number of complete chunks from central chunk fullminp/fullmaxp
+ // to effective mapgen limits.
+ s16 numcmin = MYMAX((ccfmin - mapgen_limit_min) / csize_n, 0);
+ s16 numcmax = MYMAX((mapgen_limit_max - ccfmax) / csize_n, 0);
+ // Mapgen edges, in nodes
+ // These values may be useful later as additional class members
+ s16 mapgen_edge_min = ccmin - numcmin * csize_n;
+ s16 mapgen_edge_max = ccmax + numcmax * csize_n;
+ // SAO position limits, in Irrlicht units
+ m_sao_limit_min = mapgen_edge_min * BS - 3.0f;
+ m_sao_limit_max = mapgen_edge_max * BS + 3.0f;
+}
+
+
+bool MapgenParams::saoPosOverLimit(const v3f &p)
+{
+ if (!m_sao_limit_calculated) {
+ calcMapgenEdges();
+ m_sao_limit_calculated = true;
+ }
+ return p.X < m_sao_limit_min ||
+ p.X > m_sao_limit_max ||
+ p.Y < m_sao_limit_min ||
+ p.Y > m_sao_limit_max ||
+ p.Z < m_sao_limit_min ||
+ p.Z > m_sao_limit_max;
+}
diff --git a/src/mapgen.h b/src/mapgen.h
index b18bfb930..222838011 100644
--- a/src/mapgen.h
+++ b/src/mapgen.h
@@ -1,6 +1,8 @@
/*
Minetest
-Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2010-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2013-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2015-2017 paramat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -124,6 +126,7 @@ struct MapgenParams {
s16 chunksize;
u64 seed;
s16 water_level;
+ s16 mapgen_limit;
u32 flags;
BiomeParams *bparams;
@@ -133,8 +136,12 @@ struct MapgenParams {
chunksize(5),
seed(0),
water_level(1),
+ mapgen_limit(MAX_MAP_GENERATION_LIMIT),
flags(MG_CAVES | MG_LIGHT | MG_DECORATIONS),
- bparams(NULL)
+ bparams(NULL),
+ m_sao_limit_min(MAX_MAP_GENERATION_LIMIT * BS),
+ m_sao_limit_max(MAX_MAP_GENERATION_LIMIT * BS),
+ m_sao_limit_calculated(false)
{
}
@@ -142,6 +149,14 @@ struct MapgenParams {
virtual void readParams(const Settings *settings);
virtual void writeParams(Settings *settings) const;
+
+ bool saoPosOverLimit(const v3f &p);
+private:
+ void calcMapgenEdges();
+
+ float m_sao_limit_min;
+ float m_sao_limit_max;
+ bool m_sao_limit_calculated;
};
@@ -158,6 +173,7 @@ class Mapgen {
public:
s32 seed;
int water_level;
+ int mapgen_limit;
u32 flags;
bool generating;
int id;
@@ -240,6 +256,7 @@ public:
virtual ~MapgenBasic();
virtual void generateCaves(s16 max_stone_y, s16 large_cave_depth);
+ virtual bool generateCaverns(s16 max_stone_y);
virtual void generateDungeons(s16 max_stone_y, MgStoneType stone_type);
virtual MgStoneType generateBiomes();
virtual void dustTopNodes();
@@ -257,17 +274,19 @@ protected:
// Content required for generateBiomes
content_t c_stone;
- content_t c_water_source;
- content_t c_river_water_source;
content_t c_desert_stone;
content_t c_sandstone;
+ content_t c_water_source;
+ content_t c_river_water_source;
+ content_t c_lava_source;
// Content required for generateDungeons
content_t c_cobble;
content_t c_stair_cobble;
content_t c_mossycobble;
+ content_t c_stair_desert_stone;
content_t c_sandstonebrick;
- content_t c_stair_sandstonebrick;
+ content_t c_stair_sandstone_block;
int ystride;
int zstride;
@@ -278,7 +297,11 @@ protected:
NoiseParams np_cave1;
NoiseParams np_cave2;
+ NoiseParams np_cavern;
float cave_width;
+ float cavern_limit;
+ float cavern_taper;
+ float cavern_threshold;
};
#endif
diff --git a/src/mapgen_flat.cpp b/src/mapgen_flat.cpp
index cc120b580..604c79dd0 100644
--- a/src/mapgen_flat.cpp
+++ b/src/mapgen_flat.cpp
@@ -1,7 +1,7 @@
/*
Minetest
-Copyright (C) 2010-2015 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
-Copyright (C) 2010-2015 paramat, Matt Gregory
+Copyright (C) 2015-2017 paramat
+Copyright (C) 2015-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -33,7 +33,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "emerge.h"
#include "dungeongen.h"
#include "cavegen.h"
-#include "treegen.h"
#include "mg_biome.h"
#include "mg_ore.h"
#include "mg_decoration.h"
@@ -61,10 +60,12 @@ MapgenFlat::MapgenFlat(int mapgenid, MapgenFlatParams *params, EmergeManager *em
this->hill_threshold = params->hill_threshold;
this->hill_steepness = params->hill_steepness;
- //// 2D noise
- noise_terrain = new Noise(&params->np_terrain, seed, csize.X, csize.Z);
+ // 2D noise
noise_filler_depth = new Noise(&params->np_filler_depth, seed, csize.X, csize.Z);
+ if ((spflags & MGFLAT_LAKES) || (spflags & MGFLAT_HILLS))
+ noise_terrain = new Noise(&params->np_terrain, seed, csize.X, csize.Z);
+ // 3D noise
MapgenBasic::np_cave1 = params->np_cave1;
MapgenBasic::np_cave2 = params->np_cave2;
}
@@ -72,8 +73,10 @@ MapgenFlat::MapgenFlat(int mapgenid, MapgenFlatParams *params, EmergeManager *em
MapgenFlat::~MapgenFlat()
{
- delete noise_terrain;
delete noise_filler_depth;
+
+ if ((spflags & MGFLAT_LAKES) || (spflags & MGFLAT_HILLS))
+ delete noise_terrain;
}
@@ -137,7 +140,9 @@ void MapgenFlatParams::writeParams(Settings *settings) const
int MapgenFlat::getSpawnLevelAtPoint(v2s16 p)
{
s16 level_at_point = ground_level;
- float n_terrain = NoisePerlin2D(&noise_terrain->np, p.X, p.Y, seed);
+ float n_terrain = 0.0f;
+ if ((spflags & MGFLAT_LAKES) || (spflags & MGFLAT_HILLS))
+ n_terrain = NoisePerlin2D(&noise_terrain->np, p.X, p.Y, seed);
if ((spflags & MGFLAT_LAKES) && n_terrain < lake_threshold) {
level_at_point = ground_level -
diff --git a/src/mapgen_flat.h b/src/mapgen_flat.h
index 8b3de2bcf..18b84de76 100644
--- a/src/mapgen_flat.h
+++ b/src/mapgen_flat.h
@@ -1,7 +1,7 @@
/*
Minetest
-Copyright (C) 2010-2015 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
-Copyright (C) 2010-2015 paramat, Matt Gregory
+Copyright (C) 2015-2017 paramat
+Copyright (C) 2015-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -31,8 +31,8 @@ class BiomeManager;
extern FlagDesc flagdesc_mapgen_flat[];
-
-struct MapgenFlatParams : public MapgenParams {
+struct MapgenFlatParams : public MapgenParams
+{
u32 spflags;
s16 ground_level;
s16 large_cave_depth;
@@ -53,7 +53,8 @@ struct MapgenFlatParams : public MapgenParams {
void writeParams(Settings *settings) const;
};
-class MapgenFlat : public MapgenBasic {
+class MapgenFlat : public MapgenBasic
+{
public:
MapgenFlat(int mapgenid, MapgenFlatParams *params, EmergeManager *emerge);
~MapgenFlat();
diff --git a/src/mapgen_fractal.cpp b/src/mapgen_fractal.cpp
index a6ed18ae7..faac9e1c1 100644
--- a/src/mapgen_fractal.cpp
+++ b/src/mapgen_fractal.cpp
@@ -1,7 +1,7 @@
/*
Minetest
-Copyright (C) 2010-2015 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
-Copyright (C) 2010-2015 paramat, Matt Gregory
+Copyright (C) 2015-2017 paramat
+Copyright (C) 2015-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -33,7 +33,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "emerge.h"
#include "dungeongen.h"
#include "cavegen.h"
-#include "treegen.h"
#include "mg_biome.h"
#include "mg_ore.h"
#include "mg_decoration.h"
diff --git a/src/mapgen_fractal.h b/src/mapgen_fractal.h
index 3331848bc..a5a09ccb9 100644
--- a/src/mapgen_fractal.h
+++ b/src/mapgen_fractal.h
@@ -1,7 +1,7 @@
/*
Minetest
-Copyright (C) 2010-2015 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
-Copyright (C) 2010-2015 paramat, Matt Gregory
+Copyright (C) 2015-2017 paramat
+Copyright (C) 2015-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
Fractal formulas from http://www.bugman123.com/Hypercomplex/index.html
by Paul Nylander, and from http://www.fractalforums.com, thank you.
@@ -32,8 +32,8 @@ class BiomeManager;
extern FlagDesc flagdesc_mapgen_fractal[];
-
-struct MapgenFractalParams : public MapgenParams {
+struct MapgenFractalParams : public MapgenParams
+{
u32 spflags;
float cave_width;
u16 fractal;
@@ -57,7 +57,8 @@ struct MapgenFractalParams : public MapgenParams {
void writeParams(Settings *settings) const;
};
-class MapgenFractal : public MapgenBasic {
+class MapgenFractal : public MapgenBasic
+{
public:
MapgenFractal(int mapgenid, MapgenFractalParams *params, EmergeManager *emerge);
~MapgenFractal();
diff --git a/src/mapgen_singlenode.cpp b/src/mapgen_singlenode.cpp
index ff985dd34..f49059f7f 100644
--- a/src/mapgen_singlenode.cpp
+++ b/src/mapgen_singlenode.cpp
@@ -1,6 +1,8 @@
/*
Minetest
-Copyright (C) 2010-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2013-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2013-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2015-2017 paramat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
diff --git a/src/mapgen_singlenode.h b/src/mapgen_singlenode.h
index 07520134d..5171bfbca 100644
--- a/src/mapgen_singlenode.h
+++ b/src/mapgen_singlenode.h
@@ -1,6 +1,8 @@
/*
Minetest
-Copyright (C) 2010-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2013-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2013-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2015-2017 paramat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -22,7 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapgen.h"
-struct MapgenSinglenodeParams : public MapgenParams {
+struct MapgenSinglenodeParams : public MapgenParams
+{
MapgenSinglenodeParams() {}
~MapgenSinglenodeParams() {}
@@ -30,7 +33,8 @@ struct MapgenSinglenodeParams : public MapgenParams {
void writeParams(Settings *settings) const {}
};
-class MapgenSinglenode : public Mapgen {
+class MapgenSinglenode : public Mapgen
+{
public:
u32 flags;
content_t c_node;
diff --git a/src/mapgen_v5.cpp b/src/mapgen_v5.cpp
index 9f189e253..932677e2a 100644
--- a/src/mapgen_v5.cpp
+++ b/src/mapgen_v5.cpp
@@ -1,7 +1,7 @@
/*
Minetest
-Copyright (C) 2010-2015 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
-Copyright (C) 2010-2015 paramat, Matt Gregory
+Copyright (C) 2014-2017 paramat
+Copyright (C) 2014-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -33,7 +33,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "emerge.h"
#include "dungeongen.h"
#include "cavegen.h"
-#include "treegen.h"
#include "mg_biome.h"
#include "mg_ore.h"
#include "mg_decoration.h"
@@ -41,15 +40,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
FlagDesc flagdesc_mapgen_v5[] = {
- {NULL, 0}
+ {"caverns", MGV5_CAVERNS},
+ {NULL, 0}
};
MapgenV5::MapgenV5(int mapgenid, MapgenV5Params *params, EmergeManager *emerge)
: MapgenBasic(mapgenid, params, emerge)
{
- this->spflags = params->spflags;
- this->cave_width = params->cave_width;
+ this->spflags = params->spflags;
+ this->cave_width = params->cave_width;
+ this->cavern_limit = params->cavern_limit;
+ this->cavern_taper = params->cavern_taper;
+ this->cavern_threshold = params->cavern_threshold;
// Terrain noise
noise_filler_depth = new Noise(&params->np_filler_depth, seed, csize.X, csize.Z);
@@ -59,9 +62,10 @@ MapgenV5::MapgenV5(int mapgenid, MapgenV5Params *params, EmergeManager *emerge)
// 3D terrain noise
// 1-up 1-down overgeneration
noise_ground = new Noise(&params->np_ground, seed, csize.X, csize.Y + 2, csize.Z);
-
- MapgenBasic::np_cave1 = params->np_cave1;
- MapgenBasic::np_cave2 = params->np_cave2;
+ // 1 down overgeneration
+ MapgenBasic::np_cave1 = params->np_cave1;
+ MapgenBasic::np_cave2 = params->np_cave2;
+ MapgenBasic::np_cavern = params->np_cavern;
}
@@ -76,47 +80,55 @@ MapgenV5::~MapgenV5()
MapgenV5Params::MapgenV5Params()
{
- spflags = 0;
- cave_width = 0.125;
+ spflags = MGV5_CAVERNS;
+ cave_width = 0.125;
+ cavern_limit = -256;
+ cavern_taper = 256;
+ cavern_threshold = 0.7;
np_filler_depth = NoiseParams(0, 1, v3f(150, 150, 150), 261, 4, 0.7, 2.0);
np_factor = NoiseParams(0, 1, v3f(250, 250, 250), 920381, 3, 0.45, 2.0);
np_height = NoiseParams(0, 10, v3f(250, 250, 250), 84174, 4, 0.5, 2.0);
+ np_ground = NoiseParams(0, 40, v3f(80, 80, 80), 983240, 4, 0.55, 2.0, NOISE_FLAG_EASED);
np_cave1 = NoiseParams(0, 12, v3f(50, 50, 50), 52534, 4, 0.5, 2.0);
np_cave2 = NoiseParams(0, 12, v3f(50, 50, 50), 10325, 4, 0.5, 2.0);
- np_ground = NoiseParams(0, 40, v3f(80, 80, 80), 983240, 4, 0.55, 2.0, NOISE_FLAG_EASED);
+ np_cavern = NoiseParams(0, 1, v3f(384, 128, 384), 723, 5, 0.63, 2.0);
}
-//#define CAVE_NOISE_SCALE 12.0
-//#define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE) = 0.125
-
-
void MapgenV5Params::readParams(const Settings *settings)
{
- settings->getFlagStrNoEx("mgv5_spflags", spflags, flagdesc_mapgen_v5);
- settings->getFloatNoEx("mgv5_cave_width", cave_width);
+ settings->getFlagStrNoEx("mgv5_spflags", spflags, flagdesc_mapgen_v5);
+ settings->getFloatNoEx("mgv5_cave_width", cave_width);
+ settings->getS16NoEx("mgv5_cavern_limit", cavern_limit);
+ settings->getS16NoEx("mgv5_cavern_taper", cavern_taper);
+ settings->getFloatNoEx("mgv5_cavern_threshold", cavern_threshold);
settings->getNoiseParams("mgv5_np_filler_depth", np_filler_depth);
settings->getNoiseParams("mgv5_np_factor", np_factor);
settings->getNoiseParams("mgv5_np_height", np_height);
+ settings->getNoiseParams("mgv5_np_ground", np_ground);
settings->getNoiseParams("mgv5_np_cave1", np_cave1);
settings->getNoiseParams("mgv5_np_cave2", np_cave2);
- settings->getNoiseParams("mgv5_np_ground", np_ground);
+ settings->getNoiseParams("mgv5_np_cavern", np_cavern);
}
void MapgenV5Params::writeParams(Settings *settings) const
{
- settings->setFlagStr("mgv5_spflags", spflags, flagdesc_mapgen_v5, U32_MAX);
- settings->setFloat("mgv5_cave_width", cave_width);
+ settings->setFlagStr("mgv5_spflags", spflags, flagdesc_mapgen_v5, U32_MAX);
+ settings->setFloat("mgv5_cave_width", cave_width);
+ settings->setS16("mgv5_cavern_limit", cavern_limit);
+ settings->setS16("mgv5_cavern_taper", cavern_taper);
+ settings->setFloat("mgv5_cavern_threshold", cavern_threshold);
settings->setNoiseParams("mgv5_np_filler_depth", np_filler_depth);
settings->setNoiseParams("mgv5_np_factor", np_factor);
settings->setNoiseParams("mgv5_np_height", np_height);
+ settings->setNoiseParams("mgv5_np_ground", np_ground);
settings->setNoiseParams("mgv5_np_cave1", np_cave1);
settings->setNoiseParams("mgv5_np_cave2", np_cave2);
- settings->setNoiseParams("mgv5_np_ground", np_ground);
+ settings->setNoiseParams("mgv5_np_cavern", np_cavern);
}
@@ -190,9 +202,21 @@ void MapgenV5::makeChunk(BlockMakeData *data)
biomegen->calcBiomeNoise(node_min);
MgStoneType stone_type = generateBiomes();
- // Generate caves
- if ((flags & MG_CAVES) && (stone_surface_max_y >= node_min.Y))
- generateCaves(stone_surface_max_y, MGV5_LARGE_CAVE_DEPTH);
+ // Generate caverns, tunnels and classic caves
+ if (flags & MG_CAVES) {
+ bool near_cavern = false;
+ // Generate caverns
+ if (spflags & MGV5_CAVERNS)
+ near_cavern = generateCaverns(stone_surface_max_y);
+ // Generate tunnels and classic caves
+ if (near_cavern)
+ // Disable classic caves in this mapchunk by setting
+ // 'large cave depth' to world base. Avoids excessive liquid in
+ // large caverns and floating blobs of overgenerated liquid.
+ generateCaves(stone_surface_max_y, -MAX_MAP_GENERATION_LIMIT);
+ else
+ generateCaves(stone_surface_max_y, MGV5_LARGE_CAVE_DEPTH);
+ }
// Generate dungeons and desert temples
if (flags & MG_DUNGEONS)
@@ -223,23 +247,6 @@ void MapgenV5::makeChunk(BlockMakeData *data)
}
-//bool is_cave(u32 index) {
-// double d1 = contour(noise_cave1->result[index]);
-// double d2 = contour(noise_cave2->result[index]);
-// return d1*d2 > CAVE_NOISE_THRESHOLD;
-//}
-
-//bool val_is_ground(v3s16 p, u32 index, u32 index2d) {
-// double f = 0.55 + noise_factor->result[index2d];
-// if(f < 0.01)
-// f = 0.01;
-// else if(f >= 1.0)
-// f *= 1.6;
-// double h = WATER_LEVEL + 10 * noise_height->result[index2d];
-// return (noise_ground->result[index] * f > (double)p.Y - h);
-//}
-
-
int MapgenV5::generateBaseTerrain()
{
u32 index = 0;
diff --git a/src/mapgen_v5.h b/src/mapgen_v5.h
index ddb090a9c..b742638cd 100644
--- a/src/mapgen_v5.h
+++ b/src/mapgen_v5.h
@@ -1,7 +1,7 @@
/*
Minetest
-Copyright (C) 2010-2015 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
-Copyright (C) 2010-2015 paramat, Matt Gregory
+Copyright (C) 2014-2017 paramat
+Copyright (C) 2014-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -25,20 +25,28 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MGV5_LARGE_CAVE_DEPTH -256
+///////// Mapgen V5 flags
+#define MGV5_CAVERNS 0x01
+
class BiomeManager;
extern FlagDesc flagdesc_mapgen_v5[];
-
-struct MapgenV5Params : public MapgenParams {
+struct MapgenV5Params : public MapgenParams
+{
u32 spflags;
float cave_width;
+ s16 cavern_limit;
+ s16 cavern_taper;
+ float cavern_threshold;
+
NoiseParams np_filler_depth;
NoiseParams np_factor;
NoiseParams np_height;
+ NoiseParams np_ground;
NoiseParams np_cave1;
NoiseParams np_cave2;
- NoiseParams np_ground;
+ NoiseParams np_cavern;
MapgenV5Params();
~MapgenV5Params() {}
@@ -47,8 +55,8 @@ struct MapgenV5Params : public MapgenParams {
void writeParams(Settings *settings) const;
};
-
-class MapgenV5 : public MapgenBasic {
+class MapgenV5 : public MapgenBasic
+{
public:
MapgenV5(int mapgenid, MapgenV5Params *params, EmergeManager *emerge);
~MapgenV5();
diff --git a/src/mapgen_v6.cpp b/src/mapgen_v6.cpp
index 79617a830..fe2b0b36f 100644
--- a/src/mapgen_v6.cpp
+++ b/src/mapgen_v6.cpp
@@ -1,6 +1,8 @@
/*
Minetest
Copyright (C) 2010-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2013-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2014-2017 paramat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -99,18 +101,12 @@ MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge)
c_snowblock = ndef->getId("mapgen_snowblock");
c_ice = ndef->getId("mapgen_ice");
- c_cobble = ndef->getId("mapgen_cobble");
- c_stair_cobble = ndef->getId("mapgen_stair_cobble");
- c_mossycobble = ndef->getId("mapgen_mossycobble");
-
- if (c_desert_sand == CONTENT_IGNORE)
- c_desert_sand = c_sand;
+ if (c_gravel == CONTENT_IGNORE)
+ c_gravel = c_stone;
if (c_desert_stone == CONTENT_IGNORE)
c_desert_stone = c_stone;
- if (c_mossycobble == CONTENT_IGNORE)
- c_mossycobble = c_cobble;
- if (c_stair_cobble == CONTENT_IGNORE)
- c_stair_cobble = c_cobble;
+ if (c_desert_sand == CONTENT_IGNORE)
+ c_desert_sand = c_sand;
if (c_dirt_with_snow == CONTENT_IGNORE)
c_dirt_with_snow = c_dirt_with_grass;
if (c_snow == CONTENT_IGNORE)
@@ -119,6 +115,18 @@ MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge)
c_snowblock = c_dirt_with_grass;
if (c_ice == CONTENT_IGNORE)
c_ice = c_water_source;
+
+ c_cobble = ndef->getId("mapgen_cobble");
+ c_mossycobble = ndef->getId("mapgen_mossycobble");
+ c_stair_cobble = ndef->getId("mapgen_stair_cobble");
+ c_stair_desert_stone = ndef->getId("mapgen_stair_desert_stone");
+
+ if (c_mossycobble == CONTENT_IGNORE)
+ c_mossycobble = c_cobble;
+ if (c_stair_cobble == CONTENT_IGNORE)
+ c_stair_cobble = c_cobble;
+ if (c_stair_desert_stone == CONTENT_IGNORE)
+ c_stair_desert_stone = c_desert_stone;
}
@@ -558,34 +566,47 @@ void MapgenV6::makeChunk(BlockMakeData *data)
if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
DungeonParams dp;
- dp.seed = seed;
- dp.c_water = c_water_source;
- dp.c_river_water = c_water_source;
- dp.rooms_min = 2;
- dp.rooms_max = 16;
- dp.y_min = -MAX_MAP_GENERATION_LIMIT;
- dp.y_max = MAX_MAP_GENERATION_LIMIT;
- dp.np_density = NoiseParams(0.9, 0.5, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0);
- dp.np_alt_wall = NoiseParams(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0);
+ dp.seed = seed;
+ dp.c_water = c_water_source;
+ dp.c_river_water = c_water_source;
+
+ dp.only_in_ground = true;
+ dp.corridor_len_min = 1;
+ dp.corridor_len_max = 13;
+ dp.rooms_min = 2;
+ dp.rooms_max = 16;
+ dp.y_min = -MAX_MAP_GENERATION_LIMIT;
+ dp.y_max = MAX_MAP_GENERATION_LIMIT;
+
+ dp.np_density
+ = NoiseParams(0.9, 0.5, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0);
+ dp.np_alt_wall
+ = NoiseParams(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0);
if (getBiome(0, v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
- dp.c_wall = c_desert_stone;
- dp.c_alt_wall = CONTENT_IGNORE;
- dp.c_stair = c_desert_stone;
-
- dp.diagonal_dirs = true;
- dp.holesize = v3s16(2, 3, 2);
- dp.roomsize = v3s16(2, 5, 2);
- dp.notifytype = GENNOTIFY_TEMPLE;
+ dp.c_wall = c_desert_stone;
+ dp.c_alt_wall = CONTENT_IGNORE;
+ dp.c_stair = c_stair_desert_stone;
+
+ dp.diagonal_dirs = true;
+ dp.holesize = v3s16(2, 3, 2);
+ dp.room_size_min = v3s16(6, 9, 6);
+ dp.room_size_max = v3s16(10, 11, 10);
+ dp.room_size_large_min = v3s16(10, 13, 10);
+ dp.room_size_large_max = v3s16(18, 21, 18);
+ dp.notifytype = GENNOTIFY_TEMPLE;
} else {
- dp.c_wall = c_cobble;
- dp.c_alt_wall = c_mossycobble;
- dp.c_stair = c_stair_cobble;
-
- dp.diagonal_dirs = false;
- dp.holesize = v3s16(1, 2, 1);
- dp.roomsize = v3s16(0, 0, 0);
- dp.notifytype = GENNOTIFY_DUNGEON;
+ dp.c_wall = c_cobble;
+ dp.c_alt_wall = c_mossycobble;
+ dp.c_stair = c_stair_cobble;
+
+ dp.diagonal_dirs = false;
+ dp.holesize = v3s16(1, 2, 1);
+ dp.room_size_min = v3s16(4, 4, 4);
+ dp.room_size_max = v3s16(8, 6, 8);
+ dp.room_size_large_min = v3s16(8, 8, 8);
+ dp.room_size_large_max = v3s16(16, 16, 16);
+ dp.notifytype = GENNOTIFY_DUNGEON;
}
DungeonGen dgen(ndef, &gennotify, &dp);
@@ -817,13 +838,17 @@ void MapgenV6::flowMud(s16 &mudflow_minpos, s16 &mudflow_maxpos)
v3s16(-1, 0, 0), // left
};
- // Check that upper is air or doesn't exist.
- // Cancel dropping if upper keeps it in place
+ // Check that upper is walkable. Cancel
+ // dropping if upper keeps it in place.
u32 i3 = i;
vm->m_area.add_y(em, i3, 1);
- if (vm->m_area.contains(i3) == true &&
- ndef->get(vm->m_data[i3]).walkable)
- continue;
+ MapNode *n3 = NULL;
+
+ if (vm->m_area.contains(i3)) {
+ n3 = &vm->m_data[i3];
+ if (ndef->get(*n3).walkable)
+ continue;
+ }
// Drop mud on side
for (u32 di = 0; di < 4; di++) {
@@ -866,10 +891,18 @@ void MapgenV6::flowMud(s16 &mudflow_minpos, s16 &mudflow_maxpos)
if (!dropped_to_unknown) {
*n2 = *n;
// Set old place to be air (or water)
- if (old_is_water)
+ if (old_is_water) {
*n = MapNode(c_water_source);
- else
+ } else {
*n = MapNode(CONTENT_AIR);
+ // Upper (n3) is not walkable or is NULL. If it is
+ // not NULL and not air and not water it is a
+ // decoration that needs removing, to avoid
+ // unsupported decorations.
+ if (n3 && n3->getContent() != CONTENT_AIR &&
+ n3->getContent() != c_water_source)
+ *n3 = MapNode(CONTENT_AIR);
+ }
}
// Done
diff --git a/src/mapgen_v6.h b/src/mapgen_v6.h
index f018ffaca..2b3b4444e 100644
--- a/src/mapgen_v6.h
+++ b/src/mapgen_v6.h
@@ -1,6 +1,8 @@
/*
Minetest
Copyright (C) 2010-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2013-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2014-2017 paramat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -123,6 +125,7 @@ public:
content_t c_cobble;
content_t c_mossycobble;
content_t c_stair_cobble;
+ content_t c_stair_desert_stone;
MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge);
~MapgenV6();
diff --git a/src/mapgen_v7.cpp b/src/mapgen_v7.cpp
index 04a9e3c16..5e9bc4aa3 100644
--- a/src/mapgen_v7.cpp
+++ b/src/mapgen_v7.cpp
@@ -1,7 +1,7 @@
/*
Minetest
-Copyright (C) 2010-2015 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
-Copyright (C) 2010-2015 paramat, Matt Gregory
+Copyright (C) 2013-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2014-2017 paramat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -33,7 +33,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "emerge.h"
#include "dungeongen.h"
#include "cavegen.h"
-#include "treegen.h"
#include "mg_biome.h"
#include "mg_ore.h"
#include "mg_decoration.h"
@@ -41,10 +40,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
FlagDesc flagdesc_mapgen_v7[] = {
- {"mountains", MGV7_MOUNTAINS},
- {"ridges", MGV7_RIDGES},
- {"floatlands", MGV7_FLOATLANDS},
- {NULL, 0}
+ {"mountains", MGV7_MOUNTAINS},
+ {"ridges", MGV7_RIDGES},
+ {"floatlands", MGV7_FLOATLANDS},
+ {"caverns", MGV7_CAVERNS},
+ {NULL, 0}
};
@@ -60,52 +60,77 @@ MapgenV7::MapgenV7(int mapgenid, MapgenV7Params *params, EmergeManager *emerge)
this->float_mount_height = params->float_mount_height;
this->floatland_level = params->floatland_level;
this->shadow_limit = params->shadow_limit;
+ this->cavern_limit = params->cavern_limit;
+ this->cavern_taper = params->cavern_taper;
+ this->cavern_threshold = params->cavern_threshold;
- //// Terrain noise
- noise_terrain_base = new Noise(&params->np_terrain_base, seed, csize.X, csize.Z);
- noise_terrain_alt = new Noise(&params->np_terrain_alt, seed, csize.X, csize.Z);
- noise_terrain_persist = new Noise(&params->np_terrain_persist, seed, csize.X, csize.Z);
- noise_height_select = new Noise(&params->np_height_select, seed, csize.X, csize.Z);
- noise_filler_depth = new Noise(&params->np_filler_depth, seed, csize.X, csize.Z);
- noise_mount_height = new Noise(&params->np_mount_height, seed, csize.X, csize.Z);
- noise_ridge_uwater = new Noise(&params->np_ridge_uwater, seed, csize.X, csize.Z);
- noise_floatland_base = new Noise(&params->np_floatland_base, seed, csize.X, csize.Z);
- noise_float_base_height = new Noise(&params->np_float_base_height, seed, csize.X, csize.Z);
-
- //// 3d terrain noise
- // 1-up 1-down overgeneration
- noise_mountain = new Noise(&params->np_mountain, seed, csize.X, csize.Y + 2, csize.Z);
- noise_ridge = new Noise(&params->np_ridge, seed, csize.X, csize.Y + 2, csize.Z);
-
- MapgenBasic::np_cave1 = params->np_cave1;
- MapgenBasic::np_cave2 = params->np_cave2;
+ // 2D noise
+ noise_terrain_base = new Noise(&params->np_terrain_base, seed, csize.X, csize.Z);
+ noise_terrain_alt = new Noise(&params->np_terrain_alt, seed, csize.X, csize.Z);
+ noise_terrain_persist = new Noise(&params->np_terrain_persist, seed, csize.X, csize.Z);
+ noise_height_select = new Noise(&params->np_height_select, seed, csize.X, csize.Z);
+ noise_filler_depth = new Noise(&params->np_filler_depth, seed, csize.X, csize.Z);
+
+ if (spflags & MGV7_MOUNTAINS)
+ noise_mount_height = new Noise(&params->np_mount_height, seed, csize.X, csize.Z);
+
+ if (spflags & MGV7_FLOATLANDS) {
+ noise_floatland_base = new Noise(&params->np_floatland_base, seed, csize.X, csize.Z);
+ noise_float_base_height = new Noise(&params->np_float_base_height, seed, csize.X, csize.Z);
+ }
+
+ if (spflags & MGV7_RIDGES) {
+ noise_ridge_uwater = new Noise(&params->np_ridge_uwater, seed, csize.X, csize.Z);
+ // 3D noise, 1-up 1-down overgeneration
+ noise_ridge = new Noise(&params->np_ridge, seed, csize.X, csize.Y + 2, csize.Z);
+ }
+ // 3D noise, 1 up, 1 down overgeneration
+ if ((spflags & MGV7_MOUNTAINS) || (spflags & MGV7_FLOATLANDS))
+ noise_mountain = new Noise(&params->np_mountain, seed, csize.X, csize.Y + 2, csize.Z);
+ // 3D noise, 1 down overgeneration
+ MapgenBasic::np_cave1 = params->np_cave1;
+ MapgenBasic::np_cave2 = params->np_cave2;
+ MapgenBasic::np_cavern = params->np_cavern;
}
MapgenV7::~MapgenV7()
{
delete noise_terrain_base;
+ delete noise_terrain_alt;
delete noise_terrain_persist;
delete noise_height_select;
- delete noise_terrain_alt;
delete noise_filler_depth;
- delete noise_mount_height;
- delete noise_ridge_uwater;
- delete noise_floatland_base;
- delete noise_float_base_height;
- delete noise_mountain;
- delete noise_ridge;
+
+ if (spflags & MGV7_MOUNTAINS)
+ delete noise_mount_height;
+
+ if (spflags & MGV7_FLOATLANDS) {
+ delete noise_floatland_base;
+ delete noise_float_base_height;
+ }
+
+ if (spflags & MGV7_RIDGES) {
+ delete noise_ridge_uwater;
+ delete noise_ridge;
+ }
+
+ if ((spflags & MGV7_MOUNTAINS) || (spflags & MGV7_FLOATLANDS))
+ delete noise_mountain;
}
MapgenV7Params::MapgenV7Params()
{
- spflags = MGV7_MOUNTAINS | MGV7_RIDGES;
+ spflags = MGV7_MOUNTAINS | MGV7_RIDGES | MGV7_CAVERNS;
cave_width = 0.09;
float_mount_density = 0.6;
float_mount_height = 128.0;
floatland_level = 1280;
shadow_limit = 1024;
+ cavern_limit = -256;
+ cavern_taper = 256;
+ cavern_threshold = 0.7;
np_terrain_base = NoiseParams(4, 70, v3f(600, 600, 600), 82341, 5, 0.6, 2.0);
np_terrain_alt = NoiseParams(4, 25, v3f(600, 600, 600), 5934, 5, 0.6, 2.0);
@@ -118,6 +143,7 @@ MapgenV7Params::MapgenV7Params()
np_float_base_height = NoiseParams(48, 24, v3f(300, 300, 300), 907, 4, 0.7, 2.0);
np_mountain = NoiseParams(-0.6, 1, v3f(250, 350, 250), 5333, 5, 0.63, 2.0);
np_ridge = NoiseParams(0, 1, v3f(100, 100, 100), 6467, 4, 0.75, 2.0);
+ np_cavern = NoiseParams(0, 1, v3f(384, 128, 384), 723, 5, 0.63, 2.0);
np_cave1 = NoiseParams(0, 12, v3f(61, 61, 61), 52534, 3, 0.5, 2.0);
np_cave2 = NoiseParams(0, 12, v3f(67, 67, 67), 10325, 3, 0.5, 2.0);
}
@@ -131,6 +157,9 @@ void MapgenV7Params::readParams(const Settings *settings)
settings->getFloatNoEx("mgv7_float_mount_height", float_mount_height);
settings->getS16NoEx("mgv7_floatland_level", floatland_level);
settings->getS16NoEx("mgv7_shadow_limit", shadow_limit);
+ settings->getS16NoEx("mgv7_cavern_limit", cavern_limit);
+ settings->getS16NoEx("mgv7_cavern_taper", cavern_taper);
+ settings->getFloatNoEx("mgv7_cavern_threshold", cavern_threshold);
settings->getNoiseParams("mgv7_np_terrain_base", np_terrain_base);
settings->getNoiseParams("mgv7_np_terrain_alt", np_terrain_alt);
@@ -143,6 +172,7 @@ void MapgenV7Params::readParams(const Settings *settings)
settings->getNoiseParams("mgv7_np_float_base_height", np_float_base_height);
settings->getNoiseParams("mgv7_np_mountain", np_mountain);
settings->getNoiseParams("mgv7_np_ridge", np_ridge);
+ settings->getNoiseParams("mgv7_np_cavern", np_cavern);
settings->getNoiseParams("mgv7_np_cave1", np_cave1);
settings->getNoiseParams("mgv7_np_cave2", np_cave2);
}
@@ -156,6 +186,9 @@ void MapgenV7Params::writeParams(Settings *settings) const
settings->setFloat("mgv7_float_mount_height", float_mount_height);
settings->setS16("mgv7_floatland_level", floatland_level);
settings->setS16("mgv7_shadow_limit", shadow_limit);
+ settings->setS16("mgv7_cavern_limit", cavern_limit);
+ settings->setS16("mgv7_cavern_taper", cavern_taper);
+ settings->setFloat("mgv7_cavern_threshold", cavern_threshold);
settings->setNoiseParams("mgv7_np_terrain_base", np_terrain_base);
settings->setNoiseParams("mgv7_np_terrain_alt", np_terrain_alt);
@@ -168,6 +201,7 @@ void MapgenV7Params::writeParams(Settings *settings) const
settings->setNoiseParams("mgv7_np_float_base_height", np_float_base_height);
settings->setNoiseParams("mgv7_np_mountain", np_mountain);
settings->setNoiseParams("mgv7_np_ridge", np_ridge);
+ settings->setNoiseParams("mgv7_np_cavern", np_cavern);
settings->setNoiseParams("mgv7_np_cave1", np_cave1);
settings->setNoiseParams("mgv7_np_cave2", np_cave2);
}
@@ -256,9 +290,23 @@ void MapgenV7::makeChunk(BlockMakeData *data)
biomegen->calcBiomeNoise(node_min);
MgStoneType stone_type = generateBiomes();
- if (flags & MG_CAVES)
- generateCaves(stone_surface_max_y, water_level);
+ // Generate caverns, tunnels and classic caves
+ if (flags & MG_CAVES) {
+ bool near_cavern = false;
+ // Generate caverns
+ if (spflags & MGV7_CAVERNS)
+ near_cavern = generateCaverns(stone_surface_max_y);
+ // Generate tunnels and classic caves
+ if (near_cavern)
+ // Disable classic caves in this mapchunk by setting
+ // 'large cave depth' to world base. Avoids excessive liquid in
+ // large caverns and floating blobs of overgenerated liquid.
+ generateCaves(stone_surface_max_y, -MAX_MAP_GENERATION_LIMIT);
+ else
+ generateCaves(stone_surface_max_y, water_level);
+ }
+ // Generate dungeons
if (flags & MG_DUNGEONS)
generateDungeons(stone_surface_max_y, stone_type);
@@ -274,8 +322,10 @@ void MapgenV7::makeChunk(BlockMakeData *data)
//printf("makeChunk: %dms\n", t.stop());
+ // Update liquids
updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
+ // Calculate lighting
// Limit floatland shadow
bool propagate_shadow = !((spflags & MGV7_FLOATLANDS) &&
node_min.Y <= shadow_limit && node_max.Y >= shadow_limit);
diff --git a/src/mapgen_v7.h b/src/mapgen_v7.h
index 3972387a7..a69170057 100644
--- a/src/mapgen_v7.h
+++ b/src/mapgen_v7.h
@@ -1,7 +1,7 @@
/*
Minetest
-Copyright (C) 2010-2015 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
-Copyright (C) 2010-2015 paramat, Matt Gregory
+Copyright (C) 2013-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2014-2017 paramat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -23,10 +23,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapgen.h"
-////////////// Mapgen V7 flags
-#define MGV7_MOUNTAINS 0x01
-#define MGV7_RIDGES 0x02
-#define MGV7_FLOATLANDS 0x04
+//////////// Mapgen V7 flags
+#define MGV7_MOUNTAINS 0x01
+#define MGV7_RIDGES 0x02
+#define MGV7_FLOATLANDS 0x04
+#define MGV7_CAVERNS 0x08
class BiomeManager;
@@ -40,6 +41,9 @@ struct MapgenV7Params : public MapgenParams {
float float_mount_height;
s16 floatland_level;
s16 shadow_limit;
+ s16 cavern_limit;
+ s16 cavern_taper;
+ float cavern_threshold;
NoiseParams np_terrain_base;
NoiseParams np_terrain_alt;
@@ -52,6 +56,7 @@ struct MapgenV7Params : public MapgenParams {
NoiseParams np_float_base_height;
NoiseParams np_mountain;
NoiseParams np_ridge;
+ NoiseParams np_cavern;
NoiseParams np_cave1;
NoiseParams np_cave2;
diff --git a/src/mapgen_valleys.cpp b/src/mapgen_valleys.cpp
index ce7a95329..df318291c 100644
--- a/src/mapgen_valleys.cpp
+++ b/src/mapgen_valleys.cpp
@@ -1,8 +1,7 @@
/*
Minetest Valleys C
-Copyright (C) 2010-2015 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
-Copyright (C) 2010-2015 paramat, Matt Gregory
-Copyright (C) 2016 Duane Robertson <duane@duanerobertson.com>
+Copyright (C) 2016-2017 Duane Robertson <duane@duanerobertson.com>
+Copyright (C) 2016-2017 paramat
Based on Valleys Mapgen by Gael de Sailly
(https://forum.minetest.net/viewtopic.php?f=9&t=11430)
@@ -37,7 +36,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h" // For g_settings
#include "emerge.h"
#include "dungeongen.h"
-#include "treegen.h"
#include "mg_biome.h"
#include "mg_ore.h"
#include "mg_decoration.h"
@@ -70,9 +68,6 @@ MapgenValleys::MapgenValleys(int mapgenid, MapgenValleysParams *params, EmergeMa
// NOTE: MapgenValleys has a hard dependency on BiomeGenOriginal
this->m_bgen = (BiomeGenOriginal *)biomegen;
- this->map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
- g_settings->getU16("map_generation_limit"));
-
BiomeParamsOriginal *bp = (BiomeParamsOriginal *)params->bparams;
this->spflags = params->spflags;
@@ -110,9 +105,6 @@ MapgenValleys::MapgenValleys(int mapgenid, MapgenValleysParams *params, EmergeMa
this->lava_max_height = water_level + MYMAX(0, lava_features_lim - 4) * 50;
tcave_cache = new float[csize.Y + 2];
-
- // Resolve content to be used
- c_lava_source = ndef->getId("mapgen_lava_source");
}
@@ -238,17 +230,21 @@ void MapgenValleys::makeChunk(BlockMakeData *data)
blockseed = getBlockSeed2(full_node_min, seed);
- // Generate noise maps and base terrain height.
- calculateNoise();
-
// Generate biome noises. Note this must be executed strictly before
// generateTerrain, because generateTerrain depends on intermediate
// biome-related noises.
m_bgen->calcBiomeNoise(node_min);
+ // Generate noise maps and base terrain height.
+ // Modify heat and humidity maps.
+ calculateNoise();
+
// Generate base terrain with initial heightmaps
s16 stone_surface_max_y = generateTerrain();
+ // Recalculate heightmap
+ updateHeightmap(node_min, node_max);
+
// Place biome-specific nodes and build biomemap
MgStoneType stone_type = generateBiomes();
@@ -549,10 +545,6 @@ int MapgenValleys::generateTerrain()
index_3d += ystride;
}
- // This happens if we're generating a chunk that doesn't
- // contain the terrain surface, in which case, we need
- // to set heightmap to a value outside of the chunk,
- // to avoid confusing lua mods that use heightmap.
if (heightmap[index_2d] == -MAX_MAP_GENERATION_LIMIT) {
s16 surface_y_int = myround(surface_y);
if (surface_y_int > node_max.Y + 1 || surface_y_int < node_min.Y - 1) {
@@ -621,7 +613,7 @@ void MapgenValleys::generateCaves(s16 max_stone_y, s16 large_cave_depth)
const float massive_cave_threshold = 0.6f;
// mct: 1 = small rare caves, 0.5 1/3rd ground volume, 0 = 1/2 ground volume.
- float yblmin = -map_gen_limit + massive_cave_blend * 1.5f;
+ float yblmin = -mapgen_limit + massive_cave_blend * 1.5f;
float yblmax = massive_cave_depth - massive_cave_blend * 1.5f;
bool made_a_big_one = false;
@@ -646,11 +638,11 @@ void MapgenValleys::generateCaves(s16 max_stone_y, s16 large_cave_depth)
// lava_depth varies between one and ten as you approach
// the bottom of the world.
- s16 lava_depth = ceil((lava_max_height - node_min.Y + 1) * 10.f / map_gen_limit);
+ s16 lava_depth = ceil((lava_max_height - node_min.Y + 1) * 10.f / mapgen_limit);
// This allows random lava spawns to be less common at the surface.
s16 lava_chance = MYCUBE(lava_features_lim) * lava_depth;
// water_depth varies between ten and one on the way down.
- s16 water_depth = ceil((map_gen_limit - abs(node_min.Y) + 1) * 10.f / map_gen_limit);
+ s16 water_depth = ceil((mapgen_limit - abs(node_min.Y) + 1) * 10.f / mapgen_limit);
// This allows random water spawns to be more common at the surface.
s16 water_chance = MYCUBE(water_features_lim) * water_depth;
diff --git a/src/mapgen_valleys.h b/src/mapgen_valleys.h
index 6dd7ebc47..8a32a5a82 100644
--- a/src/mapgen_valleys.h
+++ b/src/mapgen_valleys.h
@@ -1,8 +1,7 @@
/*
Minetest Valleys C
-Copyright (C) 2010-2015 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
-Copyright (C) 2010-2015 paramat, Matt Gregory
-Copyright (C) 2016 Duane Robertson <duane@duanerobertson.com>
+Copyright (C) 2016-2017 Duane Robertson <duane@duanerobertson.com>
+Copyright (C) 2016-2017 paramat
Based on Valleys Mapgen by Gael de Sailly
(https://forum.minetest.net/viewtopic.php?f=9&t=11430)
@@ -101,8 +100,6 @@ public:
private:
BiomeGenOriginal *m_bgen;
- float map_gen_limit;
-
bool humid_rivers;
bool use_altitude_chill;
float humidity_adjust;
@@ -126,8 +123,6 @@ private:
Noise *noise_valley_depth;
Noise *noise_valley_profile;
- content_t c_lava_source;
-
float terrainLevelAtPoint(s16 x, s16 z);
void calculateNoise();
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index 5efebf3d8..d835daba2 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapnode.h"
#include "porting.h"
#include "nodedef.h"
+#include "map.h"
#include "content_mapnode.h" // For mapnode_translate_*_internal
#include "serialization.h" // For ser_ver_supported
#include "util/serialize.h"
@@ -54,6 +55,15 @@ MapNode::MapNode(INodeDefManager *ndef, const std::string &name,
param2 = a_param2;
}
+void MapNode::getColor(const ContentFeatures &f, video::SColor *color) const
+{
+ if (f.palette) {
+ *color = (*f.palette)[param2];
+ return;
+ }
+ *color = f.color;
+}
+
void MapNode::setLight(enum LightBank bank, u8 a_light, const ContentFeatures &f)
{
// If node doesn't contain light data, ignore this
@@ -145,7 +155,8 @@ bool MapNode::getLightBanks(u8 &lightday, u8 &lightnight, INodeDefManager *nodem
u8 MapNode::getFaceDir(INodeDefManager *nodemgr) const
{
const ContentFeatures &f = nodemgr->get(*this);
- if(f.param_type_2 == CPT2_FACEDIR)
+ if (f.param_type_2 == CPT2_FACEDIR ||
+ f.param_type_2 == CPT2_COLORED_FACEDIR)
return (getParam2() & 0x1F) % 24;
return 0;
}
@@ -153,7 +164,8 @@ u8 MapNode::getFaceDir(INodeDefManager *nodemgr) const
u8 MapNode::getWallMounted(INodeDefManager *nodemgr) const
{
const ContentFeatures &f = nodemgr->get(*this);
- if(f.param_type_2 == CPT2_WALLMOUNTED)
+ if (f.param_type_2 == CPT2_WALLMOUNTED ||
+ f.param_type_2 == CPT2_COLORED_WALLMOUNTED)
return getParam2() & 0x07;
return 0;
}
@@ -175,7 +187,7 @@ void MapNode::rotateAlongYAxis(INodeDefManager *nodemgr, Rotation rot)
{
ContentParamType2 cpt2 = nodemgr->get(*this).param_type_2;
- if (cpt2 == CPT2_FACEDIR) {
+ if (cpt2 == CPT2_FACEDIR || cpt2 == CPT2_COLORED_FACEDIR) {
static const u8 rotate_facedir[24 * 4] = {
// Table value = rotated facedir
// Columns: 0, 90, 180, 270 degrees rotation around vertical axis
@@ -215,7 +227,8 @@ void MapNode::rotateAlongYAxis(INodeDefManager *nodemgr, Rotation rot)
u8 index = facedir * 4 + rot;
param2 &= ~31;
param2 |= rotate_facedir[index];
- } else if (cpt2 == CPT2_WALLMOUNTED) {
+ } else if (cpt2 == CPT2_WALLMOUNTED ||
+ cpt2 == CPT2_COLORED_WALLMOUNTED) {
u8 wmountface = (param2 & 7);
if (wmountface <= 1)
return;
@@ -453,6 +466,51 @@ void transformNodeBox(const MapNode &n, const NodeBox &nodebox,
}
}
+static inline void getNeighborConnectingFace(
+ v3s16 p, INodeDefManager *nodedef,
+ Map *map, MapNode n, u8 bitmask, u8 *neighbors)
+{
+ MapNode n2 = map->getNodeNoEx(p);
+ if (nodedef->nodeboxConnects(n, n2, bitmask))
+ *neighbors |= bitmask;
+}
+
+u8 MapNode::getNeighbors(v3s16 p, Map *map)
+{
+ INodeDefManager *nodedef=map->getNodeDefManager();
+ u8 neighbors = 0;
+ const ContentFeatures &f = nodedef->get(*this);
+ // locate possible neighboring nodes to connect to
+ if (f.drawtype == NDT_NODEBOX && f.node_box.type == NODEBOX_CONNECTED) {
+ v3s16 p2 = p;
+
+ p2.Y++;
+ getNeighborConnectingFace(p2, nodedef, map, *this, 1, &neighbors);
+
+ p2 = p;
+ p2.Y--;
+ getNeighborConnectingFace(p2, nodedef, map, *this, 2, &neighbors);
+
+ p2 = p;
+ p2.Z--;
+ getNeighborConnectingFace(p2, nodedef, map, *this, 4, &neighbors);
+
+ p2 = p;
+ p2.X--;
+ getNeighborConnectingFace(p2, nodedef, map, *this, 8, &neighbors);
+
+ p2 = p;
+ p2.Z++;
+ getNeighborConnectingFace(p2, nodedef, map, *this, 16, &neighbors);
+
+ p2 = p;
+ p2.X++;
+ getNeighborConnectingFace(p2, nodedef, map, *this, 32, &neighbors);
+ }
+
+ return neighbors;
+}
+
void MapNode::getNodeBoxes(INodeDefManager *nodemgr, std::vector<aabb3f> *boxes, u8 neighbors)
{
const ContentFeatures &f = nodemgr->get(*this);
diff --git a/src/mapnode.h b/src/mapnode.h
index 0bd61c554..9c56a7e17 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -20,14 +20,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef MAPNODE_HEADER
#define MAPNODE_HEADER
-#include "irrlichttypes.h"
-#include "irr_v3d.h"
-#include "irr_aabb3d.h"
+#include "irrlichttypes_bloated.h"
#include "light.h"
#include <string>
#include <vector>
class INodeDefManager;
+class Map;
/*
Naming scheme:
@@ -142,11 +141,6 @@ struct MapNode
MapNode()
{ }
- MapNode(const MapNode & n)
- {
- *this = n;
- }
-
MapNode(content_t content, u8 a_param1=0, u8 a_param2=0)
: param0(content),
param1(a_param1),
@@ -191,6 +185,14 @@ struct MapNode
param2 = p;
}
+ /*!
+ * Returns the color of the node.
+ *
+ * \param f content features of this node
+ * \param color output, contains the node's color.
+ */
+ void getColor(const ContentFeatures &f, video::SColor *color) const;
+
void setLight(enum LightBank bank, u8 a_light, const ContentFeatures &f);
void setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr);
@@ -246,6 +248,13 @@ struct MapNode
void rotateAlongYAxis(INodeDefManager *nodemgr, Rotation rot);
+ /*!
+ * Checks which neighbors does this node connect to.
+ *
+ * \param p coordinates of the node
+ */
+ u8 getNeighbors(v3s16 p, Map *map);
+
/*
Gets list of node boxes (used for rendering (NDT_NODEBOX))
*/
diff --git a/src/mesh.cpp b/src/mesh.cpp
index b68862d22..3ab67510a 100644
--- a/src/mesh.cpp
+++ b/src/mesh.cpp
@@ -33,13 +33,33 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MY_ETLM_READ_ONLY video::ETLM_READ_ONLY
#endif
-static void applyFacesShading(video::SColor& color, float factor)
+inline static void applyShadeFactor(video::SColor& color, float factor)
{
color.setRed(core::clamp(core::round32(color.getRed()*factor), 0, 255));
color.setGreen(core::clamp(core::round32(color.getGreen()*factor), 0, 255));
color.setBlue(core::clamp(core::round32(color.getBlue()*factor), 0, 255));
}
+void applyFacesShading(video::SColor &color, const v3f &normal)
+{
+ /*
+ Some drawtypes have normals set to (0, 0, 0), this must result in
+ maximum brightness: shade factor 1.0.
+ Shade factors for aligned cube faces are:
+ +Y 1.000000 sqrt(1.0)
+ -Y 0.447213 sqrt(0.2)
+ +-X 0.670820 sqrt(0.45)
+ +-Z 0.836660 sqrt(0.7)
+ */
+ float x2 = normal.X * normal.X;
+ float y2 = normal.Y * normal.Y;
+ float z2 = normal.Z * normal.Z;
+ if (normal.Y < 0)
+ applyShadeFactor(color, 0.670820f * x2 + 0.447213f * y2 + 0.836660f * z2);
+ else if ((x2 > 1e-3) || (z2 > 1e-3))
+ applyShadeFactor(color, 0.670820f * x2 + 1.000000f * y2 + 0.836660f * z2);
+}
+
scene::IAnimatedMesh* createCubeMesh(v3f scale)
{
video::SColor c(255,255,255,255);
@@ -155,6 +175,14 @@ void translateMesh(scene::IMesh *mesh, v3f vec)
mesh->setBoundingBox(bbox);
}
+void setMeshBufferColor(scene::IMeshBuffer *buf, const video::SColor &color)
+{
+ const u32 stride = getVertexPitchFromType(buf->getVertexType());
+ u32 vertex_count = buf->getVertexCount();
+ u8 *vertices = (u8 *) buf->getVertices();
+ for (u32 i = 0; i < vertex_count; i++)
+ ((video::S3DVertex *) (vertices + i * stride))->Color = color;
+}
void setMeshColor(scene::IMesh *mesh, const video::SColor &color)
{
@@ -162,42 +190,22 @@ void setMeshColor(scene::IMesh *mesh, const video::SColor &color)
return;
u32 mc = mesh->getMeshBufferCount();
- for (u32 j = 0; j < mc; j++) {
- scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
- const u32 stride = getVertexPitchFromType(buf->getVertexType());
- u32 vertex_count = buf->getVertexCount();
- u8 *vertices = (u8 *)buf->getVertices();
- for (u32 i = 0; i < vertex_count; i++)
- ((video::S3DVertex *)(vertices + i * stride))->Color = color;
- }
+ for (u32 j = 0; j < mc; j++)
+ setMeshBufferColor(mesh->getMeshBuffer(j), color);
}
-void shadeMeshFaces(scene::IMesh *mesh)
+void colorizeMeshBuffer(scene::IMeshBuffer *buf, const video::SColor *buffercolor)
{
- if (mesh == NULL)
- return;
-
- u32 mc = mesh->getMeshBufferCount();
- for (u32 j = 0; j < mc; j++) {
- scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
- const u32 stride = getVertexPitchFromType(buf->getVertexType());
- u32 vertex_count = buf->getVertexCount();
- u8 *vertices = (u8 *)buf->getVertices();
- for (u32 i = 0; i < vertex_count; i++) {
- video::S3DVertex *vertex = (video::S3DVertex *)(vertices + i * stride);
- video::SColor &vc = vertex->Color;
- if (vertex->Normal.Y < -0.5) {
- applyFacesShading (vc, 0.447213);
- } else if (vertex->Normal.Z > 0.5) {
- applyFacesShading (vc, 0.670820);
- } else if (vertex->Normal.Z < -0.5) {
- applyFacesShading (vc, 0.670820);
- } else if (vertex->Normal.X > 0.5) {
- applyFacesShading (vc, 0.836660);
- } else if (vertex->Normal.X < -0.5) {
- applyFacesShading (vc, 0.836660);
- }
- }
+ const u32 stride = getVertexPitchFromType(buf->getVertexType());
+ u32 vertex_count = buf->getVertexCount();
+ u8 *vertices = (u8 *) buf->getVertices();
+ for (u32 i = 0; i < vertex_count; i++) {
+ video::S3DVertex *vertex = (video::S3DVertex *) (vertices + i * stride);
+ video::SColor *vc = &(vertex->Color);
+ // Reset color
+ *vc = *buffercolor;
+ // Apply shading
+ applyFacesShading(*vc, vertex->Normal);
}
}
@@ -379,48 +387,52 @@ void recalculateBoundingBox(scene::IMesh *src_mesh)
src_mesh->setBoundingBox(bbox);
}
-scene::IMesh* cloneMesh(scene::IMesh *src_mesh)
+scene::IMeshBuffer* cloneMeshBuffer(scene::IMeshBuffer *mesh_buffer)
+{
+ switch (mesh_buffer->getVertexType()) {
+ case video::EVT_STANDARD: {
+ video::S3DVertex *v = (video::S3DVertex *) mesh_buffer->getVertices();
+ u16 *indices = mesh_buffer->getIndices();
+ scene::SMeshBuffer *cloned_buffer = new scene::SMeshBuffer();
+ cloned_buffer->append(v, mesh_buffer->getVertexCount(), indices,
+ mesh_buffer->getIndexCount());
+ return cloned_buffer;
+ }
+ case video::EVT_2TCOORDS: {
+ video::S3DVertex2TCoords *v =
+ (video::S3DVertex2TCoords *) mesh_buffer->getVertices();
+ u16 *indices = mesh_buffer->getIndices();
+ scene::SMeshBufferTangents *cloned_buffer =
+ new scene::SMeshBufferTangents();
+ cloned_buffer->append(v, mesh_buffer->getVertexCount(), indices,
+ mesh_buffer->getIndexCount());
+ return cloned_buffer;
+ }
+ case video::EVT_TANGENTS: {
+ video::S3DVertexTangents *v =
+ (video::S3DVertexTangents *) mesh_buffer->getVertices();
+ u16 *indices = mesh_buffer->getIndices();
+ scene::SMeshBufferTangents *cloned_buffer =
+ new scene::SMeshBufferTangents();
+ cloned_buffer->append(v, mesh_buffer->getVertexCount(), indices,
+ mesh_buffer->getIndexCount());
+ return cloned_buffer;
+ }
+ }
+ // This should not happen.
+ sanity_check(false);
+ return NULL;
+}
+
+scene::SMesh* cloneMesh(scene::IMesh *src_mesh)
{
scene::SMesh* dst_mesh = new scene::SMesh();
for (u16 j = 0; j < src_mesh->getMeshBufferCount(); j++) {
- scene::IMeshBuffer *buf = src_mesh->getMeshBuffer(j);
- switch (buf->getVertexType()) {
- case video::EVT_STANDARD: {
- video::S3DVertex *v =
- (video::S3DVertex *) buf->getVertices();
- u16 *indices = (u16*)buf->getIndices();
- scene::SMeshBuffer *temp_buf = new scene::SMeshBuffer();
- temp_buf->append(v, buf->getVertexCount(),
- indices, buf->getIndexCount());
- dst_mesh->addMeshBuffer(temp_buf);
- temp_buf->drop();
- break;
- }
- case video::EVT_2TCOORDS: {
- video::S3DVertex2TCoords *v =
- (video::S3DVertex2TCoords *) buf->getVertices();
- u16 *indices = (u16*)buf->getIndices();
- scene::SMeshBufferTangents *temp_buf =
- new scene::SMeshBufferTangents();
- temp_buf->append(v, buf->getVertexCount(),
- indices, buf->getIndexCount());
- dst_mesh->addMeshBuffer(temp_buf);
- temp_buf->drop();
- break;
- }
- case video::EVT_TANGENTS: {
- video::S3DVertexTangents *v =
- (video::S3DVertexTangents *) buf->getVertices();
- u16 *indices = (u16*)buf->getIndices();
- scene::SMeshBufferTangents *temp_buf =
- new scene::SMeshBufferTangents();
- temp_buf->append(v, buf->getVertexCount(),
- indices, buf->getIndexCount());
- dst_mesh->addMeshBuffer(temp_buf);
- temp_buf->drop();
- break;
- }
- }
+ scene::IMeshBuffer *temp_buf = cloneMeshBuffer(
+ src_mesh->getMeshBuffer(j));
+ dst_mesh->addMeshBuffer(temp_buf);
+ temp_buf->drop();
+
}
return dst_mesh;
}
@@ -439,7 +451,7 @@ scene::IMesh* convertNodeboxesToMesh(const std::vector<aabb3f> &boxes,
buf->drop();
}
- video::SColor c(255,255,255,255);
+ video::SColor c(255,255,255,255);
for (std::vector<aabb3f>::const_iterator
i = boxes.begin();
@@ -526,7 +538,7 @@ scene::IMesh* convertNodeboxesToMesh(const std::vector<aabb3f> &boxes,
buf->append(vertices + j, 4, indices, 6);
}
}
- return dst_mesh;
+ return dst_mesh;
}
struct vcache
diff --git a/src/mesh.h b/src/mesh.h
index 10df97015..423e43aee 100644
--- a/src/mesh.h
+++ b/src/mesh.h
@@ -23,6 +23,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h"
#include "nodedef.h"
+/*!
+ * Applies shading to a color based on the surface's
+ * normal vector.
+ */
+void applyFacesShading(video::SColor &color, const v3f &normal);
+
/*
Create a new cube mesh.
Vertices are at (+-scale.X/2, +-scale.Y/2, +-scale.Z/2).
@@ -43,16 +49,21 @@ void scaleMesh(scene::IMesh *mesh, v3f scale);
*/
void translateMesh(scene::IMesh *mesh, v3f vec);
+/*!
+ * Sets a constant color for all vertices in the mesh buffer.
+ */
+void setMeshBufferColor(scene::IMeshBuffer *buf, const video::SColor &color);
+
/*
Set a constant color for all vertices in the mesh
*/
void setMeshColor(scene::IMesh *mesh, const video::SColor &color);
-/*
- Shade mesh faces according to their normals
-*/
-
-void shadeMeshFaces(scene::IMesh *mesh);
+/*!
+ * Overwrites the color of a mesh buffer.
+ * The color is darkened based on the normal vector of the vertices.
+ */
+void colorizeMeshBuffer(scene::IMeshBuffer *buf, const video::SColor *buffercolor);
/*
Set the color of all vertices in the mesh.
@@ -80,14 +91,20 @@ void rotateMeshBy6dFacedir(scene::IMesh *mesh, int facedir);
void rotateMeshXYby (scene::IMesh *mesh, f64 degrees);
void rotateMeshXZby (scene::IMesh *mesh, f64 degrees);
void rotateMeshYZby (scene::IMesh *mesh, f64 degrees);
+
+/*
+ * Clone the mesh buffer.
+ * The returned pointer should be dropped.
+ */
+scene::IMeshBuffer* cloneMeshBuffer(scene::IMeshBuffer *mesh_buffer);
/*
Clone the mesh.
*/
-scene::IMesh* cloneMesh(scene::IMesh *src_mesh);
+scene::SMesh* cloneMesh(scene::IMesh *src_mesh);
/*
- Convert nodeboxes to mesh.
+ Convert nodeboxes to mesh. Each tile goes into a different buffer.
boxes - set of nodeboxes to be converted into cuboids
uv_coords[24] - table of texture uv coords for each cuboid face
expand - factor by which cuboids will be resized
diff --git a/src/mesh_generator_thread.cpp b/src/mesh_generator_thread.cpp
new file mode 100644
index 000000000..dce788a7c
--- /dev/null
+++ b/src/mesh_generator_thread.cpp
@@ -0,0 +1,335 @@
+/*
+Minetest
+Copyright (C) 2013, 2017 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 Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "mesh_generator_thread.h"
+#include "settings.h"
+#include "profiler.h"
+#include "client.h"
+#include "mapblock.h"
+#include "map.h"
+
+/*
+ CachedMapBlockData
+*/
+
+CachedMapBlockData::CachedMapBlockData():
+ p(-1337,-1337,-1337),
+ data(NULL),
+ refcount_from_queue(0),
+ last_used_timestamp(time(0))
+{
+}
+
+CachedMapBlockData::~CachedMapBlockData()
+{
+ assert(refcount_from_queue == 0);
+
+ if (data)
+ delete[] data;
+}
+
+/*
+ QueuedMeshUpdate
+*/
+
+QueuedMeshUpdate::QueuedMeshUpdate():
+ p(-1337,-1337,-1337),
+ ack_block_to_server(false),
+ urgent(false),
+ crack_level(-1),
+ crack_pos(0,0,0),
+ data(NULL)
+{
+}
+
+QueuedMeshUpdate::~QueuedMeshUpdate()
+{
+ if (data)
+ delete data;
+}
+
+/*
+ MeshUpdateQueue
+*/
+
+MeshUpdateQueue::MeshUpdateQueue(Client *client):
+ m_client(client)
+{
+ m_cache_enable_shaders = g_settings->getBool("enable_shaders");
+ m_cache_use_tangent_vertices = m_cache_enable_shaders && (
+ g_settings->getBool("enable_bumpmapping") ||
+ g_settings->getBool("enable_parallax_occlusion"));
+ m_cache_smooth_lighting = g_settings->getBool("smooth_lighting");
+ m_meshgen_block_cache_size = g_settings->getS32("meshgen_block_cache_size");
+}
+
+MeshUpdateQueue::~MeshUpdateQueue()
+{
+ MutexAutoLock lock(m_mutex);
+
+ for (std::map<v3s16, CachedMapBlockData *>::iterator i = m_cache.begin();
+ i != m_cache.end(); ++i) {
+ delete i->second;
+ }
+
+ for (std::vector<QueuedMeshUpdate*>::iterator i = m_queue.begin();
+ i != m_queue.end(); ++i) {
+ QueuedMeshUpdate *q = *i;
+ delete q;
+ }
+}
+
+void MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server, bool urgent)
+{
+ DSTACK(FUNCTION_NAME);
+
+ MutexAutoLock lock(m_mutex);
+
+ cleanupCache();
+
+ /*
+ Cache the block data (force-update the center block, don't update the
+ neighbors but get them if they aren't already cached)
+ */
+ std::vector<CachedMapBlockData*> cached_blocks;
+ size_t cache_hit_counter = 0;
+ cached_blocks.reserve(3*3*3);
+ v3s16 dp;
+ for (dp.X = -1; dp.X <= 1; dp.X++)
+ for (dp.Y = -1; dp.Y <= 1; dp.Y++)
+ for (dp.Z = -1; dp.Z <= 1; dp.Z++) {
+ v3s16 p1 = p + dp;
+ CachedMapBlockData *cached_block;
+ if (dp == v3s16(0, 0, 0))
+ cached_block = cacheBlock(map, p1, FORCE_UPDATE);
+ else
+ cached_block = cacheBlock(map, p1, SKIP_UPDATE_IF_ALREADY_CACHED,
+ &cache_hit_counter);
+ cached_blocks.push_back(cached_block);
+ }
+ g_profiler->avg("MeshUpdateQueue MapBlock cache hit %",
+ 100.0f * cache_hit_counter / cached_blocks.size());
+
+ /*
+ Mark the block as urgent if requested
+ */
+ if (urgent)
+ m_urgents.insert(p);
+
+ /*
+ Find if block is already in queue.
+ If it is, update the data and quit.
+ */
+ for (std::vector<QueuedMeshUpdate*>::iterator i = m_queue.begin();
+ i != m_queue.end(); ++i) {
+ QueuedMeshUpdate *q = *i;
+ if (q->p == p) {
+ // NOTE: We are not adding a new position to the queue, thus
+ // refcount_from_queue stays the same.
+ if(ack_block_to_server)
+ q->ack_block_to_server = true;
+ q->crack_level = m_client->getCrackLevel();
+ q->crack_pos = m_client->getCrackPos();
+ return;
+ }
+ }
+
+ /*
+ Add the block
+ */
+ QueuedMeshUpdate *q = new QueuedMeshUpdate;
+ q->p = p;
+ q->ack_block_to_server = ack_block_to_server;
+ q->crack_level = m_client->getCrackLevel();
+ q->crack_pos = m_client->getCrackPos();
+ m_queue.push_back(q);
+
+ // This queue entry is a new reference to the cached blocks
+ for (size_t i=0; i<cached_blocks.size(); i++) {
+ cached_blocks[i]->refcount_from_queue++;
+ }
+}
+
+// Returned pointer must be deleted
+// Returns NULL if queue is empty
+QueuedMeshUpdate *MeshUpdateQueue::pop()
+{
+ MutexAutoLock lock(m_mutex);
+
+ bool must_be_urgent = !m_urgents.empty();
+ for (std::vector<QueuedMeshUpdate*>::iterator i = m_queue.begin();
+ i != m_queue.end(); ++i) {
+ QueuedMeshUpdate *q = *i;
+ if(must_be_urgent && m_urgents.count(q->p) == 0)
+ continue;
+ m_queue.erase(i);
+ m_urgents.erase(q->p);
+ fillDataFromMapBlockCache(q);
+ return q;
+ }
+ return NULL;
+}
+
+CachedMapBlockData* MeshUpdateQueue::cacheBlock(Map *map, v3s16 p, UpdateMode mode,
+ size_t *cache_hit_counter)
+{
+ std::map<v3s16, CachedMapBlockData*>::iterator it =
+ m_cache.find(p);
+ if (it != m_cache.end()) {
+ // Already in cache
+ CachedMapBlockData *cached_block = it->second;
+ if (mode == SKIP_UPDATE_IF_ALREADY_CACHED) {
+ if (cache_hit_counter)
+ (*cache_hit_counter)++;
+ return cached_block;
+ }
+ MapBlock *b = map->getBlockNoCreateNoEx(p);
+ if (b) {
+ if (cached_block->data == NULL)
+ cached_block->data =
+ new MapNode[MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE];
+ memcpy(cached_block->data, b->getData(),
+ MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE * sizeof(MapNode));
+ } else {
+ delete[] cached_block->data;
+ cached_block->data = NULL;
+ }
+ return cached_block;
+ } else {
+ // Not yet in cache
+ CachedMapBlockData *cached_block = new CachedMapBlockData();
+ m_cache[p] = cached_block;
+ MapBlock *b = map->getBlockNoCreateNoEx(p);
+ if (b) {
+ cached_block->data =
+ new MapNode[MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE];
+ memcpy(cached_block->data, b->getData(),
+ MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE * sizeof(MapNode));
+ }
+ return cached_block;
+ }
+}
+
+CachedMapBlockData* MeshUpdateQueue::getCachedBlock(const v3s16 &p)
+{
+ std::map<v3s16, CachedMapBlockData*>::iterator it = m_cache.find(p);
+ if (it != m_cache.end()) {
+ return it->second;
+ }
+ return NULL;
+}
+
+void MeshUpdateQueue::fillDataFromMapBlockCache(QueuedMeshUpdate *q)
+{
+ MeshMakeData *data = new MeshMakeData(m_client, m_cache_enable_shaders,
+ m_cache_use_tangent_vertices);
+ q->data = data;
+
+ data->fillBlockDataBegin(q->p);
+
+ int t_now = time(0);
+
+ // Collect data for 3*3*3 blocks from cache
+ v3s16 dp;
+ for (dp.X = -1; dp.X <= 1; dp.X++)
+ for (dp.Y = -1; dp.Y <= 1; dp.Y++)
+ for (dp.Z = -1; dp.Z <= 1; dp.Z++) {
+ v3s16 p = q->p + dp;
+ CachedMapBlockData *cached_block = getCachedBlock(p);
+ if (cached_block) {
+ cached_block->refcount_from_queue--;
+ cached_block->last_used_timestamp = t_now;
+ if (cached_block->data)
+ data->fillBlockData(dp, cached_block->data);
+ }
+ }
+
+ data->setCrack(q->crack_level, q->crack_pos);
+ data->setSmoothLighting(m_cache_smooth_lighting);
+}
+
+void MeshUpdateQueue::cleanupCache()
+{
+ const int mapblock_kB = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE *
+ sizeof(MapNode) / 1000;
+ g_profiler->avg("MeshUpdateQueue MapBlock cache size kB",
+ mapblock_kB * m_cache.size());
+
+ // The cache size is kept roughly below cache_soft_max_size, not letting
+ // anything get older than cache_seconds_max or deleted before 2 seconds.
+ const int cache_seconds_max = 10;
+ const int cache_soft_max_size = m_meshgen_block_cache_size * 1000 / mapblock_kB;
+ int cache_seconds = MYMAX(2, cache_seconds_max -
+ m_cache.size() / (cache_soft_max_size / cache_seconds_max));
+
+ int t_now = time(0);
+
+ for (std::map<v3s16, CachedMapBlockData*>::iterator it = m_cache.begin();
+ it != m_cache.end(); ) {
+ CachedMapBlockData *cached_block = it->second;
+ if (cached_block->refcount_from_queue == 0 &&
+ cached_block->last_used_timestamp < t_now - cache_seconds) {
+ m_cache.erase(it++);
+ delete cached_block;
+ } else {
+ ++it;
+ }
+ }
+}
+
+/*
+ MeshUpdateThread
+*/
+
+MeshUpdateThread::MeshUpdateThread(Client *client):
+ UpdateThread("Mesh"),
+ m_queue_in(client)
+{
+ m_generation_interval = g_settings->getU16("mesh_generation_interval");
+ m_generation_interval = rangelim(m_generation_interval, 0, 50);
+}
+
+void MeshUpdateThread::updateBlock(Map *map, v3s16 p, bool ack_block_to_server,
+ bool urgent)
+{
+ // Allow the MeshUpdateQueue to do whatever it wants
+ m_queue_in.addBlock(map, p, ack_block_to_server, urgent);
+ deferUpdate();
+}
+
+void MeshUpdateThread::doUpdate()
+{
+ QueuedMeshUpdate *q;
+ while ((q = m_queue_in.pop())) {
+ if (m_generation_interval)
+ sleep_ms(m_generation_interval);
+ ScopeProfiler sp(g_profiler, "Client: Mesh making");
+
+ MapBlockMesh *mesh_new = new MapBlockMesh(q->data, m_camera_offset);
+
+ MeshUpdateResult r;
+ r.p = q->p;
+ r.mesh = mesh_new;
+ r.ack_block_to_server = q->ack_block_to_server;
+
+ m_queue_out.push_back(r);
+
+ delete q;
+ }
+}
diff --git a/src/mesh_generator_thread.h b/src/mesh_generator_thread.h
new file mode 100644
index 000000000..6edb6906d
--- /dev/null
+++ b/src/mesh_generator_thread.h
@@ -0,0 +1,135 @@
+/*
+Minetest
+Copyright (C) 2013, 2017 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 Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 MESH_GENERATOR_THREAD_HEADER
+#define MESH_GENERATOR_THREAD_HEADER
+
+#include "mapblock_mesh.h"
+#include "threading/mutex_auto_lock.h"
+#include "util/thread.h"
+
+struct CachedMapBlockData
+{
+ v3s16 p;
+ MapNode *data; // A copy of the MapBlock's data member
+ int refcount_from_queue;
+ int last_used_timestamp;
+
+ CachedMapBlockData();
+ ~CachedMapBlockData();
+};
+
+struct QueuedMeshUpdate
+{
+ v3s16 p;
+ bool ack_block_to_server;
+ bool urgent;
+ int crack_level;
+ v3s16 crack_pos;
+ MeshMakeData *data; // This is generated in MeshUpdateQueue::pop()
+
+ QueuedMeshUpdate();
+ ~QueuedMeshUpdate();
+};
+
+/*
+ A thread-safe queue of mesh update tasks and a cache of MapBlock data
+*/
+class MeshUpdateQueue
+{
+ enum UpdateMode
+ {
+ FORCE_UPDATE,
+ SKIP_UPDATE_IF_ALREADY_CACHED,
+ };
+
+public:
+ MeshUpdateQueue(Client *client);
+
+ ~MeshUpdateQueue();
+
+ // Caches the block at p and its neighbors (if needed) and queues a mesh
+ // update for the block at p
+ void addBlock(Map *map, v3s16 p, bool ack_block_to_server, bool urgent);
+
+ // Returned pointer must be deleted
+ // Returns NULL if queue is empty
+ QueuedMeshUpdate *pop();
+
+ u32 size()
+ {
+ MutexAutoLock lock(m_mutex);
+ return m_queue.size();
+ }
+
+private:
+ Client *m_client;
+ std::vector<QueuedMeshUpdate *> m_queue;
+ std::set<v3s16> m_urgents;
+ std::map<v3s16, CachedMapBlockData *> m_cache;
+ Mutex m_mutex;
+
+ // TODO: Add callback to update these when g_settings changes
+ bool m_cache_enable_shaders;
+ bool m_cache_use_tangent_vertices;
+ bool m_cache_smooth_lighting;
+ int m_meshgen_block_cache_size;
+
+ CachedMapBlockData *cacheBlock(Map *map, v3s16 p, UpdateMode mode,
+ size_t *cache_hit_counter = NULL);
+ CachedMapBlockData *getCachedBlock(const v3s16 &p);
+ void fillDataFromMapBlockCache(QueuedMeshUpdate *q);
+ void cleanupCache();
+};
+
+struct MeshUpdateResult
+{
+ v3s16 p;
+ MapBlockMesh *mesh;
+ bool ack_block_to_server;
+
+ MeshUpdateResult()
+ : p(-1338, -1338, -1338), mesh(NULL), ack_block_to_server(false)
+ {
+ }
+};
+
+class MeshUpdateThread : public UpdateThread
+{
+public:
+ MeshUpdateThread(Client *client);
+
+ // Caches the block at p and its neighbors (if needed) and queues a mesh
+ // update for the block at p
+ void updateBlock(Map *map, v3s16 p, bool ack_block_to_server, bool urgent);
+
+ v3s16 m_camera_offset;
+ MutexedQueue<MeshUpdateResult> m_queue_out;
+
+private:
+ MeshUpdateQueue m_queue_in;
+
+ // TODO: Add callback to update these when g_settings changes
+ int m_generation_interval;
+
+protected:
+ virtual void doUpdate();
+};
+
+#endif
diff --git a/src/metadata.cpp b/src/metadata.cpp
new file mode 100644
index 000000000..833735464
--- /dev/null
+++ b/src/metadata.cpp
@@ -0,0 +1,108 @@
+/*
+Minetest
+Copyright (C) 2010-2013 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 Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "metadata.h"
+#include "exceptions.h"
+#include "gamedef.h"
+#include "log.h"
+#include <sstream>
+#include "constants.h" // MAP_BLOCKSIZE
+#include <sstream>
+
+/*
+ Metadata
+*/
+
+void Metadata::clear()
+{
+ m_stringvars.clear();
+}
+
+bool Metadata::empty() const
+{
+ return m_stringvars.size() == 0;
+}
+
+size_t Metadata::size() const
+{
+ return m_stringvars.size();
+}
+
+bool Metadata::contains(const std::string &name) const
+{
+ return m_stringvars.find(name) != m_stringvars.end();
+}
+
+bool Metadata::operator==(const Metadata &other) const
+{
+ if (size() != other.size())
+ return false;
+
+ for (StringMap::const_iterator it = m_stringvars.begin();
+ it != m_stringvars.end(); ++it) {
+ if (!other.contains(it->first) ||
+ other.getString(it->first) != it->second)
+ return false;
+ }
+
+ return true;
+}
+
+const std::string &Metadata::getString(const std::string &name, u16 recursion) const
+{
+ StringMap::const_iterator it = m_stringvars.find(name);
+ if (it == m_stringvars.end()) {
+ static const std::string empty_string = std::string("");
+ return empty_string;
+ }
+
+ return resolveString(it->second, recursion);
+}
+
+/**
+ * Sets var to name key in the metadata storage
+ *
+ * @param name
+ * @param var
+ * @return true if key-value pair is created or changed
+ */
+bool Metadata::setString(const std::string &name, const std::string &var)
+{
+ if (var.empty()) {
+ m_stringvars.erase(name);
+ return true;
+ }
+
+ StringMap::iterator it = m_stringvars.find(name);
+ if (it != m_stringvars.end() && it->second == var) {
+ return false;
+ }
+
+ m_stringvars[name] = var;
+ return true;
+}
+
+const std::string &Metadata::resolveString(const std::string &str, u16 recursion) const
+{
+ if (recursion <= 1 && str.substr(0, 2) == "${" && str[str.length() - 1] == '}') {
+ return getString(str.substr(2, str.length() - 3), recursion + 1);
+ } else {
+ return str;
+ }
+}
diff --git a/src/metadata.h b/src/metadata.h
new file mode 100644
index 000000000..a8270b4c4
--- /dev/null
+++ b/src/metadata.h
@@ -0,0 +1,61 @@
+/*
+Minetest
+Copyright (C) 2010-2013 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 Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 METADATA_HEADER
+#define METADATA_HEADER
+
+#include "irr_v3d.h"
+#include <iostream>
+#include <vector>
+#include "util/string.h"
+
+class Metadata
+{
+public:
+ virtual ~Metadata() {}
+
+ virtual void clear();
+ virtual bool empty() const;
+
+ bool operator==(const Metadata &other) const;
+ inline bool operator!=(const Metadata &other) const
+ {
+ return !(*this == other);
+ }
+
+ //
+ // Key-value related
+ //
+
+ size_t size() const;
+ bool contains(const std::string &name) const;
+ const std::string &getString(const std::string &name, u16 recursion = 0) const;
+ virtual bool setString(const std::string &name, const std::string &var);
+ const StringMap &getStrings() const
+ {
+ return m_stringvars;
+ }
+ // Add support for variable names in values
+ const std::string &resolveString(const std::string &str, u16 recursion = 0) const;
+protected:
+ StringMap m_stringvars;
+
+};
+
+#endif
diff --git a/src/mg_biome.cpp b/src/mg_biome.cpp
index 78034bf6c..2ef2ed16a 100644
--- a/src/mg_biome.cpp
+++ b/src/mg_biome.cpp
@@ -1,6 +1,7 @@
/*
Minetest
-Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2014-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2014-2017 paramat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -20,12 +21,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mg_biome.h"
#include "mg_decoration.h"
#include "emerge.h"
-#include "gamedef.h"
+#include "server.h"
#include "nodedef.h"
#include "map.h" //for MMVManip
-#include "log.h"
#include "util/numeric.h"
-#include "util/mathconstants.h"
#include "porting.h"
#include "settings.h"
@@ -33,10 +32,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
///////////////////////////////////////////////////////////////////////////////
-BiomeManager::BiomeManager(IGameDef *gamedef) :
- ObjDefManager(gamedef, OBJDEF_BIOME)
+BiomeManager::BiomeManager(Server *server) :
+ ObjDefManager(server, OBJDEF_BIOME)
{
- m_gamedef = gamedef;
+ m_server = server;
// Create default biome to be used in case none exist
Biome *b = new Biome;
@@ -73,7 +72,7 @@ BiomeManager::~BiomeManager()
void BiomeManager::clear()
{
- EmergeManager *emerge = m_gamedef->getEmergeManager();
+ EmergeManager *emerge = m_server->getEmergeManager();
// Remove all dangling references in Decorations
DecorationManager *decomgr = emerge->decomgr;
diff --git a/src/mg_biome.h b/src/mg_biome.h
index a10193bc3..2e07fd9cf 100644
--- a/src/mg_biome.h
+++ b/src/mg_biome.h
@@ -1,6 +1,7 @@
/*
Minetest
-Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2014-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2014-2017 paramat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -24,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodedef.h"
#include "noise.h"
+class Server;
class Settings;
class BiomeManager;
@@ -186,7 +188,7 @@ private:
class BiomeManager : public ObjDefManager {
public:
- BiomeManager(IGameDef *gamedef);
+ BiomeManager(Server *server);
virtual ~BiomeManager();
const char *getObjectTitle() const
@@ -223,7 +225,7 @@ public:
virtual void clear();
private:
- IGameDef *m_gamedef;
+ Server *m_server;
};
diff --git a/src/mg_decoration.cpp b/src/mg_decoration.cpp
index 51e4fbbcc..b0566e830 100644
--- a/src/mg_decoration.cpp
+++ b/src/mg_decoration.cpp
@@ -1,6 +1,7 @@
/*
Minetest
-Copyright (C) 2010-2014 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2014-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2015-2017 paramat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -24,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h"
#include "log.h"
#include "util/numeric.h"
+#include <algorithm>
+
FlagDesc flagdesc_deco[] = {
{"place_center_x", DECO_PLACE_CENTER_X},
diff --git a/src/mg_decoration.h b/src/mg_decoration.h
index 986328ec3..950800ec8 100644
--- a/src/mg_decoration.h
+++ b/src/mg_decoration.h
@@ -1,6 +1,7 @@
/*
Minetest
-Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2014-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2015-2017 paramat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
diff --git a/src/mg_ore.cpp b/src/mg_ore.cpp
index d840d745a..89319238e 100644
--- a/src/mg_ore.cpp
+++ b/src/mg_ore.cpp
@@ -1,6 +1,7 @@
/*
Minetest
-Copyright (C) 2010-2014 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2014-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2015-2017 paramat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -20,9 +21,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mg_ore.h"
#include "mapgen.h"
#include "noise.h"
-#include "util/numeric.h"
#include "map.h"
#include "log.h"
+#include <algorithm>
+
FlagDesc flagdesc_ore[] = {
{"absheight", OREFLAG_ABSHEIGHT},
diff --git a/src/mg_ore.h b/src/mg_ore.h
index e95fdd330..0503a6ca0 100644
--- a/src/mg_ore.h
+++ b/src/mg_ore.h
@@ -1,6 +1,7 @@
/*
Minetest
-Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2014-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2015-2017 paramat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
diff --git a/src/mg_schematic.cpp b/src/mg_schematic.cpp
index e028215dc..67931497f 100644
--- a/src/mg_schematic.cpp
+++ b/src/mg_schematic.cpp
@@ -1,6 +1,7 @@
/*
Minetest
-Copyright (C) 2010-2014 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2014-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2015-2017 paramat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -20,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <fstream>
#include <typeinfo>
#include "mg_schematic.h"
-#include "gamedef.h"
+#include "server.h"
#include "mapgen.h"
#include "emerge.h"
#include "map.h"
@@ -30,20 +31,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/serialize.h"
#include "serialization.h"
#include "filesys.h"
+#include "voxelalgorithms.h"
///////////////////////////////////////////////////////////////////////////////
-SchematicManager::SchematicManager(IGameDef *gamedef) :
- ObjDefManager(gamedef, OBJDEF_SCHEMATIC)
+SchematicManager::SchematicManager(Server *server) :
+ ObjDefManager(server, OBJDEF_SCHEMATIC)
{
- m_gamedef = gamedef;
+ m_server = server;
}
void SchematicManager::clear()
{
- EmergeManager *emerge = m_gamedef->getEmergeManager();
+ EmergeManager *emerge = m_server->getEmergeManager();
// Remove all dangling references in Decorations
DecorationManager *decomgr = emerge->decomgr;
@@ -202,7 +204,7 @@ bool Schematic::placeOnVManip(MMVManip *vm, v3s16 p, u32 flags,
return vm->m_area.contains(VoxelArea(p, p + s - v3s16(1,1,1)));
}
-void Schematic::placeOnMap(Map *map, v3s16 p, u32 flags,
+void Schematic::placeOnMap(ServerMap *map, v3s16 p, u32 flags,
Rotation rot, bool force_place)
{
std::map<v3s16, MapBlock *> lighting_modified_blocks;
@@ -238,15 +240,10 @@ void Schematic::placeOnMap(Map *map, v3s16 p, u32 flags,
blitToVManip(&vm, p, rot, force_place);
- vm.blitBackAll(&modified_blocks);
+ voxalgo::blit_back_with_light(map, &vm, &modified_blocks);
//// Carry out post-map-modification actions
- //// Update lighting
- // TODO: Optimize this by using Mapgen::calcLighting() instead
- lighting_modified_blocks.insert(modified_blocks.begin(), modified_blocks.end());
- map->updateLighting(lighting_modified_blocks, modified_blocks);
-
//// Create & dispatch map modification events to observers
MapEditEvent event;
event.type = MEET_OTHER;
diff --git a/src/mg_schematic.h b/src/mg_schematic.h
index da8859540..db040343c 100644
--- a/src/mg_schematic.h
+++ b/src/mg_schematic.h
@@ -1,6 +1,7 @@
/*
Minetest
-Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2014-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2015-2017 paramat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -25,11 +26,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h"
class Map;
+class ServerMap;
class Mapgen;
class MMVManip;
class PseudoRandom;
class NodeResolver;
-class IGameDef;
+class Server;
/*
Minetest Schematic File Format
@@ -108,7 +110,7 @@ public:
void blitToVManip(MMVManip *vm, v3s16 p, Rotation rot, bool force_place);
bool placeOnVManip(MMVManip *vm, v3s16 p, u32 flags, Rotation rot, bool force_place);
- void placeOnMap(Map *map, v3s16 p, u32 flags, Rotation rot, bool force_place);
+ void placeOnMap(ServerMap *map, v3s16 p, u32 flags, Rotation rot, bool force_place);
void applyProbabilities(v3s16 p0,
std::vector<std::pair<v3s16, u8> > *plist,
@@ -123,7 +125,7 @@ public:
class SchematicManager : public ObjDefManager {
public:
- SchematicManager(IGameDef *gamedef);
+ SchematicManager(Server *server);
virtual ~SchematicManager() {}
virtual void clear();
@@ -139,7 +141,7 @@ public:
}
private:
- IGameDef *m_gamedef;
+ Server *m_server;
};
void generate_nodelist_and_update_ids(MapNode *nodes, size_t nodecount,
diff --git a/src/minimap.cpp b/src/minimap.cpp
index 8cd0a7beb..500f49828 100644
--- a/src/minimap.cpp
+++ b/src/minimap.cpp
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "porting.h"
#include "util/numeric.h"
#include "util/string.h"
+#include "mapblock.h"
#include <math.h>
@@ -104,7 +105,7 @@ void MinimapUpdateThread::doUpdate()
// Swap two values in the map using single lookup
std::pair<std::map<v3s16, MinimapMapblock*>::iterator, bool>
result = m_blocks_cache.insert(std::make_pair(update.pos, update.data));
- if (result.second == false) {
+ if (!result.second) {
delete result.first->second;
result.first->second = update.data;
}
@@ -119,89 +120,63 @@ void MinimapUpdateThread::doUpdate()
}
if (data->map_invalidated && data->mode != MINIMAP_MODE_OFF) {
- getMap(data->pos, data->map_size, data->scan_height, data->is_radar);
+ getMap(data->pos, data->map_size, data->scan_height);
data->map_invalidated = false;
}
}
-MinimapPixel *MinimapUpdateThread::getMinimapPixel(v3s16 pos,
- s16 scan_height, s16 *pixel_height)
+void MinimapUpdateThread::getMap(v3s16 pos, s16 size, s16 height)
{
- s16 height = scan_height - MAP_BLOCKSIZE;
- v3s16 blockpos_max, blockpos_min, relpos;
-
- getNodeBlockPosWithOffset(
- v3s16(pos.X, pos.Y - scan_height / 2, pos.Z),
- blockpos_min, relpos);
- getNodeBlockPosWithOffset(
- v3s16(pos.X, pos.Y + scan_height / 2, pos.Z),
- blockpos_max, relpos);
-
- for (s16 i = blockpos_max.Y; i > blockpos_min.Y - 1; i--) {
- std::map<v3s16, MinimapMapblock *>::iterator it =
- m_blocks_cache.find(v3s16(blockpos_max.X, i, blockpos_max.Z));
- if (it != m_blocks_cache.end()) {
- MinimapMapblock *mmblock = it->second;
- MinimapPixel *pixel = &mmblock->data[relpos.Z * MAP_BLOCKSIZE + relpos.X];
- if (pixel->id != CONTENT_AIR) {
- *pixel_height = height + pixel->height;
- return pixel;
- }
- }
-
- height -= MAP_BLOCKSIZE;
- }
-
- return NULL;
-}
-
-s16 MinimapUpdateThread::getAirCount(v3s16 pos, s16 height)
-{
- s16 air_count = 0;
- v3s16 blockpos_max, blockpos_min, relpos;
-
- getNodeBlockPosWithOffset(
- v3s16(pos.X, pos.Y - height / 2, pos.Z),
- blockpos_min, relpos);
- getNodeBlockPosWithOffset(
- v3s16(pos.X, pos.Y + height / 2, pos.Z),
- blockpos_max, relpos);
-
- for (s16 i = blockpos_max.Y; i > blockpos_min.Y - 1; i--) {
- std::map<v3s16, MinimapMapblock *>::iterator it =
- m_blocks_cache.find(v3s16(blockpos_max.X, i, blockpos_max.Z));
- if (it != m_blocks_cache.end()) {
- MinimapMapblock *mmblock = it->second;
- MinimapPixel *pixel = &mmblock->data[relpos.Z * MAP_BLOCKSIZE + relpos.X];
- air_count += pixel->air_count;
- }
+ v3s16 region(size, 0, size);
+ v3s16 pos_min(pos.X - size / 2, pos.Y - height / 2, pos.Z - size / 2);
+ v3s16 pos_max(pos_min.X + size - 1, pos.Y + height / 2, pos_min.Z + size - 1);
+ v3s16 blockpos_min = getNodeBlockPos(pos_min);
+ v3s16 blockpos_max = getNodeBlockPos(pos_max);
+
+// clear the map
+ for (int z = 0; z < size; z++)
+ for (int x = 0; x < size; x++) {
+ MinimapPixel &mmpixel = data->minimap_scan[x + z * size];
+ mmpixel.air_count = 0;
+ mmpixel.height = 0;
+ mmpixel.n = MapNode(CONTENT_AIR);
}
- return air_count;
-}
-
-void MinimapUpdateThread::getMap(v3s16 pos, s16 size, s16 height, bool is_radar)
-{
- v3s16 p = v3s16(pos.X - size / 2, pos.Y, pos.Z - size / 2);
-
- for (s16 x = 0; x < size; x++)
- for (s16 z = 0; z < size; z++) {
- u16 id = CONTENT_AIR;
- MinimapPixel *mmpixel = &data->minimap_scan[x + z * size];
-
- if (!is_radar) {
- s16 pixel_height = 0;
- MinimapPixel *cached_pixel =
- getMinimapPixel(v3s16(p.X + x, p.Y, p.Z + z), height, &pixel_height);
- if (cached_pixel) {
- id = cached_pixel->id;
- mmpixel->height = pixel_height;
+// draw the map
+ v3s16 blockpos;
+ for (blockpos.Z = blockpos_min.Z; blockpos.Z <= blockpos_max.Z; ++blockpos.Z)
+ for (blockpos.Y = blockpos_min.Y; blockpos.Y <= blockpos_max.Y; ++blockpos.Y)
+ for (blockpos.X = blockpos_min.X; blockpos.X <= blockpos_max.X; ++blockpos.X) {
+ std::map<v3s16, MinimapMapblock *>::const_iterator pblock =
+ m_blocks_cache.find(blockpos);
+ if (pblock == m_blocks_cache.end())
+ continue;
+ const MinimapMapblock &block = *pblock->second;
+
+ v3s16 block_node_min(blockpos * MAP_BLOCKSIZE);
+ v3s16 block_node_max(block_node_min + MAP_BLOCKSIZE - 1);
+ // clip
+ v3s16 range_min = componentwise_max(block_node_min, pos_min);
+ v3s16 range_max = componentwise_min(block_node_max, pos_max);
+
+ v3s16 pos;
+ pos.Y = range_min.Y;
+ for (pos.Z = range_min.Z; pos.Z <= range_max.Z; ++pos.Z)
+ for (pos.X = range_min.X; pos.X <= range_max.X; ++pos.X) {
+ v3s16 inblock_pos = pos - block_node_min;
+ const MinimapPixel &in_pixel =
+ block.data[inblock_pos.Z * MAP_BLOCKSIZE + inblock_pos.X];
+
+ v3s16 inmap_pos = pos - pos_min;
+ MinimapPixel &out_pixel =
+ data->minimap_scan[inmap_pos.X + inmap_pos.Z * size];
+
+ out_pixel.air_count += in_pixel.air_count;
+ if (in_pixel.n.param0 != CONTENT_AIR) {
+ out_pixel.n = in_pixel.n;
+ out_pixel.height = inmap_pos.Y + in_pixel.height;
}
- } else {
- mmpixel->air_count = getAirCount(v3s16(p.X + x, p.Y, p.Z + z), height);
}
-
- mmpixel->id = id;
}
}
@@ -209,7 +184,7 @@ void MinimapUpdateThread::getMap(v3s16 pos, s16 size, s16 height, bool is_radar)
//// Mapper
////
-Mapper::Mapper(IrrlichtDevice *device, Client *client)
+Minimap::Minimap(IrrlichtDevice *device, Client *client)
{
this->client = client;
this->driver = device->getVideoDriver();
@@ -263,7 +238,7 @@ Mapper::Mapper(IrrlichtDevice *device, Client *client)
m_minimap_update_thread->start();
}
-Mapper::~Mapper()
+Minimap::~Minimap()
{
m_minimap_update_thread->stop();
m_minimap_update_thread->wait();
@@ -283,17 +258,12 @@ Mapper::~Mapper()
delete m_minimap_update_thread;
}
-void Mapper::addBlock(v3s16 pos, MinimapMapblock *data)
+void Minimap::addBlock(v3s16 pos, MinimapMapblock *data)
{
m_minimap_update_thread->enqueueBlock(pos, data);
}
-MinimapMode Mapper::getMinimapMode()
-{
- return data->mode;
-}
-
-void Mapper::toggleMinimapShape()
+void Minimap::toggleMinimapShape()
{
MutexAutoLock lock(m_mutex);
@@ -302,7 +272,29 @@ void Mapper::toggleMinimapShape()
m_minimap_update_thread->deferUpdate();
}
-void Mapper::setMinimapMode(MinimapMode mode)
+void Minimap::setMinimapShape(MinimapShape shape)
+{
+ MutexAutoLock lock(m_mutex);
+
+ if (shape == MINIMAP_SHAPE_SQUARE)
+ data->minimap_shape_round = false;
+ else if (shape == MINIMAP_SHAPE_ROUND)
+ data->minimap_shape_round = true;
+
+ g_settings->setBool("minimap_shape_round", data->minimap_shape_round);
+ m_minimap_update_thread->deferUpdate();
+}
+
+MinimapShape Minimap::getMinimapShape()
+{
+ if (data->minimap_shape_round) {
+ return MINIMAP_SHAPE_ROUND;
+ } else {
+ return MINIMAP_SHAPE_SQUARE;
+ }
+}
+
+void Minimap::setMinimapMode(MinimapMode mode)
{
static const MinimapModeDef modedefs[MINIMAP_MODE_COUNT] = {
{false, 0, 0},
@@ -327,7 +319,7 @@ void Mapper::setMinimapMode(MinimapMode mode)
m_minimap_update_thread->deferUpdate();
}
-void Mapper::setPos(v3s16 pos)
+void Minimap::setPos(v3s16 pos)
{
bool do_update = false;
@@ -345,36 +337,51 @@ void Mapper::setPos(v3s16 pos)
m_minimap_update_thread->deferUpdate();
}
-void Mapper::setAngle(f32 angle)
+void Minimap::setAngle(f32 angle)
{
m_angle = angle;
}
-void Mapper::blitMinimapPixelsToImageRadar(video::IImage *map_image)
+void Minimap::blitMinimapPixelsToImageRadar(video::IImage *map_image)
{
+ video::SColor c(240, 0, 0, 0);
for (s16 x = 0; x < data->map_size; x++)
for (s16 z = 0; z < data->map_size; z++) {
MinimapPixel *mmpixel = &data->minimap_scan[x + z * data->map_size];
- video::SColor c(240, 0, 0, 0);
if (mmpixel->air_count > 0)
c.setGreen(core::clamp(core::round32(32 + mmpixel->air_count * 8), 0, 255));
+ else
+ c.setGreen(0);
map_image->setPixel(x, data->map_size - z - 1, c);
}
}
-void Mapper::blitMinimapPixelsToImageSurface(
+void Minimap::blitMinimapPixelsToImageSurface(
video::IImage *map_image, video::IImage *heightmap_image)
{
+ // This variable creation/destruction has a 1% cost on rendering minimap
+ video::SColor tilecolor;
for (s16 x = 0; x < data->map_size; x++)
for (s16 z = 0; z < data->map_size; z++) {
MinimapPixel *mmpixel = &data->minimap_scan[x + z * data->map_size];
- video::SColor c = m_ndef->get(mmpixel->id).minimap_color;
- c.setAlpha(240);
+ const ContentFeatures &f = m_ndef->get(mmpixel->n);
+ const TileDef *tile = &f.tiledef[0];
- map_image->setPixel(x, data->map_size - z - 1, c);
+ // Color of the 0th tile (mostly this is the topmost)
+ if(tile->has_color)
+ tilecolor = tile->color;
+ else
+ mmpixel->n.getColor(f, &tilecolor);
+
+ tilecolor.setRed(tilecolor.getRed() * f.minimap_color.getRed() / 255);
+ tilecolor.setGreen(tilecolor.getGreen() * f.minimap_color.getGreen() / 255);
+ tilecolor.setBlue(tilecolor.getBlue() * f.minimap_color.getBlue() / 255);
+ tilecolor.setAlpha(240);
+
+ map_image->setPixel(x, data->map_size - z - 1, tilecolor);
u32 h = mmpixel->height;
heightmap_image->setPixel(x,data->map_size - z - 1,
@@ -382,7 +389,7 @@ void Mapper::blitMinimapPixelsToImageSurface(
}
}
-video::ITexture *Mapper::getMinimapTexture()
+video::ITexture *Minimap::getMinimapTexture()
{
// update minimap textures when new scan is ready
if (data->map_invalidated)
@@ -410,7 +417,7 @@ video::ITexture *Mapper::getMinimapTexture()
if (minimap_mask) {
for (s16 y = 0; y < MINIMAP_MAX_SY; y++)
for (s16 x = 0; x < MINIMAP_MAX_SX; x++) {
- video::SColor mask_col = minimap_mask->getPixel(x, y);
+ const video::SColor &mask_col = minimap_mask->getPixel(x, y);
if (!mask_col.getAlpha())
minimap_image->setPixel(x, y, video::SColor(0,0,0,0));
}
@@ -432,7 +439,7 @@ video::ITexture *Mapper::getMinimapTexture()
return data->texture;
}
-v3f Mapper::getYawVec()
+v3f Minimap::getYawVec()
{
if (data->minimap_shape_round) {
return v3f(
@@ -444,12 +451,12 @@ v3f Mapper::getYawVec()
}
}
-scene::SMeshBuffer *Mapper::getMinimapMeshBuffer()
+scene::SMeshBuffer *Minimap::getMinimapMeshBuffer()
{
scene::SMeshBuffer *buf = new scene::SMeshBuffer();
buf->Vertices.set_used(4);
buf->Indices.set_used(6);
- video::SColor c(255, 255, 255, 255);
+ static const video::SColor c(255, 255, 255, 255);
buf->Vertices[0] = video::S3DVertex(-1, -1, 0, 0, 0, 1, c, 0, 1);
buf->Vertices[1] = video::S3DVertex(-1, 1, 0, 0, 0, 1, c, 0, 0);
@@ -466,7 +473,7 @@ scene::SMeshBuffer *Mapper::getMinimapMeshBuffer()
return buf;
}
-void Mapper::drawMinimap()
+void Minimap::drawMinimap()
{
video::ITexture *minimap_texture = getMinimapTexture();
if (!minimap_texture)
@@ -564,20 +571,18 @@ void Mapper::drawMinimap()
}
}
-void Mapper::updateActiveMarkers ()
+void Minimap::updateActiveMarkers()
{
video::IImage *minimap_mask = data->minimap_shape_round ?
data->minimap_mask_round : data->minimap_mask_square;
- std::list<Nametag *> *nametags = client->getCamera()->getNametags();
+ const std::list<Nametag *> &nametags = client->getCamera()->getNametags();
m_active_markers.clear();
- for (std::list<Nametag *>::const_iterator
- i = nametags->begin();
- i != nametags->end(); ++i) {
- Nametag *nametag = *i;
- v3s16 pos = floatToInt(nametag->parent_node->getPosition() +
+ for (std::list<Nametag *>::const_iterator i = nametags.begin();
+ i != nametags.end(); ++i) {
+ v3s16 pos = floatToInt((*i)->parent_node->getPosition() +
intToFloat(client->getCamera()->getOffset(), BS), BS);
pos -= data->pos - v3s16(data->map_size / 2,
data->scan_height / 2,
@@ -589,7 +594,7 @@ void Mapper::updateActiveMarkers ()
}
pos.X = ((float)pos.X / data->map_size) * MINIMAP_MAX_SX;
pos.Z = ((float)pos.Z / data->map_size) * MINIMAP_MAX_SY;
- video::SColor mask_col = minimap_mask->getPixel(pos.X, pos.Z);
+ const video::SColor &mask_col = minimap_mask->getPixel(pos.X, pos.Z);
if (!mask_col.getAlpha()) {
continue;
}
@@ -616,7 +621,7 @@ void MinimapMapblock::getMinimapNodes(VoxelManipulator *vmanip, v3s16 pos)
MapNode n = vmanip->getNodeNoEx(pos + p);
if (!surface_found && n.getContent() != CONTENT_AIR) {
mmpixel->height = y;
- mmpixel->id = n.getContent();
+ mmpixel->n = n;
surface_found = true;
} else if (n.getContent() == CONTENT_AIR) {
air_count++;
@@ -624,7 +629,7 @@ void MinimapMapblock::getMinimapNodes(VoxelManipulator *vmanip, v3s16 pos)
}
if (!surface_found)
- mmpixel->id = CONTENT_AIR;
+ mmpixel->n = MapNode(CONTENT_AIR);
mmpixel->air_count = air_count;
}
diff --git a/src/minimap.h b/src/minimap.h
index 743b2bff2..c50530335 100644
--- a/src/minimap.h
+++ b/src/minimap.h
@@ -45,6 +45,11 @@ enum MinimapMode {
MINIMAP_MODE_COUNT,
};
+enum MinimapShape {
+ MINIMAP_SHAPE_SQUARE,
+ MINIMAP_SHAPE_ROUND,
+};
+
struct MinimapModeDef {
bool is_radar;
u16 scan_height;
@@ -52,10 +57,10 @@ struct MinimapModeDef {
};
struct MinimapPixel {
- u16 id;
+ //! The topmost node that the minimap displays.
+ MapNode n;
u16 height;
u16 air_count;
- u16 light;
};
struct MinimapMapblock {
@@ -96,13 +101,8 @@ public:
MinimapUpdateThread() : UpdateThread("Minimap") {}
virtual ~MinimapUpdateThread();
- void getMap(v3s16 pos, s16 size, s16 height, bool radar);
- MinimapPixel *getMinimapPixel(v3s16 pos, s16 height, s16 *pixel_height);
- s16 getAirCount(v3s16 pos, s16 height);
- video::SColor getColorFromId(u16 id);
-
+ void getMap(v3s16 pos, s16 size, s16 height);
void enqueueBlock(v3s16 pos, MinimapMapblock *data);
-
bool pushBlockUpdate(v3s16 pos, MinimapMapblock *data);
bool popBlockUpdate(QueuedMinimapUpdate *update);
@@ -117,20 +117,24 @@ private:
std::map<v3s16, MinimapMapblock *> m_blocks_cache;
};
-class Mapper {
+class Minimap {
public:
- Mapper(IrrlichtDevice *device, Client *client);
- ~Mapper();
+ Minimap(IrrlichtDevice *device, Client *client);
+ ~Minimap();
void addBlock(v3s16 pos, MinimapMapblock *data);
v3f getYawVec();
- MinimapMode getMinimapMode();
void setPos(v3s16 pos);
+ v3s16 getPos() const { return data->pos; }
void setAngle(f32 angle);
+ f32 getAngle() const { return m_angle; }
void setMinimapMode(MinimapMode mode);
+ MinimapMode getMinimapMode() const { return data->mode; }
void toggleMinimapShape();
+ void setMinimapShape(MinimapShape shape);
+ MinimapShape getMinimapShape();
video::ITexture *getMinimapTexture();
diff --git a/src/modalMenu.h b/src/modalMenu.h
index 43bb8e1b8..38a26535e 100644
--- a/src/modalMenu.h
+++ b/src/modalMenu.h
@@ -43,14 +43,13 @@ public:
class GUIModalMenu : public gui::IGUIElement
{
public:
- GUIModalMenu(gui::IGUIEnvironment* env,
- gui::IGUIElement* parent, s32 id,
+ GUIModalMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr):
IGUIElement(gui::EGUIET_ELEMENT, env, parent, id,
core::rect<s32>(0,0,100,100))
{
//m_force_regenerate_gui = false;
-
+
m_menumgr = menumgr;
m_allow_focus_removal = false;
m_screensize_old = v2u32(0,0);
@@ -59,6 +58,7 @@ public:
Environment->setFocus(this);
m_menumgr->createdMenu(this);
}
+
virtual ~GUIModalMenu()
{
m_menumgr->deletingMenu(this);
@@ -78,7 +78,7 @@ public:
{
if(!IsVisible)
return;
-
+
video::IVideoDriver* driver = Environment->getVideoDriver();
v2u32 screensize = driver->getScreenSize();
if(screensize != m_screensize_old /*|| m_force_regenerate_gui*/)
@@ -90,7 +90,7 @@ public:
drawMenu();
}
-
+
/*
This should be called when the menu wants to quit.
diff --git a/src/modifiedstate.h b/src/modifiedstate.h
index 75518f2f5..576c3c576 100644
--- a/src/modifiedstate.h
+++ b/src/modifiedstate.h
@@ -34,4 +34,3 @@ enum ModifiedState
};
#endif
-
diff --git a/src/mods.cpp b/src/mods.cpp
index 1b1bdb07b..0e583b2db 100644
--- a/src/mods.cpp
+++ b/src/mods.cpp
@@ -21,13 +21,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <fstream>
#include "mods.h"
#include "filesys.h"
-#include "util/strfnd.h"
#include "log.h"
#include "subgame.h"
#include "settings.h"
-#include "util/strfnd.h"
#include "convert_json.h"
#include "exceptions.h"
+#include "porting.h"
static bool parseDependsLine(std::istream &is,
std::string &dep, std::set<char> &symbols)
@@ -110,28 +109,6 @@ std::map<std::string, ModSpec> getModsInPath(std::string path, bool part_of_modp
return result;
}
-std::map<std::string, ModSpec> flattenModTree(std::map<std::string, ModSpec> mods)
-{
- std::map<std::string, ModSpec> result;
- for(std::map<std::string,ModSpec>::iterator it = mods.begin();
- it != mods.end(); ++it)
- {
- ModSpec mod = (*it).second;
- if(mod.is_modpack)
- {
- std::map<std::string, ModSpec> content =
- flattenModTree(mod.modpack_content);
- result.insert(content.begin(),content.end());
- result.insert(std::make_pair(mod.name,mod));
- }
- else //not a modpack
- {
- result.insert(std::make_pair(mod.name,mod));
- }
- }
- return result;
-}
-
std::vector<ModSpec> flattenMods(std::map<std::string, ModSpec> mods)
{
std::vector<ModSpec> result;
@@ -154,78 +131,32 @@ std::vector<ModSpec> flattenMods(std::map<std::string, ModSpec> mods)
return result;
}
-ModConfiguration::ModConfiguration(std::string worldpath)
+ModConfiguration::ModConfiguration(const std::string &worldpath):
+ m_unsatisfied_mods(),
+ m_sorted_mods(),
+ m_name_conflicts()
{
- SubgameSpec gamespec = findWorldSubgame(worldpath);
-
- // Add all game mods and all world mods
- addModsInPath(gamespec.gamemods_path);
- addModsInPath(worldpath + DIR_DELIM + "worldmods");
-
- // check world.mt file for mods explicitely declared to be
- // loaded or not by a load_mod_<modname> = ... line.
- std::string worldmt = worldpath+DIR_DELIM+"world.mt";
- Settings worldmt_settings;
- worldmt_settings.readConfigFile(worldmt.c_str());
- std::vector<std::string> names = worldmt_settings.getNames();
- std::set<std::string> include_mod_names;
- for(std::vector<std::string>::iterator it = names.begin();
- it != names.end(); ++it)
- {
- std::string name = *it;
- // for backwards compatibility: exclude only mods which are
- // explicitely excluded. if mod is not mentioned at all, it is
- // enabled. So by default, all installed mods are enabled.
- if (name.compare(0,9,"load_mod_") == 0 &&
- worldmt_settings.getBool(name))
- {
- include_mod_names.insert(name.substr(9));
- }
- }
-
- // Collect all mods that are also in include_mod_names
- std::vector<ModSpec> addon_mods;
- for(std::set<std::string>::const_iterator it_path = gamespec.addon_mods_paths.begin();
- it_path != gamespec.addon_mods_paths.end(); ++it_path)
- {
- std::vector<ModSpec> addon_mods_in_path = flattenMods(getModsInPath(*it_path));
- for(std::vector<ModSpec>::iterator it = addon_mods_in_path.begin();
- it != addon_mods_in_path.end(); ++it)
- {
- ModSpec& mod = *it;
- if(include_mod_names.count(mod.name) != 0)
- addon_mods.push_back(mod);
- else
- worldmt_settings.setBool("load_mod_" + mod.name, false);
- }
- }
- worldmt_settings.updateConfigFile(worldmt.c_str());
-
- addMods(addon_mods);
+}
- // report on name conflicts
- if(!m_name_conflicts.empty()){
- std::string s = "Unresolved name conflicts for mods ";
- for(std::set<std::string>::const_iterator it = m_name_conflicts.begin();
- it != m_name_conflicts.end(); ++it)
- {
- if(it != m_name_conflicts.begin()) s += ", ";
- s += std::string("\"") + (*it) + "\"";
- }
- s += ".";
- throw ModError(s);
+void ModConfiguration::printUnsatisfiedModsError() const
+{
+ for (std::vector<ModSpec>::const_iterator it = m_unsatisfied_mods.begin();
+ it != m_unsatisfied_mods.end(); ++it) {
+ ModSpec mod = *it;
+ errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
+ for (UNORDERED_SET<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
+ dep_it != mod.unsatisfied_depends.end(); ++dep_it)
+ errorstream << " \"" << *dep_it << "\"";
+ errorstream << std::endl;
}
-
- // get the mods in order
- resolveDependencies();
}
-void ModConfiguration::addModsInPath(std::string path)
+void ModConfiguration::addModsInPath(const std::string &path)
{
addMods(flattenMods(getModsInPath(path)));
}
-void ModConfiguration::addMods(std::vector<ModSpec> new_mods)
+void ModConfiguration::addMods(const std::vector<ModSpec> &new_mods)
{
// Maintain a map of all existing m_unsatisfied_mods.
// Keys are mod names and values are indices into m_unsatisfied_mods.
@@ -243,8 +174,8 @@ void ModConfiguration::addMods(std::vector<ModSpec> new_mods)
std::set<std::string> seen_this_iteration;
- for(std::vector<ModSpec>::const_iterator it = new_mods.begin();
- it != new_mods.end(); ++it){
+ for (std::vector<ModSpec>::const_iterator it = new_mods.begin();
+ it != new_mods.end(); ++it) {
const ModSpec &mod = *it;
if(mod.part_of_modpack != (bool)want_from_modpack)
continue;
@@ -283,6 +214,73 @@ void ModConfiguration::addMods(std::vector<ModSpec> new_mods)
}
}
+void ModConfiguration::addModsFormConfig(const std::string &settings_path, const std::set<std::string> &mods)
+{
+ Settings conf;
+ std::set<std::string> load_mod_names;
+
+ conf.readConfigFile(settings_path.c_str());
+ std::vector<std::string> names = conf.getNames();
+ for (std::vector<std::string>::iterator it = names.begin();
+ it != names.end(); ++it) {
+ std::string name = *it;
+ if (name.compare(0,9,"load_mod_")==0 && conf.getBool(name))
+ load_mod_names.insert(name.substr(9));
+ }
+
+ std::vector<ModSpec> addon_mods;
+ for (std::set<std::string>::const_iterator i = mods.begin();
+ i != mods.end(); ++i) {
+ std::vector<ModSpec> addon_mods_in_path = flattenMods(getModsInPath(*i));
+ for (std::vector<ModSpec>::const_iterator it = addon_mods_in_path.begin();
+ it != addon_mods_in_path.end(); ++it) {
+ const ModSpec& mod = *it;
+ if (load_mod_names.count(mod.name) != 0)
+ addon_mods.push_back(mod);
+ else
+ conf.setBool("load_mod_" + mod.name, false);
+ }
+ }
+ conf.updateConfigFile(settings_path.c_str());
+
+ addMods(addon_mods);
+ checkConflictsAndDeps();
+
+ // complain about mods declared to be loaded, but not found
+ for (std::vector<ModSpec>::iterator it = addon_mods.begin();
+ it != addon_mods.end(); ++it)
+ load_mod_names.erase((*it).name);
+ std::vector<ModSpec> UnsatisfiedMods = getUnsatisfiedMods();
+ for (std::vector<ModSpec>::iterator it = UnsatisfiedMods.begin();
+ it != UnsatisfiedMods.end(); ++it)
+ load_mod_names.erase((*it).name);
+ if (!load_mod_names.empty()) {
+ errorstream << "The following mods could not be found:";
+ for (std::set<std::string>::iterator it = load_mod_names.begin();
+ it != load_mod_names.end(); ++it)
+ errorstream << " \"" << (*it) << "\"";
+ errorstream << std::endl;
+ }
+}
+
+void ModConfiguration::checkConflictsAndDeps()
+{
+ // report on name conflicts
+ if (!m_name_conflicts.empty()) {
+ std::string s = "Unresolved name conflicts for mods ";
+ for (UNORDERED_SET<std::string>::const_iterator it = m_name_conflicts.begin();
+ it != m_name_conflicts.end(); ++it) {
+ if (it != m_name_conflicts.begin()) s += ", ";
+ s += std::string("\"") + (*it) + "\"";
+ }
+ s += ".";
+ throw ModError(s);
+ }
+
+ // get the mods in order
+ resolveDependencies();
+}
+
void ModConfiguration::resolveDependencies()
{
// Step 1: Compile a list of the mod names we're working with
@@ -296,19 +294,19 @@ void ModConfiguration::resolveDependencies()
// of each mod, split mods into satisfied and unsatisfied
std::list<ModSpec> satisfied;
std::list<ModSpec> unsatisfied;
- for(std::vector<ModSpec>::iterator it = m_unsatisfied_mods.begin();
- it != m_unsatisfied_mods.end(); ++it){
+ for (std::vector<ModSpec>::iterator it = m_unsatisfied_mods.begin();
+ it != m_unsatisfied_mods.end(); ++it) {
ModSpec mod = *it;
mod.unsatisfied_depends = mod.depends;
// check which optional dependencies actually exist
- for(std::set<std::string>::iterator it_optdep = mod.optdepends.begin();
- it_optdep != mod.optdepends.end(); ++it_optdep){
+ for (UNORDERED_SET<std::string>::iterator it_optdep = mod.optdepends.begin();
+ it_optdep != mod.optdepends.end(); ++it_optdep) {
std::string optdep = *it_optdep;
- if(modnames.count(optdep) != 0)
+ if (modnames.count(optdep) != 0)
mod.unsatisfied_depends.insert(optdep);
}
// if a mod has no depends it is initially satisfied
- if(mod.unsatisfied_depends.empty())
+ if (mod.unsatisfied_depends.empty())
satisfied.push_back(mod);
else
unsatisfied.push_back(mod);
@@ -338,8 +336,36 @@ void ModConfiguration::resolveDependencies()
m_unsatisfied_mods.assign(unsatisfied.begin(), unsatisfied.end());
}
+ServerModConfiguration::ServerModConfiguration(const std::string &worldpath):
+ ModConfiguration(worldpath)
+{
+ SubgameSpec gamespec = findWorldSubgame(worldpath);
+
+ // Add all game mods and all world mods
+ addModsInPath(gamespec.gamemods_path);
+ addModsInPath(worldpath + DIR_DELIM + "worldmods");
+
+ // Load normal mods
+ std::string worldmt = worldpath + DIR_DELIM + "world.mt";
+ addModsFormConfig(worldmt, gamespec.addon_mods_paths);
+}
+
+#ifndef SERVER
+ClientModConfiguration::ClientModConfiguration(const std::string &path):
+ ModConfiguration(path)
+{
+ std::set<std::string> paths;
+ std::string path_user = porting::path_user + DIR_DELIM + "clientmods";
+ paths.insert(path);
+ paths.insert(path_user);
+
+ std::string settings_path = path_user + DIR_DELIM + "mods.conf";
+ addModsFormConfig(settings_path, paths);
+}
+#endif
+
#if USE_CURL
-Json::Value getModstoreUrl(std::string url)
+Json::Value getModstoreUrl(const std::string &url)
{
std::vector<std::string> extra_headers;
@@ -356,3 +382,80 @@ Json::Value getModstoreUrl(std::string url)
}
#endif
+
+ModMetadata::ModMetadata(const std::string &mod_name):
+ m_mod_name(mod_name),
+ m_modified(false)
+{
+ m_stringvars.clear();
+}
+
+void ModMetadata::clear()
+{
+ Metadata::clear();
+ m_modified = true;
+}
+
+bool ModMetadata::save(const std::string &root_path)
+{
+ Json::Value json;
+ for (StringMap::const_iterator it = m_stringvars.begin();
+ it != m_stringvars.end(); ++it) {
+ json[it->first] = it->second;
+ }
+
+ if (!fs::PathExists(root_path)) {
+ if (!fs::CreateAllDirs(root_path)) {
+ errorstream << "ModMetadata[" << m_mod_name << "]: Unable to save. '"
+ << root_path << "' tree cannot be created." << std::endl;
+ return false;
+ }
+ } else if (!fs::IsDir(root_path)) {
+ errorstream << "ModMetadata[" << m_mod_name << "]: Unable to save. '"
+ << root_path << "' is not a directory." << std::endl;
+ return false;
+ }
+
+ bool w_ok = fs::safeWriteToFile(root_path + DIR_DELIM + m_mod_name,
+ Json::FastWriter().write(json));
+
+ if (w_ok) {
+ m_modified = false;
+ } else {
+ errorstream << "ModMetadata[" << m_mod_name << "]: failed write file." << std::endl;
+ }
+ return w_ok;
+}
+
+bool ModMetadata::load(const std::string &root_path)
+{
+ m_stringvars.clear();
+
+ std::ifstream is((root_path + DIR_DELIM + m_mod_name).c_str(), std::ios_base::binary);
+ if (!is.good()) {
+ return false;
+ }
+
+ Json::Reader reader;
+ Json::Value root;
+ if (!reader.parse(is, root)) {
+ errorstream << "ModMetadata[" << m_mod_name << "]: failed read data "
+ "(Json decoding failure)." << std::endl;
+ return false;
+ }
+
+ const Json::Value::Members attr_list = root.getMemberNames();
+ for (Json::Value::Members::const_iterator it = attr_list.begin();
+ it != attr_list.end(); ++it) {
+ Json::Value attr_value = root[*it];
+ m_stringvars[*it] = attr_value.asString();
+ }
+
+ return true;
+}
+
+bool ModMetadata::setString(const std::string &name, const std::string &var)
+{
+ m_modified = Metadata::setString(name, var);
+ return m_modified;
+}
diff --git a/src/mods.h b/src/mods.h
index af7777d18..7455a51ea 100644
--- a/src/mods.h
+++ b/src/mods.h
@@ -27,7 +27,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
#include <map>
#include <json/json.h>
+#include "util/cpp11_container.h"
#include "config.h"
+#include "metadata.h"
#define MODNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_"
@@ -36,9 +38,9 @@ struct ModSpec
std::string name;
std::string path;
//if normal mod:
- std::set<std::string> depends;
- std::set<std::string> optdepends;
- std::set<std::string> unsatisfied_depends;
+ UNORDERED_SET<std::string> depends;
+ UNORDERED_SET<std::string> optdepends;
+ UNORDERED_SET<std::string> unsatisfied_depends;
bool part_of_modpack;
bool is_modpack;
@@ -61,12 +63,6 @@ void parseModContents(ModSpec &mod);
std::map<std::string,ModSpec> getModsInPath(std::string path, bool part_of_modpack = false);
-// If failed, returned modspec has name==""
-ModSpec findCommonMod(const std::string &modname);
-
-// expands modpack contents, but does not replace them.
-std::map<std::string, ModSpec> flattenModTree(std::map<std::string, ModSpec> mods);
-
// replaces modpack Modspecs with their content
std::vector<ModSpec> flattenMods(std::map<std::string,ModSpec> mods);
@@ -76,17 +72,8 @@ std::vector<ModSpec> flattenMods(std::map<std::string,ModSpec> mods);
class ModConfiguration
{
public:
- ModConfiguration():
- m_unsatisfied_mods(),
- m_sorted_mods(),
- m_name_conflicts()
- {}
-
-
- ModConfiguration(std::string worldpath);
-
// checks if all dependencies are fullfilled.
- bool isConsistent()
+ bool isConsistent() const
{
return m_unsatisfied_mods.empty();
}
@@ -96,19 +83,26 @@ public:
return m_sorted_mods;
}
- std::vector<ModSpec> getUnsatisfiedMods()
+ const std::vector<ModSpec> &getUnsatisfiedMods() const
{
return m_unsatisfied_mods;
}
-private:
+ void printUnsatisfiedModsError() const;
+
+protected:
+ ModConfiguration(const std::string &worldpath);
// adds all mods in the given path. used for games, modpacks
// and world-specific mods (worldmods-folders)
- void addModsInPath(std::string path);
+ void addModsInPath(const std::string &path);
// adds all mods in the set.
- void addMods(std::vector<ModSpec> new_mods);
+ void addMods(const std::vector<ModSpec> &new_mods);
+ void addModsFormConfig(const std::string &settings_path, const std::set<std::string> &mods);
+
+ void checkConflictsAndDeps();
+private:
// move mods from m_unsatisfied_mods to m_sorted_mods
// in an order that satisfies dependencies
void resolveDependencies();
@@ -131,14 +125,33 @@ private:
// 1. game mod in modpack; 2. game mod;
// 3. world mod in modpack; 4. world mod;
// 5. addon mod in modpack; 6. addon mod.
- std::set<std::string> m_name_conflicts;
+ UNORDERED_SET<std::string> m_name_conflicts;
+
+ // Deleted default constructor
+ ModConfiguration() {}
+
+};
+
+class ServerModConfiguration: public ModConfiguration
+{
+public:
+ ServerModConfiguration(const std::string &worldpath);
};
+#ifndef SERVER
+class ClientModConfiguration: public ModConfiguration
+{
+public:
+ ClientModConfiguration(const std::string &path);
+};
+#endif
+
#if USE_CURL
-Json::Value getModstoreUrl(std::string url);
+Json::Value getModstoreUrl(const std::string &url);
#else
-inline Json::Value getModstoreUrl(std::string url) {
+inline Json::Value getModstoreUrl(const std::string &url)
+{
return Json::Value();
}
#endif
@@ -205,4 +218,24 @@ struct ModStoreModDetails {
bool valid;
};
+class ModMetadata: public Metadata
+{
+public:
+ ModMetadata(const std::string &mod_name);
+ ~ModMetadata() {}
+
+ virtual void clear();
+
+ bool save(const std::string &root_path);
+ bool load(const std::string &root_path);
+
+ bool isModified() const { return m_modified; }
+ const std::string &getModName() const { return m_mod_name; }
+
+ virtual bool setString(const std::string &name, const std::string &var);
+private:
+ std::string m_mod_name;
+ bool m_modified;
+};
+
#endif
diff --git a/src/nameidmapping.cpp b/src/nameidmapping.cpp
index 2af8befff..d031f0808 100644
--- a/src/nameidmapping.cpp
+++ b/src/nameidmapping.cpp
@@ -25,27 +25,25 @@ void NameIdMapping::serialize(std::ostream &os) const
{
writeU8(os, 0); // version
writeU16(os, m_id_to_name.size());
- for(UNORDERED_MAP<u16, std::string>::const_iterator
- i = m_id_to_name.begin();
- i != m_id_to_name.end(); ++i){
+ for (UNORDERED_MAP<u16, std::string>::const_iterator i = m_id_to_name.begin();
+ i != m_id_to_name.end(); ++i) {
writeU16(os, i->first);
- os<<serializeString(i->second);
+ os << serializeString(i->second);
}
}
void NameIdMapping::deSerialize(std::istream &is)
{
int version = readU8(is);
- if(version != 0)
+ if (version != 0)
throw SerializationError("unsupported NameIdMapping version");
u32 count = readU16(is);
m_id_to_name.clear();
m_name_to_id.clear();
- for(u32 i=0; i<count; i++){
+ for (u32 i = 0; i < count; i++) {
u16 id = readU16(is);
std::string name = deSerializeString(is);
m_id_to_name[id] = name;
m_name_to_id[name] = id;
}
}
-
diff --git a/src/nameidmapping.h b/src/nameidmapping.h
index 23838c8ff..a2f3a3062 100644
--- a/src/nameidmapping.h
+++ b/src/nameidmapping.h
@@ -32,51 +32,57 @@ public:
void serialize(std::ostream &os) const;
void deSerialize(std::istream &is);
- void clear(){
+ void clear()
+ {
m_id_to_name.clear();
m_name_to_id.clear();
}
- void set(u16 id, const std::string &name){
+
+ void set(u16 id, const std::string &name)
+ {
m_id_to_name[id] = name;
m_name_to_id[name] = id;
}
- void removeId(u16 id){
+ void removeId(u16 id)
+ {
std::string name;
bool found = getName(id, name);
- if(!found) return;
+ if (!found)
+ return;
m_id_to_name.erase(id);
m_name_to_id.erase(name);
}
- void eraseName(const std::string &name){
+ void eraseName(const std::string &name)
+ {
u16 id;
bool found = getId(name, id);
- if(!found) return;
+ if (!found)
+ return;
m_id_to_name.erase(id);
m_name_to_id.erase(name);
}
- bool getName(u16 id, std::string &result) const{
+ bool getName(u16 id, std::string &result) const
+ {
UNORDERED_MAP<u16, std::string>::const_iterator i;
i = m_id_to_name.find(id);
- if(i == m_id_to_name.end())
+ if (i == m_id_to_name.end())
return false;
result = i->second;
return true;
}
- bool getId(const std::string &name, u16 &result) const{
+ bool getId(const std::string &name, u16 &result) const
+ {
UNORDERED_MAP<std::string, u16>::const_iterator i;
i = m_name_to_id.find(name);
- if(i == m_name_to_id.end())
+ if (i == m_name_to_id.end())
return false;
result = i->second;
return true;
}
- u16 size() const{
- return m_id_to_name.size();
- }
+ u16 size() const { return m_id_to_name.size(); }
private:
UNORDERED_MAP<u16, std::string> m_id_to_name;
UNORDERED_MAP<std::string, u16> m_name_to_id;
};
#endif
-
diff --git a/src/network/clientopcodes.cpp b/src/network/clientopcodes.cpp
index 3364de8c5..bdcb1dfce 100644
--- a/src/network/clientopcodes.cpp
+++ b/src/network/clientopcodes.cpp
@@ -78,12 +78,12 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
{ "TOCLIENT_HP", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_HP }, // 0x33
{ "TOCLIENT_MOVE_PLAYER", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_MovePlayer }, // 0x34
{ "TOCLIENT_ACCESS_DENIED_LEGACY", TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_AccessDenied }, // 0x35
- { "TOCLIENT_PLAYERITEM", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_PlayerItem }, // 0x36
+ null_command_handler,
{ "TOCLIENT_DEATHSCREEN", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_DeathScreen }, // 0x37
{ "TOCLIENT_MEDIA", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_Media }, // 0x38
- { "TOCLIENT_TOOLDEF", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_ToolDef }, // 0x39
+ null_command_handler,
{ "TOCLIENT_NODEDEF", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_NodeDef }, // 0x3a
- { "TOCLIENT_CRAFTITEMDEF", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_CraftItemDef }, // 0x3b
+ null_command_handler,
{ "TOCLIENT_ANNOUNCE_MEDIA", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_AnnounceMedia }, // 0x3c
{ "TOCLIENT_ITEMDEF", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_ItemDef }, // 0x3d
null_command_handler,
@@ -108,8 +108,8 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
{ "TOCLIENT_LOCAL_PLAYER_ANIMATIONS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_LocalPlayerAnimations }, // 0x51
{ "TOCLIENT_EYE_OFFSET", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_EyeOffset }, // 0x52
{ "TOCLIENT_DELETE_PARTICLESPAWNER", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_DeleteParticleSpawner }, // 0x53
- null_command_handler,
- null_command_handler,
+ { "TOCLIENT_CLOUD_PARAMS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_CloudParams }, // 0x54
+ { "TOCLIENT_FADE_SOUND", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_FadeSound }, // 0x55
null_command_handler,
null_command_handler,
null_command_handler,
@@ -193,7 +193,7 @@ const ServerCommandFactory serverCommandFactoryTable[TOSERVER_NUM_MSG_TYPES] =
null_command_factory, // 0x3f
{ "TOSERVER_REQUEST_MEDIA", 1, true }, // 0x40
{ "TOSERVER_RECEIVED_MEDIA", 1, true }, // 0x41
- { "TOSERVER_BREATH", 0, true }, // 0x42
+ { "TOSERVER_BREATH", 0, true }, // 0x42 old TOSERVER_BREATH. Ignored by servers
{ "TOSERVER_CLIENT_READY", 0, true }, // 0x43
null_command_factory, // 0x44
null_command_factory, // 0x45
diff --git a/src/network/clientopcodes.h b/src/network/clientopcodes.h
index 9143865b8..43a93bb4f 100644
--- a/src/network/clientopcodes.h
+++ b/src/network/clientopcodes.h
@@ -41,7 +41,7 @@ struct ToClientCommandHandler
struct ServerCommandFactory
{
const char* name;
- u16 channel;
+ u8 channel;
bool reliable;
};
diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp
index 411982f69..59669fe6d 100644
--- a/src/network/clientpackethandler.cpp
+++ b/src/network/clientpackethandler.cpp
@@ -30,8 +30,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server.h"
#include "util/strfnd.h"
#include "network/clientopcodes.h"
+#include "script/scripting_client.h"
#include "util/serialize.h"
#include "util/srp.h"
+#include "tileanimation.h"
void Client::handleCommand_Deprecated(NetworkPacket* pkt)
{
@@ -140,7 +142,7 @@ void Client::handleCommand_AcceptSudoMode(NetworkPacket* pkt)
}
void Client::handleCommand_DenySudoMode(NetworkPacket* pkt)
{
- m_chat_queue.push(L"Password change denied. Password NOT changed.");
+ pushToChatQueue(L"Password change denied. Password NOT changed.");
// reset everything and be sad
deleteAuthData();
}
@@ -410,7 +412,10 @@ void Client::handleCommand_ChatMessage(NetworkPacket* pkt)
message += (wchar_t)read_wchar;
}
- m_chat_queue.push(message);
+ // If chat message not consummed by client lua API
+ if (!moddingEnabled() || !m_script->on_receiving_message(wide_to_utf8(message))) {
+ pushToChatQueue(message);
+ }
}
void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt)
@@ -521,6 +526,10 @@ void Client::handleCommand_HP(NetworkPacket* pkt)
player->hp = hp;
+ if (moddingEnabled()) {
+ m_script->on_hp_modification(hp);
+ }
+
if (hp < oldhp) {
// Add to ClientEvent queue
ClientEvent event;
@@ -552,7 +561,6 @@ void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
*pkt >> pos >> pitch >> yaw;
- player->got_teleported = true;
player->setPosition(pos);
infostream << "Client got TOCLIENT_MOVE_PLAYER"
@@ -578,11 +586,6 @@ void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
m_ignore_damage_timer = 3.0;
}
-void Client::handleCommand_PlayerItem(NetworkPacket* pkt)
-{
- warningstream << "Client: Ignoring TOCLIENT_PLAYERITEM" << std::endl;
-}
-
void Client::handleCommand_DeathScreen(NetworkPacket* pkt)
{
bool set_camera_point_target;
@@ -709,11 +712,6 @@ void Client::handleCommand_Media(NetworkPacket* pkt)
}
}
-void Client::handleCommand_ToolDef(NetworkPacket* pkt)
-{
- warningstream << "Client: Ignoring TOCLIENT_TOOLDEF" << std::endl;
-}
-
void Client::handleCommand_NodeDef(NetworkPacket* pkt)
{
infostream << "Client: Received node definitions: packet size: "
@@ -724,9 +722,7 @@ void Client::handleCommand_NodeDef(NetworkPacket* pkt)
sanity_check(!m_mesh_update_thread.isRunning());
// Decompress node definitions
- std::string datastring(pkt->getString(0), pkt->getSize());
- std::istringstream is(datastring, std::ios_base::binary);
- std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
+ std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
std::ostringstream tmp_os;
decompressZlib(tmp_is, tmp_os);
@@ -736,11 +732,6 @@ void Client::handleCommand_NodeDef(NetworkPacket* pkt)
m_nodedef_received = true;
}
-void Client::handleCommand_CraftItemDef(NetworkPacket* pkt)
-{
- warningstream << "Client: Ignoring TOCLIENT_CRAFTITEMDEF" << std::endl;
-}
-
void Client::handleCommand_ItemDef(NetworkPacket* pkt)
{
infostream << "Client: Received item definitions: packet size: "
@@ -751,9 +742,7 @@ void Client::handleCommand_ItemDef(NetworkPacket* pkt)
sanity_check(!m_mesh_update_thread.isRunning());
// Decompress item definitions
- std::string datastring(pkt->getString(0), pkt->getSize());
- std::istringstream is(datastring, std::ios_base::binary);
- std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
+ std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
std::ostringstream tmp_os;
decompressZlib(tmp_is, tmp_os);
@@ -765,21 +754,39 @@ void Client::handleCommand_ItemDef(NetworkPacket* pkt)
void Client::handleCommand_PlaySound(NetworkPacket* pkt)
{
+ /*
+ [0] u32 server_id
+ [4] u16 name length
+ [6] char name[len]
+ [ 6 + len] f32 gain
+ [10 + len] u8 type
+ [11 + len] (f32 * 3) pos
+ [23 + len] u16 object_id
+ [25 + len] bool loop
+ [26 + len] f32 fade
+ */
+
s32 server_id;
std::string name;
+
float gain;
u8 type; // 0=local, 1=positional, 2=object
v3f pos;
u16 object_id;
bool loop;
+ float fade = 0;
*pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
+ try {
+ *pkt >> fade;
+ } catch (PacketError &e) {};
+
// Start playing
int client_id = -1;
switch(type) {
case 0: // local
- client_id = m_sound->playSound(name, loop, gain);
+ client_id = m_sound->playSound(name, loop, gain, fade);
break;
case 1: // positional
client_id = m_sound->playSoundAt(name, loop, gain, pos);
@@ -818,6 +825,21 @@ void Client::handleCommand_StopSound(NetworkPacket* pkt)
}
}
+void Client::handleCommand_FadeSound(NetworkPacket *pkt)
+{
+ s32 sound_id;
+ float step;
+ float gain;
+
+ *pkt >> sound_id >> step >> gain;
+
+ UNORDERED_MAP<s32, int>::iterator i =
+ m_sounds_server_to_client.find(sound_id);
+
+ if (i != m_sounds_server_to_client.end())
+ m_sound->fadeSound(i->second, step, gain);
+}
+
void Client::handleCommand_Privileges(NetworkPacket* pkt)
{
m_privileges.clear();
@@ -896,9 +918,14 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
std::string texture = deSerializeLongString(is);
bool vertical = false;
bool collision_removal = false;
+ struct TileAnimationParams animation;
+ animation.type = TAT_NONE;
+ u8 glow = 0;
try {
vertical = readU8(is);
collision_removal = readU8(is);
+ animation.deSerialize(is, m_proto_ver);
+ glow = readU8(is);
} catch (...) {}
ClientEvent event;
@@ -912,6 +939,8 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
event.spawn_particle.collision_removal = collision_removal;
event.spawn_particle.vertical = vertical;
event.spawn_particle.texture = new std::string(texture);
+ event.spawn_particle.animation = animation;
+ event.spawn_particle.glow = glow;
m_client_event_queue.push(event);
}
@@ -943,12 +972,20 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
bool vertical = false;
bool collision_removal = false;
+ struct TileAnimationParams animation;
+ animation.type = TAT_NONE;
+ u8 glow = 0;
u16 attached_id = 0;
try {
*pkt >> vertical;
*pkt >> collision_removal;
*pkt >> attached_id;
+ // This is horrible but required (why are there two ways to deserialize pkts?)
+ std::string datastring(pkt->getRemainingString(), pkt->getRemainingBytes());
+ std::istringstream is(datastring, std::ios_base::binary);
+ animation.deSerialize(is, m_proto_ver);
+ glow = readU8(is);
} catch (...) {}
ClientEvent event;
@@ -971,6 +1008,8 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
event.add_particlespawner.vertical = vertical;
event.add_particlespawner.texture = new std::string(texture);
event.add_particlespawner.id = id;
+ event.add_particlespawner.animation = animation;
+ event.add_particlespawner.glow = glow;
m_client_event_queue.push(event);
}
@@ -1111,10 +1150,10 @@ void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
m_minimap_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
// Hide minimap if it has been disabled by the server
- if (m_minimap_disabled_by_server && was_minimap_visible) {
+ if (m_minimap && m_minimap_disabled_by_server && was_minimap_visible) {
// defers a minimap update, therefore only call it if really
// needed, by checking that minimap was visible before
- m_mapper->setMinimapMode(MINIMAP_MODE_OFF);
+ m_minimap->setMinimapMode(MINIMAP_MODE_OFF);
}
}
@@ -1153,11 +1192,45 @@ void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
for (size_t i = 0; i < count; i++)
params->push_back(deSerializeString(is));
+ bool clouds = true;
+ try {
+ clouds = readU8(is);
+ } catch (...) {}
+
ClientEvent event;
event.type = CE_SET_SKY;
event.set_sky.bgcolor = bgcolor;
event.set_sky.type = type;
event.set_sky.params = params;
+ event.set_sky.clouds = clouds;
+ m_client_event_queue.push(event);
+}
+
+void Client::handleCommand_CloudParams(NetworkPacket* pkt)
+{
+ f32 density;
+ video::SColor color_bright;
+ video::SColor color_ambient;
+ f32 height;
+ f32 thickness;
+ v2f speed;
+
+ *pkt >> density >> color_bright >> color_ambient
+ >> height >> thickness >> speed;
+
+ ClientEvent event;
+ event.type = CE_CLOUD_PARAMS;
+ event.cloud_params.density = density;
+ // use the underlying u32 representation, because we can't
+ // use struct members with constructors here, and this way
+ // we avoid using new() and delete() for no good reason
+ event.cloud_params.color_bright = color_bright.color;
+ event.cloud_params.color_ambient = color_ambient.color;
+ event.cloud_params.height = height;
+ event.cloud_params.thickness = thickness;
+ // same here: deconstruct to skip constructor
+ event.cloud_params.speed_x = speed.X;
+ event.cloud_params.speed_y = speed.Y;
m_client_event_queue.push(event);
}
diff --git a/src/network/connection.cpp b/src/network/connection.cpp
index b711cae11..fb3ba92ae 100644
--- a/src/network/connection.cpp
+++ b/src/network/connection.cpp
@@ -54,7 +54,8 @@ Mutex log_message_mutex;
#endif
-static inline float CALC_DTIME(unsigned int lasttime, unsigned int curtime) {
+static inline float CALC_DTIME(u64 lasttime, u64 curtime)
+{
float value = ( curtime - lasttime) / 1000.0;
return MYMAX(MYMIN(value,0.1),0.0);
}
@@ -930,7 +931,7 @@ void Peer::DecUseCount()
delete this;
}
-void Peer::RTTStatistics(float rtt, std::string profiler_id,
+void Peer::RTTStatistics(float rtt, const std::string &profiler_id,
unsigned int num_samples) {
if (m_last_rtt > 0) {
@@ -969,8 +970,7 @@ void Peer::RTTStatistics(float rtt, std::string profiler_id,
m_rtt.jitter_avg = m_rtt.jitter_avg * (num_samples/(num_samples-1)) +
jitter * (1/num_samples);
- if (profiler_id != "")
- {
+ if (profiler_id != "") {
g_profiler->graphAdd(profiler_id + "_rtt", rtt);
g_profiler->graphAdd(profiler_id + "_jitter", jitter);
}
@@ -982,7 +982,7 @@ void Peer::RTTStatistics(float rtt, std::string profiler_id,
bool Peer::isTimedOut(float timeout)
{
MutexAutoLock lock(m_exclusive_access_mutex);
- u32 current_time = porting::getTimeMs();
+ u64 current_time = porting::getTimeMs();
float dtime = CALC_DTIME(m_last_timeout_check,current_time);
m_last_timeout_check = current_time;
@@ -1237,7 +1237,7 @@ void UDPPeer::RunCommandQueues(
u16 UDPPeer::getNextSplitSequenceNumber(u8 channel)
{
assert(channel < CHANNEL_COUNT); // Pre-condition
- return channels[channel].readNextIncomingSeqNum();
+ return channels[channel].readNextSplitSeqNum();
}
void UDPPeer::setNextSplitSequenceNumber(u8 channel, u16 seqnum)
@@ -1277,8 +1277,8 @@ void * ConnectionSendThread::run()
LOG(dout_con<<m_connection->getDesc()
<<"ConnectionSend thread started"<<std::endl);
- u32 curtime = porting::getTimeMs();
- u32 lasttime = curtime;
+ u64 curtime = porting::getTimeMs();
+ u64 lasttime = curtime;
PROFILE(std::stringstream ThreadIdentifier);
PROFILE(ThreadIdentifier << "ConnectionSend: [" << m_connection->getDesc() << "]");
@@ -2047,8 +2047,8 @@ void * ConnectionReceiveThread::run()
PROFILE(ThreadIdentifier << "ConnectionReceive: [" << m_connection->getDesc() << "]");
#ifdef DEBUG_CONNECTION_KBPS
- u32 curtime = porting::getTimeMs();
- u32 lasttime = curtime;
+ u64 curtime = porting::getTimeMs();
+ u64 lasttime = curtime;
float debug_print_timer = 0.0;
#endif
@@ -2391,7 +2391,7 @@ SharedBuffer<u8> ConnectionReceiveThread::processPacket(Channel *channel,
// only calculate rtt from straight sent packets
if (p.resend_count == 0) {
// Get round trip time
- unsigned int current_time = porting::getTimeMs();
+ u64 current_time = porting::getTimeMs();
// a overflow is quite unlikely but as it'd result in major
// rtt miscalculation we handle it here
diff --git a/src/network/connection.h b/src/network/connection.h
index 5ee53b9d4..8b7ed9773 100644
--- a/src/network/connection.h
+++ b/src/network/connection.h
@@ -175,7 +175,7 @@ struct BufferedPacket
Buffer<u8> data; // Data of the packet, including headers
float time; // Seconds from buffering the packet or re-sending
float totaltime; // Seconds from buffering the packet
- unsigned int absolute_send_time;
+ u64 absolute_send_time;
Address address; // Sender or destination
unsigned int resend_count;
};
@@ -383,7 +383,7 @@ struct OutgoingPacket
bool reliable;
bool ack;
- OutgoingPacket(u16 peer_id_, u8 channelnum_, SharedBuffer<u8> data_,
+ OutgoingPacket(u16 peer_id_, u8 channelnum_, const SharedBuffer<u8> &data_,
bool reliable_,bool ack_=false):
peer_id(peer_id_),
channelnum(channelnum_),
@@ -448,7 +448,7 @@ struct ConnectionCommand
reliable = reliable_;
}
- void ack(u16 peer_id_, u8 channelnum_, SharedBuffer<u8> data_)
+ void ack(u16 peer_id_, u8 channelnum_, const SharedBuffer<u8> &data_)
{
type = CONCMD_ACK;
peer_id = peer_id_;
@@ -457,7 +457,7 @@ struct ConnectionCommand
reliable = false;
}
- void createPeer(u16 peer_id_, SharedBuffer<u8> data_)
+ void createPeer(u16 peer_id_, const SharedBuffer<u8> &data_)
{
type = CONCMD_CREATE_PEER;
peer_id = peer_id_;
@@ -467,7 +467,7 @@ struct ConnectionCommand
raw = true;
}
- void disableLegacy(u16 peer_id_, SharedBuffer<u8> data_)
+ void disableLegacy(u16 peer_id_, const SharedBuffer<u8> &data_)
{
type = CONCMD_DISABLE_LEGACY;
peer_id = peer_id_;
@@ -732,8 +732,8 @@ class Peer {
virtual void reportRTT(float rtt) {};
void RTTStatistics(float rtt,
- std::string profiler_id="",
- unsigned int num_samples=1000);
+ const std::string &profiler_id = "",
+ unsigned int num_samples = 1000);
bool IncUseCount();
void DecUseCount();
@@ -769,7 +769,7 @@ class Peer {
// Seconds from last receive
float m_timeout_counter;
- u32 m_last_timeout_check;
+ u64 m_last_timeout_check;
};
class UDPPeer : public Peer
@@ -874,7 +874,7 @@ struct ConnectionEvent
return "Invalid ConnectionEvent";
}
- void dataReceived(u16 peer_id_, SharedBuffer<u8> data_)
+ void dataReceived(u16 peer_id_, const SharedBuffer<u8> &data_)
{
type = CONNEVENT_DATA_RECEIVED;
peer_id = peer_id_;
diff --git a/src/network/networkpacket.cpp b/src/network/networkpacket.cpp
index 388afc18e..f7a6499dd 100644
--- a/src/network/networkpacket.cpp
+++ b/src/network/networkpacket.cpp
@@ -63,7 +63,7 @@ void NetworkPacket::putRawPacket(u8 *data, u32 datasize, u16 peer_id)
m_data = std::vector<u8>(&data[2], &data[2 + m_datasize]);
}
-char* NetworkPacket::getString(u32 from_offset)
+const char* NetworkPacket::getString(u32 from_offset)
{
checkReadOffset(from_offset, 0);
@@ -105,7 +105,7 @@ NetworkPacket& NetworkPacket::operator>>(std::string& dst)
return *this;
}
-NetworkPacket& NetworkPacket::operator<<(std::string src)
+NetworkPacket& NetworkPacket::operator<<(const std::string &src)
{
u16 msgsize = src.size();
if (msgsize > STRING_MAX_LEN) {
@@ -119,7 +119,7 @@ NetworkPacket& NetworkPacket::operator<<(std::string src)
return *this;
}
-void NetworkPacket::putLongString(std::string src)
+void NetworkPacket::putLongString(const std::string &src)
{
u32 msgsize = src.size();
if (msgsize > LONG_STRING_MAX_LEN) {
@@ -155,7 +155,7 @@ NetworkPacket& NetworkPacket::operator>>(std::wstring& dst)
return *this;
}
-NetworkPacket& NetworkPacket::operator<<(std::wstring src)
+NetworkPacket& NetworkPacket::operator<<(const std::wstring &src)
{
u16 msgsize = src.size();
if (msgsize > WIDE_STRING_MAX_LEN) {
diff --git a/src/network/networkpacket.h b/src/network/networkpacket.h
index 524470999..83dc33f6f 100644
--- a/src/network/networkpacket.h
+++ b/src/network/networkpacket.h
@@ -41,20 +41,23 @@ public:
u16 getPeerId() { return m_peer_id; }
u16 getCommand() { return m_command; }
const u32 getRemainingBytes() const { return m_datasize - m_read_offset; }
+ const char* getRemainingString() { return getString(m_read_offset); }
// Returns a c-string without copying.
// A better name for this would be getRawString()
- char* getString(u32 from_offset);
+ const char* getString(u32 from_offset);
// major difference to putCString(): doesn't write len into the buffer
void putRawString(const char* src, u32 len);
+ void putRawString(const std::string &src)
+ { putRawString(src.c_str(), src.size()); }
NetworkPacket& operator>>(std::string& dst);
- NetworkPacket& operator<<(std::string src);
+ NetworkPacket& operator<<(const std::string &src);
- void putLongString(std::string src);
+ void putLongString(const std::string &src);
NetworkPacket& operator>>(std::wstring& dst);
- NetworkPacket& operator<<(std::wstring src);
+ NetworkPacket& operator<<(const std::wstring &src);
std::string readLongString();
diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h
index 018b392b6..7126c237b 100644
--- a/src/network/networkprotocol.h
+++ b/src/network/networkprotocol.h
@@ -50,6 +50,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
ContentFeatures and NodeDefManager use a different serialization
format; better for future version cross-compatibility
Many things
+ Obsolete TOCLIENT_PLAYERITEM
PROTOCOL_VERSION 10:
TOCLIENT_PRIVILEGES
Version raised to force 'fly' and 'fast' privileges into effect.
@@ -104,7 +105,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
PROTOCOL_VERSION 22:
add swap_node
PROTOCOL_VERSION 23:
- TOSERVER_CLIENT_READY
+ Obsolete TOSERVER_RECEIVED_MEDIA
+ Server: Stop using TOSERVER_CLIENT_READY
PROTOCOL_VERSION 24:
ContentFeatures version 7
ContentFeatures: change number of special tiles to 6 (CF_SPECIAL_COUNT)
@@ -138,19 +140,34 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Add nodedef v3 - connected nodeboxes
PROTOCOL_VERSION 28:
CPT2_MESHOPTIONS
+ PROTOCOL_VERSION 29:
+ Server doesn't accept TOSERVER_BREATH anymore
+ serialization of TileAnimation params changed
+ TAT_SHEET_2D
+ Removed client-sided chat perdiction
+ PROTOCOL VERSION 30:
+ New ContentFeatures serialization version
+ Add node and tile color and palette
+ Fix plantlike visual_scale being applied squared and add compatibility
+ with pre-30 clients by sending sqrt(visual_scale)
+ PROTOCOL VERSION 31:
+ Add tile overlay
+ Stop sending TOSERVER_CLIENT_READY
+ PROTOCOL VERSION 32:
+ Add fading sounds
*/
-#define LATEST_PROTOCOL_VERSION 28
+#define LATEST_PROTOCOL_VERSION 32
// Server's supported network protocol range
-#define SERVER_PROTOCOL_VERSION_MIN 13
+#define SERVER_PROTOCOL_VERSION_MIN 24
#define SERVER_PROTOCOL_VERSION_MAX LATEST_PROTOCOL_VERSION
// Client's supported network protocol range
// The minimal version depends on whether
// send_pre_v25_init is enabled or not
#define CLIENT_PROTOCOL_VERSION_MIN 25
-#define CLIENT_PROTOCOL_VERSION_MIN_LEGACY 13
+#define CLIENT_PROTOCOL_VERSION_MIN_LEGACY 24
#define CLIENT_PROTOCOL_VERSION_MAX LATEST_PROTOCOL_VERSION
// Constant that differentiates the protocol from random data and other protocols
@@ -567,6 +584,7 @@ enum ToClientCommand
foreach count:
u8 len
u8[len] param
+ u8 clouds (boolean)
*/
TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO = 0x50,
@@ -595,6 +613,23 @@ enum ToClientCommand
u32 id
*/
+ TOCLIENT_CLOUD_PARAMS = 0x54,
+ /*
+ f1000 density
+ u8[4] color_diffuse (ARGB)
+ u8[4] color_ambient (ARGB)
+ f1000 height
+ f1000 thickness
+ v2f1000 speed
+ */
+
+ TOCLIENT_FADE_SOUND = 0x55,
+ /*
+ s32 sound_id
+ float step
+ float gain
+ */
+
TOCLIENT_SRP_BYTES_S_B = 0x60,
/*
Belonging to AUTH_MECHANISM_LEGACY_PASSWORD and AUTH_MECHANISM_SRP.
@@ -833,7 +868,7 @@ enum ToServerCommand
<no payload data>
*/
- TOSERVER_BREATH = 0x42,
+ TOSERVER_BREATH = 0x42, // Obsolete
/*
u16 breath
*/
diff --git a/src/network/serveropcodes.cpp b/src/network/serveropcodes.cpp
index 9b14a1be3..19978a2b6 100644
--- a/src/network/serveropcodes.cpp
+++ b/src/network/serveropcodes.cpp
@@ -89,8 +89,8 @@ const ToServerCommandHandler toServerCommandTable[TOSERVER_NUM_MSG_TYPES] =
null_command_handler, // 0x3e
null_command_handler, // 0x3f
{ "TOSERVER_REQUEST_MEDIA", TOSERVER_STATE_STARTUP, &Server::handleCommand_RequestMedia }, // 0x40
- { "TOSERVER_RECEIVED_MEDIA", TOSERVER_STATE_STARTUP, &Server::handleCommand_ReceivedMedia }, // 0x41
- { "TOSERVER_BREATH", TOSERVER_STATE_INGAME, &Server::handleCommand_Breath }, // 0x42
+ { "TOSERVER_RECEIVED_MEDIA", TOSERVER_STATE_STARTUP, &Server::handleCommand_Deprecated }, // 0x41 not used by the server since protocol version 23
+ { "TOSERVER_BREATH", TOSERVER_STATE_INGAME, &Server::handleCommand_Deprecated }, // 0x42 Old breath model which is now deprecated for anticheating
{ "TOSERVER_CLIENT_READY", TOSERVER_STATE_STARTUP, &Server::handleCommand_ClientReady }, // 0x43
null_command_handler, // 0x44
null_command_handler, // 0x45
@@ -197,8 +197,8 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
{ "TOCLIENT_LOCAL_PLAYER_ANIMATIONS", 0, true }, // 0x51
{ "TOCLIENT_EYE_OFFSET", 0, true }, // 0x52
{ "TOCLIENT_DELETE_PARTICLESPAWNER", 0, true }, // 0x53
- null_command_factory,
- null_command_factory,
+ { "TOCLIENT_CLOUD_PARAMS", 0, true }, // 0x54
+ { "TOCLIENT_FADE_SOUND", 0, true }, // 0x55
null_command_factory,
null_command_factory,
null_command_factory,
diff --git a/src/network/serveropcodes.h b/src/network/serveropcodes.h
index aa3301069..72323ae24 100644
--- a/src/network/serveropcodes.h
+++ b/src/network/serveropcodes.h
@@ -41,7 +41,7 @@ struct ToServerCommandHandler
struct ClientCommandFactory
{
const char* name;
- u16 channel;
+ u8 channel;
bool reliable;
};
diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp
index dca9aabc4..5b026bbdb 100644
--- a/src/network/serverpackethandler.cpp
+++ b/src/network/serverpackethandler.cpp
@@ -23,10 +23,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_abm.h"
#include "content_sao.h"
#include "emerge.h"
+#include "mapblock.h"
#include "nodedef.h"
#include "player.h"
#include "rollback_interface.h"
-#include "scripting_game.h"
+#include "scripting_server.h"
#include "settings.h"
#include "tool.h"
#include "version.h"
@@ -613,20 +614,6 @@ void Server::handleCommand_Init2(NetworkPacket* pkt)
u16 protocol_version = m_clients.getProtocolVersion(pkt->getPeerId());
- ///// begin compatibility code
- PlayerSAO* playersao = NULL;
- if (protocol_version <= 22) {
- playersao = StageTwoClientInit(pkt->getPeerId());
-
- if (playersao == NULL) {
- actionstream
- << "TOSERVER_INIT2 stage 2 client init failed for peer "
- << pkt->getPeerId() << std::endl;
- return;
- }
- }
- ///// end compatibility code
-
/*
Send some initialization data
*/
@@ -656,13 +643,6 @@ void Server::handleCommand_Init2(NetworkPacket* pkt)
float time_speed = g_settings->getFloat("time_speed");
SendTimeOfDay(pkt->getPeerId(), time, time_speed);
- ///// begin compatibility code
- if (protocol_version <= 22) {
- m_clients.event(pkt->getPeerId(), CSE_SetClientReady);
- m_script->on_joinplayer(playersao);
- }
- ///// end compatibility code
-
// Warnings about protocol version can be issued here
if (getClient(pkt->getPeerId())->net_proto_version < LATEST_PROTOCOL_VERSION) {
SendChatMessage(pkt->getPeerId(), L"# Server: WARNING: YOUR CLIENT'S "
@@ -694,10 +674,6 @@ void Server::handleCommand_RequestMedia(NetworkPacket* pkt)
sendRequestedMedia(pkt->getPeerId(), tosend);
}
-void Server::handleCommand_ReceivedMedia(NetworkPacket* pkt)
-{
-}
-
void Server::handleCommand_ClientReady(NetworkPacket* pkt)
{
u16 peer_id = pkt->getPeerId();
@@ -742,6 +718,13 @@ void Server::handleCommand_ClientReady(NetworkPacket* pkt)
m_clients.event(peer_id, CSE_SetClientReady);
m_script->on_joinplayer(playersao);
+ // Send shutdown timer if shutdown has been scheduled
+ if (m_shutdown_timer > 0.0f) {
+ std::wstringstream ws;
+ ws << L"*** Server shutting down in "
+ << duration_to_string(myround(m_shutdown_timer)).c_str() << ".";
+ SendChatMessage(pkt->getPeerId(), ws.str());
+ }
}
void Server::handleCommand_GotBlocks(NetworkPacket* pkt)
@@ -810,7 +793,7 @@ void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
v3f speed((f32)ss.X / 100.0, (f32)ss.Y / 100.0, (f32)ss.Z / 100.0);
pitch = modulo360f(pitch);
- yaw = modulo360f(yaw);
+ yaw = wrapDegrees_0_360(yaw);
playersao->setBasePosition(position);
player->setSpeed(speed);
@@ -1021,6 +1004,15 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
delete a;
return;
}
+
+ // Disallow dropping items if dead
+ if (playersao->isDead()) {
+ infostream << "Ignoring IDropAction from "
+ << (da->from_inv.dump()) << ":" << da->from_list
+ << " because player is dead." << std::endl;
+ delete a;
+ return;
+ }
}
/*
Handle restrictions and special cases of the craft action
@@ -1118,6 +1110,13 @@ void Server::handleCommand_Damage(NetworkPacket* pkt)
}
if (g_settings->getBool("enable_damage")) {
+ if (playersao->isDead()) {
+ verbosestream << "Server::ProcessData(): Info: "
+ "Ignoring damage as player " << player->getName()
+ << " is already dead." << std::endl;
+ return;
+ }
+
actionstream << player->getName() << " damaged by "
<< (int)damage << " hp at " << PP(playersao->getBasePosition() / BS)
<< std::endl;
@@ -1127,46 +1126,6 @@ void Server::handleCommand_Damage(NetworkPacket* pkt)
}
}
-void Server::handleCommand_Breath(NetworkPacket* pkt)
-{
- u16 breath;
-
- *pkt >> breath;
-
- RemotePlayer *player = m_env->getPlayer(pkt->getPeerId());
-
- if (player == NULL) {
- errorstream << "Server::ProcessData(): Canceling: "
- "No player for peer_id=" << pkt->getPeerId()
- << " disconnecting peer!" << std::endl;
- m_con.DisconnectPeer(pkt->getPeerId());
- return;
- }
-
-
- PlayerSAO *playersao = player->getPlayerSAO();
- if (playersao == NULL) {
- errorstream << "Server::ProcessData(): Canceling: "
- "No player object for peer_id=" << pkt->getPeerId()
- << " disconnecting peer!" << std::endl;
- m_con.DisconnectPeer(pkt->getPeerId());
- return;
- }
-
- /*
- * If player is dead, we don't need to update the breath
- * He is dead !
- */
- if (playersao->isDead()) {
- verbosestream << "TOSERVER_BREATH: " << player->getName()
- << " is dead. Ignoring packet";
- return;
- }
-
- playersao->setBreath(breath);
- SendPlayerBreath(pkt->getPeerId());
-}
-
void Server::handleCommand_Password(NetworkPacket* pkt)
{
if (pkt->getSize() != PASSWORD_SIZE * 2)
@@ -1313,6 +1272,7 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
2: digging completed
3: place block or item (to abovesurface)
4: use item
+ 5: rightclick air ("activate")
*/
u8 action;
u16 item_i;
@@ -1345,8 +1305,16 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
}
if (playersao->isDead()) {
- verbosestream << "TOSERVER_INTERACT: " << player->getName()
- << " is dead. Ignoring packet";
+ actionstream << "Server: NoCheat: " << player->getName()
+ << " tried to interact while dead; ignoring." << std::endl;
+ if (pointed.type == POINTEDTHING_NODE) {
+ // Re-send block to revert change on client-side
+ RemoteClient *client = getClient(pkt->getPeerId());
+ v3s16 blockpos = getNodeBlockPos(pointed.node_undersurface);
+ client->SetBlockNotSent(blockpos);
+ }
+ // Call callbacks
+ m_script->on_cheat(playersao, "interacted_while_dead");
return;
}
@@ -1385,15 +1353,48 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
}
/*
+ Make sure the player is allowed to do it
+ */
+ if (!checkPriv(player->getName(), "interact")) {
+ actionstream<<player->getName()<<" attempted to interact with "
+ <<pointed.dump()<<" without 'interact' privilege"
+ <<std::endl;
+ // Re-send block to revert change on client-side
+ RemoteClient *client = getClient(pkt->getPeerId());
+ // Digging completed -> under
+ if (action == 2) {
+ v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
+ client->SetBlockNotSent(blockpos);
+ }
+ // Placement -> above
+ if (action == 3) {
+ v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
+ client->SetBlockNotSent(blockpos);
+ }
+ return;
+ }
+
+ /*
Check that target is reasonably close
(only when digging or placing things)
*/
static const bool enable_anticheat = !g_settings->getBool("disable_anticheat");
- if ((action == 0 || action == 2 || action == 3) &&
+ if ((action == 0 || action == 2 || action == 3 || action == 4) &&
(enable_anticheat && !isSingleplayer())) {
float d = player_pos.getDistanceFrom(pointed_pos_under);
- float max_d = BS * 14; // Just some large enough value
- if (d > max_d) {
+ const ItemDefinition &playeritem_def =
+ playersao->getWieldedItem().getDefinition(m_itemdef);
+ float max_d = BS * playeritem_def.range;
+ InventoryList *hlist = playersao->getInventory()->getList("hand");
+ const ItemDefinition &hand_def =
+ hlist ? (hlist->getItem(0).getDefinition(m_itemdef)) : (m_itemdef->get(""));
+ float max_d_hand = BS * hand_def.range;
+ if (max_d < 0 && max_d_hand >= 0)
+ max_d = max_d_hand;
+ else if (max_d < 0)
+ max_d = BS * 4.0;
+ // cube diagonal: sqrt(3) = 1.73
+ if (d > max_d * 1.73) {
actionstream << "Player " << player->getName()
<< " tried to access " << pointed.dump()
<< " from too far: "
@@ -1411,28 +1412,6 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
}
/*
- Make sure the player is allowed to do it
- */
- if (!checkPriv(player->getName(), "interact")) {
- actionstream<<player->getName()<<" attempted to interact with "
- <<pointed.dump()<<" without 'interact' privilege"
- <<std::endl;
- // Re-send block to revert change on client-side
- RemoteClient *client = getClient(pkt->getPeerId());
- // Digging completed -> under
- if (action == 2) {
- v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
- client->SetBlockNotSent(blockpos);
- }
- // Placement -> above
- if (action == 3) {
- v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
- client->SetBlockNotSent(blockpos);
- }
- return;
- }
-
- /*
If something goes wrong, this player is to blame
*/
RollbackScopeActor rollback_scope(m_rollback,
@@ -1443,11 +1422,6 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
*/
if (action == 0) {
if (pointed.type == POINTEDTHING_NODE) {
- /*
- NOTE: This can be used in the future to check if
- somebody is cheating, by checking the timing.
- */
-
MapNode n(CONTENT_IGNORE);
bool pos_ok;
@@ -1475,7 +1449,7 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
<<pointed.object_id<<": "
<<pointed_object->getDescription()<<std::endl;
- ItemStack punchitem = playersao->getWieldedItem();
+ ItemStack punchitem = playersao->getWieldedItemOrHand();
ToolCapabilities toolcap =
punchitem.getToolCapabilities(m_itemdef);
v3f dir = (pointed_object->getBasePosition() -
@@ -1542,7 +1516,7 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
m_script->on_cheat(playersao, "finished_unknown_dig");
}
// Get player's wielded item
- ItemStack playeritem = playersao->getWieldedItem();
+ ItemStack playeritem = playersao->getWieldedItemOrHand();
ToolCapabilities playeritem_toolcap =
playeritem.getToolCapabilities(m_itemdef);
// Get diggability and expected digging time
@@ -1550,7 +1524,9 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
&playeritem_toolcap);
// If can't dig, try hand
if (!params.diggable) {
- const ItemDefinition &hand = m_itemdef->get("");
+ InventoryList *hlist = playersao->getInventory()->getList("hand");
+ const ItemDefinition &hand =
+ hlist ? hlist->getItem(0).getDefinition(m_itemdef) : m_itemdef->get("");
const ToolCapabilities *tp = hand.tool_capabilities;
if (tp)
params = getDigParams(m_nodedef->get(n).groups, tp);
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index ccbb42c66..98b34ea9e 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef SERVER
#include "client/tile.h"
#include "mesh.h"
+#include "client.h"
#include <IMeshManipulator.h>
#endif
#include "log.h"
@@ -60,11 +61,10 @@ void NodeBox::reset()
void NodeBox::serialize(std::ostream &os, u16 protocol_version) const
{
- int version = 1;
+ // Protocol >= 21
+ int version = 2;
if (protocol_version >= 27)
version = 3;
- else if (protocol_version >= 21)
- version = 2;
writeU8(os, version);
switch (type) {
@@ -188,39 +188,51 @@ void NodeBox::deSerialize(std::istream &is)
void TileDef::serialize(std::ostream &os, u16 protocol_version) const
{
- if (protocol_version >= 26)
+ if (protocol_version >= 30)
+ writeU8(os, 4);
+ else if (protocol_version >= 29)
+ writeU8(os, 3);
+ else if (protocol_version >= 26)
writeU8(os, 2);
- else if (protocol_version >= 17)
- writeU8(os, 1);
else
- writeU8(os, 0);
- os<<serializeString(name);
- writeU8(os, animation.type);
- writeU16(os, animation.aspect_w);
- writeU16(os, animation.aspect_h);
- writeF1000(os, animation.length);
- if (protocol_version >= 17)
- writeU8(os, backface_culling);
+ writeU8(os, 1);
+
+ os << serializeString(name);
+ animation.serialize(os, protocol_version);
+ writeU8(os, backface_culling);
if (protocol_version >= 26) {
writeU8(os, tileable_horizontal);
writeU8(os, tileable_vertical);
}
+ if (protocol_version >= 30) {
+ writeU8(os, has_color);
+ if (has_color) {
+ writeU8(os, color.getRed());
+ writeU8(os, color.getGreen());
+ writeU8(os, color.getBlue());
+ }
+ }
}
void TileDef::deSerialize(std::istream &is, const u8 contenfeatures_version, const NodeDrawType drawtype)
{
int version = readU8(is);
name = deSerializeString(is);
- animation.type = (TileAnimationType)readU8(is);
- animation.aspect_w = readU16(is);
- animation.aspect_h = readU16(is);
- animation.length = readF1000(is);
+ animation.deSerialize(is, version >= 3 ? 29 : 26);
if (version >= 1)
backface_culling = readU8(is);
if (version >= 2) {
tileable_horizontal = readU8(is);
tileable_vertical = readU8(is);
}
+ if (version >= 4) {
+ has_color = readU8(is);
+ if (has_color) {
+ color.setRed(readU8(is));
+ color.setGreen(readU8(is));
+ color.setBlue(readU8(is));
+ }
+ }
if ((contenfeatures_version < 8) &&
((drawtype == NDT_MESH) ||
@@ -254,10 +266,15 @@ void TextureSettings::readSettings()
bool enable_shaders = g_settings->getBool("enable_shaders");
bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping");
bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion");
+ bool smooth_lighting = g_settings->getBool("smooth_lighting");
enable_mesh_cache = g_settings->getBool("enable_mesh_cache");
enable_minimap = g_settings->getBool("enable_minimap");
std::string leaves_style_str = g_settings->get("leaves_style");
+ // Mesh cache is not supported in combination with smooth lighting
+ if (smooth_lighting)
+ enable_mesh_cache = false;
+
use_normal_texture = enable_shaders &&
(enable_bumpmapping || enable_parallax_occlusion);
if (leaves_style_str == "fancy") {
@@ -354,172 +371,224 @@ void ContentFeatures::reset()
connects_to.clear();
connects_to_ids.clear();
connect_sides = 0;
+ color = video::SColor(0xFFFFFFFF);
+ palette_name = "";
+ palette = NULL;
}
void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
{
- if(protocol_version < 24){
+ if (protocol_version < 31) {
serializeOld(os, protocol_version);
return;
}
- writeU8(os, protocol_version < 27 ? 7 : 8);
+ // version
+ writeU8(os, 10);
- os<<serializeString(name);
+ // general
+ os << serializeString(name);
writeU16(os, groups.size());
- for(ItemGroupList::const_iterator
- i = groups.begin(); i != groups.end(); ++i){
- os<<serializeString(i->first);
+ for (ItemGroupList::const_iterator i = groups.begin(); i != groups.end();
+ ++i) {
+ os << serializeString(i->first);
writeS16(os, i->second);
}
+ writeU8(os, param_type);
+ writeU8(os, param_type_2);
+
+ // visual
writeU8(os, drawtype);
+ os << serializeString(mesh);
writeF1000(os, visual_scale);
writeU8(os, 6);
- for(u32 i = 0; i < 6; i++)
+ for (u32 i = 0; i < 6; i++)
tiledef[i].serialize(os, protocol_version);
+ for (u32 i = 0; i < 6; i++)
+ tiledef_overlay[i].serialize(os, protocol_version);
writeU8(os, CF_SPECIAL_COUNT);
- for(u32 i = 0; i < CF_SPECIAL_COUNT; i++){
+ for (u32 i = 0; i < CF_SPECIAL_COUNT; i++) {
tiledef_special[i].serialize(os, protocol_version);
}
writeU8(os, alpha);
+ writeU8(os, color.getRed());
+ writeU8(os, color.getGreen());
+ writeU8(os, color.getBlue());
+ os << serializeString(palette_name);
+ writeU8(os, waving);
+ writeU8(os, connect_sides);
+ writeU16(os, connects_to_ids.size());
+ for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
+ i != connects_to_ids.end(); ++i)
+ writeU16(os, *i);
writeU8(os, post_effect_color.getAlpha());
writeU8(os, post_effect_color.getRed());
writeU8(os, post_effect_color.getGreen());
writeU8(os, post_effect_color.getBlue());
- writeU8(os, param_type);
- if ((protocol_version < 28) && (param_type_2 == CPT2_MESHOPTIONS))
- writeU8(os, CPT2_NONE);
- else
- writeU8(os, param_type_2);
- writeU8(os, is_ground_content);
+ writeU8(os, leveled);
+
+ // lighting
writeU8(os, light_propagates);
writeU8(os, sunlight_propagates);
+ writeU8(os, light_source);
+
+ // map generation
+ writeU8(os, is_ground_content);
+
+ // interaction
writeU8(os, walkable);
writeU8(os, pointable);
writeU8(os, diggable);
writeU8(os, climbable);
writeU8(os, buildable_to);
- os<<serializeString(""); // legacy: used to be metadata_name
+ writeU8(os, rightclickable);
+ writeU32(os, damage_per_second);
+
+ // liquid
writeU8(os, liquid_type);
- os<<serializeString(liquid_alternative_flowing);
- os<<serializeString(liquid_alternative_source);
+ os << serializeString(liquid_alternative_flowing);
+ os << serializeString(liquid_alternative_source);
writeU8(os, liquid_viscosity);
writeU8(os, liquid_renewable);
- writeU8(os, light_source);
- writeU32(os, damage_per_second);
+ writeU8(os, liquid_range);
+ writeU8(os, drowning);
+ writeU8(os, floodable);
+
+ // node boxes
node_box.serialize(os, protocol_version);
selection_box.serialize(os, protocol_version);
- writeU8(os, legacy_facedir_simple);
- writeU8(os, legacy_wallmounted);
+ collision_box.serialize(os, protocol_version);
+
+ // sound
serializeSimpleSoundSpec(sound_footstep, os);
serializeSimpleSoundSpec(sound_dig, os);
serializeSimpleSoundSpec(sound_dug, os);
- writeU8(os, rightclickable);
- writeU8(os, drowning);
- writeU8(os, leveled);
- writeU8(os, liquid_range);
- writeU8(os, waving);
- // Stuff below should be moved to correct place in a version that otherwise changes
- // the protocol version
- os<<serializeString(mesh);
- collision_box.serialize(os, protocol_version);
- writeU8(os, floodable);
- writeU16(os, connects_to_ids.size());
- for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
- i != connects_to_ids.end(); ++i)
- writeU16(os, *i);
- writeU8(os, connect_sides);
+
+ // legacy
+ writeU8(os, legacy_facedir_simple);
+ writeU8(os, legacy_wallmounted);
+}
+
+void ContentFeatures::correctAlpha(TileDef *tiles, int length)
+{
+ // alpha == 0 means that the node is using texture alpha
+ if (alpha == 0 || alpha == 255)
+ return;
+
+ for (int i = 0; i < length; i++) {
+ if (tiles[i].name == "")
+ continue;
+ std::stringstream s;
+ s << tiles[i].name << "^[noalpha^[opacity:" << ((int)alpha);
+ tiles[i].name = s.str();
+ }
}
void ContentFeatures::deSerialize(std::istream &is)
{
+ // version detection
int version = readU8(is);
- if (version < 7) {
+ if (version < 9) {
deSerializeOld(is, version);
return;
- } else if (version > 8) {
+ } else if (version > 10) {
throw SerializationError("unsupported ContentFeatures version");
}
+ // general
name = deSerializeString(is);
groups.clear();
u32 groups_size = readU16(is);
- for(u32 i = 0; i < groups_size; i++){
+ for (u32 i = 0; i < groups_size; i++) {
std::string name = deSerializeString(is);
int value = readS16(is);
groups[name] = value;
}
- drawtype = (enum NodeDrawType)readU8(is);
+ param_type = (enum ContentParamType) readU8(is);
+ param_type_2 = (enum ContentParamType2) readU8(is);
+ // visual
+ drawtype = (enum NodeDrawType) readU8(is);
+ mesh = deSerializeString(is);
visual_scale = readF1000(is);
- if(readU8(is) != 6)
+ if (readU8(is) != 6)
throw SerializationError("unsupported tile count");
- for(u32 i = 0; i < 6; i++)
+ for (u32 i = 0; i < 6; i++)
tiledef[i].deSerialize(is, version, drawtype);
- if(readU8(is) != CF_SPECIAL_COUNT)
+ if (version >= 10)
+ for (u32 i = 0; i < 6; i++)
+ tiledef_overlay[i].deSerialize(is, version, drawtype);
+ if (readU8(is) != CF_SPECIAL_COUNT)
throw SerializationError("unsupported CF_SPECIAL_COUNT");
- for(u32 i = 0; i < CF_SPECIAL_COUNT; i++)
+ for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
tiledef_special[i].deSerialize(is, version, drawtype);
alpha = readU8(is);
+ color.setRed(readU8(is));
+ color.setGreen(readU8(is));
+ color.setBlue(readU8(is));
+ palette_name = deSerializeString(is);
+ waving = readU8(is);
+ connect_sides = readU8(is);
+ u16 connects_to_size = readU16(is);
+ connects_to_ids.clear();
+ for (u16 i = 0; i < connects_to_size; i++)
+ connects_to_ids.insert(readU16(is));
post_effect_color.setAlpha(readU8(is));
post_effect_color.setRed(readU8(is));
post_effect_color.setGreen(readU8(is));
post_effect_color.setBlue(readU8(is));
- param_type = (enum ContentParamType)readU8(is);
- param_type_2 = (enum ContentParamType2)readU8(is);
- is_ground_content = readU8(is);
+ leveled = readU8(is);
+
+ // lighting-related
light_propagates = readU8(is);
sunlight_propagates = readU8(is);
+ light_source = readU8(is);
+ light_source = MYMIN(light_source, LIGHT_MAX);
+
+ // map generation
+ is_ground_content = readU8(is);
+
+ // interaction
walkable = readU8(is);
pointable = readU8(is);
diggable = readU8(is);
climbable = readU8(is);
buildable_to = readU8(is);
- deSerializeString(is); // legacy: used to be metadata_name
- liquid_type = (enum LiquidType)readU8(is);
+ rightclickable = readU8(is);
+ damage_per_second = readU32(is);
+
+ // liquid
+ liquid_type = (enum LiquidType) readU8(is);
liquid_alternative_flowing = deSerializeString(is);
liquid_alternative_source = deSerializeString(is);
liquid_viscosity = readU8(is);
liquid_renewable = readU8(is);
- light_source = readU8(is);
- light_source = MYMIN(light_source, LIGHT_MAX);
- damage_per_second = readU32(is);
+ liquid_range = readU8(is);
+ drowning = readU8(is);
+ floodable = readU8(is);
+
+ // node boxes
node_box.deSerialize(is);
selection_box.deSerialize(is);
- legacy_facedir_simple = readU8(is);
- legacy_wallmounted = readU8(is);
+ collision_box.deSerialize(is);
+
+ // sounds
deSerializeSimpleSoundSpec(sound_footstep, is);
deSerializeSimpleSoundSpec(sound_dig, is);
deSerializeSimpleSoundSpec(sound_dug, is);
- rightclickable = readU8(is);
- drowning = readU8(is);
- leveled = readU8(is);
- liquid_range = readU8(is);
- waving = readU8(is);
- // If you add anything here, insert it primarily inside the try-catch
- // block to not need to increase the version.
- try{
- // Stuff below should be moved to correct place in a version that
- // otherwise changes the protocol version
- mesh = deSerializeString(is);
- collision_box.deSerialize(is);
- floodable = readU8(is);
- u16 connects_to_size = readU16(is);
- connects_to_ids.clear();
- for (u16 i = 0; i < connects_to_size; i++)
- connects_to_ids.insert(readU16(is));
- connect_sides = readU8(is);
- }catch(SerializationError &e) {};
+
+ // read legacy properties
+ legacy_facedir_simple = readU8(is);
+ legacy_wallmounted = readU8(is);
}
#ifndef SERVER
-void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
+void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileLayer *tile,
TileDef *tiledef, u32 shader_id, bool use_normal_texture,
- bool backface_culling, u8 alpha, u8 material_type)
+ bool backface_culling, u8 material_type)
{
tile->shader_id = shader_id;
tile->texture = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id);
- tile->alpha = alpha;
tile->material_type = material_type;
// Normal texture and shader flags texture
@@ -532,29 +601,32 @@ void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
tile->material_flags = 0;
if (backface_culling)
tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
- if (tiledef->animation.type == TAT_VERTICAL_FRAMES)
- tile->material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
+ if (tiledef->animation.type != TAT_NONE)
+ tile->material_flags |= MATERIAL_FLAG_ANIMATION;
if (tiledef->tileable_horizontal)
tile->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL;
if (tiledef->tileable_vertical)
tile->material_flags |= MATERIAL_FLAG_TILEABLE_VERTICAL;
+ // Color
+ tile->has_color = tiledef->has_color;
+ if (tiledef->has_color)
+ tile->color = tiledef->color;
+ else
+ tile->color = color;
+
// Animation parameters
int frame_count = 1;
- if (tile->material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) {
- // Get texture size to determine frame count by aspect ratio
- v2u32 size = tile->texture->getOriginalSize();
- int frame_height = (float)size.X /
- (float)tiledef->animation.aspect_w *
- (float)tiledef->animation.aspect_h;
- frame_count = size.Y / frame_height;
- int frame_length_ms = 1000.0 * tiledef->animation.length / frame_count;
+ if (tile->material_flags & MATERIAL_FLAG_ANIMATION) {
+ int frame_length_ms;
+ tiledef->animation.determineParams(tile->texture->getOriginalSize(),
+ &frame_count, &frame_length_ms, NULL);
tile->animation_frame_count = frame_count;
tile->animation_frame_length_ms = frame_length_ms;
}
if (frame_count == 1) {
- tile->material_flags &= ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
+ tile->material_flags &= ~MATERIAL_FLAG_ANIMATION;
} else {
std::ostringstream os(std::ios::binary);
tile->frames.resize(frame_count);
@@ -564,8 +636,9 @@ void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
FrameSpec frame;
os.str("");
- os << tiledef->name << "^[verticalframe:"
- << frame_count << ":" << i;
+ os << tiledef->name;
+ tiledef->animation.getTextureModifer(os,
+ tile->texture->getOriginalSize(), i);
frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id);
if (tile->normal_texture)
@@ -579,8 +652,7 @@ void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
#ifndef SERVER
void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc,
- scene::ISceneManager *smgr, scene::IMeshManipulator *meshmanip,
- IGameDef *gamedef, const TextureSettings &tsettings)
+ scene::IMeshManipulator *meshmanip, Client *client, const TextureSettings &tsettings)
{
// minimap pixel color - the average color of a texture
if (tsettings.enable_minimap && tiledef[0].name != "")
@@ -593,9 +665,16 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
if (tdef[j].name == "")
tdef[j].name = "unknown_node.png";
}
+ // also the overlay tiles
+ TileDef tdef_overlay[6];
+ for (u32 j = 0; j < 6; j++)
+ tdef_overlay[j] = tiledef_overlay[j];
+ // also the special tiles
+ TileDef tdef_spec[6];
+ for (u32 j = 0; j < CF_SPECIAL_COUNT; j++)
+ tdef_spec[j] = tiledef_special[j];
bool is_liquid = false;
- bool is_water_surface = false;
u8 material_type = (alpha == 255) ?
TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
@@ -646,8 +725,8 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
visual_solidness = 1;
} else if (tsettings.leaves_style == LEAVES_SIMPLE) {
for (u32 j = 0; j < 6; j++) {
- if (tiledef_special[j].name != "")
- tdef[j].name = tiledef_special[j].name;
+ if (tdef_spec[j].name != "")
+ tdef[j].name = tdef_spec[j].name;
}
drawtype = NDT_GLASSLIKE;
solidness = 0;
@@ -658,34 +737,40 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
for (u32 i = 0; i < 6; i++)
tdef[i].name += std::string("^[noalpha");
}
- if (waving == 1)
+ if (waving >= 1)
material_type = TILE_MATERIAL_WAVING_LEAVES;
break;
case NDT_PLANTLIKE:
solidness = 0;
- if (waving == 1)
+ if (waving >= 1)
material_type = TILE_MATERIAL_WAVING_PLANTS;
break;
case NDT_FIRELIKE:
solidness = 0;
break;
case NDT_MESH:
+ case NDT_NODEBOX:
solidness = 0;
+ if (waving == 1)
+ material_type = TILE_MATERIAL_WAVING_PLANTS;
+ else if (waving == 2)
+ material_type = TILE_MATERIAL_WAVING_LEAVES;
break;
case NDT_TORCHLIKE:
case NDT_SIGNLIKE:
case NDT_FENCELIKE:
case NDT_RAILLIKE:
- case NDT_NODEBOX:
solidness = 0;
break;
}
if (is_liquid) {
+ // Vertex alpha is no longer supported, correct if necessary.
+ correctAlpha(tdef, 6);
+ correctAlpha(tdef_overlay, 6);
+ correctAlpha(tdef_spec, CF_SPECIAL_COUNT);
material_type = (alpha == 255) ?
TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT;
- if (name == "default:water_source")
- is_water_surface = true;
}
u32 tile_shader[6];
@@ -694,29 +779,33 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
material_type, drawtype);
}
- if (is_water_surface) {
- tile_shader[0] = shdsrc->getShader("water_surface_shader",
- material_type, drawtype);
- }
-
// Tiles (fill in f->tiles[])
for (u16 j = 0; j < 6; j++) {
- fillTileAttribs(tsrc, &tiles[j], &tdef[j], tile_shader[j],
+ fillTileAttribs(tsrc, &tiles[j].layers[0], &tdef[j], tile_shader[j],
tsettings.use_normal_texture,
- tiledef[j].backface_culling, alpha, material_type);
+ tdef[j].backface_culling, material_type);
+ if (tdef_overlay[j].name != "")
+ fillTileAttribs(tsrc, &tiles[j].layers[1], &tdef_overlay[j],
+ tile_shader[j], tsettings.use_normal_texture,
+ tdef[j].backface_culling, material_type);
}
// Special tiles (fill in f->special_tiles[])
for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) {
- fillTileAttribs(tsrc, &special_tiles[j], &tiledef_special[j],
+ fillTileAttribs(tsrc, &special_tiles[j].layers[0], &tdef_spec[j],
tile_shader[j], tsettings.use_normal_texture,
- tiledef_special[j].backface_culling, alpha, material_type);
+ tdef_spec[j].backface_culling, material_type);
}
+ if (param_type_2 == CPT2_COLOR ||
+ param_type_2 == CPT2_COLORED_FACEDIR ||
+ param_type_2 == CPT2_COLORED_WALLMOUNTED)
+ palette = tsrc->getPalette(palette_name);
+
if ((drawtype == NDT_MESH) && (mesh != "")) {
// Meshnode drawtype
// Read the mesh and apply scale
- mesh_ptr[0] = gamedef->getMesh(mesh);
+ mesh_ptr[0] = client->getMesh(mesh);
if (mesh_ptr[0]){
v3f scale = v3f(1.0, 1.0, 1.0) * BS * visual_scale;
scaleMesh(mesh_ptr[0], scale);
@@ -738,15 +827,19 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
}
//Cache 6dfacedir and wallmounted rotated clones of meshes
- if (tsettings.enable_mesh_cache && mesh_ptr[0] && (param_type_2 == CPT2_FACEDIR)) {
+ if (tsettings.enable_mesh_cache && mesh_ptr[0] &&
+ (param_type_2 == CPT2_FACEDIR
+ || param_type_2 == CPT2_COLORED_FACEDIR)) {
for (u16 j = 1; j < 24; j++) {
mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
rotateMeshBy6dFacedir(mesh_ptr[j], j);
recalculateBoundingBox(mesh_ptr[j]);
meshmanip->recalculateNormals(mesh_ptr[j], true, false);
}
- } else if (tsettings.enable_mesh_cache && mesh_ptr[0] && (param_type_2 == CPT2_WALLMOUNTED)) {
- static const u8 wm_to_6d[6] = {20, 0, 16+1, 12+3, 8, 4+2};
+ } else if (tsettings.enable_mesh_cache && mesh_ptr[0]
+ && (param_type_2 == CPT2_WALLMOUNTED ||
+ param_type_2 == CPT2_COLORED_WALLMOUNTED)) {
+ static const u8 wm_to_6d[6] = { 20, 0, 16 + 1, 12 + 3, 8, 4 + 2 };
for (u16 j = 1; j < 6; j++) {
mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
rotateMeshBy6dFacedir(mesh_ptr[j], wm_to_6d[j]);
@@ -788,7 +881,6 @@ public:
void serialize(std::ostream &os, u16 protocol_version) const;
void deSerialize(std::istream &is);
- inline virtual bool getNodeRegistrationStatus() const;
inline virtual void setNodeRegistrationStatus(bool completed);
virtual void pendNodeResolve(NodeResolver *nr);
@@ -797,9 +889,18 @@ public:
virtual void resetNodeResolveState();
virtual void mapNodeboxConnections();
virtual bool nodeboxConnects(MapNode from, MapNode to, u8 connect_face);
+ virtual core::aabbox3d<s16> getSelectionBoxIntUnion() const
+ {
+ return m_selection_box_int_union;
+ }
private:
void addNameIdMapping(content_t i, std::string name);
+ /*!
+ * Recalculates m_selection_box_int_union based on
+ * m_selection_box_union.
+ */
+ void fixSelectionBoxIntUnion();
// Features indexed by id
std::vector<ContentFeatures> m_content_features;
@@ -826,6 +927,14 @@ private:
// True when all nodes have been registered
bool m_node_registration_complete;
+
+ //! The union of all nodes' selection boxes.
+ aabb3f m_selection_box_union;
+ /*!
+ * The smallest box in node coordinates that
+ * contains all nodes' selection boxes.
+ */
+ core::aabbox3d<s16> m_selection_box_int_union;
};
@@ -856,6 +965,8 @@ void CNodeDefManager::clear()
m_name_id_mapping_with_aliases.clear();
m_group_to_items.clear();
m_next_id = 0;
+ m_selection_box_union.reset(0,0,0);
+ m_selection_box_int_union.reset(0,0,0);
resetNodeResolveState();
@@ -1014,6 +1125,124 @@ content_t CNodeDefManager::allocateId()
}
+/*!
+ * Returns the smallest box that contains all boxes
+ * in the vector. Box_union is expanded.
+ * @param[in] boxes the vector containing the boxes
+ * @param[in, out] box_union the union of the arguments
+ */
+void boxVectorUnion(const std::vector<aabb3f> &boxes, aabb3f *box_union)
+{
+ for (std::vector<aabb3f>::const_iterator it = boxes.begin();
+ it != boxes.end(); ++it) {
+ box_union->addInternalBox(*it);
+ }
+}
+
+
+/*!
+ * Returns a box that contains the nodebox in every case.
+ * The argument node_union is expanded.
+ * @param[in] nodebox the nodebox to be measured
+ * @param[in] features used to decide whether the nodebox
+ * can be rotated
+ * @param[in, out] box_union the union of the arguments
+ */
+void getNodeBoxUnion(const NodeBox &nodebox, const ContentFeatures &features,
+ aabb3f *box_union)
+{
+ switch(nodebox.type) {
+ case NODEBOX_FIXED:
+ case NODEBOX_LEVELED: {
+ // Raw union
+ aabb3f half_processed(0, 0, 0, 0, 0, 0);
+ boxVectorUnion(nodebox.fixed, &half_processed);
+ // Set leveled boxes to maximal
+ if (nodebox.type == NODEBOX_LEVELED) {
+ half_processed.MaxEdge.Y = +BS / 2;
+ }
+ if (features.param_type_2 == CPT2_FACEDIR ||
+ features.param_type_2 == CPT2_COLORED_FACEDIR) {
+ // Get maximal coordinate
+ f32 coords[] = {
+ fabsf(half_processed.MinEdge.X),
+ fabsf(half_processed.MinEdge.Y),
+ fabsf(half_processed.MinEdge.Z),
+ fabsf(half_processed.MaxEdge.X),
+ fabsf(half_processed.MaxEdge.Y),
+ fabsf(half_processed.MaxEdge.Z) };
+ f32 max = 0;
+ for (int i = 0; i < 6; i++) {
+ if (max < coords[i]) {
+ max = coords[i];
+ }
+ }
+ // Add the union of all possible rotated boxes
+ box_union->addInternalPoint(-max, -max, -max);
+ box_union->addInternalPoint(+max, +max, +max);
+ } else {
+ box_union->addInternalBox(half_processed);
+ }
+ break;
+ }
+ case NODEBOX_WALLMOUNTED: {
+ // Add fix boxes
+ box_union->addInternalBox(nodebox.wall_top);
+ box_union->addInternalBox(nodebox.wall_bottom);
+ // Find maximal coordinate in the X-Z plane
+ f32 coords[] = {
+ fabsf(nodebox.wall_side.MinEdge.X),
+ fabsf(nodebox.wall_side.MinEdge.Z),
+ fabsf(nodebox.wall_side.MaxEdge.X),
+ fabsf(nodebox.wall_side.MaxEdge.Z) };
+ f32 max = 0;
+ for (int i = 0; i < 4; i++) {
+ if (max < coords[i]) {
+ max = coords[i];
+ }
+ }
+ // Add the union of all possible rotated boxes
+ box_union->addInternalPoint(-max, nodebox.wall_side.MinEdge.Y, -max);
+ box_union->addInternalPoint(max, nodebox.wall_side.MaxEdge.Y, max);
+ break;
+ }
+ case NODEBOX_CONNECTED: {
+ // Add all possible connected boxes
+ boxVectorUnion(nodebox.fixed, box_union);
+ boxVectorUnion(nodebox.connect_top, box_union);
+ boxVectorUnion(nodebox.connect_bottom, box_union);
+ boxVectorUnion(nodebox.connect_front, box_union);
+ boxVectorUnion(nodebox.connect_left, box_union);
+ boxVectorUnion(nodebox.connect_back, box_union);
+ boxVectorUnion(nodebox.connect_right, box_union);
+ break;
+ }
+ default: {
+ // NODEBOX_REGULAR
+ box_union->addInternalPoint(-BS / 2, -BS / 2, -BS / 2);
+ box_union->addInternalPoint(+BS / 2, +BS / 2, +BS / 2);
+ }
+ }
+}
+
+
+inline void CNodeDefManager::fixSelectionBoxIntUnion()
+{
+ m_selection_box_int_union.MinEdge.X = floorf(
+ m_selection_box_union.MinEdge.X / BS + 0.5f);
+ m_selection_box_int_union.MinEdge.Y = floorf(
+ m_selection_box_union.MinEdge.Y / BS + 0.5f);
+ m_selection_box_int_union.MinEdge.Z = floorf(
+ m_selection_box_union.MinEdge.Z / BS + 0.5f);
+ m_selection_box_int_union.MaxEdge.X = ceilf(
+ m_selection_box_union.MaxEdge.X / BS - 0.5f);
+ m_selection_box_int_union.MaxEdge.Y = ceilf(
+ m_selection_box_union.MaxEdge.Y / BS - 0.5f);
+ m_selection_box_int_union.MaxEdge.Z = ceilf(
+ m_selection_box_union.MaxEdge.Z / BS - 0.5f);
+}
+
+
// IWritableNodeDefManager
content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
{
@@ -1044,6 +1273,8 @@ content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &d
verbosestream << "NodeDefManager: registering content id \"" << id
<< "\": name=\"" << def.name << "\""<<std::endl;
+ getNodeBoxUnion(def.selection_box, def, &m_selection_box_union);
+ fixSelectionBoxIntUnion();
// Add this content to the list of all groups it belongs to
// FIXME: This should remove a node from groups it no longer
// belongs to when a node is re-registered
@@ -1088,34 +1319,34 @@ void CNodeDefManager::removeNode(const std::string &name)
// Erase node content from all groups it belongs to
for (UNORDERED_MAP<std::string, GroupItems>::iterator iter_groups =
- m_group_to_items.begin();
- iter_groups != m_group_to_items.end();) {
+ m_group_to_items.begin(); iter_groups != m_group_to_items.end();) {
GroupItems &items = iter_groups->second;
for (GroupItems::iterator iter_groupitems = items.begin();
iter_groupitems != items.end();) {
if (iter_groupitems->first == id)
items.erase(iter_groupitems++);
else
- iter_groupitems++;
+ ++iter_groupitems;
}
// Check if group is empty
if (items.size() == 0)
m_group_to_items.erase(iter_groups++);
else
- iter_groups++;
+ ++iter_groups;
}
}
void CNodeDefManager::updateAliases(IItemDefManager *idef)
{
- std::set<std::string> all = idef->getAll();
+ std::set<std::string> all;
+ idef->getAll(all);
m_name_id_mapping_with_aliases.clear();
- for (std::set<std::string>::iterator
+ for (std::set<std::string>::const_iterator
i = all.begin(); i != all.end(); ++i) {
- std::string name = *i;
- std::string convert_to = idef->getAlias(name);
+ const std::string &name = *i;
+ const std::string &convert_to = idef->getAlias(name);
content_t id;
if (m_name_id_mapping.getId(convert_to, id)) {
m_name_id_mapping_with_aliases.insert(
@@ -1185,9 +1416,11 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef,
#ifndef SERVER
infostream << "CNodeDefManager::updateTextures(): Updating "
"textures in node definitions" << std::endl;
- ITextureSource *tsrc = gamedef->tsrc();
- IShaderSource *shdsrc = gamedef->getShaderSource();
- scene::ISceneManager* smgr = gamedef->getSceneManager();
+
+ Client *client = (Client *)gamedef;
+ ITextureSource *tsrc = client->tsrc();
+ IShaderSource *shdsrc = client->getShaderSource();
+ scene::ISceneManager* smgr = client->getSceneManager();
scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
TextureSettings tsettings;
tsettings.readSettings();
@@ -1195,7 +1428,8 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef,
u32 size = m_content_features.size();
for (u32 i = 0; i < size; i++) {
- m_content_features[i].updateTextures(tsrc, shdsrc, smgr, meshmanip, gamedef, tsettings);
+ ContentFeatures *f = &(m_content_features[i]);
+ f->updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
progress_callback(progress_callback_args, i, size);
}
#endif
@@ -1273,6 +1507,9 @@ void CNodeDefManager::deSerialize(std::istream &is)
m_content_features[i] = f;
addNameIdMapping(i, f.name);
verbosestream << "deserialized " << f.name << std::endl;
+
+ getNodeBoxUnion(f.selection_box, f, &m_selection_box_union);
+ fixSelectionBoxIntUnion();
}
}
@@ -1293,72 +1530,52 @@ IWritableNodeDefManager *createNodeDefManager()
//// Serialization of old ContentFeatures formats
void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
{
- if (protocol_version == 13)
- {
- writeU8(os, 5); // version
- os<<serializeString(name);
- writeU16(os, groups.size());
- for (ItemGroupList::const_iterator
- i = groups.begin(); i != groups.end(); ++i) {
- os<<serializeString(i->first);
- writeS16(os, i->second);
+ u8 compatible_param_type_2 = param_type_2;
+ if ((protocol_version < 28)
+ && (compatible_param_type_2 == CPT2_MESHOPTIONS))
+ compatible_param_type_2 = CPT2_NONE;
+ else if (protocol_version < 30) {
+ if (compatible_param_type_2 == CPT2_COLOR)
+ compatible_param_type_2 = CPT2_NONE;
+ else if (compatible_param_type_2 == CPT2_COLORED_FACEDIR)
+ compatible_param_type_2 = CPT2_FACEDIR;
+ else if (compatible_param_type_2 == CPT2_COLORED_WALLMOUNTED)
+ compatible_param_type_2 = CPT2_WALLMOUNTED;
+ }
+
+ float compatible_visual_scale = visual_scale;
+ if (protocol_version < 30 && drawtype == NDT_PLANTLIKE)
+ compatible_visual_scale = sqrt(visual_scale);
+
+ TileDef compatible_tiles[6];
+ for (u8 i = 0; i < 6; i++) {
+ compatible_tiles[i] = tiledef[i];
+ if (tiledef_overlay[i].name != "") {
+ std::stringstream s;
+ s << "(" << tiledef[i].name << ")^(" << tiledef_overlay[i].name
+ << ")";
+ compatible_tiles[i].name = s.str();
}
- writeU8(os, drawtype);
- writeF1000(os, visual_scale);
- writeU8(os, 6);
- for (u32 i = 0; i < 6; i++)
- tiledef[i].serialize(os, protocol_version);
- //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
- writeU8(os, 2);
- for (u32 i = 0; i < 2; i++)
- tiledef_special[i].serialize(os, protocol_version);
- writeU8(os, alpha);
- writeU8(os, post_effect_color.getAlpha());
- writeU8(os, post_effect_color.getRed());
- writeU8(os, post_effect_color.getGreen());
- writeU8(os, post_effect_color.getBlue());
- writeU8(os, param_type);
- writeU8(os, param_type_2);
- writeU8(os, is_ground_content);
- writeU8(os, light_propagates);
- writeU8(os, sunlight_propagates);
- writeU8(os, walkable);
- writeU8(os, pointable);
- writeU8(os, diggable);
- writeU8(os, climbable);
- writeU8(os, buildable_to);
- os<<serializeString(""); // legacy: used to be metadata_name
- writeU8(os, liquid_type);
- os<<serializeString(liquid_alternative_flowing);
- os<<serializeString(liquid_alternative_source);
- writeU8(os, liquid_viscosity);
- writeU8(os, light_source);
- writeU32(os, damage_per_second);
- node_box.serialize(os, protocol_version);
- selection_box.serialize(os, protocol_version);
- writeU8(os, legacy_facedir_simple);
- writeU8(os, legacy_wallmounted);
- serializeSimpleSoundSpec(sound_footstep, os);
- serializeSimpleSoundSpec(sound_dig, os);
- serializeSimpleSoundSpec(sound_dug, os);
}
- else if (protocol_version > 13 && protocol_version < 24) {
- writeU8(os, 6); // version
- os<<serializeString(name);
+
+ // Protocol >= 24
+ if (protocol_version < 31) {
+ writeU8(os, protocol_version < 27 ? 7 : 8);
+
+ os << serializeString(name);
writeU16(os, groups.size());
- for (ItemGroupList::const_iterator
- i = groups.begin(); i != groups.end(); ++i) {
- os<<serializeString(i->first);
- writeS16(os, i->second);
+ for (ItemGroupList::const_iterator i = groups.begin();
+ i != groups.end(); ++i) {
+ os << serializeString(i->first);
+ writeS16(os, i->second);
}
writeU8(os, drawtype);
- writeF1000(os, visual_scale);
+ writeF1000(os, compatible_visual_scale);
writeU8(os, 6);
for (u32 i = 0; i < 6; i++)
- tiledef[i].serialize(os, protocol_version);
- //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
- writeU8(os, 2);
- for (u32 i = 0; i < 2; i++)
+ compatible_tiles[i].serialize(os, protocol_version);
+ writeU8(os, CF_SPECIAL_COUNT);
+ for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
tiledef_special[i].serialize(os, protocol_version);
writeU8(os, alpha);
writeU8(os, post_effect_color.getAlpha());
@@ -1366,7 +1583,7 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
writeU8(os, post_effect_color.getGreen());
writeU8(os, post_effect_color.getBlue());
writeU8(os, param_type);
- writeU8(os, param_type_2);
+ writeU8(os, compatible_param_type_2);
writeU8(os, is_ground_content);
writeU8(os, light_propagates);
writeU8(os, sunlight_propagates);
@@ -1375,10 +1592,10 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
writeU8(os, diggable);
writeU8(os, climbable);
writeU8(os, buildable_to);
- os<<serializeString(""); // legacy: used to be metadata_name
+ os << serializeString(""); // legacy: used to be metadata_name
writeU8(os, liquid_type);
- os<<serializeString(liquid_alternative_flowing);
- os<<serializeString(liquid_alternative_source);
+ os << serializeString(liquid_alternative_flowing);
+ os << serializeString(liquid_alternative_source);
writeU8(os, liquid_viscosity);
writeU8(os, liquid_renewable);
writeU8(os, light_source);
@@ -1394,9 +1611,19 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
writeU8(os, drowning);
writeU8(os, leveled);
writeU8(os, liquid_range);
- } else
+ writeU8(os, waving);
+ os << serializeString(mesh);
+ collision_box.serialize(os, protocol_version);
+ writeU8(os, floodable);
+ writeU16(os, connects_to_ids.size());
+ for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
+ i != connects_to_ids.end(); ++i)
+ writeU16(os, *i);
+ writeU8(os, connect_sides);
+ } else {
throw SerializationError("ContentFeatures::serialize(): "
"Unsupported version requested");
+ }
}
void ContentFeatures::deSerializeOld(std::istream &is, int version)
@@ -1506,18 +1733,77 @@ void ContentFeatures::deSerializeOld(std::istream &is, int version)
drowning = readU8(is);
leveled = readU8(is);
liquid_range = readU8(is);
- } else {
+ } else if (version == 7 || version == 8){
+ name = deSerializeString(is);
+ groups.clear();
+ u32 groups_size = readU16(is);
+ for (u32 i = 0; i < groups_size; i++) {
+ std::string name = deSerializeString(is);
+ int value = readS16(is);
+ groups[name] = value;
+ }
+ drawtype = (enum NodeDrawType) readU8(is);
+
+ visual_scale = readF1000(is);
+ if (readU8(is) != 6)
+ throw SerializationError("unsupported tile count");
+ for (u32 i = 0; i < 6; i++)
+ tiledef[i].deSerialize(is, version, drawtype);
+ if (readU8(is) != CF_SPECIAL_COUNT)
+ throw SerializationError("unsupported CF_SPECIAL_COUNT");
+ for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
+ tiledef_special[i].deSerialize(is, version, drawtype);
+ alpha = readU8(is);
+ post_effect_color.setAlpha(readU8(is));
+ post_effect_color.setRed(readU8(is));
+ post_effect_color.setGreen(readU8(is));
+ post_effect_color.setBlue(readU8(is));
+ param_type = (enum ContentParamType) readU8(is);
+ param_type_2 = (enum ContentParamType2) readU8(is);
+ is_ground_content = readU8(is);
+ light_propagates = readU8(is);
+ sunlight_propagates = readU8(is);
+ walkable = readU8(is);
+ pointable = readU8(is);
+ diggable = readU8(is);
+ climbable = readU8(is);
+ buildable_to = readU8(is);
+ deSerializeString(is); // legacy: used to be metadata_name
+ liquid_type = (enum LiquidType) readU8(is);
+ liquid_alternative_flowing = deSerializeString(is);
+ liquid_alternative_source = deSerializeString(is);
+ liquid_viscosity = readU8(is);
+ liquid_renewable = readU8(is);
+ light_source = readU8(is);
+ light_source = MYMIN(light_source, LIGHT_MAX);
+ damage_per_second = readU32(is);
+ node_box.deSerialize(is);
+ selection_box.deSerialize(is);
+ legacy_facedir_simple = readU8(is);
+ legacy_wallmounted = readU8(is);
+ deSerializeSimpleSoundSpec(sound_footstep, is);
+ deSerializeSimpleSoundSpec(sound_dig, is);
+ deSerializeSimpleSoundSpec(sound_dug, is);
+ rightclickable = readU8(is);
+ drowning = readU8(is);
+ leveled = readU8(is);
+ liquid_range = readU8(is);
+ waving = readU8(is);
+ try {
+ mesh = deSerializeString(is);
+ collision_box.deSerialize(is);
+ floodable = readU8(is);
+ u16 connects_to_size = readU16(is);
+ connects_to_ids.clear();
+ for (u16 i = 0; i < connects_to_size; i++)
+ connects_to_ids.insert(readU16(is));
+ connect_sides = readU8(is);
+ } catch (SerializationError &e) {};
+ }else{
throw SerializationError("unsupported ContentFeatures version");
}
}
-
-inline bool CNodeDefManager::getNodeRegistrationStatus() const
-{
- return m_node_registration_complete;
-}
-
-
inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
{
m_node_registration_complete = completed;
@@ -1600,19 +1886,23 @@ bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
// does to node declare usable faces?
if (f2.connect_sides > 0) {
- if ((f2.param_type_2 == CPT2_FACEDIR) && (connect_face >= 4)) {
- static const u8 rot[33 * 4] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 - back
- 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 - right
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 16, 8, 4, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - front
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 32, 16, 8, 4 // 32 - left
- };
- return (f2.connect_sides & rot[(connect_face * 4) + to.param2]);
+ if ((f2.param_type_2 == CPT2_FACEDIR ||
+ f2.param_type_2 == CPT2_COLORED_FACEDIR)
+ && (connect_face >= 4)) {
+ static const u8 rot[33 * 4] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, // 4 - back
+ 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, // 8 - right
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8, 4, 32, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, // 16 - front
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 32, 16, 8, 4 // 32 - left
+ };
+ return (f2.connect_sides
+ & rot[(connect_face * 4) + (to.param2 & 0x1F)]);
}
return (f2.connect_sides & connect_face);
}
diff --git a/src/nodedef.h b/src/nodedef.h
index 80396f992..4669df7f0 100644
--- a/src/nodedef.h
+++ b/src/nodedef.h
@@ -30,10 +30,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef SERVER
#include "client/tile.h"
#include "shader.h"
+class Client;
#endif
#include "itemgroup.h"
#include "sound.h" // SimpleSoundSpec
#include "constants.h" // BS
+#include "tileanimation.h"
class INodeDefManager;
class IItemDefManager;
@@ -66,7 +68,15 @@ enum ContentParamType2
// 2D rotation for things like plants
CPT2_DEGROTATE,
// Mesh options for plants
- CPT2_MESHOPTIONS
+ CPT2_MESHOPTIONS,
+ // Index for palette
+ CPT2_COLOR,
+ // 3 bits of palette index, then facedir
+ CPT2_COLORED_FACEDIR,
+ // 5 bits of palette index, then wallmounted
+ CPT2_COLORED_WALLMOUNTED,
+ // Glasslike framed drawtype internal liquid level, param2 values 0 to 63
+ CPT2_GLASSLIKE_LIQUID_LEVEL,
};
enum LiquidType
@@ -136,58 +146,87 @@ public:
enum NodeDrawType
{
- NDT_NORMAL, // A basic solid block
- NDT_AIRLIKE, // Nothing is drawn
- NDT_LIQUID, // Do not draw face towards same kind of flowing/source liquid
- NDT_FLOWINGLIQUID, // A very special kind of thing
- NDT_GLASSLIKE, // Glass-like, don't draw faces towards other glass
- NDT_ALLFACES, // Leaves-like, draw all faces no matter what
- NDT_ALLFACES_OPTIONAL, // Fancy -> allfaces, fast -> normal
+ // A basic solid block
+ NDT_NORMAL,
+ // Nothing is drawn
+ NDT_AIRLIKE,
+ // Do not draw face towards same kind of flowing/source liquid
+ NDT_LIQUID,
+ // A very special kind of thing
+ NDT_FLOWINGLIQUID,
+ // Glass-like, don't draw faces towards other glass
+ NDT_GLASSLIKE,
+ // Leaves-like, draw all faces no matter what
+ NDT_ALLFACES,
+ // Enabled -> ndt_allfaces, disabled -> ndt_normal
+ NDT_ALLFACES_OPTIONAL,
+ // Single plane perpendicular to a surface
NDT_TORCHLIKE,
+ // Single plane parallel to a surface
NDT_SIGNLIKE,
+ // 2 vertical planes in a 'X' shape diagonal to XZ axes.
+ // paramtype2 = "meshoptions" allows various forms, sizes and
+ // vertical and horizontal random offsets.
NDT_PLANTLIKE,
+ // Fenceposts that connect to neighbouring fenceposts with horizontal bars
NDT_FENCELIKE,
+ // Selects appropriate junction texture to connect like rails to
+ // neighbouring raillikes.
NDT_RAILLIKE,
+ // Custom Lua-definable structure of multiple cuboids
NDT_NODEBOX,
- NDT_GLASSLIKE_FRAMED, // Glass-like, draw connected frames and all all
- // visible faces
- // uses 2 textures, one for frames, second for faces
- NDT_FIRELIKE, // Draw faces slightly rotated and only on connecting nodes,
- NDT_GLASSLIKE_FRAMED_OPTIONAL, // enabled -> connected, disabled -> Glass-like
- // uses 2 textures, one for frames, second for faces
- NDT_MESH, // Uses static meshes
+ // Glass-like, draw connected frames and all visible faces.
+ // param2 > 0 defines 64 levels of internal liquid
+ // Uses 3 textures, one for frames, second for faces,
+ // optional third is a 'special tile' for the liquid.
+ NDT_GLASSLIKE_FRAMED,
+ // Draw faces slightly rotated and only on neighbouring nodes
+ NDT_FIRELIKE,
+ // Enabled -> ndt_glasslike_framed, disabled -> ndt_glasslike
+ NDT_GLASSLIKE_FRAMED_OPTIONAL,
+ // Uses static meshes
+ NDT_MESH,
+};
+
+// Mesh options for NDT_PLANTLIKE with CPT2_MESHOPTIONS
+static const u8 MO_MASK_STYLE = 0x07;
+static const u8 MO_BIT_RANDOM_OFFSET = 0x08;
+static const u8 MO_BIT_SCALE_SQRT2 = 0x10;
+static const u8 MO_BIT_RANDOM_OFFSET_Y = 0x20;
+enum PlantlikeStyle {
+ PLANT_STYLE_CROSS,
+ PLANT_STYLE_CROSS2,
+ PLANT_STYLE_STAR,
+ PLANT_STYLE_HASH,
+ PLANT_STYLE_HASH2,
};
/*
Stand-alone definition of a TileSpec (basically a server-side TileSpec)
*/
-enum TileAnimationType{
- TAT_NONE=0,
- TAT_VERTICAL_FRAMES=1,
-};
+
struct TileDef
{
std::string name;
bool backface_culling; // Takes effect only in special cases
bool tileable_horizontal;
bool tileable_vertical;
- struct{
- enum TileAnimationType type;
- int aspect_w; // width for aspect ratio
- int aspect_h; // height for aspect ratio
- float length; // seconds
- } animation;
-
- TileDef()
+ //! If true, the tile has its own color.
+ bool has_color;
+ //! The color of the tile.
+ video::SColor color;
+
+ struct TileAnimationParams animation;
+
+ TileDef() :
+ name(""),
+ backface_culling(true),
+ tileable_horizontal(true),
+ tileable_vertical(true),
+ has_color(false),
+ color(video::SColor(0xFFFFFFFF))
{
- name = "";
- backface_culling = true;
- tileable_horizontal = true;
- tileable_vertical = true;
animation.type = TAT_NONE;
- animation.aspect_w = 1;
- animation.aspect_h = 1;
- animation.length = 1.0;
}
void serialize(std::ostream &os, u16 protocol_version) const;
@@ -200,7 +239,7 @@ struct ContentFeatures
{
/*
Cached stuff
- */
+ */
#ifndef SERVER
// 0 1 2 3 4 5
// up down right left back front
@@ -220,12 +259,19 @@ struct ContentFeatures
/*
Actual data
- */
+ */
+
+ // --- GENERAL PROPERTIES ---
std::string name; // "" = undefined node
ItemGroupList groups; // Same as in itemdef
+ // Type of MapNode::param1
+ ContentParamType param_type;
+ // Type of MapNode::param2
+ ContentParamType2 param_type_2;
+
+ // --- VISUAL PROPERTIES ---
- // Visual definition
enum NodeDrawType drawtype;
std::string mesh;
#ifndef SERVER
@@ -234,20 +280,41 @@ struct ContentFeatures
#endif
float visual_scale; // Misc. scale parameter
TileDef tiledef[6];
+ // These will be drawn over the base tiles.
+ TileDef tiledef_overlay[6];
TileDef tiledef_special[CF_SPECIAL_COUNT]; // eg. flowing liquid
+ // If 255, the node is opaque.
+ // Otherwise it uses texture alpha.
u8 alpha;
-
+ // The color of the node.
+ video::SColor color;
+ std::string palette_name;
+ std::vector<video::SColor> *palette;
+ // Used for waving leaves/plants
+ u8 waving;
+ // for NDT_CONNECTED pairing
+ u8 connect_sides;
+ std::vector<std::string> connects_to;
+ std::set<content_t> connects_to_ids;
// Post effect color, drawn when the camera is inside the node.
video::SColor post_effect_color;
+ // Flowing liquid or snow, value = default level
+ u8 leveled;
+
+ // --- LIGHTING-RELATED ---
- // Type of MapNode::param1
- ContentParamType param_type;
- // Type of MapNode::param2
- ContentParamType2 param_type_2;
- // True for all ground-like things like stone and mud, false for eg. trees
- bool is_ground_content;
bool light_propagates;
bool sunlight_propagates;
+ // Amount of light the node emits
+ u8 light_source;
+
+ // --- MAP GENERATION ---
+
+ // True for all ground-like things like stone and mud, false for eg. trees
+ bool is_ground_content;
+
+ // --- INTERACTION PROPERTIES ---
+
// This is used for collision detection.
// Also for general solidness queries.
bool walkable;
@@ -259,12 +326,12 @@ struct ContentFeatures
bool climbable;
// Player can build on these
bool buildable_to;
- // Liquids flow into and replace node
- bool floodable;
// Player cannot build to these (placement prediction disabled)
bool rightclickable;
- // Flowing liquid or snow, value = default level
- u8 leveled;
+ u32 damage_per_second;
+
+ // --- LIQUID PROPERTIES ---
+
// Whether the node is non-liquid, source liquid or flowing liquid
enum LiquidType liquid_type;
// If the content is liquid, this is the flowing version of the liquid.
@@ -280,29 +347,28 @@ struct ContentFeatures
// Number of flowing liquids surrounding source
u8 liquid_range;
u8 drowning;
- // Amount of light the node emits
- u8 light_source;
- u32 damage_per_second;
+ // Liquids flow into and replace node
+ bool floodable;
+
+ // --- NODEBOXES ---
+
NodeBox node_box;
NodeBox selection_box;
NodeBox collision_box;
- // Used for waving leaves/plants
- u8 waving;
- // Compatibility with old maps
- // Set to true if paramtype used to be 'facedir_simple'
- bool legacy_facedir_simple;
- // Set to true if wall_mounted used to be set to true
- bool legacy_wallmounted;
- // for NDT_CONNECTED pairing
- u8 connect_sides;
- // Sound properties
+ // --- SOUND PROPERTIES ---
+
SimpleSoundSpec sound_footstep;
SimpleSoundSpec sound_dig;
SimpleSoundSpec sound_dug;
- std::vector<std::string> connects_to;
- std::set<content_t> connects_to_ids;
+ // --- LEGACY ---
+
+ // Compatibility with old maps
+ // Set to true if paramtype used to be 'facedir_simple'
+ bool legacy_facedir_simple;
+ // Set to true if wall_mounted used to be set to true
+ bool legacy_wallmounted;
/*
Methods
@@ -315,6 +381,14 @@ struct ContentFeatures
void deSerialize(std::istream &is);
void serializeOld(std::ostream &os, u16 protocol_version) const;
void deSerializeOld(std::istream &is, int version);
+ /*!
+ * Since vertex alpha is no longer supported, this method
+ * adds opacity directly to the texture pixels.
+ *
+ * \param tiles array of the tile definitions.
+ * \param length length of tiles
+ */
+ void correctAlpha(TileDef *tiles, int length);
/*
Some handy methods
@@ -327,13 +401,17 @@ struct ContentFeatures
return (liquid_alternative_flowing == f.liquid_alternative_flowing);
}
+ int getGroup(const std::string &group) const
+ {
+ return itemgroup_get(groups, group);
+ }
+
#ifndef SERVER
- void fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, TileDef *tiledef,
+ void fillTileAttribs(ITextureSource *tsrc, TileLayer *tile, TileDef *tiledef,
u32 shader_id, bool use_normal_texture, bool backface_culling,
- u8 alpha, u8 material_type);
+ u8 material_type);
void updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc,
- scene::ISceneManager *smgr, scene::IMeshManipulator *meshmanip,
- IGameDef *gamedef, const TextureSettings &tsettings);
+ scene::IMeshManipulator *meshmanip, Client *client, const TextureSettings &tsettings);
#endif
};
@@ -354,11 +432,14 @@ public:
virtual void serialize(std::ostream &os, u16 protocol_version) const=0;
- virtual bool getNodeRegistrationStatus() const=0;
-
virtual void pendNodeResolve(NodeResolver *nr)=0;
virtual bool cancelNodeResolveCallback(NodeResolver *nr)=0;
virtual bool nodeboxConnects(const MapNode from, const MapNode to, u8 connect_face)=0;
+ /*!
+ * Returns the smallest box in node coordinates that
+ * contains all nodes' selection boxes.
+ */
+ virtual core::aabbox3d<s16> getSelectionBoxIntUnion() const=0;
};
class IWritableNodeDefManager : public INodeDefManager {
@@ -408,7 +489,6 @@ public:
virtual void serialize(std::ostream &os, u16 protocol_version) const=0;
virtual void deSerialize(std::istream &is)=0;
- virtual bool getNodeRegistrationStatus() const=0;
virtual void setNodeRegistrationStatus(bool completed)=0;
virtual void pendNodeResolve(NodeResolver *nr)=0;
@@ -416,6 +496,7 @@ public:
virtual void runNodeResolveCallbacks()=0;
virtual void resetNodeResolveState()=0;
virtual void mapNodeboxConnections()=0;
+ virtual core::aabbox3d<s16> getSelectionBoxIntUnion() const=0;
};
IWritableNodeDefManager *createNodeDefManager();
diff --git a/src/nodemetadata.cpp b/src/nodemetadata.cpp
index 0801a028b..0e8195c34 100644
--- a/src/nodemetadata.cpp
+++ b/src/nodemetadata.cpp
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "inventory.h"
#include "log.h"
#include "util/serialize.h"
+#include "util/basic_macros.h"
#include "constants.h" // MAP_BLOCKSIZE
#include <sstream>
@@ -31,38 +32,46 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
NodeMetadata::NodeMetadata(IItemDefManager *item_def_mgr):
- m_stringvars(),
m_inventory(new Inventory(item_def_mgr))
-{
-}
+{}
NodeMetadata::~NodeMetadata()
{
delete m_inventory;
}
-void NodeMetadata::serialize(std::ostream &os) const
+void NodeMetadata::serialize(std::ostream &os, u8 version, bool disk) const
{
- int num_vars = m_stringvars.size();
+ int num_vars = disk ? m_stringvars.size() : countNonPrivate();
writeU32(os, num_vars);
for (StringMap::const_iterator
it = m_stringvars.begin();
it != m_stringvars.end(); ++it) {
+ bool priv = isPrivate(it->first);
+ if (!disk && priv)
+ continue;
+
os << serializeString(it->first);
os << serializeLongString(it->second);
+ if (version >= 2)
+ writeU8(os, (priv) ? 1 : 0);
}
m_inventory->serialize(os);
}
-void NodeMetadata::deSerialize(std::istream &is)
+void NodeMetadata::deSerialize(std::istream &is, u8 version)
{
- m_stringvars.clear();
+ clear();
int num_vars = readU32(is);
for(int i=0; i<num_vars; i++){
std::string name = deSerializeString(is);
std::string var = deSerializeLongString(is);
m_stringvars[name] = var;
+ if (version >= 2) {
+ if (readU8(is) == 1)
+ markPrivate(name, true);
+ }
}
m_inventory->deSerialize(is);
@@ -70,20 +79,44 @@ void NodeMetadata::deSerialize(std::istream &is)
void NodeMetadata::clear()
{
- m_stringvars.clear();
+ Metadata::clear();
+ m_privatevars.clear();
m_inventory->clear();
}
bool NodeMetadata::empty() const
{
- return m_stringvars.size() == 0 && m_inventory->getLists().size() == 0;
+ return Metadata::empty() && m_inventory->getLists().size() == 0;
+}
+
+
+void NodeMetadata::markPrivate(const std::string &name, bool set)
+{
+ if (set)
+ m_privatevars.insert(name);
+ else
+ m_privatevars.erase(name);
+}
+
+int NodeMetadata::countNonPrivate() const
+{
+ // m_privatevars can contain names not actually present
+ // DON'T: return m_stringvars.size() - m_privatevars.size();
+ int n = 0;
+ for (StringMap::const_iterator
+ it = m_stringvars.begin();
+ it != m_stringvars.end(); ++it) {
+ if (isPrivate(it->first) == false)
+ n++;
+ }
+ return n;
}
/*
NodeMetadataList
*/
-void NodeMetadataList::serialize(std::ostream &os) const
+void NodeMetadataList::serialize(std::ostream &os, u8 blockver, bool disk) const
{
/*
Version 0 is a placeholder for "nothing to see here; go away."
@@ -95,7 +128,8 @@ void NodeMetadataList::serialize(std::ostream &os) const
return;
}
- writeU8(os, 1); // version
+ u8 version = (blockver > 27) ? 2 : 1;
+ writeU8(os, version);
writeU16(os, count);
for(std::map<v3s16, NodeMetadata*>::const_iterator
@@ -110,7 +144,7 @@ void NodeMetadataList::serialize(std::ostream &os) const
u16 p16 = p.Z * MAP_BLOCKSIZE * MAP_BLOCKSIZE + p.Y * MAP_BLOCKSIZE + p.X;
writeU16(os, p16);
- data->serialize(os);
+ data->serialize(os, version, disk);
}
}
@@ -125,7 +159,7 @@ void NodeMetadataList::deSerialize(std::istream &is, IItemDefManager *item_def_m
return;
}
- if (version != 1) {
+ if (version > 2) {
std::string err_str = std::string(FUNCTION_NAME)
+ ": version " + itos(version) + " not supported";
infostream << err_str << std::endl;
@@ -134,7 +168,7 @@ void NodeMetadataList::deSerialize(std::istream &is, IItemDefManager *item_def_m
u16 count = readU16(is);
- for (u16 i=0; i < count; i++) {
+ for (u16 i = 0; i < count; i++) {
u16 p16 = readU16(is);
v3s16 p;
@@ -145,15 +179,14 @@ void NodeMetadataList::deSerialize(std::istream &is, IItemDefManager *item_def_m
p.X = p16;
if (m_data.find(p) != m_data.end()) {
- warningstream<<"NodeMetadataList::deSerialize(): "
- <<"already set data at position"
- <<"("<<p.X<<","<<p.Y<<","<<p.Z<<"): Ignoring."
- <<std::endl;
+ warningstream << "NodeMetadataList::deSerialize(): "
+ << "already set data at position " << PP(p)
+ << ": Ignoring." << std::endl;
continue;
}
NodeMetadata *data = new NodeMetadata(item_def_mgr);
- data->deSerialize(is);
+ data->deSerialize(is, version);
m_data[p] = data;
}
}
@@ -216,35 +249,3 @@ int NodeMetadataList::countNonEmpty() const
}
return n;
}
-
-std::string NodeMetadata::getString(const std::string &name,
- unsigned short recursion) const
-{
- StringMap::const_iterator it = m_stringvars.find(name);
- if (it == m_stringvars.end())
- return "";
-
- return resolveString(it->second, recursion);
-}
-
-void NodeMetadata::setString(const std::string &name, const std::string &var)
-{
- if (var.empty()) {
- m_stringvars.erase(name);
- } else {
- m_stringvars[name] = var;
- }
-}
-
-std::string NodeMetadata::resolveString(const std::string &str,
- unsigned short recursion) const
-{
- if (recursion > 1) {
- return str;
- }
- if (str.substr(0, 2) == "${" && str[str.length() - 1] == '}') {
- return getString(str.substr(2, str.length() - 3), recursion + 1);
- }
- return str;
-}
-
diff --git a/src/nodemetadata.h b/src/nodemetadata.h
index da1bf595d..0d72485bc 100644
--- a/src/nodemetadata.h
+++ b/src/nodemetadata.h
@@ -20,10 +20,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef NODEMETADATA_HEADER
#define NODEMETADATA_HEADER
-#include "irr_v3d.h"
-#include <iostream>
-#include <vector>
-#include "util/string.h"
+#include "metadata.h"
+#include "util/cpp11_container.h"
/*
NodeMetadata stores arbitary amounts of data for special blocks.
@@ -37,37 +35,35 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Inventory;
class IItemDefManager;
-class NodeMetadata
+class NodeMetadata : public Metadata
{
public:
NodeMetadata(IItemDefManager *item_def_mgr);
~NodeMetadata();
- void serialize(std::ostream &os) const;
- void deSerialize(std::istream &is);
+ void serialize(std::ostream &os, u8 version, bool disk=true) const;
+ void deSerialize(std::istream &is, u8 version);
void clear();
bool empty() const;
- // Generic key/value store
- std::string getString(const std::string &name, unsigned short recursion = 0) const;
- void setString(const std::string &name, const std::string &var);
- // Support variable names in values
- std::string resolveString(const std::string &str, unsigned short recursion = 0) const;
- StringMap getStrings() const
- {
- return m_stringvars;
- }
-
// The inventory
Inventory *getInventory()
{
return m_inventory;
}
+ inline bool isPrivate(const std::string &name) const
+ {
+ return m_privatevars.count(name) != 0;
+ }
+ void markPrivate(const std::string &name, bool set);
+
private:
- StringMap m_stringvars;
+ int countNonPrivate() const;
+
Inventory *m_inventory;
+ UNORDERED_SET<std::string> m_privatevars;
};
@@ -80,7 +76,7 @@ class NodeMetadataList
public:
~NodeMetadataList();
- void serialize(std::ostream &os) const;
+ void serialize(std::ostream &os, u8 blockver, bool disk=true) const;
void deSerialize(std::istream &is, IItemDefManager *item_def_mgr);
// Add all keys in this list to the vector keys
@@ -101,4 +97,3 @@ private:
};
#endif
-
diff --git a/src/object_properties.cpp b/src/object_properties.cpp
index 89ca26274..a77368151 100644
--- a/src/object_properties.cpp
+++ b/src/object_properties.cpp
@@ -21,11 +21,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_bloated.h"
#include "exceptions.h"
#include "util/serialize.h"
+#include "util/basic_macros.h"
#include <sstream>
-#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
-#define PP2(x) "("<<(x).X<<","<<(x).Y<<")"
-
ObjectProperties::ObjectProperties():
hp_max(1),
physical(false),
@@ -119,6 +117,7 @@ void ObjectProperties::serialize(std::ostream &os) const
writeARGB8(os, nametag_color);
writeF1000(os, automatic_face_movement_max_rotation_per_sec);
os << serializeString(infotext);
+ os << serializeString(wield_item);
// Add stuff only at the bottom.
// Never remove anything, because we don't want new versions of this
@@ -161,6 +160,7 @@ void ObjectProperties::deSerialize(std::istream &is)
nametag_color = readARGB8(is);
automatic_face_movement_max_rotation_per_sec = readF1000(is);
infotext = deSerializeString(is);
+ wield_item = deSerializeString(is);
}catch(SerializationError &e){}
}
else
diff --git a/src/object_properties.h b/src/object_properties.h
index 082d9a529..908757a64 100644
--- a/src/object_properties.h
+++ b/src/object_properties.h
@@ -52,6 +52,8 @@ struct ObjectProperties
video::SColor nametag_color;
f32 automatic_face_movement_max_rotation_per_sec;
std::string infotext;
+ //! For dropped items, this contains item information.
+ std::string wield_item;
ObjectProperties();
std::string dump();
diff --git a/src/particles.cpp b/src/particles.cpp
index acf9cc815..e89e182e6 100644
--- a/src/particles.cpp
+++ b/src/particles.cpp
@@ -18,11 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "particles.h"
-#include "constants.h"
-#include "debug.h"
-#include "settings.h"
-#include "client/tile.h"
-#include "gamedef.h"
+#include "client.h"
#include "collision.h"
#include <stdlib.h>
#include "util/numeric.h"
@@ -31,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "clientmap.h"
#include "mapnode.h"
#include "client.h"
+#include "settings.h"
/*
Utility
@@ -58,7 +55,10 @@ Particle::Particle(
bool vertical,
video::ITexture *texture,
v2f texpos,
- v2f texsize
+ v2f texsize,
+ const struct TileAnimationParams &anim,
+ u8 glow,
+ video::SColor color
):
scene::ISceneNode(smgr->getRootSceneNode(), smgr)
{
@@ -75,7 +75,13 @@ Particle::Particle(
m_material.setTexture(0, texture);
m_texpos = texpos;
m_texsize = texsize;
+ m_animation = anim;
+ m_animation_frame = 0;
+ m_animation_time = 0.0;
+ // Color
+ m_base_color = color;
+ m_color = color;
// Particle related
m_pos = pos;
@@ -88,6 +94,7 @@ Particle::Particle(
m_collisiondetection = collisiondetection;
m_collision_removal = collision_removal;
m_vertical = vertical;
+ m_glow = glow;
// Irrlicht stuff
m_collisionbox = aabb3f
@@ -146,6 +153,18 @@ void Particle::step(float dtime)
m_velocity += m_acceleration * dtime;
m_pos += m_velocity * dtime;
}
+ if (m_animation.type != TAT_NONE) {
+ m_animation_time += dtime;
+ int frame_length_i, frame_count;
+ m_animation.determineParams(
+ m_material.getTexture(0)->getSize(),
+ &frame_count, &frame_length_i, NULL);
+ float frame_length = frame_length_i / 1000.0;
+ while (m_animation_time > frame_length) {
+ m_animation_frame++;
+ m_animation_time -= frame_length;
+ }
+ }
// Update lighting
updateLight();
@@ -170,25 +189,44 @@ void Particle::updateLight()
else
light = blend_light(m_env->getDayNightRatio(), LIGHT_SUN, 0);
- m_light = decode_light(light);
+ u8 m_light = decode_light(light + m_glow);
+ m_color.set(255,
+ m_light * m_base_color.getRed() / 255,
+ m_light * m_base_color.getGreen() / 255,
+ m_light * m_base_color.getBlue() / 255);
}
void Particle::updateVertices()
{
- video::SColor c(255, m_light, m_light, m_light);
- f32 tx0 = m_texpos.X;
- f32 tx1 = m_texpos.X + m_texsize.X;
- f32 ty0 = m_texpos.Y;
- f32 ty1 = m_texpos.Y + m_texsize.Y;
-
- m_vertices[0] = video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0,
- c, tx0, ty1);
- m_vertices[1] = video::S3DVertex(m_size/2,-m_size/2,0, 0,0,0,
- c, tx1, ty1);
- m_vertices[2] = video::S3DVertex(m_size/2,m_size/2,0, 0,0,0,
- c, tx1, ty0);
- m_vertices[3] = video::S3DVertex(-m_size/2,m_size/2,0, 0,0,0,
- c, tx0, ty0);
+ f32 tx0, tx1, ty0, ty1;
+
+ if (m_animation.type != TAT_NONE) {
+ const v2u32 texsize = m_material.getTexture(0)->getSize();
+ v2f texcoord, framesize_f;
+ v2u32 framesize;
+ texcoord = m_animation.getTextureCoords(texsize, m_animation_frame);
+ m_animation.determineParams(texsize, NULL, NULL, &framesize);
+ framesize_f = v2f(framesize.X / (float) texsize.X, framesize.Y / (float) texsize.Y);
+
+ tx0 = m_texpos.X + texcoord.X;
+ tx1 = m_texpos.X + texcoord.X + framesize_f.X * m_texsize.X;
+ ty0 = m_texpos.Y + texcoord.Y;
+ ty1 = m_texpos.Y + texcoord.Y + framesize_f.Y * m_texsize.Y;
+ } else {
+ tx0 = m_texpos.X;
+ tx1 = m_texpos.X + m_texsize.X;
+ ty0 = m_texpos.Y;
+ ty1 = m_texpos.Y + m_texsize.Y;
+ }
+
+ m_vertices[0] = video::S3DVertex(-m_size / 2, -m_size / 2,
+ 0, 0, 0, 0, m_color, tx0, ty1);
+ m_vertices[1] = video::S3DVertex(m_size / 2, -m_size / 2,
+ 0, 0, 0, 0, m_color, tx1, ty1);
+ m_vertices[2] = video::S3DVertex(m_size / 2, m_size / 2,
+ 0, 0, 0, 0, m_color, tx1, ty0);
+ m_vertices[3] = video::S3DVertex(-m_size / 2, m_size / 2,
+ 0, 0, 0, 0, m_color, tx0, ty0);
v3s16 camera_offset = m_env->getCameraOffset();
for(u16 i=0; i<4; i++)
@@ -214,7 +252,9 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
float minexptime, float maxexptime, float minsize, float maxsize,
bool collisiondetection, bool collision_removal, u16 attached_id, bool vertical,
- video::ITexture *texture, u32 id, ParticleManager *p_manager) :
+ video::ITexture *texture, u32 id, const struct TileAnimationParams &anim,
+ u8 glow,
+ ParticleManager *p_manager) :
m_particlemanager(p_manager)
{
m_gamedef = gamedef;
@@ -238,6 +278,8 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
m_vertical = vertical;
m_texture = texture;
m_time = 0;
+ m_animation = anim;
+ m_glow = glow;
for (u16 i = 0; i<=m_amount; i++)
{
@@ -252,6 +294,9 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
{
m_time += dtime;
+ static const float radius =
+ g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE;
+
bool unloaded = false;
bool is_attached = false;
v3f attached_pos = v3f(0,0,0);
@@ -275,11 +320,74 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
{
m_amount--;
- // Pretend to, but don't actually spawn a
- // particle if it is attached to an unloaded
- // object.
+ // Pretend to, but don't actually spawn a particle if it is
+ // attached to an unloaded object or distant from player.
if (!unloaded) {
+ v3f ppos = m_player->getPosition() / BS;
v3f pos = random_v3f(m_minpos, m_maxpos);
+
+ if (pos.getDistanceFrom(ppos) <= radius) {
+ v3f vel = random_v3f(m_minvel, m_maxvel);
+ v3f acc = random_v3f(m_minacc, m_maxacc);
+
+ if (is_attached) {
+ // Apply attachment yaw and position
+ pos.rotateXZBy(attached_yaw);
+ pos += attached_pos;
+ vel.rotateXZBy(attached_yaw);
+ acc.rotateXZBy(attached_yaw);
+ }
+
+ float exptime = rand()/(float)RAND_MAX
+ *(m_maxexptime-m_minexptime)
+ +m_minexptime;
+ float size = rand()/(float)RAND_MAX
+ *(m_maxsize-m_minsize)
+ +m_minsize;
+
+ Particle* toadd = new Particle(
+ m_gamedef,
+ m_smgr,
+ m_player,
+ env,
+ pos,
+ vel,
+ acc,
+ exptime,
+ size,
+ m_collisiondetection,
+ m_collision_removal,
+ m_vertical,
+ m_texture,
+ v2f(0.0, 0.0),
+ v2f(1.0, 1.0),
+ m_animation,
+ m_glow);
+ m_particlemanager->addParticle(toadd);
+ }
+ }
+ i = m_spawntimes.erase(i);
+ }
+ else
+ {
+ ++i;
+ }
+ }
+ }
+ else // Spawner exists for an infinity timespan, spawn on a per-second base
+ {
+ // Skip this step if attached to an unloaded object
+ if (unloaded)
+ return;
+ for (int i = 0; i <= m_amount; i++)
+ {
+ if (rand()/(float)RAND_MAX < dtime)
+ {
+ // Do not spawn particle if distant from player
+ v3f ppos = m_player->getPosition() / BS;
+ v3f pos = random_v3f(m_minpos, m_maxpos);
+
+ if (pos.getDistanceFrom(ppos) <= radius) {
v3f vel = random_v3f(m_minvel, m_maxvel);
v3f acc = random_v3f(m_minacc, m_maxacc);
@@ -313,62 +421,11 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
m_vertical,
m_texture,
v2f(0.0, 0.0),
- v2f(1.0, 1.0));
+ v2f(1.0, 1.0),
+ m_animation,
+ m_glow);
m_particlemanager->addParticle(toadd);
}
- i = m_spawntimes.erase(i);
- }
- else
- {
- ++i;
- }
- }
- }
- else // Spawner exists for an infinity timespan, spawn on a per-second base
- {
- // Skip this step if attached to an unloaded object
- if (unloaded)
- return;
- for (int i = 0; i <= m_amount; i++)
- {
- if (rand()/(float)RAND_MAX < dtime)
- {
- v3f pos = random_v3f(m_minpos, m_maxpos);
- v3f vel = random_v3f(m_minvel, m_maxvel);
- v3f acc = random_v3f(m_minacc, m_maxacc);
-
- if (is_attached) {
- // Apply attachment yaw and position
- pos.rotateXZBy(attached_yaw);
- pos += attached_pos;
- vel.rotateXZBy(attached_yaw);
- acc.rotateXZBy(attached_yaw);
- }
-
- float exptime = rand()/(float)RAND_MAX
- *(m_maxexptime-m_minexptime)
- +m_minexptime;
- float size = rand()/(float)RAND_MAX
- *(m_maxsize-m_minsize)
- +m_minsize;
-
- Particle* toadd = new Particle(
- m_gamedef,
- m_smgr,
- m_player,
- env,
- pos,
- vel,
- acc,
- exptime,
- size,
- m_collisiondetection,
- m_collision_removal,
- m_vertical,
- m_texture,
- v2f(0.0, 0.0),
- v2f(1.0, 1.0));
- m_particlemanager->addParticle(toadd);
}
}
}
@@ -452,7 +509,7 @@ void ParticleManager::clearAll ()
}
}
-void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
+void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client,
scene::ISceneManager* smgr, LocalPlayer *player)
{
switch (event->type) {
@@ -477,9 +534,9 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
}
video::ITexture *texture =
- gamedef->tsrc()->getTextureForMesh(*(event->add_particlespawner.texture));
+ client->tsrc()->getTextureForMesh(*(event->add_particlespawner.texture));
- ParticleSpawner* toadd = new ParticleSpawner(gamedef, smgr, player,
+ ParticleSpawner* toadd = new ParticleSpawner(client, smgr, player,
event->add_particlespawner.amount,
event->add_particlespawner.spawntime,
*event->add_particlespawner.minpos,
@@ -498,6 +555,8 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
event->add_particlespawner.vertical,
texture,
event->add_particlespawner.id,
+ event->add_particlespawner.animation,
+ event->add_particlespawner.glow,
this);
/* delete allocated content of event */
@@ -520,9 +579,9 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
}
case CE_SPAWN_PARTICLE: {
video::ITexture *texture =
- gamedef->tsrc()->getTextureForMesh(*(event->spawn_particle.texture));
+ client->tsrc()->getTextureForMesh(*(event->spawn_particle.texture));
- Particle* toadd = new Particle(gamedef, smgr, player, m_env,
+ Particle* toadd = new Particle(client, smgr, player, m_env,
*event->spawn_particle.pos,
*event->spawn_particle.vel,
*event->spawn_particle.acc,
@@ -533,13 +592,16 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
event->spawn_particle.vertical,
texture,
v2f(0.0, 0.0),
- v2f(1.0, 1.0));
+ v2f(1.0, 1.0),
+ event->spawn_particle.animation,
+ event->spawn_particle.glow);
addParticle(toadd);
delete event->spawn_particle.pos;
delete event->spawn_particle.vel;
delete event->spawn_particle.acc;
+ delete event->spawn_particle.texture;
break;
}
@@ -547,39 +609,46 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
}
}
-void ParticleManager::addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
- LocalPlayer *player, v3s16 pos, const TileSpec tiles[])
+void ParticleManager::addDiggingParticles(IGameDef* gamedef,
+ scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos,
+ const MapNode &n, const ContentFeatures &f)
{
for (u16 j = 0; j < 32; j++) // set the amount of particles here
{
- addNodeParticle(gamedef, smgr, player, pos, tiles);
+ addNodeParticle(gamedef, smgr, player, pos, n, f);
}
}
-void ParticleManager::addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
- LocalPlayer *player, v3s16 pos, const TileSpec tiles[])
+void ParticleManager::addPunchingParticles(IGameDef* gamedef,
+ scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos,
+ const MapNode &n, const ContentFeatures &f)
{
- addNodeParticle(gamedef, smgr, player, pos, tiles);
+ addNodeParticle(gamedef, smgr, player, pos, n, f);
}
-void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
- LocalPlayer *player, v3s16 pos, const TileSpec tiles[])
+void ParticleManager::addNodeParticle(IGameDef* gamedef,
+ scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos,
+ const MapNode &n, const ContentFeatures &f)
{
// Texture
u8 texid = myrand_range(0, 5);
- video::ITexture *texture = tiles[texid].texture;
+ const TileLayer &tile = f.tiles[texid].layers[0];
+ video::ITexture *texture;
+ struct TileAnimationParams anim;
+ anim.type = TAT_NONE;
// Only use first frame of animated texture
- f32 ymax = 1;
- if(tiles[texid].material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
- ymax /= tiles[texid].animation_frame_count;
+ if (tile.material_flags & MATERIAL_FLAG_ANIMATION)
+ texture = tile.frames[0].texture;
+ else
+ texture = tile.texture;
float size = rand() % 64 / 512.;
float visual_size = BS * size;
- v2f texsize(size * 2, ymax * size * 2);
+ v2f texsize(size * 2, size * 2);
v2f texpos;
texpos.X = ((rand() % 64) / 64. - texsize.X);
- texpos.Y = ymax * ((rand() % 64) / 64. - texsize.Y);
+ texpos.Y = ((rand() % 64) / 64. - texsize.Y);
// Physics
v3f velocity((rand() % 100 / 50. - 1) / 1.5,
@@ -593,6 +662,12 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s
(f32) pos.Z + rand() %100 /200. - 0.25
);
+ video::SColor color;
+ if (tile.has_color)
+ color = tile.color;
+ else
+ n.getColor(f, &color);
+
Particle* toadd = new Particle(
gamedef,
smgr,
@@ -608,7 +683,10 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s
false,
texture,
texpos,
- texsize);
+ texsize,
+ anim,
+ 0,
+ color);
addParticle(toadd);
}
diff --git a/src/particles.h b/src/particles.h
index eb8c6665d..eaec1f0fa 100644
--- a/src/particles.h
+++ b/src/particles.h
@@ -20,17 +20,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef PARTICLES_HEADER
#define PARTICLES_HEADER
-#define DIGGING_PARTICLES_AMOUNT 10
-
#include <iostream>
#include "irrlichttypes_extrabloated.h"
#include "client/tile.h"
#include "localplayer.h"
#include "environment.h"
+#include "tileanimation.h"
struct ClientEvent;
class ParticleManager;
class ClientEnvironment;
+struct MapNode;
+struct ContentFeatures;
class Particle : public scene::ISceneNode
{
@@ -50,7 +51,10 @@ class Particle : public scene::ISceneNode
bool vertical,
video::ITexture *texture,
v2f texpos,
- v2f texsize
+ v2f texsize,
+ const struct TileAnimationParams &anim,
+ u8 glow,
+ video::SColor color = video::SColor(0xFFFFFFFF)
);
~Particle();
@@ -97,11 +101,18 @@ private:
v3f m_acceleration;
LocalPlayer *m_player;
float m_size;
- u8 m_light;
+ //! Color without lighting
+ video::SColor m_base_color;
+ //! Final rendered color
+ video::SColor m_color;
bool m_collisiondetection;
bool m_collision_removal;
bool m_vertical;
v3s16 m_camera_offset;
+ struct TileAnimationParams m_animation;
+ float m_animation_time;
+ int m_animation_frame;
+ u8 m_glow;
};
class ParticleSpawner
@@ -123,6 +134,7 @@ class ParticleSpawner
bool vertical,
video::ITexture *texture,
u32 id,
+ const struct TileAnimationParams &anim, u8 glow,
ParticleManager* p_manager);
~ParticleSpawner();
@@ -156,6 +168,8 @@ class ParticleSpawner
bool m_collision_removal;
bool m_vertical;
u16 m_attached_id;
+ struct TileAnimationParams m_animation;
+ u8 m_glow;
};
/**
@@ -170,17 +184,20 @@ public:
void step (float dtime);
- void handleParticleEvent(ClientEvent *event,IGameDef *gamedef,
+ void handleParticleEvent(ClientEvent *event, Client *client,
scene::ISceneManager* smgr, LocalPlayer *player);
void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
- LocalPlayer *player, v3s16 pos, const TileSpec tiles[]);
+ LocalPlayer *player, v3s16 pos, const MapNode &n,
+ const ContentFeatures &f);
void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
- LocalPlayer *player, v3s16 pos, const TileSpec tiles[]);
+ LocalPlayer *player, v3s16 pos, const MapNode &n,
+ const ContentFeatures &f);
void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
- LocalPlayer *player, v3s16 pos, const TileSpec tiles[]);
+ LocalPlayer *player, v3s16 pos, const MapNode &n,
+ const ContentFeatures &f);
protected:
void addParticle(Particle* toadd);
diff --git a/src/pathfinder.cpp b/src/pathfinder.cpp
index 57a008ead..16c5678ee 100644
--- a/src/pathfinder.cpp
+++ b/src/pathfinder.cpp
@@ -23,12 +23,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
/******************************************************************************/
#include "pathfinder.h"
-#include "environment.h"
-#include "gamedef.h"
+#include "serverenvironment.h"
+#include "server.h"
#include "nodedef.h"
-#include "map.h"
-#include "log.h"
-#include "irr_aabb3d.h"
//#define PATHFINDER_DEBUG
//#define PATHFINDER_CALC_TIME
@@ -47,9 +44,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
/* Typedefs and macros */
/******************************************************************************/
-/** shortcut to print a 3d pos */
-#define PPOS(pos) "(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
-
#define LVL "(" << level << ")" <<
#ifdef PATHFINDER_DEBUG
@@ -61,7 +55,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define DEBUG_OUT(a) while(0)
#define INFO_TARGET infostream << "Pathfinder: "
#define VERBOSE_TARGET verbosestream << "Pathfinder: "
-#define ERROR_TARGET errorstream << "Pathfinder: "
+#define ERROR_TARGET warningstream << "Pathfinder: "
#endif
/******************************************************************************/
@@ -117,7 +111,7 @@ public:
* @param dir direction to set cost for
* @cost cost to set
*/
- void setCost(v3s16 dir, PathCost cost);
+ void setCost(v3s16 dir, const PathCost &cost);
bool valid; /**< node is on surface */
bool target; /**< node is target position */
@@ -502,7 +496,7 @@ PathCost PathGridnode::getCost(v3s16 dir)
}
/******************************************************************************/
-void PathGridnode::setCost(v3s16 dir, PathCost cost)
+void PathGridnode::setCost(v3s16 dir, const PathCost &cost)
{
if (dir.X > 0) {
directions[DIR_XP] = cost;
@@ -531,25 +525,25 @@ void GridNodeContainer::initNode(v3s16 ipos, PathGridnode *p_node)
if ((current.param0 == CONTENT_IGNORE) ||
(below.param0 == CONTENT_IGNORE)) {
- DEBUG_OUT("Pathfinder: " << PPOS(realpos) <<
+ DEBUG_OUT("Pathfinder: " << PP(realpos) <<
" current or below is invalid element" << std::endl);
if (current.param0 == CONTENT_IGNORE) {
elem.type = 'i';
- DEBUG_OUT(PPOS(ipos) << ": " << 'i' << std::endl);
+ DEBUG_OUT(PP(ipos) << ": " << 'i' << std::endl);
}
return;
}
//don't add anything if it isn't an air node
if (ndef->get(current).walkable || !ndef->get(below).walkable) {
- DEBUG_OUT("Pathfinder: " << PPOS(realpos)
+ DEBUG_OUT("Pathfinder: " << PP(realpos)
<< " not on surface" << std::endl);
if (ndef->get(current).walkable) {
elem.type = 's';
- DEBUG_OUT(PPOS(ipos) << ": " << 's' << std::endl);
+ DEBUG_OUT(PP(ipos) << ": " << 's' << std::endl);
} else {
elem.type = '-';
- DEBUG_OUT(PPOS(ipos) << ": " << '-' << std::endl);
+ DEBUG_OUT(PP(ipos) << ": " << '-' << std::endl);
}
return;
}
@@ -557,7 +551,7 @@ void GridNodeContainer::initNode(v3s16 ipos, PathGridnode *p_node)
elem.valid = true;
elem.pos = realpos;
elem.type = 'g';
- DEBUG_OUT(PPOS(ipos) << ": " << 'a' << std::endl);
+ DEBUG_OUT(PP(ipos) << ": " << 'a' << std::endl);
if (m_pathf->m_prefetch) {
elem.directions[DIR_XP] = m_pathf->calcCost(realpos, v3s16( 1, 0, 0));
@@ -686,14 +680,14 @@ std::vector<v3s16> Pathfinder::getPath(ServerEnvironment *env,
if (!startpos.valid) {
VERBOSE_TARGET << "invalid startpos" <<
- "Index: " << PPOS(StartIndex) <<
- "Realpos: " << PPOS(getRealPos(StartIndex)) << std::endl;
+ "Index: " << PP(StartIndex) <<
+ "Realpos: " << PP(getRealPos(StartIndex)) << std::endl;
return retval;
}
if (!endpos.valid) {
VERBOSE_TARGET << "invalid stoppos" <<
- "Index: " << PPOS(EndIndex) <<
- "Realpos: " << PPOS(getRealPos(EndIndex)) << std::endl;
+ "Index: " << PP(EndIndex) <<
+ "Realpos: " << PP(getRealPos(EndIndex)) << std::endl;
return retval;
}
@@ -809,7 +803,7 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir)
//check limits
if (!m_limits.isPointInside(pos2)) {
- DEBUG_OUT("Pathfinder: " << PPOS(pos2) <<
+ DEBUG_OUT("Pathfinder: " << PP(pos2) <<
" no cost -> out of limits" << std::endl);
return retval;
}
@@ -819,7 +813,7 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir)
//did we get information about node?
if (node_at_pos2.param0 == CONTENT_IGNORE ) {
VERBOSE_TARGET << "Pathfinder: (1) area at pos: "
- << PPOS(pos2) << " not loaded";
+ << PP(pos2) << " not loaded";
return retval;
}
@@ -830,7 +824,7 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir)
//did we get information about node?
if (node_below_pos2.param0 == CONTENT_IGNORE ) {
VERBOSE_TARGET << "Pathfinder: (2) area at pos: "
- << PPOS((pos2 + v3s16(0, -1, 0))) << " not loaded";
+ << PP((pos2 + v3s16(0, -1, 0))) << " not loaded";
return retval;
}
@@ -838,7 +832,7 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir)
retval.valid = true;
retval.value = 1;
retval.direction = 0;
- DEBUG_OUT("Pathfinder: "<< PPOS(pos)
+ DEBUG_OUT("Pathfinder: "<< PP(pos)
<< " cost same height found" << std::endl);
}
else {
@@ -991,8 +985,8 @@ bool Pathfinder::updateAllCosts(v3s16 ipos,
v3s16 ipos2 = ipos + directions[i];
if (!isValidIndex(ipos2)) {
- DEBUG_OUT(LVL " Pathfinder: " << PPOS(ipos2) <<
- " out of range, max=" << PPOS(m_limits.MaxEdge) << std::endl);
+ DEBUG_OUT(LVL " Pathfinder: " << PP(ipos2) <<
+ " out of range, max=" << PP(m_limits.MaxEdge) << std::endl);
continue;
}
@@ -1000,7 +994,7 @@ bool Pathfinder::updateAllCosts(v3s16 ipos,
if (!g_pos2.valid) {
VERBOSE_TARGET << LVL "Pathfinder: no data for new position: "
- << PPOS(ipos2) << std::endl;
+ << PP(ipos2) << std::endl;
continue;
}
@@ -1017,7 +1011,7 @@ bool Pathfinder::updateAllCosts(v3s16 ipos,
if ((g_pos2.totalcost < 0) ||
(g_pos2.totalcost > new_cost)) {
DEBUG_OUT(LVL "Pathfinder: updating path at: "<<
- PPOS(ipos2) << " from: " << g_pos2.totalcost << " to "<<
+ PP(ipos2) << " from: " << g_pos2.totalcost << " to "<<
new_cost << std::endl);
if (updateAllCosts(ipos2, invert(directions[i]),
new_cost, level)) {
@@ -1027,13 +1021,13 @@ bool Pathfinder::updateAllCosts(v3s16 ipos,
else {
DEBUG_OUT(LVL "Pathfinder:"
" already found shorter path to: "
- << PPOS(ipos2) << std::endl);
+ << PP(ipos2) << std::endl);
}
}
else {
DEBUG_OUT(LVL "Pathfinder:"
" not moving to invalid direction: "
- << PPOS(directions[i]) << std::endl);
+ << PP(directions[i]) << std::endl);
}
}
}
@@ -1147,8 +1141,8 @@ bool Pathfinder::updateCostHeuristic( v3s16 ipos,
v3s16 ipos2 = ipos + direction;
if (!isValidIndex(ipos2)) {
- DEBUG_OUT(LVL " Pathfinder: " << PPOS(ipos2) <<
- " out of range, max=" << PPOS(m_limits.MaxEdge) << std::endl);
+ DEBUG_OUT(LVL " Pathfinder: " << PP(ipos2) <<
+ " out of range, max=" << PP(m_limits.MaxEdge) << std::endl);
direction = getDirHeuristic(directions, g_pos);
continue;
}
@@ -1157,7 +1151,7 @@ bool Pathfinder::updateCostHeuristic( v3s16 ipos,
if (!g_pos2.valid) {
VERBOSE_TARGET << LVL "Pathfinder: no data for new position: "
- << PPOS(ipos2) << std::endl;
+ << PP(ipos2) << std::endl;
direction = getDirHeuristic(directions, g_pos);
continue;
}
@@ -1171,16 +1165,16 @@ bool Pathfinder::updateCostHeuristic( v3s16 ipos,
(m_min_target_distance < new_cost)) {
DEBUG_OUT(LVL "Pathfinder:"
" already longer than best already found path "
- << PPOS(ipos2) << std::endl);
+ << PP(ipos2) << std::endl);
return false;
}
if ((g_pos2.totalcost < 0) ||
(g_pos2.totalcost > new_cost)) {
DEBUG_OUT(LVL "Pathfinder: updating path at: "<<
- PPOS(ipos2) << " from: " << g_pos2.totalcost << " to "<<
+ PP(ipos2) << " from: " << g_pos2.totalcost << " to "<<
new_cost << " srcdir=" <<
- PPOS(invert(direction))<< std::endl);
+ PP(invert(direction))<< std::endl);
if (updateCostHeuristic(ipos2, invert(direction),
new_cost, level)) {
retval = true;
@@ -1189,19 +1183,19 @@ bool Pathfinder::updateCostHeuristic( v3s16 ipos,
else {
DEBUG_OUT(LVL "Pathfinder:"
" already found shorter path to: "
- << PPOS(ipos2) << std::endl);
+ << PP(ipos2) << std::endl);
}
}
else {
DEBUG_OUT(LVL "Pathfinder:"
" not moving to invalid direction: "
- << PPOS(direction) << std::endl);
+ << PP(direction) << std::endl);
}
}
else {
DEBUG_OUT(LVL "Pathfinder:"
" skipping srcdir: "
- << PPOS(direction) << std::endl);
+ << PP(direction) << std::endl);
}
direction = getDirHeuristic(directions, g_pos);
}
@@ -1409,7 +1403,7 @@ void Pathfinder::printPath(std::vector<v3s16> path)
unsigned int current = 0;
for (std::vector<v3s16>::iterator i = path.begin();
i != path.end(); ++i) {
- std::cout << std::setw(3) << current << ":" << PPOS((*i)) << std::endl;
+ std::cout << std::setw(3) << current << ":" << PP((*i)) << std::endl;
current++;
}
}
diff --git a/src/player.h b/src/player.h
index 5f9bb7ec9..3432069c0 100644
--- a/src/player.h
+++ b/src/player.h
@@ -22,7 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_bloated.h"
#include "inventory.h"
-#include "constants.h" // BS
#include "threading/mutex.h"
#include <list>
diff --git a/src/porting.cpp b/src/porting.cpp
index 023f0cca7..10b6fc940 100644
--- a/src/porting.cpp
+++ b/src/porting.cpp
@@ -408,7 +408,7 @@ bool setSystemPaths()
#endif
for (std::list<std::string>::const_iterator
- i = trylist.begin(); i != trylist.end(); i++) {
+ i = trylist.begin(); i != trylist.end(); ++i) {
const std::string &trypath = *i;
if (!fs::PathExists(trypath) ||
!fs::PathExists(trypath + DIR_DELIM + "builtin")) {
@@ -611,9 +611,9 @@ void setXorgClassHint(const video::SExposedVideoData &video_data,
#endif
}
-bool setXorgWindowIcon(IrrlichtDevice *device)
+bool setWindowIcon(IrrlichtDevice *device)
{
-#ifdef XORG_USED
+#if defined(XORG_USED)
# if RUN_IN_PLACE
return setXorgWindowIconFromPath(device,
path_share + "/misc/" PROJECT_NAME "-xorg-icon-128.png");
@@ -627,6 +627,36 @@ bool setXorgWindowIcon(IrrlichtDevice *device)
setXorgWindowIconFromPath(device,
path_share + "/misc/" PROJECT_NAME "-xorg-icon-128.png");
# endif
+#elif defined(_WIN32)
+ const video::SExposedVideoData exposedData = device->getVideoDriver()->getExposedVideoData();
+ HWND hWnd; // Window handle
+
+ switch (device->getVideoDriver()->getDriverType()) {
+ case video::EDT_DIRECT3D8:
+ hWnd = reinterpret_cast<HWND>(exposedData.D3D8.HWnd);
+ break;
+ case video::EDT_DIRECT3D9:
+ hWnd = reinterpret_cast<HWND>(exposedData.D3D9.HWnd);
+ break;
+ case video::EDT_OPENGL:
+ hWnd = reinterpret_cast<HWND>(exposedData.OpenGLWin32.HWnd);
+ break;
+ default:
+ return false;
+ }
+
+ // Load the ICON from resource file
+ const HICON hicon = LoadIcon(
+ GetModuleHandle(NULL),
+ MAKEINTRESOURCE(130) // The ID of the ICON defined in winresource.rc
+ );
+
+ if (hicon) {
+ SendMessage(hWnd, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(hicon));
+ SendMessage(hWnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(hicon));
+ return true;
+ }
+ return false;
#else
return false;
#endif
@@ -899,4 +929,31 @@ bool secure_rand_fill_buf(void *buf, size_t len)
#endif
+void attachOrCreateConsole(void)
+{
+#ifdef _WIN32
+ static bool consoleAllocated = false;
+ const bool redirected = (_fileno(stdout) == -2 || _fileno(stdout) == -1); // If output is redirected to e.g a file
+ if (!consoleAllocated && redirected && (AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole())) {
+ freopen("CONOUT$", "w", stdout);
+ freopen("CONOUT$", "w", stderr);
+ consoleAllocated = true;
+ }
+#endif
+}
+
+// Load performance counter frequency only once at startup
+#ifdef _WIN32
+
+inline double get_perf_freq()
+{
+ LARGE_INTEGER freq;
+ QueryPerformanceFrequency(&freq);
+ return freq.QuadPart;
+}
+
+double perf_freq = get_perf_freq();
+
+#endif
+
} //namespace porting
diff --git a/src/porting.h b/src/porting.h
index f5c7efcb2..7034d956b 100644
--- a/src/porting.h
+++ b/src/porting.h
@@ -181,124 +181,99 @@ std::string get_sysinfo();
void initIrrlicht(irr::IrrlichtDevice * );
-/*
- Resolution is 10-20ms.
- Remember to check for overflows.
- Overflow can occur at any value higher than 10000000.
-*/
-#ifdef _WIN32 // Windows
- inline u32 getTimeS()
- {
- return GetTickCount() / 1000;
- }
+// Monotonic counter getters.
- inline u32 getTimeMs()
- {
- return GetTickCount();
- }
+#ifdef _WIN32 // Windows
- inline u32 getTimeUs()
- {
- LARGE_INTEGER freq, t;
- QueryPerformanceFrequency(&freq);
- QueryPerformanceCounter(&t);
- return (double)(t.QuadPart) / ((double)(freq.QuadPart) / 1000000.0);
- }
+extern double perf_freq;
- inline u32 getTimeNs()
- {
- LARGE_INTEGER freq, t;
- QueryPerformanceFrequency(&freq);
- QueryPerformanceCounter(&t);
- return (double)(t.QuadPart) / ((double)(freq.QuadPart) / 1000000000.0);
- }
+inline u64 os_get_time(double mult)
+{
+ LARGE_INTEGER t;
+ QueryPerformanceCounter(&t);
+ return static_cast<double>(t.QuadPart) / (perf_freq / mult);
+}
+
+// Resolution is <1us.
+inline u64 getTimeS() { return os_get_time(1); }
+inline u64 getTimeMs() { return os_get_time(1000); }
+inline u64 getTimeUs() { return os_get_time(1000*1000); }
+inline u64 getTimeNs() { return os_get_time(1000*1000*1000); }
#else // Posix
- inline void _os_get_clock(struct timespec *ts)
- {
+
+inline void os_get_clock(struct timespec *ts)
+{
#if defined(__MACH__) && defined(__APPLE__)
- // from http://stackoverflow.com/questions/5167269/clock-gettime-alternative-in-mac-os-x
- // OS X does not have clock_gettime, use clock_get_time
- clock_serv_t cclock;
- mach_timespec_t mts;
- host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
- clock_get_time(cclock, &mts);
- mach_port_deallocate(mach_task_self(), cclock);
- ts->tv_sec = mts.tv_sec;
- ts->tv_nsec = mts.tv_nsec;
+// From http://stackoverflow.com/questions/5167269/clock-gettime-alternative-in-mac-os-x
+// OS X does not have clock_gettime, use clock_get_time
+ clock_serv_t cclock;
+ mach_timespec_t mts;
+ host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
+ clock_get_time(cclock, &mts);
+ mach_port_deallocate(mach_task_self(), cclock);
+ ts->tv_sec = mts.tv_sec;
+ ts->tv_nsec = mts.tv_nsec;
#elif defined(CLOCK_MONOTONIC_RAW)
- clock_gettime(CLOCK_MONOTONIC_RAW, ts);
+ clock_gettime(CLOCK_MONOTONIC_RAW, ts);
#elif defined(_POSIX_MONOTONIC_CLOCK)
- clock_gettime(CLOCK_MONOTONIC, ts);
+ clock_gettime(CLOCK_MONOTONIC, ts);
#else
- struct timeval tv;
- gettimeofday(&tv, NULL);
- TIMEVAL_TO_TIMESPEC(&tv, ts);
-#endif // defined(__MACH__) && defined(__APPLE__)
- }
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ TIMEVAL_TO_TIMESPEC(&tv, ts);
+#endif
+}
- // Note: these clock functions do not return wall time, but
- // generally a clock that starts at 0 when the process starts.
- inline u32 getTimeS()
- {
- struct timespec ts;
- _os_get_clock(&ts);
- return ts.tv_sec;
- }
+inline u64 getTimeS()
+{
+ struct timespec ts;
+ os_get_clock(&ts);
+ return ts.tv_sec;
+}
- inline u32 getTimeMs()
- {
- struct timespec ts;
- _os_get_clock(&ts);
- return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
- }
+inline u64 getTimeMs()
+{
+ struct timespec ts;
+ os_get_clock(&ts);
+ return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
+}
- inline u32 getTimeUs()
- {
- struct timespec ts;
- _os_get_clock(&ts);
- return ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
- }
+inline u64 getTimeUs()
+{
+ struct timespec ts;
+ os_get_clock(&ts);
+ return ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+}
- inline u32 getTimeNs()
- {
- struct timespec ts;
- _os_get_clock(&ts);
- return ts.tv_sec * 1000000000 + ts.tv_nsec;
- }
+inline u64 getTimeNs()
+{
+ struct timespec ts;
+ os_get_clock(&ts);
+ return ts.tv_sec * 1000000000 + ts.tv_nsec;
+}
- /*#include <sys/timeb.h>
- inline u32 getTimeMs()
- {
- struct timeb tb;
- ftime(&tb);
- return tb.time * 1000 + tb.millitm;
- }*/
#endif
-inline u32 getTime(TimePrecision prec)
+inline u64 getTime(TimePrecision prec)
{
switch (prec) {
- case PRECISION_SECONDS:
- return getTimeS();
- case PRECISION_MILLI:
- return getTimeMs();
- case PRECISION_MICRO:
- return getTimeUs();
- case PRECISION_NANO:
- return getTimeNs();
+ case PRECISION_SECONDS: return getTimeS();
+ case PRECISION_MILLI: return getTimeMs();
+ case PRECISION_MICRO: return getTimeUs();
+ case PRECISION_NANO: return getTimeNs();
}
- return 0;
+ FATAL_ERROR("Called getTime with invalid time precision");
}
/**
- * Delta calculation function taking two 32bit arguments.
- * @param old_time_ms old time for delta calculation (order is relevant!)
- * @param new_time_ms new time for delta calculation (order is relevant!)
- * @return positive 32bit delta value
+ * Delta calculation function arguments.
+ * @param old_time_ms old time for delta calculation
+ * @param new_time_ms new time for delta calculation
+ * @return positive delta value
*/
-inline u32 getDeltaMs(u32 old_time_ms, u32 new_time_ms)
+inline u64 getDeltaMs(u64 old_time_ms, u64 new_time_ms)
{
if (new_time_ms >= old_time_ms) {
return (new_time_ms - old_time_ms);
@@ -367,7 +342,7 @@ inline const char *getPlatformName()
void setXorgClassHint(const video::SExposedVideoData &video_data,
const std::string &name);
-bool setXorgWindowIcon(IrrlichtDevice *device);
+bool setWindowIcon(IrrlichtDevice *device);
bool setXorgWindowIconFromPath(IrrlichtDevice *device,
const std::string &icon_file);
@@ -377,6 +352,9 @@ bool setXorgWindowIconFromPath(IrrlichtDevice *device,
void setWin32ExceptionHandler();
bool secure_rand_fill_buf(void *buf, size_t len);
+
+// This attaches to the parents process console, or creates a new one if it doesnt exist.
+void attachOrCreateConsole(void);
} // namespace porting
#ifdef __ANDROID__
diff --git a/src/profiler.cpp b/src/profiler.cpp
index 197e094f6..8e997442c 100644
--- a/src/profiler.cpp
+++ b/src/profiler.cpp
@@ -21,3 +21,33 @@ with this program; if not, write to the Free Software Foundation, Inc.,
static Profiler main_profiler;
Profiler *g_profiler = &main_profiler;
+ScopeProfiler::ScopeProfiler(
+ Profiler *profiler, const std::string &name, ScopeProfilerType type)
+ : m_profiler(profiler), m_name(name), m_timer(NULL), m_type(type)
+{
+ if (m_profiler)
+ m_timer = new TimeTaker(m_name);
+}
+
+ScopeProfiler::~ScopeProfiler()
+{
+ if (!m_timer)
+ return;
+
+ 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;
+ case SPT_GRAPH_ADD:
+ m_profiler->graphAdd(m_name, duration);
+ break;
+ }
+ }
+ delete m_timer;
+}
diff --git a/src/profiler.h b/src/profiler.h
index e8eac86b1..ce60c6262 100644
--- a/src/profiler.h
+++ b/src/profiler.h
@@ -119,39 +119,34 @@ public:
u32 minindex, maxindex;
paging(m_data.size(), page, pagecount, minindex, maxindex);
- for(std::map<std::string, float>::iterator
- i = m_data.begin();
- i != m_data.end(); ++i)
- {
- if(maxindex == 0)
+ for (std::map<std::string, float>::const_iterator i = m_data.begin();
+ i != m_data.end(); ++i) {
+ if (maxindex == 0)
break;
maxindex--;
- if(minindex != 0)
- {
+ if (minindex != 0) {
minindex--;
continue;
}
- std::string name = i->first;
int avgcount = 1;
- std::map<std::string, int>::iterator n = m_avgcounts.find(name);
- if(n != m_avgcounts.end()){
+ std::map<std::string, int>::const_iterator n = m_avgcounts.find(i->first);
+ if (n != m_avgcounts.end()) {
if(n->second >= 1)
avgcount = n->second;
}
- o<<" "<<name<<": ";
+ o << " " << i->first << ": ";
s32 clampsize = 40;
- s32 space = clampsize - name.size();
- for(s32 j=0; j<space; j++)
- {
- if(j%2 == 0 && j < space - 1)
- o<<"-";
+ s32 space = clampsize - i->first.size();
+ for(s32 j = 0; j < space; j++) {
+ if (j % 2 == 0 && j < space - 1)
+ o << "-";
else
- o<<" ";
+ o << " ";
}
- o<<(i->second / avgcount);
- o<<std::endl;
+ o << (i->second / avgcount);
+ o << std::endl;
}
}
@@ -198,48 +193,8 @@ class ScopeProfiler
{
public:
ScopeProfiler(Profiler *profiler, const std::string &name,
- enum ScopeProfilerType type = SPT_ADD):
- m_profiler(profiler),
- m_name(name),
- 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,
- enum ScopeProfilerType type = SPT_ADD):
- m_profiler(profiler),
- m_name(name),
- m_timer(NULL),
- m_type(type)
- {
- if(m_profiler)
- m_timer = new TimeTaker(m_name.c_str());
- }
- ~ScopeProfiler()
- {
- if(m_timer)
- {
- 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;
- case SPT_GRAPH_ADD:
- m_profiler->graphAdd(m_name, duration);
- break;
- }
- }
- delete m_timer;
- }
- }
+ ScopeProfilerType type = SPT_ADD);
+ ~ScopeProfiler();
private:
Profiler *m_profiler;
std::string m_name;
diff --git a/src/raycast.cpp b/src/raycast.cpp
new file mode 100644
index 000000000..58102c993
--- /dev/null
+++ b/src/raycast.cpp
@@ -0,0 +1,89 @@
+/*
+Minetest
+Copyright (C) 2016 juhdanad, Daniel Juhasz <juhdanad@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "irr_v3d.h"
+#include "irr_aabb3d.h"
+
+bool boxLineCollision(const aabb3f &box, const v3f &start,
+ const v3f &dir, v3f *collision_point, v3s16 *collision_normal) {
+ if (box.isPointInside(start)) {
+ *collision_point = start;
+ collision_normal->set(0, 0, 0);
+ return true;
+ }
+ float m = 0;
+
+ // Test X collision
+ if (dir.X != 0) {
+ if (dir.X > 0)
+ m = (box.MinEdge.X - start.X) / dir.X;
+ else
+ m = (box.MaxEdge.X - start.X) / dir.X;
+
+ if (m >= 0 && m <= 1) {
+ *collision_point = start + dir * m;
+ if ((collision_point->Y >= box.MinEdge.Y)
+ && (collision_point->Y <= box.MaxEdge.Y)
+ && (collision_point->Z >= box.MinEdge.Z)
+ && (collision_point->Z <= box.MaxEdge.Z)) {
+ collision_normal->set((dir.X > 0) ? -1 : 1, 0, 0);
+ return true;
+ }
+ }
+ }
+
+ // Test Y collision
+ if (dir.Y != 0) {
+ if (dir.Y > 0)
+ m = (box.MinEdge.Y - start.Y) / dir.Y;
+ else
+ m = (box.MaxEdge.Y - start.Y) / dir.Y;
+
+ if (m >= 0 && m <= 1) {
+ *collision_point = start + dir * m;
+ if ((collision_point->X >= box.MinEdge.X)
+ && (collision_point->X <= box.MaxEdge.X)
+ && (collision_point->Z >= box.MinEdge.Z)
+ && (collision_point->Z <= box.MaxEdge.Z)) {
+ collision_normal->set(0, (dir.Y > 0) ? -1 : 1, 0);
+ return true;
+ }
+ }
+ }
+
+ // Test Z collision
+ if (dir.Z != 0) {
+ if (dir.Z > 0)
+ m = (box.MinEdge.Z - start.Z) / dir.Z;
+ else
+ m = (box.MaxEdge.Z - start.Z) / dir.Z;
+
+ if (m >= 0 && m <= 1) {
+ *collision_point = start + dir * m;
+ if ((collision_point->X >= box.MinEdge.X)
+ && (collision_point->X <= box.MaxEdge.X)
+ && (collision_point->Y >= box.MinEdge.Y)
+ && (collision_point->Y <= box.MaxEdge.Y)) {
+ collision_normal->set(0, 0, (dir.Z > 0) ? -1 : 1);
+ return true;
+ }
+ }
+ }
+ return false;
+}
diff --git a/src/raycast.h b/src/raycast.h
new file mode 100644
index 000000000..d7ec8c843
--- /dev/null
+++ b/src/raycast.h
@@ -0,0 +1,38 @@
+/*
+Minetest
+Copyright (C) 2016 juhdanad, Daniel Juhasz <juhdanad@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 SRC_RAYCAST_H_
+#define SRC_RAYCAST_H_
+
+
+/*!
+ * Checks if a line and a box intersects.
+ * @param[in] box box to test collision
+ * @param[in] start starting point of the line
+ * @param[in] dir direction and length of the line
+ * @param[out] collision_point first point of the collision
+ * @param[out] collision_normal normal vector at the collision, points
+ * outwards of the surface. If start is in the box, zero vector.
+ * @returns true if a collision point was found
+ */
+bool boxLineCollision(const aabb3f &box, const v3f &start, const v3f &dir,
+ v3f *collision_point, v3s16 *collision_normal);
+
+
+#endif /* SRC_RAYCAST_H_ */
diff --git a/src/reflowscan.cpp b/src/reflowscan.cpp
index 49b9406d7..eec371022 100644
--- a/src/reflowscan.cpp
+++ b/src/reflowscan.cpp
@@ -22,12 +22,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapblock.h"
#include "nodedef.h"
#include "util/timetaker.h"
+#include "util/cpp11.h"
ReflowScan::ReflowScan(Map *map, INodeDefManager *ndef) :
m_map(map),
m_ndef(ndef),
- m_liquid_queue(NULL)
+ m_liquid_queue(nullptr)
{
}
@@ -41,7 +42,7 @@ void ReflowScan::scan(MapBlock *block, UniqueQueue<v3s16> *liquid_queue)
// scanned block. Blocks are only added to the lookup if they are really
// needed. The lookup is indexed manually to use the same index in a
// bit-array (of uint32 type) which stores for unloaded blocks that they
- // were already fetched from Map but were actually NULL.
+ // were already fetched from Map but were actually nullptr.
memset(m_lookup, 0, sizeof(m_lookup));
int block_idx = 1 + (1 * 9) + (1 * 3);
m_lookup[block_idx] = block;
diff --git a/src/remoteplayer.cpp b/src/remoteplayer.cpp
index 67ab89113..540132978 100644
--- a/src/remoteplayer.cpp
+++ b/src/remoteplayer.cpp
@@ -19,13 +19,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "remoteplayer.h"
+#include <json/json.h>
#include "content_sao.h"
#include "filesys.h"
#include "gamedef.h"
#include "porting.h" // strlcpy
+#include "server.h"
#include "settings.h"
-
/*
RemotePlayer
*/
@@ -64,57 +65,31 @@ RemotePlayer::RemotePlayer(const char *name, IItemDefManager *idef):
movement_liquid_fluidity_smooth = g_settings->getFloat("movement_liquid_fluidity_smooth") * BS;
movement_liquid_sink = g_settings->getFloat("movement_liquid_sink") * BS;
movement_gravity = g_settings->getFloat("movement_gravity") * BS;
+
+ // copy defaults
+ m_cloud_params.density = 0.4f;
+ m_cloud_params.color_bright = video::SColor(229, 240, 240, 255);
+ m_cloud_params.color_ambient = video::SColor(255, 0, 0, 0);
+ m_cloud_params.height = 120.0f;
+ m_cloud_params.thickness = 16.0f;
+ m_cloud_params.speed = v2f(0.0f, -2.0f);
}
-void RemotePlayer::save(std::string savedir, IGameDef *gamedef)
+void RemotePlayer::serializeExtraAttributes(std::string &output)
{
- /*
- * We have to open all possible player files in the players directory
- * and check their player names because some file systems are not
- * case-sensitive and player names are case-sensitive.
- */
-
- // A player to deserialize files into to check their names
- RemotePlayer testplayer("", gamedef->idef());
-
- savedir += DIR_DELIM;
- std::string path = savedir + m_name;
- for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) {
- if (!fs::PathExists(path)) {
- // Open file and serialize
- std::ostringstream ss(std::ios_base::binary);
- serialize(ss);
- if (!fs::safeWriteToFile(path, ss.str())) {
- infostream << "Failed to write " << path << std::endl;
- }
- setModified(false);
- return;
- }
- // Open file and deserialize
- std::ifstream is(path.c_str(), std::ios_base::binary);
- if (!is.good()) {
- infostream << "Failed to open " << path << std::endl;
- return;
- }
- testplayer.deSerialize(is, path, NULL);
- is.close();
- if (strcmp(testplayer.getName(), m_name) == 0) {
- // Open file and serialize
- std::ostringstream ss(std::ios_base::binary);
- serialize(ss);
- if (!fs::safeWriteToFile(path, ss.str())) {
- infostream << "Failed to write " << path << std::endl;
- }
- setModified(false);
- return;
- }
- path = savedir + m_name + itos(i);
+ assert(m_sao);
+ Json::Value json_root;
+ const PlayerAttributes &attrs = m_sao->getExtendedAttributes();
+ for (PlayerAttributes::const_iterator it = attrs.begin(); it != attrs.end(); ++it) {
+ json_root[(*it).first] = (*it).second;
}
- infostream << "Didn't find free file for player " << m_name << std::endl;
- return;
+ Json::FastWriter writer;
+ output = writer.write(json_root);
+ m_sao->setExtendedAttributeModified(false);
}
+
void RemotePlayer::deSerialize(std::istream &is, const std::string &playername,
PlayerSAO *sao)
{
@@ -126,7 +101,7 @@ void RemotePlayer::deSerialize(std::istream &is, const std::string &playername,
m_dirty = true;
//args.getS32("version"); // Version field value not used
- std::string name = args.get("name");
+ const std::string &name = args.get("name");
strlcpy(m_name, name.c_str(), PLAYERNAME_SIZE);
if (sao) {
@@ -148,7 +123,21 @@ void RemotePlayer::deSerialize(std::istream &is, const std::string &playername,
} catch (SettingNotFoundException &e) {}
try {
- sao->setBreath(args.getS32("breath"));
+ sao->setBreath(args.getS32("breath"), false);
+ } catch (SettingNotFoundException &e) {}
+
+ try {
+ const std::string &extended_attributes = args.get("extended_attributes");
+ Json::Reader reader;
+ Json::Value attr_root;
+ reader.parse(extended_attributes, attr_root);
+
+ const Json::Value::Members attr_list = attr_root.getMemberNames();
+ for (Json::Value::Members::const_iterator it = attr_list.begin();
+ it != attr_list.end(); ++it) {
+ Json::Value attr_value = attr_root[*it];
+ sao->setExtendedAttribute(*it, attr_value.asString());
+ }
} catch (SettingNotFoundException &e) {}
}
@@ -175,7 +164,6 @@ void RemotePlayer::serialize(std::ostream &os)
Settings args;
args.setS32("version", 1);
args.set("name", m_name);
- //args.set("password", m_password);
// This should not happen
assert(m_sao);
@@ -185,6 +173,10 @@ void RemotePlayer::serialize(std::ostream &os)
args.setFloat("yaw", m_sao->getYaw());
args.setS32("breath", m_sao->getBreath());
+ std::string extended_attrs = "";
+ serializeExtraAttributes(extended_attrs);
+ args.set("extended_attributes", extended_attrs);
+
args.writeLines(os);
os<<"PlayerArgsEnd\n";
diff --git a/src/remoteplayer.h b/src/remoteplayer.h
index 61b5a23de..ee0d625b6 100644
--- a/src/remoteplayer.h
+++ b/src/remoteplayer.h
@@ -22,24 +22,28 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define REMOTEPLAYER_HEADER
#include "player.h"
+#include "cloudparams.h"
class PlayerSAO;
-enum RemotePlayerChatResult {
+enum RemotePlayerChatResult
+{
RPLAYER_CHATRESULT_OK,
RPLAYER_CHATRESULT_FLOODING,
RPLAYER_CHATRESULT_KICK,
};
+
/*
Player on the server
*/
class RemotePlayer : public Player
{
+ friend class PlayerDatabaseFiles;
+
public:
RemotePlayer(const char *name, IItemDefManager *idef);
virtual ~RemotePlayer() {}
- void save(std::string savedir, IGameDef *gamedef);
void deSerialize(std::istream &is, const std::string &playername, PlayerSAO *sao);
PlayerSAO *getPlayerSAO() { return m_sao; }
@@ -66,15 +70,9 @@ public:
*ratio = m_day_night_ratio;
}
- void setHotbarImage(const std::string &name)
- {
- hud_hotbar_image = name;
- }
+ void setHotbarImage(const std::string &name) { hud_hotbar_image = name; }
- std::string getHotbarImage() const
- {
- return hud_hotbar_image;
- }
+ std::string getHotbarImage() const { return hud_hotbar_image; }
void setHotbarSelectedImage(const std::string &name)
{
@@ -87,21 +85,30 @@ public:
}
void setSky(const video::SColor &bgcolor, const std::string &type,
- const std::vector<std::string> &params)
+ const std::vector<std::string> &params, bool &clouds)
{
m_sky_bgcolor = bgcolor;
m_sky_type = type;
m_sky_params = params;
+ m_sky_clouds = clouds;
}
void getSky(video::SColor *bgcolor, std::string *type,
- std::vector<std::string> *params)
+ std::vector<std::string> *params, bool *clouds)
{
*bgcolor = m_sky_bgcolor;
*type = m_sky_type;
*params = m_sky_params;
+ *clouds = m_sky_clouds;
}
+ void setCloudParams(const CloudParams &cloud_params)
+ {
+ m_cloud_params = cloud_params;
+ }
+
+ const CloudParams &getCloudParams() const { return m_cloud_params; }
+
bool checkModified() const { return m_dirty || inventory.checkModified(); }
void setModified(const bool x)
@@ -128,6 +135,7 @@ public:
void setDirty(bool dirty) { m_dirty = true; }
u16 protocol_version;
+
private:
/*
serialize() writes a bunch of text that can contain
@@ -135,6 +143,7 @@ private:
deSerialize stops reading exactly at the right point.
*/
void serialize(std::ostream &os);
+ void serializeExtraAttributes(std::string &output);
PlayerSAO *m_sao;
bool m_dirty;
@@ -155,6 +164,9 @@ private:
std::string m_sky_type;
video::SColor m_sky_bgcolor;
std::vector<std::string> m_sky_params;
+ bool m_sky_clouds;
+
+ CloudParams m_cloud_params;
};
#endif
diff --git a/src/rollback_interface.cpp b/src/rollback_interface.cpp
index bffe0a82c..d02d1cb3e 100644
--- a/src/rollback_interface.cpp
+++ b/src/rollback_interface.cpp
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/serialize.h"
#include "util/string.h"
#include "util/numeric.h"
+#include "util/basic_macros.h"
#include "map.h"
#include "gamedef.h"
#include "nodedef.h"
@@ -32,8 +33,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "inventory.h"
#include "mapblock.h"
-#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
-
RollbackNode::RollbackNode(Map *map, v3s16 p, IGameDef *gamedef)
{
@@ -45,7 +44,7 @@ RollbackNode::RollbackNode(Map *map, v3s16 p, IGameDef *gamedef)
NodeMetadata *metap = map->getNodeMetadata(p);
if (metap) {
std::ostringstream os(std::ios::binary);
- metap->serialize(os);
+ metap->serialize(os, 1); // FIXME: version bump??
meta = os.str();
}
}
@@ -166,7 +165,7 @@ bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gam
}
}
std::istringstream is(n_old.meta, std::ios::binary);
- meta->deSerialize(is);
+ meta->deSerialize(is, 1); // FIXME: version bump??
}
// Inform other things that the meta data has changed
v3s16 blockpos = getContainerPos(p, MAP_BLOCKSIZE);
@@ -191,7 +190,6 @@ bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gam
case TYPE_MODIFY_INVENTORY_STACK: {
InventoryLocation loc;
loc.deSerialize(inventory_location);
- std::string real_name = gamedef->idef()->getAlias(inventory_stack.name);
Inventory *inv = imgr->getInventory(loc);
if (!inv) {
infostream << "RollbackAction::applyRevert(): Could not get "
@@ -212,10 +210,12 @@ bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gam
<< inventory_location << std::endl;
return false;
}
+
// If item was added, take away item, otherwise add removed item
if (inventory_add) {
// Silently ignore different current item
- if (list->getItem(inventory_index).name != real_name)
+ if (list->getItem(inventory_index).name !=
+ gamedef->idef()->getAlias(inventory_stack.name))
return false;
list->takeItem(inventory_index, inventory_stack.count);
} else {
diff --git a/src/script/CMakeLists.txt b/src/script/CMakeLists.txt
index 5ef672ca9..bebe2f037 100644
--- a/src/script/CMakeLists.txt
+++ b/src/script/CMakeLists.txt
@@ -3,16 +3,17 @@ add_subdirectory(cpp_api)
add_subdirectory(lua_api)
# Used by server and client
-set(common_SCRIPT_SRCS
- ${CMAKE_CURRENT_SOURCE_DIR}/scripting_game.cpp
+set(common_SCRIPT_SRCS
+ ${CMAKE_CURRENT_SOURCE_DIR}/scripting_server.cpp
${common_SCRIPT_COMMON_SRCS}
${common_SCRIPT_CPP_API_SRCS}
${common_SCRIPT_LUA_API_SRCS}
PARENT_SCOPE)
# Used by client only
-set(client_SCRIPT_SRCS
+set(client_SCRIPT_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/scripting_mainmenu.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/scripting_client.cpp
${client_SCRIPT_COMMON_SRCS}
${client_SCRIPT_CPP_API_SRCS}
${client_SCRIPT_LUA_API_SRCS}
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index 541744895..c0e29abf0 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -20,7 +20,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common/c_converter.h"
#include "common/c_types.h"
#include "nodedef.h"
-#include "itemdef.h"
#include "object_properties.h"
#include "cpp_api/s_node.h"
#include "lua_api/l_object.h"
@@ -33,31 +32,37 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "porting.h"
#include "mg_schematic.h"
#include "noise.h"
+#include "util/pointedthing.h"
+#include "debug.h" // For FATAL_ERROR
#include <json/json.h>
struct EnumString es_TileAnimationType[] =
{
{TAT_NONE, "none"},
{TAT_VERTICAL_FRAMES, "vertical_frames"},
+ {TAT_SHEET_2D, "sheet_2d"},
{0, NULL},
};
/******************************************************************************/
-ItemDefinition read_item_definition(lua_State* L,int index,
- ItemDefinition default_def)
+void read_item_definition(lua_State* L, int index,
+ const ItemDefinition &default_def, ItemDefinition &def)
{
- if(index < 0)
+ if (index < 0)
index = lua_gettop(L) + 1 + index;
- // Read the item definition
- ItemDefinition def = default_def;
-
def.type = (ItemType)getenumfield(L, index, "type",
es_ItemType, ITEM_NONE);
getstringfield(L, index, "name", def.name);
getstringfield(L, index, "description", def.description);
getstringfield(L, index, "inventory_image", def.inventory_image);
getstringfield(L, index, "wield_image", def.wield_image);
+ getstringfield(L, index, "palette", def.palette_image);
+
+ // Read item color.
+ lua_getfield(L, index, "color");
+ read_color(L, -1, &def.color);
+ lua_pop(L, 1);
lua_getfield(L, index, "wield_scale");
if(lua_istable(L, -1)){
@@ -112,13 +117,66 @@ ItemDefinition read_item_definition(lua_State* L,int index,
// "" = no prediction
getstringfield(L, index, "node_placement_prediction",
def.node_placement_prediction);
+}
+
+/******************************************************************************/
+void push_item_definition(lua_State *L, const ItemDefinition &i)
+{
+ lua_newtable(L);
+ lua_pushstring(L, i.name.c_str());
+ lua_setfield(L, -2, "name");
+ lua_pushstring(L, i.description.c_str());
+ lua_setfield(L, -2, "description");
+}
- return def;
+void push_item_definition_full(lua_State *L, const ItemDefinition &i)
+{
+ std::string type(es_ItemType[(int)i.type].str);
+
+ lua_newtable(L);
+ lua_pushstring(L, i.name.c_str());
+ lua_setfield(L, -2, "name");
+ lua_pushstring(L, i.description.c_str());
+ lua_setfield(L, -2, "description");
+ lua_pushstring(L, type.c_str());
+ lua_setfield(L, -2, "type");
+ lua_pushstring(L, i.inventory_image.c_str());
+ lua_setfield(L, -2, "inventory_image");
+ lua_pushstring(L, i.wield_image.c_str());
+ lua_setfield(L, -2, "wield_image");
+ lua_pushstring(L, i.palette_image.c_str());
+ lua_setfield(L, -2, "palette_image");
+ push_ARGB8(L, i.color);
+ lua_setfield(L, -2, "color");
+ push_v3f(L, i.wield_scale);
+ lua_setfield(L, -2, "wield_scale");
+ lua_pushinteger(L, i.stack_max);
+ lua_setfield(L, -2, "stack_max");
+ lua_pushboolean(L, i.usable);
+ lua_setfield(L, -2, "usable");
+ lua_pushboolean(L, i.liquids_pointable);
+ lua_setfield(L, -2, "liquids_pointable");
+ if (i.type == ITEM_TOOL) {
+ push_tool_capabilities(L, ToolCapabilities(
+ i.tool_capabilities->full_punch_interval,
+ i.tool_capabilities->max_drop_level,
+ i.tool_capabilities->groupcaps,
+ i.tool_capabilities->damageGroups));
+ lua_setfield(L, -2, "tool_capabilities");
+ }
+ push_groups(L, i.groups);
+ lua_setfield(L, -2, "groups");
+ push_soundspec(L, i.sound_place);
+ lua_setfield(L, -2, "sound_place");
+ push_soundspec(L, i.sound_place_failed);
+ lua_setfield(L, -2, "sound_place_failed");
+ lua_pushstring(L, i.node_placement_prediction.c_str());
+ lua_setfield(L, -2, "node_placement_prediction");
}
/******************************************************************************/
void read_object_properties(lua_State *L, int index,
- ObjectProperties *prop)
+ ObjectProperties *prop, IItemDefManager *idef)
{
if(index < 0)
index = lua_gettop(L) + 1 + index;
@@ -216,6 +274,10 @@ void read_object_properties(lua_State *L, int index,
}
lua_pop(L, 1);
getstringfield(L, -1, "infotext", prop->infotext);
+ lua_getfield(L, -1, "wield_item");
+ if (!lua_isnil(L, -1))
+ prop->wield_item = read_item(L, -1, idef).getItemString();
+ lua_pop(L, 1);
}
/******************************************************************************/
@@ -284,6 +346,8 @@ void push_object_properties(lua_State *L, ObjectProperties *prop)
lua_setfield(L, -2, "automatic_face_movement_max_rotation_per_sec");
lua_pushlstring(L, prop->infotext.c_str(), prop->infotext.size());
lua_setfield(L, -2, "infotext");
+ lua_pushlstring(L, prop->wield_item.c_str(), prop->wield_item.size());
+ lua_setfield(L, -2, "wield_item");
}
/******************************************************************************/
@@ -321,7 +385,7 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
}
else if(lua_istable(L, index))
{
- // {name="default_lava.png", animation={}}
+ // name="default_lava.png"
tiledef.name = "";
getstringfield(L, index, "name", tiledef.name);
getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat.
@@ -331,20 +395,13 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
L, index, "tileable_horizontal", default_tiling);
tiledef.tileable_vertical = getboolfield_default(
L, index, "tileable_vertical", default_tiling);
+ // color = ...
+ lua_getfield(L, index, "color");
+ tiledef.has_color = read_color(L, -1, &tiledef.color);
+ lua_pop(L, 1);
// animation = {}
lua_getfield(L, index, "animation");
- if(lua_istable(L, -1)){
- // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
- tiledef.animation.type = (TileAnimationType)
- getenumfield(L, -1, "type", es_TileAnimationType,
- TAT_NONE);
- tiledef.animation.aspect_w =
- getintfield_default(L, -1, "aspect_w", 16);
- tiledef.animation.aspect_h =
- getintfield_default(L, -1, "aspect_h", 16);
- tiledef.animation.length =
- getfloatfield_default(L, -1, "length", 1.0);
- }
+ tiledef.animation = read_animation_definition(L, -1);
lua_pop(L, 1);
}
@@ -426,6 +483,34 @@ ContentFeatures read_content_features(lua_State *L, int index)
}
lua_pop(L, 1);
+ // overlay_tiles = {}
+ lua_getfield(L, index, "overlay_tiles");
+ if (lua_istable(L, -1)) {
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ int i = 0;
+ while (lua_next(L, table) != 0) {
+ // Read tiledef from value
+ f.tiledef_overlay[i] = read_tiledef(L, -1, f.drawtype);
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ i++;
+ if (i == 6) {
+ lua_pop(L, 1);
+ break;
+ }
+ }
+ // Copy last value to all remaining textures
+ if (i >= 1) {
+ TileDef lasttile = f.tiledef_overlay[i - 1];
+ while (i < 6) {
+ f.tiledef_overlay[i] = lasttile;
+ i++;
+ }
+ }
+ }
+ lua_pop(L, 1);
+
// special_tiles = {}
lua_getfield(L, index, "special_tiles");
// If nil, try the deprecated name "special_materials" instead
@@ -460,6 +545,13 @@ ContentFeatures read_content_features(lua_State *L, int index)
if (usealpha)
f.alpha = 0;
+ // Read node color.
+ lua_getfield(L, index, "color");
+ read_color(L, -1, &f.color);
+ lua_pop(L, 1);
+
+ getstringfield(L, index, "palette", f.palette_name);
+
/* Other stuff */
lua_getfield(L, index, "post_effect_color");
@@ -471,6 +563,13 @@ ContentFeatures read_content_features(lua_State *L, int index)
f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
ScriptApiNode::es_ContentParamType2, CPT2_NONE);
+ if (f.palette_name != "" &&
+ !(f.param_type_2 == CPT2_COLOR ||
+ f.param_type_2 == CPT2_COLORED_FACEDIR ||
+ f.param_type_2 == CPT2_COLORED_WALLMOUNTED))
+ warningstream << "Node " << f.name.c_str()
+ << " has a palette, but not a suitable paramtype2." << std::endl;
+
// Warn about some deprecated fields
warn_if_field_exists(L, index, "wall_mounted",
"Deprecated; use paramtype2 = 'wallmounted'");
@@ -616,6 +715,204 @@ ContentFeatures read_content_features(lua_State *L, int index)
return f;
}
+void push_content_features(lua_State *L, const ContentFeatures &c)
+{
+ std::string paramtype(ScriptApiNode::es_ContentParamType[(int)c.param_type].str);
+ std::string paramtype2(ScriptApiNode::es_ContentParamType2[(int)c.param_type_2].str);
+ std::string drawtype(ScriptApiNode::es_DrawType[(int)c.drawtype].str);
+ std::string liquid_type(ScriptApiNode::es_LiquidType[(int)c.liquid_type].str);
+
+ /* Missing "tiles" because I don't see a usecase (at least not yet). */
+
+ lua_newtable(L);
+ lua_pushboolean(L, c.has_on_construct);
+ lua_setfield(L, -2, "has_on_construct");
+ lua_pushboolean(L, c.has_on_destruct);
+ lua_setfield(L, -2, "has_on_destruct");
+ lua_pushboolean(L, c.has_after_destruct);
+ lua_setfield(L, -2, "has_after_destruct");
+ lua_pushstring(L, c.name.c_str());
+ lua_setfield(L, -2, "name");
+ push_groups(L, c.groups);
+ lua_setfield(L, -2, "groups");
+ lua_pushstring(L, paramtype.c_str());
+ lua_setfield(L, -2, "paramtype");
+ lua_pushstring(L, paramtype2.c_str());
+ lua_setfield(L, -2, "paramtype2");
+ lua_pushstring(L, drawtype.c_str());
+ lua_setfield(L, -2, "drawtype");
+ if (!c.mesh.empty()) {
+ lua_pushstring(L, c.mesh.c_str());
+ lua_setfield(L, -2, "mesh");
+ }
+#ifndef SERVER
+ push_ARGB8(L, c.minimap_color); // I know this is not set-able w/ register_node,
+ lua_setfield(L, -2, "minimap_color"); // but the people need to know!
+#endif
+ lua_pushnumber(L, c.visual_scale);
+ lua_setfield(L, -2, "visual_scale");
+ lua_pushnumber(L, c.alpha);
+ lua_setfield(L, -2, "alpha");
+ if (!c.palette_name.empty()) {
+ push_ARGB8(L, c.color);
+ lua_setfield(L, -2, "color");
+
+ lua_pushstring(L, c.palette_name.c_str());
+ lua_setfield(L, -2, "palette_name");
+
+ push_palette(L, c.palette);
+ lua_setfield(L, -2, "palette");
+ }
+ lua_pushnumber(L, c.waving);
+ lua_setfield(L, -2, "waving");
+ lua_pushnumber(L, c.connect_sides);
+ lua_setfield(L, -2, "connect_sides");
+
+ lua_newtable(L);
+ u16 i = 1;
+ for (std::vector<std::string>::const_iterator it = c.connects_to.begin();
+ it != c.connects_to.end(); ++it) {
+ lua_pushlstring(L, it->c_str(), it->size());
+ lua_rawseti(L, -2, i);
+ }
+ lua_setfield(L, -2, "connects_to");
+
+ push_ARGB8(L, c.post_effect_color);
+ lua_setfield(L, -2, "post_effect_color");
+ lua_pushnumber(L, c.leveled);
+ lua_setfield(L, -2, "leveled");
+ lua_pushboolean(L, c.sunlight_propagates);
+ lua_setfield(L, -2, "sunlight_propagates");
+ lua_pushnumber(L, c.light_source);
+ lua_setfield(L, -2, "light_source");
+ lua_pushboolean(L, c.is_ground_content);
+ lua_setfield(L, -2, "is_ground_content");
+ lua_pushboolean(L, c.walkable);
+ lua_setfield(L, -2, "walkable");
+ lua_pushboolean(L, c.pointable);
+ lua_setfield(L, -2, "pointable");
+ lua_pushboolean(L, c.diggable);
+ lua_setfield(L, -2, "diggable");
+ lua_pushboolean(L, c.climbable);
+ lua_setfield(L, -2, "climbable");
+ lua_pushboolean(L, c.buildable_to);
+ lua_setfield(L, -2, "buildable_to");
+ lua_pushboolean(L, c.rightclickable);
+ lua_setfield(L, -2, "rightclickable");
+ lua_pushnumber(L, c.damage_per_second);
+ lua_setfield(L, -2, "damage_per_second");
+ if (c.isLiquid()) {
+ lua_pushstring(L, liquid_type.c_str());
+ lua_setfield(L, -2, "liquid_type");
+ lua_pushstring(L, c.liquid_alternative_flowing.c_str());
+ lua_setfield(L, -2, "liquid_alternative_flowing");
+ lua_pushstring(L, c.liquid_alternative_source.c_str());
+ lua_setfield(L, -2, "liquid_alternative_source");
+ lua_pushnumber(L, c.liquid_viscosity);
+ lua_setfield(L, -2, "liquid_viscosity");
+ lua_pushboolean(L, c.liquid_renewable);
+ lua_setfield(L, -2, "liquid_renewable");
+ lua_pushnumber(L, c.liquid_range);
+ lua_setfield(L, -2, "liquid_range");
+ }
+ lua_pushnumber(L, c.drowning);
+ lua_setfield(L, -2, "drowning");
+ lua_pushboolean(L, c.floodable);
+ lua_setfield(L, -2, "floodable");
+ push_nodebox(L, c.node_box);
+ lua_setfield(L, -2, "node_box");
+ push_nodebox(L, c.selection_box);
+ lua_setfield(L, -2, "selection_box");
+ push_nodebox(L, c.collision_box);
+ lua_setfield(L, -2, "collision_box");
+ lua_newtable(L);
+ push_soundspec(L, c.sound_footstep);
+ lua_setfield(L, -2, "sound_footstep");
+ push_soundspec(L, c.sound_dig);
+ lua_setfield(L, -2, "sound_dig");
+ push_soundspec(L, c.sound_dug);
+ lua_setfield(L, -2, "sound_dug");
+ lua_setfield(L, -2, "sounds");
+ lua_pushboolean(L, c.legacy_facedir_simple);
+ lua_setfield(L, -2, "legacy_facedir_simple");
+ lua_pushboolean(L, c.legacy_wallmounted);
+ lua_setfield(L, -2, "legacy_wallmounted");
+}
+
+/******************************************************************************/
+void push_nodebox(lua_State *L, const NodeBox &box)
+{
+ lua_newtable(L);
+ switch (box.type)
+ {
+ case NODEBOX_REGULAR:
+ lua_pushstring(L, "regular");
+ lua_setfield(L, -2, "type");
+ break;
+ case NODEBOX_LEVELED:
+ case NODEBOX_FIXED:
+ lua_pushstring(L, "fixed");
+ lua_setfield(L, -2, "type");
+ push_box(L, box.fixed);
+ lua_setfield(L, -2, "fixed");
+ break;
+ case NODEBOX_WALLMOUNTED:
+ lua_pushstring(L, "wallmounted");
+ lua_setfield(L, -2, "type");
+ push_aabb3f(L, box.wall_top);
+ lua_setfield(L, -2, "wall_top");
+ push_aabb3f(L, box.wall_bottom);
+ lua_setfield(L, -2, "wall_bottom");
+ push_aabb3f(L, box.wall_side);
+ lua_setfield(L, -2, "wall_side");
+ break;
+ case NODEBOX_CONNECTED:
+ lua_pushstring(L, "connected");
+ lua_setfield(L, -2, "type");
+ push_box(L, box.connect_top);
+ lua_setfield(L, -2, "connect_top");
+ push_box(L, box.connect_bottom);
+ lua_setfield(L, -2, "connect_bottom");
+ push_box(L, box.connect_front);
+ lua_setfield(L, -2, "connect_front");
+ push_box(L, box.connect_back);
+ lua_setfield(L, -2, "connect_back");
+ push_box(L, box.connect_left);
+ lua_setfield(L, -2, "connect_left");
+ push_box(L, box.connect_right);
+ lua_setfield(L, -2, "connect_right");
+ break;
+ default:
+ FATAL_ERROR("Invalid box.type");
+ break;
+ }
+}
+
+void push_box(lua_State *L, const std::vector<aabb3f> &box)
+{
+ lua_newtable(L);
+ u8 i = 1;
+ for (std::vector<aabb3f>::const_iterator it = box.begin();
+ it != box.end(); ++it) {
+ push_aabb3f(L, (*it));
+ lua_rawseti(L, -2, i);
+ }
+}
+
+/******************************************************************************/
+void push_palette(lua_State *L, const std::vector<video::SColor> *palette)
+{
+ lua_createtable(L, palette->size(), 0);
+ int newTable = lua_gettop(L);
+ int index = 1;
+ std::vector<video::SColor>::const_iterator iter;
+ for (iter = palette->begin(); iter != palette->end(); ++iter) {
+ push_ARGB8(L, (*iter));
+ lua_rawseti(L, newTable, index);
+ index++;
+ }
+}
+
/******************************************************************************/
void read_server_sound_params(lua_State *L, int index,
ServerSoundParams &params)
@@ -627,6 +924,7 @@ void read_server_sound_params(lua_State *L, int index,
if(lua_istable(L, index)){
getfloatfield(L, index, "gain", params.gain);
getstringfield(L, index, "to_player", params.to_player);
+ getfloatfield(L, index, "fade", params.fade);
lua_getfield(L, index, "pos");
if(!lua_isnil(L, -1)){
v3f p = read_v3f(L, -1)*BS;
@@ -659,11 +957,23 @@ void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
} else if(lua_istable(L, index)){
getstringfield(L, index, "name", spec.name);
getfloatfield(L, index, "gain", spec.gain);
+ getfloatfield(L, index, "fade", spec.fade);
} else if(lua_isstring(L, index)){
spec.name = lua_tostring(L, index);
}
}
+void push_soundspec(lua_State *L, const SimpleSoundSpec &spec)
+{
+ lua_newtable(L);
+ lua_pushstring(L, spec.name.c_str());
+ lua_setfield(L, -2, "name");
+ lua_pushnumber(L, spec.gain);
+ lua_setfield(L, -2, "gain");
+ lua_pushnumber(L, spec.fade);
+ lua_setfield(L, -2, "fade");
+}
+
/******************************************************************************/
NodeBox read_nodebox(lua_State *L, int index)
{
@@ -776,7 +1086,7 @@ bool string_to_enum(const EnumString *spec, int &result,
}
/******************************************************************************/
-ItemStack read_item(lua_State* L, int index,Server* srv)
+ItemStack read_item(lua_State* L, int index, IItemDefManager *idef)
{
if(index < 0)
index = lua_gettop(L) + 1 + index;
@@ -795,7 +1105,6 @@ ItemStack read_item(lua_State* L, int index,Server* srv)
{
// Convert from itemstring
std::string itemstring = lua_tostring(L, index);
- IItemDefManager *idef = srv->idef();
try
{
ItemStack item;
@@ -812,15 +1121,34 @@ ItemStack read_item(lua_State* L, int index,Server* srv)
else if(lua_istable(L, index))
{
// Convert from table
- IItemDefManager *idef = srv->idef();
std::string name = getstringfield_default(L, index, "name", "");
int count = getintfield_default(L, index, "count", 1);
int wear = getintfield_default(L, index, "wear", 0);
- std::string metadata = getstringfield_default(L, index, "metadata", "");
- return ItemStack(name, count, wear, metadata, idef);
- }
- else
- {
+
+ ItemStack istack(name, count, wear, idef);
+
+ // BACKWARDS COMPATIBLITY
+ std::string value = getstringfield_default(L, index, "metadata", "");
+ istack.metadata.setString("", value);
+
+ // Get meta
+ lua_getfield(L, index, "meta");
+ int fieldstable = lua_gettop(L);
+ if (lua_istable(L, fieldstable)) {
+ lua_pushnil(L);
+ while (lua_next(L, fieldstable) != 0) {
+ // key at index -2 and value at index -1
+ std::string key = lua_tostring(L, -2);
+ size_t value_len;
+ const char *value_cs = lua_tolstring(L, -1, &value_len);
+ std::string value(value_cs, value_len);
+ istack.metadata.setString(key, value);
+ lua_pop(L, 1); // removes value, keeps key for next iteration
+ }
+ }
+
+ return istack;
+ } else {
throw LuaError("Expecting itemstack, itemstring, table or nil");
}
}
@@ -836,7 +1164,7 @@ void push_tool_capabilities(lua_State *L,
lua_newtable(L);
// For each groupcap
for (ToolGCMap::const_iterator i = toolcap.groupcaps.begin();
- i != toolcap.groupcaps.end(); i++) {
+ i != toolcap.groupcaps.end(); ++i) {
// Create groupcap table
lua_newtable(L);
const std::string &name = i->first;
@@ -844,7 +1172,7 @@ void push_tool_capabilities(lua_State *L,
// Create subtable "times"
lua_newtable(L);
for (UNORDERED_MAP<int, float>::const_iterator
- i = groupcap.times.begin(); i != groupcap.times.end(); i++) {
+ i = groupcap.times.begin(); i != groupcap.times.end(); ++i) {
lua_pushinteger(L, i->first);
lua_pushnumber(L, i->second);
lua_settable(L, -3);
@@ -863,7 +1191,7 @@ void push_tool_capabilities(lua_State *L,
lua_newtable(L);
// For each damage group
for (DamageGroup::const_iterator i = toolcap.damageGroups.begin();
- i != toolcap.damageGroups.end(); i++) {
+ i != toolcap.damageGroups.end(); ++i) {
// Create damage group table
lua_pushinteger(L, i->second);
lua_setfield(L, -2, i->first.c_str());
@@ -902,7 +1230,7 @@ void read_inventory_list(lua_State *L, int tableindex,
InventoryList *invlist = inv->addList(name, listsize);
int index = 0;
for(std::vector<ItemStack>::const_iterator
- i = items.begin(); i != items.end(); i++){
+ i = items.begin(); i != items.end(); ++i){
if(forcesize != -1 && index == forcesize)
break;
invlist->changeItem(index, *i);
@@ -915,6 +1243,41 @@ void read_inventory_list(lua_State *L, int tableindex,
}
/******************************************************************************/
+struct TileAnimationParams read_animation_definition(lua_State *L, int index)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ struct TileAnimationParams anim;
+ anim.type = TAT_NONE;
+ if (!lua_istable(L, index))
+ return anim;
+
+ anim.type = (TileAnimationType)
+ getenumfield(L, index, "type", es_TileAnimationType,
+ TAT_NONE);
+ if (anim.type == TAT_VERTICAL_FRAMES) {
+ // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
+ anim.vertical_frames.aspect_w =
+ getintfield_default(L, index, "aspect_w", 16);
+ anim.vertical_frames.aspect_h =
+ getintfield_default(L, index, "aspect_h", 16);
+ anim.vertical_frames.length =
+ getfloatfield_default(L, index, "length", 1.0);
+ } else if (anim.type == TAT_SHEET_2D) {
+ // {type="sheet_2d", frames_w=5, frames_h=3, frame_length=0.5}
+ getintfield(L, index, "frames_w",
+ anim.sheet_2d.frames_w);
+ getintfield(L, index, "frames_h",
+ anim.sheet_2d.frames_h);
+ getfloatfield(L, index, "frame_length",
+ anim.sheet_2d.frame_length);
+ }
+
+ return anim;
+}
+
+/******************************************************************************/
ToolCapabilities read_tool_capabilities(
lua_State *L, int table)
{
@@ -1124,7 +1487,7 @@ std::vector<ItemStack> read_items(lua_State *L, int index, Server *srv)
if (items.size() < (u32) key) {
items.resize(key);
}
- items[key - 1] = read_item(L, -1, srv);
+ items[key - 1] = read_item(L, -1, srv->idef());
lua_pop(L, 1);
}
return items;
@@ -1332,3 +1695,42 @@ void read_json_value(lua_State *L, Json::Value &root, int index, u8 recursion)
}
lua_pop(L, 1); // Pop value
}
+
+void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm)
+{
+ lua_newtable(L);
+ if (pointed.type == POINTEDTHING_NODE) {
+ lua_pushstring(L, "node");
+ lua_setfield(L, -2, "type");
+ push_v3s16(L, pointed.node_undersurface);
+ lua_setfield(L, -2, "under");
+ push_v3s16(L, pointed.node_abovesurface);
+ lua_setfield(L, -2, "above");
+ } else if (pointed.type == POINTEDTHING_OBJECT) {
+ lua_pushstring(L, "object");
+ lua_setfield(L, -2, "type");
+
+ if (csm) {
+ lua_pushinteger(L, pointed.object_id);
+ lua_setfield(L, -2, "id");
+ } else {
+ push_objectRef(L, pointed.object_id);
+ lua_setfield(L, -2, "ref");
+ }
+ } else {
+ lua_pushstring(L, "nothing");
+ lua_setfield(L, -2, "type");
+ }
+}
+
+void push_objectRef(lua_State *L, const u16 id)
+{
+ // Get core.object_refs[i]
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "object_refs");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_pushnumber(L, id);
+ lua_gettable(L, -2);
+ lua_remove(L, -2); // object_refs
+ lua_remove(L, -2); // core
+}
diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h
index 2a2228b6d..9b8796297 100644
--- a/src/script/common/c_content.h
+++ b/src/script/common/c_content.h
@@ -38,6 +38,8 @@ extern "C" {
#include "irrlichttypes_bloated.h"
#include "util/string.h"
#include "itemgroup.h"
+#include "itemdef.h"
+#include "c_types.h"
namespace Json { class Value; }
@@ -63,8 +65,20 @@ class Schematic;
ContentFeatures read_content_features (lua_State *L, int index);
+void push_content_features (lua_State *L,
+ const ContentFeatures &c);
+
+void push_nodebox (lua_State *L,
+ const NodeBox &box);
+void push_box (lua_State *L,
+ const std::vector<aabb3f> &box);
+
+void push_palette (lua_State *L,
+ const std::vector<video::SColor> *palette);
+
TileDef read_tiledef (lua_State *L, int index,
u8 drawtype);
+
void read_soundspec (lua_State *L, int index,
SimpleSoundSpec &spec);
NodeBox read_nodebox (lua_State *L, int index);
@@ -77,17 +91,24 @@ void push_dig_params (lua_State *L,
void push_hit_params (lua_State *L,
const HitParams &params);
-ItemStack read_item (lua_State *L, int index, Server *srv);
+ItemStack read_item (lua_State *L, int index, IItemDefManager *idef);
+struct TileAnimationParams read_animation_definition(lua_State *L, int index);
ToolCapabilities read_tool_capabilities (lua_State *L, int table);
void push_tool_capabilities (lua_State *L,
const ToolCapabilities &prop);
-ItemDefinition read_item_definition (lua_State *L, int index,
- ItemDefinition default_def);
+void read_item_definition (lua_State *L, int index, const ItemDefinition &default_def,
+ ItemDefinition &def);
+void push_item_definition (lua_State *L,
+ const ItemDefinition &i);
+void push_item_definition_full (lua_State *L,
+ const ItemDefinition &i);
+
void read_object_properties (lua_State *L, int index,
- ObjectProperties *prop);
+ ObjectProperties *prop,
+ IItemDefManager *idef);
void push_object_properties (lua_State *L,
ObjectProperties *prop);
@@ -142,6 +163,8 @@ std::vector<ItemStack> read_items (lua_State *L,
void read_soundspec (lua_State *L,
int index,
SimpleSoundSpec &spec);
+void push_soundspec (lua_State *L,
+ const SimpleSoundSpec &spec);
bool string_to_enum (const EnumString *spec,
int &result,
@@ -159,6 +182,10 @@ bool push_json_value (lua_State *L,
void read_json_value (lua_State *L, Json::Value &root,
int index, u8 recursion = 0);
+void push_pointed_thing (lua_State *L, const PointedThing &pointed, bool csm = false);
+
+void push_objectRef (lua_State *L, const u16 id);
+
extern struct EnumString es_TileAnimationType[];
#endif /* C_CONTENT_H_ */
diff --git a/src/script/common/c_converter.cpp b/src/script/common/c_converter.cpp
index f36298915..fc516d56a 100644
--- a/src/script/common/c_converter.cpp
+++ b/src/script/common/c_converter.cpp
@@ -26,15 +26,17 @@ extern "C" {
#include "util/serialize.h"
#include "util/string.h"
#include "common/c_converter.h"
+#include "common/c_internal.h"
#include "constants.h"
#define CHECK_TYPE(index, name, type) do { \
int t = lua_type(L, (index)); \
if (t != (type)) { \
+ std::string traceback = script_get_backtrace(L); \
throw LuaError(std::string("Invalid ") + (name) + \
" (expected " + lua_typename(L, (type)) + \
- " got " + lua_typename(L, t) + ")."); \
+ " got " + lua_typename(L, t) + ").\n" + traceback); \
} \
} while(0)
#define CHECK_POS_COORD(name) CHECK_TYPE(-1, "position coordinate '" name "'", LUA_TNUMBER)
diff --git a/src/script/common/c_converter.h b/src/script/common/c_converter.h
index a5fbee765..b0f61a8ca 100644
--- a/src/script/common/c_converter.h
+++ b/src/script/common/c_converter.h
@@ -77,6 +77,8 @@ void setfloatfield(lua_State *L, int table,
const char *fieldname, float value);
void setboolfield(lua_State *L, int table,
const char *fieldname, bool value);
+void setstringfield(lua_State *L, int table,
+ const char *fieldname, const char *value);
v3f checkFloatPos (lua_State *L, int index);
v2f check_v2f (lua_State *L, int index);
diff --git a/src/script/cpp_api/CMakeLists.txt b/src/script/cpp_api/CMakeLists.txt
index be4d0131e..4b13356a8 100644
--- a/src/script/cpp_api/CMakeLists.txt
+++ b/src/script/cpp_api/CMakeLists.txt
@@ -13,6 +13,7 @@ set(common_SCRIPT_CPP_API_SRCS
PARENT_SCOPE)
set(client_SCRIPT_CPP_API_SRCS
+ ${CMAKE_CURRENT_SOURCE_DIR}/s_client.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_mainmenu.cpp
PARENT_SCOPE)
diff --git a/src/script/cpp_api/s_async.cpp b/src/script/cpp_api/s_async.cpp
index 1fb84fab6..722359066 100644
--- a/src/script/cpp_api/s_async.cpp
+++ b/src/script/cpp_api/s_async.cpp
@@ -46,26 +46,26 @@ AsyncEngine::~AsyncEngine()
// Request all threads to stop
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
- it != workerThreads.end(); it++) {
+ it != workerThreads.end(); ++it) {
(*it)->stop();
}
// Wake up all threads
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
- it != workerThreads.end(); it++) {
+ it != workerThreads.end(); ++it) {
jobQueueCounter.post();
}
// Wait for threads to finish
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
- it != workerThreads.end(); it++) {
+ it != workerThreads.end(); ++it) {
(*it)->wait();
}
// Force kill all threads
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
- it != workerThreads.end(); it++) {
+ it != workerThreads.end(); ++it) {
delete *it;
}
@@ -76,14 +76,9 @@ AsyncEngine::~AsyncEngine()
}
/******************************************************************************/
-bool AsyncEngine::registerFunction(const char* name, lua_CFunction func)
+void AsyncEngine::registerStateInitializer(StateInitializer func)
{
- if (initDone) {
- return false;
- }
-
- functionList[name] = func;
- return true;
+ stateInitializers.push_back(func);
}
/******************************************************************************/
@@ -100,7 +95,8 @@ void AsyncEngine::initialize(unsigned int numEngines)
}
/******************************************************************************/
-unsigned int AsyncEngine::queueAsyncJob(std::string func, std::string params)
+unsigned int AsyncEngine::queueAsyncJob(const std::string &func,
+ const std::string &params)
{
jobQueueMutex.lock();
LuaJobInfo toAdd;
@@ -124,7 +120,6 @@ LuaJobInfo AsyncEngine::getJob()
jobQueueMutex.lock();
LuaJobInfo retval;
- retval.valid = false;
if (!jobQueue.empty()) {
retval = jobQueue.front();
@@ -137,7 +132,7 @@ LuaJobInfo AsyncEngine::getJob()
}
/******************************************************************************/
-void AsyncEngine::putJobResult(LuaJobInfo result)
+void AsyncEngine::putJobResult(const LuaJobInfo &result)
{
resultQueueMutex.lock();
resultQueue.push_back(result);
@@ -204,11 +199,9 @@ void AsyncEngine::pushFinishedJobs(lua_State* L) {
/******************************************************************************/
void AsyncEngine::prepareEnvironment(lua_State* L, int top)
{
- for (UNORDERED_MAP<std::string, lua_CFunction>::iterator it = functionList.begin();
- it != functionList.end(); it++) {
- lua_pushstring(L, it->first.c_str());
- lua_pushcfunction(L, it->second);
- lua_settable(L, top);
+ for (std::vector<StateInitializer>::iterator it = stateInitializers.begin();
+ it != stateInitializers.end(); it++) {
+ (*it)(L, top);
}
}
@@ -264,7 +257,7 @@ void* AsyncWorkerThread::run()
// Wait for job
LuaJobInfo toProcess = jobDispatcher->getJob();
- if (toProcess.valid == false || stopRequested()) {
+ if (!toProcess.valid || stopRequested()) {
continue;
}
diff --git a/src/script/cpp_api/s_async.h b/src/script/cpp_api/s_async.h
index 016381e5f..dbe0654e2 100644
--- a/src/script/cpp_api/s_async.h
+++ b/src/script/cpp_api/s_async.h
@@ -38,7 +38,16 @@ class AsyncEngine;
// Declarations
// Data required to queue a job
-struct LuaJobInfo {
+struct LuaJobInfo
+{
+ LuaJobInfo() :
+ serializedFunction(""),
+ serializedParams(""),
+ serializedResult(""),
+ id(0),
+ valid(false)
+ {}
+
// Function to be called in async environment
std::string serializedFunction;
// Parameter to be passed to function
@@ -66,16 +75,16 @@ private:
// Asynchornous thread and job management
class AsyncEngine {
friend class AsyncWorkerThread;
+ typedef void (*StateInitializer)(lua_State *L, int top);
public:
AsyncEngine();
~AsyncEngine();
/**
- * Register function to be used within engine
- * @param name Function name to be used within Lua environment
+ * Register function to be called on new states
* @param func C function to be called
*/
- bool registerFunction(const char* name, lua_CFunction func);
+ void registerStateInitializer(StateInitializer func);
/**
* Create async engine tasks and lock function registration
@@ -89,7 +98,7 @@ public:
* @param params Serialized parameters
* @return jobid The job is queued
*/
- unsigned int queueAsyncJob(std::string func, std::string params);
+ unsigned int queueAsyncJob(const std::string &func, const std::string &params);
/**
* Engine step to process finished jobs
@@ -116,7 +125,7 @@ protected:
* Put a Job result back to result queue
* @param result result of completed job
*/
- void putJobResult(LuaJobInfo result);
+ void putJobResult(const LuaJobInfo &result);
/**
* Initialize environment with current registred functions
@@ -131,8 +140,8 @@ private:
// Variable locking the engine against further modification
bool initDone;
- // Internal store for registred functions
- UNORDERED_MAP<std::string, lua_CFunction> functionList;
+ // Internal store for registred state initializers
+ std::vector<StateInitializer> stateInitializers;
// Internal counter to create job IDs
unsigned int jobIdCounter;
diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp
index 679a517ee..4d7461c5b 100644
--- a/src/script/cpp_api/s_base.cpp
+++ b/src/script/cpp_api/s_base.cpp
@@ -23,12 +23,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_object.h"
#include "common/c_converter.h"
#include "serverobject.h"
-#include "debug.h"
#include "filesys.h"
-#include "log.h"
#include "mods.h"
#include "porting.h"
#include "util/string.h"
+#include "server.h"
+#ifndef SERVER
+#include "client.h"
+#endif
extern "C" {
@@ -40,6 +42,8 @@ extern "C" {
#include <stdio.h>
#include <cstdarg>
+#include "script/common/c_content.h"
+#include <sstream>
class ModNameStorer
@@ -68,7 +72,8 @@ public:
*/
ScriptApiBase::ScriptApiBase() :
- m_luastackmutex()
+ m_luastackmutex(),
+ m_gamedef(NULL)
{
#ifdef SCRIPTAPI_LOCK_DEBUG
m_lock_recursion_count = 0;
@@ -77,6 +82,8 @@ ScriptApiBase::ScriptApiBase() :
m_luastack = luaL_newstate();
FATAL_ERROR_IF(!m_luastack, "luaL_newstate() failed");
+ lua_atpanic(m_luastack, &luaPanic);
+
luaL_openlibs(m_luastack);
// Make the ScriptApiBase* accessible to ModApiBase
@@ -110,7 +117,6 @@ ScriptApiBase::ScriptApiBase() :
// Default to false otherwise
m_secure = false;
- m_server = NULL;
m_environment = NULL;
m_guiengine = NULL;
}
@@ -120,6 +126,16 @@ ScriptApiBase::~ScriptApiBase()
lua_close(m_luastack);
}
+int ScriptApiBase::luaPanic(lua_State *L)
+{
+ std::ostringstream oss;
+ oss << "LUA PANIC: unprotected error in call to Lua API ("
+ << lua_tostring(L, -1) << ")";
+ FATAL_ERROR(oss.str().c_str());
+ // NOTREACHED
+ return 0;
+}
+
void ScriptApiBase::loadMod(const std::string &script_path,
const std::string &mod_name)
{
@@ -224,7 +240,7 @@ void ScriptApiBase::stackDump(std::ostream &o)
break;
case LUA_TNUMBER: /* numbers */ {
char buf[10];
- snprintf(buf, 10, "%g", lua_tonumber(m_luastack, i));
+ snprintf(buf, 10, "%lf", lua_tonumber(m_luastack, i));
o << buf;
break;
}
@@ -305,18 +321,17 @@ void ScriptApiBase::objectrefGetOrCreate(lua_State *L,
if (cobj == NULL || cobj->getId() == 0) {
ObjectRef::create(L, cobj);
} else {
- objectrefGet(L, cobj->getId());
+ push_objectRef(L, cobj->getId());
}
}
-void ScriptApiBase::objectrefGet(lua_State *L, u16 id)
+Server* ScriptApiBase::getServer()
{
- // Get core.object_refs[i]
- lua_getglobal(L, "core");
- lua_getfield(L, -1, "object_refs");
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_pushnumber(L, id);
- lua_gettable(L, -2);
- lua_remove(L, -2); // object_refs
- lua_remove(L, -2); // core
+ return dynamic_cast<Server *>(m_gamedef);
}
+#ifndef SERVER
+Client* ScriptApiBase::getClient()
+{
+ return dynamic_cast<Client *>(m_gamedef);
+}
+#endif
diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h
index f52474f00..5b047a081 100644
--- a/src/script/cpp_api/s_base.h
+++ b/src/script/cpp_api/s_base.h
@@ -55,6 +55,10 @@ extern "C" {
setOriginFromTableRaw(index, __FUNCTION__)
class Server;
+#ifndef SERVER
+class Client;
+#endif
+class IGameDef;
class Environment;
class GUIEngine;
class ServerActiveObject;
@@ -75,7 +79,11 @@ public:
void addObjectReference(ServerActiveObject *cobj);
void removeObjectReference(ServerActiveObject *cobj);
- Server* getServer() { return m_server; }
+ IGameDef *getGameDef() { return m_gamedef; }
+ Server* getServer();
+#ifndef SERVER
+ Client* getClient();
+#endif
std::string getOrigin() { return m_last_run_mod; }
void setOriginDirect(const char *origin);
@@ -98,7 +106,7 @@ protected:
void scriptError(int result, const char *fxn);
void stackDump(std::ostream &o);
- void setServer(Server* server) { m_server = server; }
+ void setGameDef(IGameDef* gamedef) { m_gamedef = gamedef; }
Environment* getEnv() { return m_environment; }
void setEnv(Environment* env) { m_environment = env; }
@@ -107,7 +115,6 @@ protected:
void setGuiEngine(GUIEngine* guiengine) { m_guiengine = guiengine; }
void objectrefGetOrCreate(lua_State *L, ServerActiveObject *cobj);
- void objectrefGet(lua_State *L, u16 id);
RecursiveMutex m_luastackmutex;
std::string m_last_run_mod;
@@ -118,9 +125,11 @@ protected:
#endif
private:
+ static int luaPanic(lua_State *L);
+
lua_State* m_luastack;
- Server* m_server;
+ IGameDef* m_gamedef;
Environment* m_environment;
GUIEngine* m_guiengine;
};
diff --git a/src/script/cpp_api/s_client.cpp b/src/script/cpp_api/s_client.cpp
new file mode 100644
index 000000000..55d309fda
--- /dev/null
+++ b/src/script/cpp_api/s_client.cpp
@@ -0,0 +1,230 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "s_client.h"
+#include "s_internal.h"
+#include "client.h"
+#include "common/c_converter.h"
+#include "common/c_content.h"
+#include "s_item.h"
+
+void ScriptApiClient::on_shutdown()
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get registered shutdown hooks
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_shutdown");
+ // Call callbacks
+ runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
+}
+
+void ScriptApiClient::on_connect()
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // get registered connect hooks
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_connect");
+ // Call callback
+ runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
+}
+
+bool ScriptApiClient::on_sending_message(const std::string &message)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_chat_messages
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_sending_chat_messages");
+ // Call callbacks
+ lua_pushstring(L, message.c_str());
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC);
+ bool ate = lua_toboolean(L, -1);
+ return ate;
+}
+
+bool ScriptApiClient::on_receiving_message(const std::string &message)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_chat_messages
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_receiving_chat_messages");
+ // Call callbacks
+ lua_pushstring(L, message.c_str());
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC);
+ bool ate = lua_toboolean(L, -1);
+ return ate;
+}
+
+void ScriptApiClient::on_damage_taken(int32_t damage_amount)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_chat_messages
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_damage_taken");
+ // Call callbacks
+ lua_pushinteger(L, damage_amount);
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC);
+}
+
+void ScriptApiClient::on_hp_modification(int32_t newhp)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_chat_messages
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_hp_modification");
+ // Call callbacks
+ lua_pushinteger(L, newhp);
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC);
+}
+
+void ScriptApiClient::on_death()
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get registered shutdown hooks
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_death");
+ // Call callbacks
+ runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
+}
+
+void ScriptApiClient::environment_step(float dtime)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_globalsteps
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_globalsteps");
+ // Call callbacks
+ lua_pushnumber(L, dtime);
+ try {
+ runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
+ } catch (LuaError &e) {
+ getClient()->setFatalError(std::string("Client environment_step: ") + e.what() + "\n"
+ + script_get_backtrace(L));
+ }
+}
+
+void ScriptApiClient::on_formspec_input(const std::string &formname,
+ const StringMap &fields)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_chat_messages
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_formspec_input");
+ // Call callbacks
+ // param 1
+ lua_pushstring(L, formname.c_str());
+ // param 2
+ lua_newtable(L);
+ StringMap::const_iterator it;
+ for (it = fields.begin(); it != fields.end(); ++it) {
+ const std::string &name = it->first;
+ const std::string &value = it->second;
+ lua_pushstring(L, name.c_str());
+ lua_pushlstring(L, value.c_str(), value.size());
+ lua_settable(L, -3);
+ }
+ runCallbacks(2, RUN_CALLBACKS_MODE_OR_SC);
+}
+
+bool ScriptApiClient::on_dignode(v3s16 p, MapNode node)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ INodeDefManager *ndef = getClient()->ndef();
+
+ // Get core.registered_on_dignode
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_dignode");
+
+ // Push data
+ push_v3s16(L, p);
+ pushnode(L, node, ndef);
+
+ // Call functions
+ runCallbacks(2, RUN_CALLBACKS_MODE_OR);
+ return lua_toboolean(L, -1);
+}
+
+bool ScriptApiClient::on_punchnode(v3s16 p, MapNode node)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ INodeDefManager *ndef = getClient()->ndef();
+
+ // Get core.registered_on_punchgnode
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_punchnode");
+
+ // Push data
+ push_v3s16(L, p);
+ pushnode(L, node, ndef);
+
+ // Call functions
+ runCallbacks(2, RUN_CALLBACKS_MODE_OR);
+ bool blocked = lua_toboolean(L, -1);
+ return blocked;
+}
+
+bool ScriptApiClient::on_placenode(const PointedThing &pointed, const ItemDefinition &item)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_placenode
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_placenode");
+
+ // Push data
+ push_pointed_thing(L, pointed, true);
+ push_item_definition(L, item);
+
+ // Call functions
+ runCallbacks(2, RUN_CALLBACKS_MODE_OR);
+ return lua_toboolean(L, -1);
+}
+
+bool ScriptApiClient::on_item_use(const ItemStack &item, const PointedThing &pointed)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_item_use
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_item_use");
+
+ // Push data
+ LuaItemStack::create(L, item);
+ push_pointed_thing(L, pointed, true);
+
+ // Call functions
+ runCallbacks(2, RUN_CALLBACKS_MODE_OR);
+ return lua_toboolean(L, -1);
+}
+
+void ScriptApiClient::setEnv(ClientEnvironment *env)
+{
+ ScriptApiBase::setEnv(env);
+}
diff --git a/src/script/cpp_api/s_client.h b/src/script/cpp_api/s_client.h
new file mode 100644
index 000000000..9133637a6
--- /dev/null
+++ b/src/script/cpp_api/s_client.h
@@ -0,0 +1,63 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 S_CLIENT_H_
+#define S_CLIENT_H_
+
+#include "util/pointedthing.h"
+#include "cpp_api/s_base.h"
+#include "mapnode.h"
+#include "itemdef.h"
+#include "util/string.h"
+#include "util/pointedthing.h"
+#include "lua_api/l_item.h"
+
+#ifdef _CRT_MSVCP_CURRENT
+#include <cstdint>
+#endif
+
+class ClientEnvironment;
+
+class ScriptApiClient : virtual public ScriptApiBase
+{
+public:
+ // Calls on_shutdown handlers
+ void on_shutdown();
+
+ void on_connect();
+
+ // Chat message handlers
+ bool on_sending_message(const std::string &message);
+ bool on_receiving_message(const std::string &message);
+
+ void on_damage_taken(int32_t damage_amount);
+ void on_hp_modification(int32_t newhp);
+ void on_death();
+ void environment_step(float dtime);
+ void on_formspec_input(const std::string &formname, const StringMap &fields);
+
+ bool on_dignode(v3s16 p, MapNode node);
+ bool on_punchnode(v3s16 p, MapNode node);
+ bool on_placenode(const PointedThing &pointed, const ItemDefinition &item);
+ bool on_item_use(const ItemStack &item, const PointedThing &pointed);
+
+ void setEnv(ClientEnvironment *env);
+};
+#endif
diff --git a/src/script/cpp_api/s_entity.cpp b/src/script/cpp_api/s_entity.cpp
index 378a6bf09..4c1e296d4 100644
--- a/src/script/cpp_api/s_entity.cpp
+++ b/src/script/cpp_api/s_entity.cpp
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "object_properties.h"
#include "common/c_converter.h"
#include "common/c_content.h"
+#include "server.h"
bool ScriptApiEntity::luaentity_Add(u16 id, const char *name)
{
@@ -56,7 +57,7 @@ bool ScriptApiEntity::luaentity_Add(u16 id, const char *name)
// Add object reference
// This should be userdata with metatable ObjectRef
- objectrefGet(L, id);
+ push_objectRef(L, id);
luaL_checktype(L, -1, LUA_TUSERDATA);
if (!luaL_checkudata(L, -1, "ObjectRef"))
luaL_typerror(L, -1, "ObjectRef");
@@ -187,11 +188,11 @@ void ScriptApiEntity::luaentity_GetProperties(u16 id,
getstringfield(L, -1, "mesh", prop->mesh);
// Deprecated: read object properties directly
- read_object_properties(L, -1, prop);
+ read_object_properties(L, -1, prop, getServer()->idef());
// Read initial_properties
lua_getfield(L, -1, "initial_properties");
- read_object_properties(L, -1, prop);
+ read_object_properties(L, -1, prop, getServer()->idef());
lua_pop(L, 1);
}
@@ -224,10 +225,10 @@ void ScriptApiEntity::luaentity_Step(u16 id, float dtime)
}
// Calls entity:on_punch(ObjectRef puncher, time_from_last_punch,
-// tool_capabilities, direction)
-void ScriptApiEntity::luaentity_Punch(u16 id,
+// tool_capabilities, direction, damage)
+bool ScriptApiEntity::luaentity_Punch(u16 id,
ServerActiveObject *puncher, float time_from_last_punch,
- const ToolCapabilities *toolcap, v3f dir)
+ const ToolCapabilities *toolcap, v3f dir, s16 damage)
{
SCRIPTAPI_PRECHECKHEADER
@@ -242,8 +243,8 @@ void ScriptApiEntity::luaentity_Punch(u16 id,
// Get function
lua_getfield(L, -1, "on_punch");
if (lua_isnil(L, -1)) {
- lua_pop(L, 2); // Pop on_punch and entitu
- return;
+ lua_pop(L, 2); // Pop on_punch and entity
+ return false;
}
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self
@@ -251,11 +252,14 @@ void ScriptApiEntity::luaentity_Punch(u16 id,
lua_pushnumber(L, time_from_last_punch);
push_tool_capabilities(L, *toolcap);
push_v3f(L, dir);
+ lua_pushnumber(L, damage);
setOriginFromTable(object);
- PCALL_RES(lua_pcall(L, 5, 0, error_handler));
+ PCALL_RES(lua_pcall(L, 6, 1, error_handler));
+ bool retval = lua_toboolean(L, -1);
lua_pop(L, 2); // Pop object and error handler
+ return retval;
}
// Calls entity:on_rightclick(ObjectRef clicker)
diff --git a/src/script/cpp_api/s_entity.h b/src/script/cpp_api/s_entity.h
index 8df9d7f00..4e2a056bb 100644
--- a/src/script/cpp_api/s_entity.h
+++ b/src/script/cpp_api/s_entity.h
@@ -38,9 +38,9 @@ public:
void luaentity_GetProperties(u16 id,
ObjectProperties *prop);
void luaentity_Step(u16 id, float dtime);
- void luaentity_Punch(u16 id,
+ bool luaentity_Punch(u16 id,
ServerActiveObject *puncher, float time_from_last_punch,
- const ToolCapabilities *toolcap, v3f dir);
+ const ToolCapabilities *toolcap, v3f dir, s16 damage);
void luaentity_Rightclick(u16 id,
ServerActiveObject *clicker);
};
diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp
index 913d8539d..b1404bf22 100644
--- a/src/script/cpp_api/s_env.cpp
+++ b/src/script/cpp_api/s_env.cpp
@@ -54,7 +54,9 @@ void ScriptApiEnv::environment_Step(float dtime)
try {
runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
} catch (LuaError &e) {
- getServer()->setAsyncFatalError(e.what());
+ getServer()->setAsyncFatalError(
+ std::string("environment_Step: ") + e.what() + "\n"
+ + script_get_backtrace(L));
}
}
@@ -75,7 +77,9 @@ void ScriptApiEnv::player_event(ServerActiveObject *player, const std::string &t
try {
runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
} catch (LuaError &e) {
- getServer()->setAsyncFatalError(e.what());
+ getServer()->setAsyncFatalError(
+ std::string("player_event: ") + e.what() + "\n"
+ + script_get_backtrace(L) );
}
}
@@ -237,7 +241,9 @@ void ScriptApiEnv::on_emerge_area_completion(
try {
PCALL_RES(lua_pcall(L, 4, 0, error_handler));
} catch (LuaError &e) {
- server->setAsyncFatalError(e.what());
+ server->setAsyncFatalError(
+ std::string("on_emerge_area_completion: ") + e.what() + "\n"
+ + script_get_backtrace(L));
}
lua_pop(L, 1); // Pop error handler
diff --git a/src/script/cpp_api/s_item.cpp b/src/script/cpp_api/s_item.cpp
index 3c84fb8cf..032018f2f 100644
--- a/src/script/cpp_api/s_item.cpp
+++ b/src/script/cpp_api/s_item.cpp
@@ -47,7 +47,7 @@ bool ScriptApiItem::item_OnDrop(ItemStack &item,
PCALL_RES(lua_pcall(L, 3, 1, error_handler));
if (!lua_isnil(L, -1)) {
try {
- item = read_item(L,-1, getServer());
+ item = read_item(L, -1, getServer()->idef());
} catch (LuaError &e) {
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
@@ -74,7 +74,7 @@ bool ScriptApiItem::item_OnPlace(ItemStack &item,
PCALL_RES(lua_pcall(L, 3, 1, error_handler));
if (!lua_isnil(L, -1)) {
try {
- item = read_item(L,-1, getServer());
+ item = read_item(L, -1, getServer()->idef());
} catch (LuaError &e) {
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
@@ -101,7 +101,7 @@ bool ScriptApiItem::item_OnUse(ItemStack &item,
PCALL_RES(lua_pcall(L, 3, 1, error_handler));
if(!lua_isnil(L, -1)) {
try {
- item = read_item(L,-1, getServer());
+ item = read_item(L, -1, getServer()->idef());
} catch (LuaError &e) {
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
@@ -127,7 +127,7 @@ bool ScriptApiItem::item_OnSecondaryUse(ItemStack &item, ServerActiveObject *use
PCALL_RES(lua_pcall(L, 3, 1, error_handler));
if (!lua_isnil(L, -1)) {
try {
- item = read_item(L, -1, getServer());
+ item = read_item(L, -1, getServer()->idef());
} catch (LuaError &e) {
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
@@ -159,7 +159,7 @@ bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user,
PCALL_RES(lua_pcall(L, 4, 1, error_handler));
if (!lua_isnil(L, -1)) {
try {
- item = read_item(L,-1, getServer());
+ item = read_item(L, -1, getServer()->idef());
} catch (LuaError &e) {
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
@@ -191,7 +191,7 @@ bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user,
PCALL_RES(lua_pcall(L, 4, 1, error_handler));
if (!lua_isnil(L, -1)) {
try {
- item = read_item(L,-1, getServer());
+ item = read_item(L, -1, getServer()->idef());
} catch (LuaError &e) {
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
@@ -249,27 +249,6 @@ void ScriptApiItem::pushPointedThing(const PointedThing& pointed)
{
lua_State* L = getStack();
- lua_newtable(L);
- if(pointed.type == POINTEDTHING_NODE)
- {
- lua_pushstring(L, "node");
- lua_setfield(L, -2, "type");
- push_v3s16(L, pointed.node_undersurface);
- lua_setfield(L, -2, "under");
- push_v3s16(L, pointed.node_abovesurface);
- lua_setfield(L, -2, "above");
- }
- else if(pointed.type == POINTEDTHING_OBJECT)
- {
- lua_pushstring(L, "object");
- lua_setfield(L, -2, "type");
- objectrefGet(L, pointed.object_id);
- lua_setfield(L, -2, "ref");
- }
- else
- {
- lua_pushstring(L, "nothing");
- lua_setfield(L, -2, "type");
- }
+ push_pointed_thing(L, pointed);
}
diff --git a/src/script/cpp_api/s_mainmenu.cpp b/src/script/cpp_api/s_mainmenu.cpp
index e9a7a13b9..1e9ba3a41 100644
--- a/src/script/cpp_api/s_mainmenu.cpp
+++ b/src/script/cpp_api/s_mainmenu.cpp
@@ -34,8 +34,7 @@ void ScriptApiMainMenu::setMainMenuData(MainMenuDataForScript *data)
lua_pushnil(L);
}
lua_settable(L, gamedata_idx);
- setboolfield(L, gamedata_idx, "reconnect_requested",
- data->reconnect_requested);
+ setboolfield(L, gamedata_idx, "reconnect_requested", data->reconnect_requested);
lua_pop(L, 1);
}
@@ -58,7 +57,7 @@ void ScriptApiMainMenu::handleMainMenuEvent(std::string text)
// Call it
lua_pushstring(L, text.c_str());
PCALL_RES(lua_pcall(L, 1, 0, error_handler));
- lua_pop(L, 1); // Pop error handler
+ lua_pop(L, 1); // Pop error handler
}
void ScriptApiMainMenu::handleMainMenuButtons(const StringMap &fields)
@@ -90,6 +89,5 @@ void ScriptApiMainMenu::handleMainMenuButtons(const StringMap &fields)
// Call it
PCALL_RES(lua_pcall(L, 1, 0, error_handler));
- lua_pop(L, 1); // Pop error handler
+ lua_pop(L, 1); // Pop error handler
}
-
diff --git a/src/script/cpp_api/s_node.cpp b/src/script/cpp_api/s_node.cpp
index 379ed773f..1ae8f58a5 100644
--- a/src/script/cpp_api/s_node.cpp
+++ b/src/script/cpp_api/s_node.cpp
@@ -59,6 +59,10 @@ struct EnumString ScriptApiNode::es_ContentParamType2[] =
{CPT2_LEVELED, "leveled"},
{CPT2_DEGROTATE, "degrotate"},
{CPT2_MESHOPTIONS, "meshoptions"},
+ {CPT2_COLOR, "color"},
+ {CPT2_COLORED_FACEDIR, "colorfacedir"},
+ {CPT2_COLORED_WALLMOUNTED, "colorwallmounted"},
+ {CPT2_GLASSLIKE_LIQUID_LEVEL, "glasslikeliquidlevel"},
{0, NULL},
};
@@ -174,6 +178,27 @@ void ScriptApiNode::node_on_destruct(v3s16 p, MapNode node)
lua_pop(L, 1); // Pop error handler
}
+bool ScriptApiNode::node_on_flood(v3s16 p, MapNode node, MapNode newnode)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
+ INodeDefManager *ndef = getServer()->ndef();
+
+ // Push callback function on stack
+ if (!getItemCallback(ndef->get(node).name.c_str(), "on_flood"))
+ return false;
+
+ // Call function
+ push_v3s16(L, p);
+ pushnode(L, node, ndef);
+ pushnode(L, newnode, ndef);
+ PCALL_RES(lua_pcall(L, 3, 1, error_handler));
+ lua_remove(L, error_handler);
+ return (bool) lua_isboolean(L, -1) && (bool) lua_toboolean(L, -1) == true;
+}
+
void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node)
{
SCRIPTAPI_PRECHECKHEADER
@@ -238,7 +263,7 @@ void ScriptApiNode::node_on_receive_fields(v3s16 p,
lua_pushstring(L, formname.c_str()); // formname
lua_newtable(L); // fields
StringMap::const_iterator it;
- for (it = fields.begin(); it != fields.end(); it++) {
+ for (it = fields.begin(); it != fields.end(); ++it) {
const std::string &name = it->first;
const std::string &value = it->second;
lua_pushstring(L, name.c_str());
diff --git a/src/script/cpp_api/s_node.h b/src/script/cpp_api/s_node.h
index fe1180cb3..eb127909d 100644
--- a/src/script/cpp_api/s_node.h
+++ b/src/script/cpp_api/s_node.h
@@ -42,6 +42,7 @@ public:
ServerActiveObject *digger);
void node_on_construct(v3s16 p, MapNode node);
void node_on_destruct(v3s16 p, MapNode node);
+ bool node_on_flood(v3s16 p, MapNode node, MapNode newnode);
void node_after_destruct(v3s16 p, MapNode node);
bool node_on_timer(v3s16 p, MapNode node, f32 dtime);
void node_on_receive_fields(v3s16 p,
diff --git a/src/script/cpp_api/s_player.h b/src/script/cpp_api/s_player.h
index 86ee1b024..9b4611f9e 100644
--- a/src/script/cpp_api/s_player.h
+++ b/src/script/cpp_api/s_player.h
@@ -26,8 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
struct ToolCapabilities;
-class ScriptApiPlayer
- : virtual public ScriptApiBase
+class ScriptApiPlayer : virtual public ScriptApiBase
{
public:
virtual ~ScriptApiPlayer();
@@ -36,17 +35,16 @@ public:
void on_dieplayer(ServerActiveObject *player);
bool on_respawnplayer(ServerActiveObject *player);
bool on_prejoinplayer(const std::string &name, const std::string &ip,
- std::string *reason);
+ std::string *reason);
void on_joinplayer(ServerActiveObject *player);
void on_leaveplayer(ServerActiveObject *player, bool timeout);
void on_cheat(ServerActiveObject *player, const std::string &cheat_type);
- bool on_punchplayer(ServerActiveObject *player,
- ServerActiveObject *hitter, float time_from_last_punch,
- const ToolCapabilities *toolcap, v3f dir, s16 damage);
+ bool on_punchplayer(ServerActiveObject *player, ServerActiveObject *hitter,
+ float time_from_last_punch, const ToolCapabilities *toolcap,
+ v3f dir, s16 damage);
s16 on_player_hpchange(ServerActiveObject *player, s16 hp_change);
void on_playerReceiveFields(ServerActiveObject *player,
- const std::string &formname, const StringMap &fields);
+ const std::string &formname, const StringMap &fields);
};
-
#endif /* S_PLAYER_H_ */
diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp
index 1b1f148cd..5ad7947d5 100644
--- a/src/script/cpp_api/s_security.cpp
+++ b/src/script/cpp_api/s_security.cpp
@@ -99,7 +99,6 @@ void ScriptApiSecurity::initializeSecurity()
"clock",
"date",
"difftime",
- "exit",
"getenv",
"setlocale",
"time",
@@ -124,6 +123,7 @@ void ScriptApiSecurity::initializeSecurity()
"path",
"searchpath",
};
+#if USE_LUAJIT
static const char *jit_whitelist[] = {
"arch",
"flush",
@@ -135,37 +135,13 @@ void ScriptApiSecurity::initializeSecurity()
"version",
"version_num",
};
-
+#endif
m_secure = true;
lua_State *L = getStack();
- // Backup globals to the registry
- lua_getglobal(L, "_G");
- lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
-
- // Replace the global environment with an empty one
-#if LUA_VERSION_NUM <= 501
- int is_main = lua_pushthread(L); // Push the main thread
- FATAL_ERROR_IF(!is_main, "Security: ScriptApi's Lua state "
- "isn't the main Lua thread!");
-#endif
- lua_newtable(L); // Create new environment
- lua_pushvalue(L, -1);
- lua_setfield(L, -2, "_G"); // Set _G of new environment
-#if LUA_VERSION_NUM >= 502 // Lua >= 5.2
- // Set the global environment
- lua_rawseti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
-#else // Lua <= 5.1
- // Set the environment of the main thread
- FATAL_ERROR_IF(!lua_setfenv(L, -2), "Security: Unable to set "
- "environment of the main Lua thread!");
- lua_pop(L, 1); // Pop thread
-#endif
- // Get old globals
- lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
- int old_globals = lua_gettop(L);
+ int old_globals = backupGlobals(L);
// Copy safe base functions
@@ -224,7 +200,113 @@ void ScriptApiSecurity::initializeSecurity()
lua_setglobal(L, "package");
lua_pop(L, 1); // Pop old package
+#if USE_LUAJIT
+ // Copy safe jit functions, if they exist
+ lua_getfield(L, -1, "jit");
+ if (!lua_isnil(L, -1)) {
+ lua_newtable(L);
+ copy_safe(L, jit_whitelist, sizeof(jit_whitelist));
+ lua_setglobal(L, "jit");
+ }
+ lua_pop(L, 1); // Pop old jit
+#endif
+
+ lua_pop(L, 1); // Pop globals_backup
+}
+
+void ScriptApiSecurity::initializeSecurityClient()
+{
+ static const char *whitelist[] = {
+ "assert",
+ "core",
+ "collectgarbage",
+ "DIR_DELIM",
+ "error",
+ "getfenv",
+ "ipairs",
+ "next",
+ "pairs",
+ "pcall",
+ "print",
+ "rawequal",
+ "rawget",
+ "rawset",
+ "select",
+ "setfenv",
+ "setmetatable",
+ "tonumber",
+ "tostring",
+ "type",
+ "unpack",
+ "_VERSION",
+ "xpcall",
+ // Completely safe libraries
+ "coroutine",
+ "string",
+ "table",
+ "math",
+ };
+ static const char *os_whitelist[] = {
+ "clock",
+ "date",
+ "difftime",
+ "time",
+ "setlocale",
+ };
+ static const char *debug_whitelist[] = {
+ "getinfo",
+ };
+
+#if USE_LUAJIT
+ static const char *jit_whitelist[] = {
+ "arch",
+ "flush",
+ "off",
+ "on",
+ "opt",
+ "os",
+ "status",
+ "version",
+ "version_num",
+ };
+#endif
+
+ m_secure = true;
+
+ lua_State *L = getStack();
+
+
+ int old_globals = backupGlobals(L);
+
+
+ // Copy safe base functions
+ lua_getglobal(L, "_G");
+ copy_safe(L, whitelist, sizeof(whitelist));
+
+ // And replace unsafe ones
+ SECURE_API(g, dofile);
+ SECURE_API(g, loadstring);
+ SECURE_API(g, require);
+ lua_pop(L, 1);
+
+
+
+ // Copy safe OS functions
+ lua_getfield(L, old_globals, "os");
+ lua_newtable(L);
+ copy_safe(L, os_whitelist, sizeof(os_whitelist));
+ lua_setglobal(L, "os");
+ lua_pop(L, 1); // Pop old OS
+
+
+ // Copy safe debug functions
+ lua_getfield(L, old_globals, "debug");
+ lua_newtable(L);
+ copy_safe(L, debug_whitelist, sizeof(debug_whitelist));
+ lua_setglobal(L, "debug");
+ lua_pop(L, 1); // Pop old debug
+#if USE_LUAJIT
// Copy safe jit functions, if they exist
lua_getfield(L, -1, "jit");
if (!lua_isnil(L, -1)) {
@@ -233,10 +315,40 @@ void ScriptApiSecurity::initializeSecurity()
lua_setglobal(L, "jit");
}
lua_pop(L, 1); // Pop old jit
+#endif
lua_pop(L, 1); // Pop globals_backup
}
+int ScriptApiSecurity::backupGlobals(lua_State *L)
+{
+ // Backup globals to the registry
+ lua_getglobal(L, "_G");
+ lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
+
+ // Replace the global environment with an empty one
+#if LUA_VERSION_NUM <= 501
+ int is_main = lua_pushthread(L); // Push the main thread
+ FATAL_ERROR_IF(!is_main, "Security: ScriptApi's Lua state "
+ "isn't the main Lua thread!");
+#endif
+ lua_newtable(L); // Create new environment
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "_G"); // Set _G of new environment
+#if LUA_VERSION_NUM >= 502 // Lua >= 5.2
+ // Set the global environment
+ lua_rawseti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
+#else // Lua <= 5.1
+ // Set the environment of the main thread
+ FATAL_ERROR_IF(!lua_setfenv(L, -2), "Security: Unable to set "
+ "environment of the main Lua thread!");
+ lua_pop(L, 1); // Pop thread
+#endif
+
+ // Get old globals
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
+ return lua_gettop(L);
+}
bool ScriptApiSecurity::isSecure(lua_State *L)
{
@@ -294,7 +406,14 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path)
// Read the file
int ret = std::fseek(fp, 0, SEEK_END);
- CHECK_FILE_ERR(ret, fp);
+ if (ret) {
+ lua_pushfstring(L, "%s: %s", path, strerror(errno));
+ std::fclose(fp);
+ if (path) {
+ delete [] chunk_name;
+ }
+ return false;
+ }
size_t size = std::ftell(fp) - start;
char *code = new char[size];
@@ -383,9 +502,9 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI);
ScriptApiBase *script = (ScriptApiBase *) lua_touserdata(L, -1);
lua_pop(L, 1);
- const Server *server = script->getServer();
-
- if (!server) return false;
+ const IGameDef *gamedef = script->getGameDef();
+ if (!gamedef)
+ return false;
// Get mod name
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
@@ -401,7 +520,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
// Allow paths in mod path
// Don't bother if write access isn't important, since it will be handled later
if (write_required || write_allowed != NULL) {
- const ModSpec *mod = server->getModSpec(mod_name);
+ const ModSpec *mod = gamedef->getModSpec(mod_name);
if (mod) {
str = fs::AbsolutePath(mod->path);
if (!str.empty() && fs::PathStartsWith(abs_path, str)) {
@@ -415,7 +534,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
// Allow read-only access to all mod directories
if (!write_required) {
- const std::vector<ModSpec> mods = server->getMods();
+ const std::vector<ModSpec> mods = gamedef->getMods();
for (size_t i = 0; i < mods.size(); ++i) {
str = fs::AbsolutePath(mods[i].path);
if (!str.empty() && fs::PathStartsWith(abs_path, str)) {
@@ -424,7 +543,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
}
}
- str = fs::AbsolutePath(server->getWorldPath());
+ str = fs::AbsolutePath(gamedef->getWorldPath());
if (!str.empty()) {
// Don't allow access to other paths in the world mod/game path.
// These have to be blocked so you can't override a trusted mod
diff --git a/src/script/cpp_api/s_security.h b/src/script/cpp_api/s_security.h
index 6876108e8..f0eef00bb 100644
--- a/src/script/cpp_api/s_security.h
+++ b/src/script/cpp_api/s_security.h
@@ -41,8 +41,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class ScriptApiSecurity : virtual public ScriptApiBase
{
public:
+ int backupGlobals(lua_State *L);
// Sets up security on the ScriptApi's Lua state
void initializeSecurity();
+ void initializeSecurityClient();
// Checks if the Lua state has been secured
static bool isSecure(lua_State *L);
// Loads a file as Lua code safely (doesn't allow bytecode).
diff --git a/src/script/lua_api/CMakeLists.txt b/src/script/lua_api/CMakeLists.txt
index d507dcf70..1a78580e6 100644
--- a/src/script/lua_api/CMakeLists.txt
+++ b/src/script/lua_api/CMakeLists.txt
@@ -5,7 +5,9 @@ set(common_SCRIPT_LUA_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/l_env.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_inventory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_item.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/l_itemstackmeta.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_mapgen.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/l_metadata.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_nodemeta.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_nodetimer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_noise.cpp
@@ -13,6 +15,7 @@ set(common_SCRIPT_LUA_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/l_particles.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_rollback.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_server.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/l_storage.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_util.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_vmanip.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_settings.cpp
@@ -20,6 +23,11 @@ set(common_SCRIPT_LUA_API_SRCS
PARENT_SCOPE)
set(client_SCRIPT_LUA_API_SRCS
+ ${CMAKE_CURRENT_SOURCE_DIR}/l_client.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_mainmenu.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/l_minimap.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/l_storage.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/l_sound.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/l_localplayer.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/l_camera.cpp
PARENT_SCOPE)
-
diff --git a/src/script/lua_api/l_areastore.cpp b/src/script/lua_api/l_areastore.cpp
index 09a5c78f9..b81985a7f 100644
--- a/src/script/lua_api/l_areastore.cpp
+++ b/src/script/lua_api/l_areastore.cpp
@@ -74,7 +74,7 @@ static inline void push_areas(lua_State *L, const std::vector<Area *> &areas,
static int deserialization_helper(lua_State *L, AreaStore *as,
std::istream &is)
{
- try {
+ try {
as->deserialize(is);
} catch (const SerializationError &e) {
lua_pushboolean(L, false);
@@ -380,7 +380,7 @@ void LuaAreaStore::Register(lua_State *L)
}
const char LuaAreaStore::className[] = "AreaStore";
-const luaL_reg LuaAreaStore::methods[] = {
+const luaL_Reg LuaAreaStore::methods[] = {
luamethod(LuaAreaStore, get_area),
luamethod(LuaAreaStore, get_areas_for_pos),
luamethod(LuaAreaStore, get_areas_in_area),
diff --git a/src/script/lua_api/l_areastore.h b/src/script/lua_api/l_areastore.h
index 4bd94cebe..8292e7712 100644
--- a/src/script/lua_api/l_areastore.h
+++ b/src/script/lua_api/l_areastore.h
@@ -22,14 +22,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_base.h"
-
class AreaStore;
-class LuaAreaStore : public ModApiBase {
+class LuaAreaStore : public ModApiBase
+{
private:
-
static const char className[];
- static const luaL_reg methods[];
+ static const luaL_Reg methods[];
static int gc_object(lua_State *L);
diff --git a/src/script/lua_api/l_base.cpp b/src/script/lua_api/l_base.cpp
index 515a7d933..5d7ba9640 100644
--- a/src/script/lua_api/l_base.cpp
+++ b/src/script/lua_api/l_base.cpp
@@ -37,6 +37,18 @@ Server *ModApiBase::getServer(lua_State *L)
return getScriptApiBase(L)->getServer();
}
+#ifndef SERVER
+Client *ModApiBase::getClient(lua_State *L)
+{
+ return getScriptApiBase(L)->getClient();
+}
+#endif
+
+IGameDef *ModApiBase::getGameDef(lua_State *L)
+{
+ return getScriptApiBase(L)->getGameDef();
+}
+
Environment *ModApiBase::getEnv(lua_State *L)
{
return getScriptApiBase(L)->getEnv();
@@ -62,17 +74,13 @@ std::string ModApiBase::getCurrentModPath(lua_State *L)
}
-bool ModApiBase::registerFunction(
- lua_State *L,
- const char *name,
- lua_CFunction fct,
- int top)
+bool ModApiBase::registerFunction(lua_State *L, const char *name,
+ lua_CFunction func, int top)
{
- //TODO check presence first!
+ // TODO: Check presence first!
- lua_pushstring(L,name);
- lua_pushcfunction(L,fct);
- lua_settable(L, top);
+ lua_pushcfunction(L, func);
+ lua_setfield(L, top, name);
return true;
}
diff --git a/src/script/lua_api/l_base.h b/src/script/lua_api/l_base.h
index 641013dfd..af89afd93 100644
--- a/src/script/lua_api/l_base.h
+++ b/src/script/lua_api/l_base.h
@@ -22,12 +22,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common/c_types.h"
#include "common/c_internal.h"
+#include "gamedef.h"
extern "C" {
#include <lua.h>
#include <lauxlib.h>
}
+#ifndef SERVER
+#include "client.h"
+#endif
+
class ScriptApiBase;
class Server;
class Environment;
@@ -38,6 +43,12 @@ class ModApiBase {
public:
static ScriptApiBase* getScriptApiBase(lua_State *L);
static Server* getServer(lua_State *L);
+ #ifndef SERVER
+ static Client* getClient(lua_State *L);
+ #endif // !SERVER
+
+ static IGameDef* getGameDef(lua_State *L);
+
static Environment* getEnv(lua_State *L);
static GUIEngine* getGuiEngine(lua_State *L);
// When we are not loading the mod, this function returns "."
@@ -57,9 +68,8 @@ public:
static bool registerFunction(lua_State *L,
const char* name,
- lua_CFunction fct,
- int top
- );
+ lua_CFunction func,
+ int top);
};
#endif /* L_BASE_H_ */
diff --git a/src/script/lua_api/l_camera.cpp b/src/script/lua_api/l_camera.cpp
new file mode 100644
index 000000000..862384198
--- /dev/null
+++ b/src/script/lua_api/l_camera.cpp
@@ -0,0 +1,202 @@
+#include "script/common/c_converter.h"
+#include "l_camera.h"
+#include "l_internal.h"
+#include "content_cao.h"
+#include "camera.h"
+
+LuaCamera::LuaCamera(Camera *m)
+{
+ m_camera = m;
+}
+
+void LuaCamera::create(lua_State *L, Camera *m)
+{
+ LuaCamera *o = new LuaCamera(m);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+
+ int camera_object = lua_gettop(L);
+
+ lua_getglobal(L, "core");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ int coretable = lua_gettop(L);
+
+ lua_pushvalue(L, camera_object);
+ lua_setfield(L, coretable, "camera");
+}
+
+int LuaCamera::l_set_camera_mode(lua_State *L)
+{
+ Camera *camera = getobject(L, 1);
+ GenericCAO *playercao = getClient(L)->getEnv().getLocalPlayer()->getCAO();
+ if (!camera)
+ return 0;
+ sanity_check(playercao);
+ if (!lua_isnumber(L, 2))
+ return 0;
+
+ camera->setCameraMode((CameraMode)((int)lua_tonumber(L, 2)));
+ playercao->setVisible(camera->getCameraMode() > CAMERA_MODE_FIRST);
+ playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST);
+ return 0;
+}
+
+int LuaCamera::l_get_camera_mode(lua_State *L)
+{
+ Camera *camera = getobject(L, 1);
+ if (!camera)
+ return 0;
+
+ lua_pushnumber(L, (int)camera->getCameraMode());
+
+ return 1;
+}
+
+int LuaCamera::l_get_fov(lua_State *L)
+{
+ Camera *camera = getobject(L, 1);
+ if (!camera)
+ return 0;
+
+ lua_newtable(L);
+ lua_pushnumber(L, camera->getFovX() * core::DEGTORAD);
+ lua_setfield(L, -2, "x");
+ lua_pushnumber(L, camera->getFovY() * core::DEGTORAD);
+ lua_setfield(L, -2, "y");
+ lua_pushnumber(L, camera->getCameraNode()->getFOV() * core::RADTODEG);
+ lua_setfield(L, -2, "actual");
+ lua_pushnumber(L, camera->getFovMax() * core::RADTODEG);
+ lua_setfield(L, -2, "max");
+ return 1;
+}
+
+int LuaCamera::l_get_pos(lua_State *L)
+{
+ Camera *camera = getobject(L, 1);
+ if (!camera)
+ return 0;
+
+ push_v3f(L, camera->getPosition());
+ return 1;
+}
+
+int LuaCamera::l_get_offset(lua_State *L)
+{
+ Camera *camera = getobject(L, 1);
+ if (!camera)
+ return 0;
+
+ push_v3s16(L, camera->getOffset());
+ return 1;
+}
+
+int LuaCamera::l_get_look_dir(lua_State *L)
+{
+ LocalPlayer *player = getClient(L)->getEnv().getLocalPlayer();
+ sanity_check(player);
+
+ float pitch = -1.0 * player->getPitch() * core::DEGTORAD;
+ float yaw = (player->getYaw() + 90.) * core::DEGTORAD;
+ v3f v(cos(pitch) * cos(yaw), sin(pitch), cos(pitch) * sin(yaw));
+
+ push_v3f(L, v);
+ return 1;
+}
+
+int LuaCamera::l_get_look_horizontal(lua_State *L)
+{
+ LocalPlayer *player = getClient(L)->getEnv().getLocalPlayer();
+ sanity_check(player);
+
+ lua_pushnumber(L, (player->getYaw() + 90.) * core::DEGTORAD);
+ return 1;
+}
+
+int LuaCamera::l_get_look_vertical(lua_State *L)
+{
+ LocalPlayer *player = getClient(L)->getEnv().getLocalPlayer();
+ sanity_check(player);
+
+ lua_pushnumber(L, -1.0 * player->getPitch() * core::DEGTORAD);
+ return 1;
+}
+
+int LuaCamera::l_get_aspect_ratio(lua_State *L)
+{
+ Camera *camera = getobject(L, 1);
+ if (!camera)
+ return 0;
+
+ lua_pushnumber(L, camera->getCameraNode()->getAspectRatio());
+ return 1;
+}
+
+LuaCamera *LuaCamera::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+
+ void *ud = luaL_checkudata(L, narg, className);
+ if (!ud)
+ luaL_typerror(L, narg, className);
+
+ return *(LuaCamera **)ud;
+}
+
+Camera *LuaCamera::getobject(LuaCamera *ref)
+{
+ return ref->m_camera;
+}
+
+Camera *LuaCamera::getobject(lua_State *L, int narg)
+{
+ LuaCamera *ref = checkobject(L, narg);
+ assert(ref);
+ Camera *camera = getobject(ref);
+ if (!camera)
+ return NULL;
+ return camera;
+}
+
+int LuaCamera::gc_object(lua_State *L)
+{
+ LuaCamera *o = *(LuaCamera **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+void LuaCamera::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1);
+
+ luaL_openlib(L, 0, methods, 0);
+ lua_pop(L, 1);
+}
+
+const char LuaCamera::className[] = "Camera";
+const luaL_Reg LuaCamera::methods[] = {luamethod(LuaCamera, set_camera_mode),
+ luamethod(LuaCamera, get_camera_mode), luamethod(LuaCamera, get_fov),
+ luamethod(LuaCamera, get_pos), luamethod(LuaCamera, get_offset),
+ luamethod(LuaCamera, get_look_dir),
+ luamethod(LuaCamera, get_look_vertical),
+ luamethod(LuaCamera, get_look_horizontal),
+ luamethod(LuaCamera, get_aspect_ratio),
+
+ {0, 0}};
diff --git a/src/script/lua_api/l_camera.h b/src/script/lua_api/l_camera.h
new file mode 100644
index 000000000..04921ad03
--- /dev/null
+++ b/src/script/lua_api/l_camera.h
@@ -0,0 +1,44 @@
+#ifndef L_CAMERA_H
+#define L_CAMERA_H
+
+#include "l_base.h"
+
+class Camera;
+
+class LuaCamera : public ModApiBase
+{
+private:
+ static const char className[];
+ static const luaL_Reg methods[];
+
+ // garbage collector
+ static int gc_object(lua_State *L);
+
+ static int l_set_camera_mode(lua_State *L);
+ static int l_get_camera_mode(lua_State *L);
+
+ static int l_get_fov(lua_State *L);
+
+ static int l_get_pos(lua_State *L);
+ static int l_get_offset(lua_State *L);
+ static int l_get_look_dir(lua_State *L);
+ static int l_get_look_vertical(lua_State *L);
+ static int l_get_look_horizontal(lua_State *L);
+ static int l_get_aspect_ratio(lua_State *L);
+
+ Camera *m_camera;
+
+public:
+ LuaCamera(Camera *m);
+ ~LuaCamera() {}
+
+ static void create(lua_State *L, Camera *m);
+
+ static LuaCamera *checkobject(lua_State *L, int narg);
+ static Camera *getobject(LuaCamera *ref);
+ static Camera *getobject(lua_State *L, int narg);
+
+ static void Register(lua_State *L);
+};
+
+#endif // L_CAMERA_H
diff --git a/src/script/lua_api/l_client.cpp b/src/script/lua_api/l_client.cpp
new file mode 100644
index 000000000..3c2955bcd
--- /dev/null
+++ b/src/script/lua_api/l_client.cpp
@@ -0,0 +1,356 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "l_client.h"
+#include "clientenvironment.h"
+#include "common/c_content.h"
+#include "common/c_converter.h"
+#include "cpp_api/s_base.h"
+#include "gettext.h"
+#include "l_internal.h"
+#include "lua_api/l_item.h"
+#include "lua_api/l_nodemeta.h"
+#include "mainmenumanager.h"
+#include "map.h"
+#include "util/string.h"
+#include "nodedef.h"
+
+extern MainGameCallback *g_gamecallback;
+
+int ModApiClient::l_get_current_modname(lua_State *L)
+{
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
+ return 1;
+}
+
+// get_last_run_mod()
+int ModApiClient::l_get_last_run_mod(lua_State *L)
+{
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
+ const char *current_mod = lua_tostring(L, -1);
+ if (current_mod == NULL || current_mod[0] == '\0') {
+ lua_pop(L, 1);
+ lua_pushstring(L, getScriptApiBase(L)->getOrigin().c_str());
+ }
+ return 1;
+}
+
+// set_last_run_mod(modname)
+int ModApiClient::l_set_last_run_mod(lua_State *L)
+{
+ if (!lua_isstring(L, 1))
+ return 0;
+
+ const char *mod = lua_tostring(L, 1);
+ getScriptApiBase(L)->setOriginDirect(mod);
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+// print(text)
+int ModApiClient::l_print(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ std::string text = luaL_checkstring(L, 1);
+ rawstream << text << std::endl;
+ return 0;
+}
+
+// display_chat_message(message)
+int ModApiClient::l_display_chat_message(lua_State *L)
+{
+ if (!lua_isstring(L, 1))
+ return 0;
+
+ std::string message = luaL_checkstring(L, 1);
+ getClient(L)->pushToChatQueue(utf8_to_wide(message));
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+// send_chat_message(message)
+int ModApiClient::l_send_chat_message(lua_State *L)
+{
+ if (!lua_isstring(L, 1))
+ return 0;
+ std::string message = luaL_checkstring(L, 1);
+ getClient(L)->sendChatMessage(utf8_to_wide(message));
+ return 0;
+}
+
+// clear_out_chat_queue()
+int ModApiClient::l_clear_out_chat_queue(lua_State *L)
+{
+ getClient(L)->clearOutChatQueue();
+ return 0;
+}
+
+// get_player_names()
+int ModApiClient::l_get_player_names(lua_State *L)
+{
+ const std::list<std::string> &plist = getClient(L)->getConnectedPlayerNames();
+ lua_createtable(L, plist.size(), 0);
+ int newTable = lua_gettop(L);
+ int index = 1;
+ std::list<std::string>::const_iterator iter;
+ for (iter = plist.begin(); iter != plist.end(); ++iter) {
+ lua_pushstring(L, (*iter).c_str());
+ lua_rawseti(L, newTable, index);
+ index++;
+ }
+ return 1;
+}
+
+// show_formspec(formspec)
+int ModApiClient::l_show_formspec(lua_State *L)
+{
+ if (!lua_isstring(L, 1) || !lua_isstring(L, 2))
+ return 0;
+
+ ClientEvent event;
+ event.type = CE_SHOW_LOCAL_FORMSPEC;
+ event.show_formspec.formname = new std::string(luaL_checkstring(L, 1));
+ event.show_formspec.formspec = new std::string(luaL_checkstring(L, 2));
+ getClient(L)->pushToEventQueue(event);
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+// send_respawn()
+int ModApiClient::l_send_respawn(lua_State *L)
+{
+ getClient(L)->sendRespawn();
+ return 0;
+}
+
+// disconnect()
+int ModApiClient::l_disconnect(lua_State *L)
+{
+ // Stops badly written Lua code form causing boot loops
+ if (getClient(L)->isShutdown()) {
+ lua_pushboolean(L, false);
+ return 1;
+ }
+
+ g_gamecallback->disconnect();
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+// gettext(text)
+int ModApiClient::l_gettext(lua_State *L)
+{
+ std::string text = strgettext(std::string(luaL_checkstring(L, 1)));
+ lua_pushstring(L, text.c_str());
+
+ return 1;
+}
+
+// get_node(pos)
+// pos = {x=num, y=num, z=num}
+int ModApiClient::l_get_node(lua_State *L)
+{
+ // pos
+ v3s16 pos = read_v3s16(L, 1);
+ // Do it
+ bool pos_ok;
+ MapNode n = getClient(L)->getNode(pos, &pos_ok);
+ // Return node
+ pushnode(L, n, getClient(L)->ndef());
+ return 1;
+}
+
+// get_node_or_nil(pos)
+// pos = {x=num, y=num, z=num}
+int ModApiClient::l_get_node_or_nil(lua_State *L)
+{
+ // pos
+ v3s16 pos = read_v3s16(L, 1);
+ // Do it
+ bool pos_ok;
+ MapNode n = getClient(L)->getNode(pos, &pos_ok);
+ if (pos_ok) {
+ // Return node
+ pushnode(L, n, getClient(L)->ndef());
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+int ModApiClient::l_get_wielded_item(lua_State *L)
+{
+ Client *client = getClient(L);
+
+ Inventory local_inventory(client->idef());
+ client->getLocalInventory(local_inventory);
+
+ InventoryList *mlist = local_inventory.getList("main");
+
+ if (mlist && client->getPlayerItem() < mlist->getSize()) {
+ LuaItemStack::create(L, mlist->getItem(client->getPlayerItem()));
+ } else {
+ LuaItemStack::create(L, ItemStack());
+ }
+ return 1;
+}
+
+// get_meta(pos)
+int ModApiClient::l_get_meta(lua_State *L)
+{
+ v3s16 p = read_v3s16(L, 1);
+ NodeMetadata *meta = getClient(L)->getEnv().getMap().getNodeMetadata(p);
+ NodeMetaRef::createClient(L, meta);
+ return 1;
+}
+
+int ModApiClient::l_sound_play(lua_State *L)
+{
+ ISoundManager *sound = getClient(L)->getSoundManager();
+
+ SimpleSoundSpec spec;
+ read_soundspec(L, 1, spec);
+ float gain = 1.0;
+ bool looped = false;
+ s32 handle;
+
+ if (lua_istable(L, 2)) {
+ getfloatfield(L, 2, "gain", gain);
+ getboolfield(L, 2, "loop", looped);
+
+ lua_getfield(L, 2, "pos");
+ if (!lua_isnil(L, -1)) {
+ v3f pos = read_v3f(L, -1) * BS;
+ lua_pop(L, 1);
+ handle = sound->playSoundAt(
+ spec.name, looped, gain * spec.gain, pos);
+ lua_pushinteger(L, handle);
+ return 1;
+ }
+ }
+
+ handle = sound->playSound(spec.name, looped, gain * spec.gain);
+ lua_pushinteger(L, handle);
+
+ return 1;
+}
+
+int ModApiClient::l_sound_stop(lua_State *L)
+{
+ u32 handle = luaL_checkinteger(L, 1);
+
+ getClient(L)->getSoundManager()->stopSound(handle);
+
+ return 0;
+}
+
+// get_server_info()
+int ModApiClient::l_get_server_info(lua_State *L)
+{
+ Client *client = getClient(L);
+ Address serverAddress = client->getServerAddress();
+ lua_newtable(L);
+ lua_pushstring(L, client->getAddressName().c_str());
+ lua_setfield(L, -2, "address");
+ lua_pushstring(L, serverAddress.serializeString().c_str());
+ lua_setfield(L, -2, "ip");
+ lua_pushinteger(L, serverAddress.getPort());
+ lua_setfield(L, -2, "port");
+ lua_pushinteger(L, client->getProtoVersion());
+ lua_setfield(L, -2, "protocol_version");
+ return 1;
+}
+
+// get_item_def(itemstring)
+int ModApiClient::l_get_item_def(lua_State *L)
+{
+ IGameDef *gdef = getGameDef(L);
+ assert(gdef);
+
+ IItemDefManager *idef = gdef->idef();
+ assert(idef);
+
+ if (!lua_isstring(L, 1))
+ return 0;
+
+ const std::string &name(lua_tostring(L, 1));
+ if (!idef->isKnown(name))
+ return 0;
+ const ItemDefinition &def = idef->get(name);
+
+ push_item_definition_full(L, def);
+
+ return 1;
+}
+
+// get_node_def(nodename)
+int ModApiClient::l_get_node_def(lua_State *L)
+{
+ IGameDef *gdef = getGameDef(L);
+ assert(gdef);
+
+ INodeDefManager *ndef = gdef->ndef();
+ assert(ndef);
+
+ if (!lua_isstring(L, 1))
+ return 0;
+
+ const std::string &name = lua_tostring(L, 1);
+ const ContentFeatures &cf = ndef->get(ndef->getId(name));
+ if (cf.name != name) // Unknown node. | name = <whatever>, cf.name = ignore
+ return 0;
+
+ push_content_features(L, cf);
+
+ return 1;
+}
+
+int ModApiClient::l_take_screenshot(lua_State *L)
+{
+ Client *client = getClient(L);
+ client->makeScreenshot(client->getDevice());
+ return 0;
+}
+
+void ModApiClient::Initialize(lua_State *L, int top)
+{
+ API_FCT(get_current_modname);
+ API_FCT(print);
+ API_FCT(display_chat_message);
+ API_FCT(send_chat_message);
+ API_FCT(clear_out_chat_queue);
+ API_FCT(get_player_names);
+ API_FCT(set_last_run_mod);
+ API_FCT(get_last_run_mod);
+ API_FCT(show_formspec);
+ API_FCT(send_respawn);
+ API_FCT(gettext);
+ API_FCT(get_node);
+ API_FCT(get_node_or_nil);
+ API_FCT(get_wielded_item);
+ API_FCT(disconnect);
+ API_FCT(get_meta);
+ API_FCT(sound_play);
+ API_FCT(sound_stop);
+ API_FCT(get_server_info);
+ API_FCT(get_item_def);
+ API_FCT(get_node_def);
+ API_FCT(take_screenshot);
+}
diff --git a/src/script/lua_api/l_client.h b/src/script/lua_api/l_client.h
new file mode 100644
index 000000000..fe5780fb1
--- /dev/null
+++ b/src/script/lua_api/l_client.h
@@ -0,0 +1,98 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 L_CLIENT_H_
+#define L_CLIENT_H_
+
+#include "lua_api/l_base.h"
+#include "itemdef.h"
+#include "tool.h"
+
+class ModApiClient : public ModApiBase
+{
+private:
+ // get_current_modname()
+ static int l_get_current_modname(lua_State *L);
+
+ // print(text)
+ static int l_print(lua_State *L);
+
+ // display_chat_message(message)
+ static int l_display_chat_message(lua_State *L);
+
+ // send_chat_message(message)
+ static int l_send_chat_message(lua_State *L);
+
+ // clear_out_chat_queue()
+ static int l_clear_out_chat_queue(lua_State *L);
+
+ // get_player_names()
+ static int l_get_player_names(lua_State *L);
+
+ // show_formspec(name, formspec)
+ static int l_show_formspec(lua_State *L);
+
+ // send_respawn()
+ static int l_send_respawn(lua_State *L);
+
+ // disconnect()
+ static int l_disconnect(lua_State *L);
+
+ // gettext(text)
+ static int l_gettext(lua_State *L);
+
+ // get_last_run_mod(n)
+ static int l_get_last_run_mod(lua_State *L);
+
+ // set_last_run_mod(modname)
+ static int l_set_last_run_mod(lua_State *L);
+
+ // get_node(pos)
+ static int l_get_node(lua_State *L);
+
+ // get_node_or_nil(pos)
+ static int l_get_node_or_nil(lua_State *L);
+
+ // get_wielded_item()
+ static int l_get_wielded_item(lua_State *L);
+
+ // get_meta(pos)
+ static int l_get_meta(lua_State *L);
+
+ static int l_sound_play(lua_State *L);
+
+ static int l_sound_stop(lua_State *L);
+
+ // get_server_info()
+ static int l_get_server_info(lua_State *L);
+
+ // get_item_def(itemstring)
+ static int l_get_item_def(lua_State *L);
+
+ // get_node_def(nodename)
+ static int l_get_node_def(lua_State *L);
+
+ static int l_take_screenshot(lua_State *L);
+
+public:
+ static void Initialize(lua_State *L, int top);
+};
+
+#endif
diff --git a/src/script/lua_api/l_craft.cpp b/src/script/lua_api/l_craft.cpp
index 2236566de..315391856 100644
--- a/src/script/lua_api/l_craft.cpp
+++ b/src/script/lua_api/l_craft.cpp
@@ -414,7 +414,7 @@ static void push_craft_recipe(lua_State *L, IGameDef *gdef,
lua_newtable(L); // items
std::vector<ItemStack>::const_iterator iter = input.items.begin();
- for (u16 j = 1; iter != input.items.end(); iter++, j++) {
+ for (u16 j = 1; iter != input.items.end(); ++iter, j++) {
if (iter->empty())
continue;
lua_pushstring(L, iter->name.c_str());
diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp
index 68d10308c..b8b6bc5ba 100644
--- a/src/script/lua_api/l_env.cpp
+++ b/src/script/lua_api/l_env.cpp
@@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_vmanip.h"
#include "common/c_converter.h"
#include "common/c_content.h"
-#include "scripting_game.h"
+#include "scripting_server.h"
#include "environment.h"
#include "server.h"
#include "nodedef.h"
@@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "treegen.h"
#include "emerge.h"
#include "pathfinder.h"
+#include "face_position_cache.h"
struct EnumString ModApiEnvMod::es_ClearObjectsMode[] =
{
@@ -49,7 +50,7 @@ struct EnumString ModApiEnvMod::es_ClearObjectsMode[] =
void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
u32 active_object_count, u32 active_object_count_wider)
{
- GameScripting *scriptIface = env->getScriptIface();
+ ServerScripting *scriptIface = env->getScriptIface();
scriptIface->realityCheck();
lua_State *L = scriptIface->getStack();
@@ -92,7 +93,7 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n)
{
- GameScripting *scriptIface = env->getScriptIface();
+ ServerScripting *scriptIface = env->getScriptIface();
scriptIface->realityCheck();
lua_State *L = scriptIface->getStack();
@@ -284,7 +285,7 @@ int ModApiEnvMod::l_place_node(lua_State *L)
return 1;
}
// Create item to place
- ItemStack item(ndef->get(n).name, 1, 0, "", idef);
+ ItemStack item(ndef->get(n).name, 1, 0, idef);
// Make pointed position
PointedThing pointed;
pointed.type = POINTEDTHING_NODE;
@@ -347,7 +348,10 @@ int ModApiEnvMod::l_punch_node(lua_State *L)
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_get_node_max_level(lua_State *L)
{
- GET_ENV_PTR;
+ Environment *env = getEnv(L);
+ if (!env) {
+ return 0;
+ }
v3s16 pos = read_v3s16(L, 1);
MapNode n = env->getMap().getNodeNoEx(pos);
@@ -359,7 +363,10 @@ int ModApiEnvMod::l_get_node_max_level(lua_State *L)
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_get_node_level(lua_State *L)
{
- GET_ENV_PTR;
+ Environment *env = getEnv(L);
+ if (!env) {
+ return 0;
+ }
v3s16 pos = read_v3s16(L, 1);
MapNode n = env->getMap().getNodeNoEx(pos);
@@ -440,7 +447,7 @@ int ModApiEnvMod::l_get_node_timer(lua_State *L)
return 1;
}
-// add_entity(pos, entityname) -> ObjectRef or nil
+// add_entity(pos, entityname, [staticdata]) -> ObjectRef or nil
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_add_entity(lua_State *L)
{
@@ -450,8 +457,10 @@ int ModApiEnvMod::l_add_entity(lua_State *L)
v3f pos = checkFloatPos(L, 1);
// content
const char *name = luaL_checkstring(L, 2);
+ // staticdata
+ const char *staticdata = luaL_optstring(L, 3, "");
// Do it
- ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, "");
+ ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, staticdata);
int objectid = env->addActiveObject(obj);
// If failed to add, return nothing (reads as nil)
if(objectid == 0)
@@ -470,7 +479,7 @@ int ModApiEnvMod::l_add_item(lua_State *L)
// pos
//v3f pos = checkFloatPos(L, 1);
// item
- ItemStack item = read_item(L, 2,getServer(L));
+ ItemStack item = read_item(L, 2,getServer(L)->idef());
if(item.empty() || !item.isKnown(getServer(L)->idef()))
return 0;
@@ -526,7 +535,7 @@ int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L)
ScriptApiBase *script = getScriptApiBase(L);
lua_createtable(L, ids.size(), 0);
std::vector<u16>::const_iterator iter = ids.begin();
- for(u32 i = 0; iter != ids.end(); iter++) {
+ for(u32 i = 0; iter != ids.end(); ++iter) {
ServerActiveObject *obj = env->getActiveObject(*iter);
// Insert object reference into table
script->objectrefGetOrCreate(L, obj);
@@ -556,11 +565,14 @@ int ModApiEnvMod::l_set_timeofday(lua_State *L)
// get_timeofday() -> 0...1
int ModApiEnvMod::l_get_timeofday(lua_State *L)
{
- GET_ENV_PTR;
+ Environment *env = getEnv(L);
+ if (!env) {
+ return 0;
+ }
// Do it
int timeofday_mh = env->getTimeOfDay();
- float timeofday_f = (float)timeofday_mh / 24000.0;
+ float timeofday_f = (float)timeofday_mh / 24000.0f;
lua_pushnumber(L, timeofday_f);
return 1;
}
@@ -568,7 +580,10 @@ int ModApiEnvMod::l_get_timeofday(lua_State *L)
// get_day_count() -> int
int ModApiEnvMod::l_get_day_count(lua_State *L)
{
- GET_ENV_PTR;
+ Environment *env = getEnv(L);
+ if (!env) {
+ return 0;
+ }
lua_pushnumber(L, env->getDayCount());
return 1;
@@ -585,37 +600,40 @@ int ModApiEnvMod::l_get_gametime(lua_State *L)
}
-// find_node_near(pos, radius, nodenames) -> pos or nil
+// find_node_near(pos, radius, nodenames, search_center) -> pos or nil
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
int ModApiEnvMod::l_find_node_near(lua_State *L)
{
- GET_ENV_PTR;
+ Environment *env = getEnv(L);
+ if (!env) {
+ return 0;
+ }
- INodeDefManager *ndef = getServer(L)->ndef();
+ INodeDefManager *ndef = getGameDef(L)->ndef();
v3s16 pos = read_v3s16(L, 1);
int radius = luaL_checkinteger(L, 2);
std::set<content_t> filter;
- if(lua_istable(L, 3)){
- int table = 3;
+ if (lua_istable(L, 3)) {
lua_pushnil(L);
- while(lua_next(L, table) != 0){
+ while (lua_next(L, 3) != 0) {
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TSTRING);
ndef->getIds(lua_tostring(L, -1), filter);
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
- } else if(lua_isstring(L, 3)){
+ } else if (lua_isstring(L, 3)) {
ndef->getIds(lua_tostring(L, 3), filter);
}
- for(int d=1; d<=radius; d++){
+ int start_radius = (lua_toboolean(L, 4)) ? 0 : 1;
+ for (int d = start_radius; d <= radius; d++) {
std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
- for(std::vector<v3s16>::iterator i = list.begin();
- i != list.end(); ++i){
+ for (std::vector<v3s16>::iterator i = list.begin();
+ i != list.end(); ++i) {
v3s16 p = pos + (*i);
content_t c = env->getMap().getNodeNoEx(p).getContent();
- if(filter.count(c) != 0){
+ if (filter.count(c) != 0) {
push_v3s16(L, p);
return 1;
}
@@ -830,6 +848,36 @@ int ModApiEnvMod::l_line_of_sight(lua_State *L)
return 1;
}
+// fix_light(p1, p2)
+int ModApiEnvMod::l_fix_light(lua_State *L)
+{
+ GET_ENV_PTR;
+
+ v3s16 blockpos1 = getContainerPos(read_v3s16(L, 1), MAP_BLOCKSIZE);
+ v3s16 blockpos2 = getContainerPos(read_v3s16(L, 2), MAP_BLOCKSIZE);
+ ServerMap &map = env->getServerMap();
+ std::map<v3s16, MapBlock *> modified_blocks;
+ bool success = true;
+ v3s16 blockpos;
+ for (blockpos.X = blockpos1.X; blockpos.X <= blockpos2.X; blockpos.X++)
+ for (blockpos.Y = blockpos1.Y; blockpos.Y <= blockpos2.Y; blockpos.Y++)
+ for (blockpos.Z = blockpos1.Z; blockpos.Z <= blockpos2.Z; blockpos.Z++) {
+ success = success & map.repairBlockLight(blockpos, &modified_blocks);
+ }
+ if (modified_blocks.size() > 0) {
+ MapEditEvent event;
+ event.type = MEET_OTHER;
+ for (std::map<v3s16, MapBlock *>::iterator it = modified_blocks.begin();
+ it != modified_blocks.end(); ++it)
+ event.modified_blocks.insert(it->first);
+
+ map.dispatchEvent(&event);
+ }
+ lua_pushboolean(L, success);
+
+ return 1;
+}
+
// emerge_area(p1, p2, [callback, context])
// emerge mapblocks in area p1..p2, calls callback with context upon completion
int ModApiEnvMod::l_emerge_area(lua_State *L)
@@ -938,8 +986,7 @@ int ModApiEnvMod::l_find_path(lua_State *L)
lua_newtable(L);
int top = lua_gettop(L);
unsigned int index = 1;
- for (std::vector<v3s16>::iterator i = path.begin(); i != path.end();i++)
- {
+ for (std::vector<v3s16>::iterator i = path.begin(); i != path.end(); ++i) {
lua_pushnumber(L,index);
push_v3s16(L, *i);
lua_settable(L, top);
@@ -1072,6 +1119,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top)
API_FCT(find_node_near);
API_FCT(find_nodes_in_area);
API_FCT(find_nodes_in_area_under_air);
+ API_FCT(fix_light);
API_FCT(emerge_area);
API_FCT(delete_area);
API_FCT(get_perlin);
@@ -1085,3 +1133,12 @@ void ModApiEnvMod::Initialize(lua_State *L, int top)
API_FCT(forceload_block);
API_FCT(forceload_free_block);
}
+
+void ModApiEnvMod::InitializeClient(lua_State *L, int top)
+{
+ API_FCT(get_timeofday);
+ API_FCT(get_day_count);
+ API_FCT(get_node_max_level);
+ API_FCT(get_node_level);
+ API_FCT(find_node_near);
+}
diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h
index 89dd7978f..7ce19b085 100644
--- a/src/script/lua_api/l_env.h
+++ b/src/script/lua_api/l_env.h
@@ -21,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define L_ENV_H_
#include "lua_api/l_base.h"
-#include "environment.h"
+#include "serverenvironment.h"
class ModApiEnvMod : public ModApiBase {
private:
@@ -116,7 +116,7 @@ private:
// get_day_count() -> int
static int l_get_day_count(lua_State *L);
- // find_node_near(pos, radius, nodenames) -> pos or nil
+ // find_node_near(pos, radius, nodenames, search_center) -> pos or nil
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
static int l_find_node_near(lua_State *L);
@@ -128,6 +128,9 @@ private:
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
static int l_find_nodes_in_area_under_air(lua_State *L);
+ // fix_light(p1, p2) -> true/false
+ static int l_fix_light(lua_State *L);
+
// emerge_area(p1, p2)
static int l_emerge_area(lua_State *L);
@@ -173,6 +176,7 @@ private:
public:
static void Initialize(lua_State *L, int top);
+ static void InitializeClient(lua_State *L, int top);
static struct EnumString es_ClearObjectsMode[];
};
@@ -199,11 +203,11 @@ public:
m_simple_catch_up(simple_catch_up)
{
}
- virtual std::set<std::string> getTriggerContents()
+ virtual const std::set<std::string> &getTriggerContents() const
{
return m_trigger_contents;
}
- virtual std::set<std::string> getRequiredNeighbors()
+ virtual const std::set<std::string> &getRequiredNeighbors() const
{
return m_required_neighbors;
}
@@ -242,7 +246,7 @@ public:
};
struct ScriptCallbackState {
- GameScripting *script;
+ ServerScripting *script;
int callback_ref;
int args_ref;
unsigned int refcount;
diff --git a/src/script/lua_api/l_internal.h b/src/script/lua_api/l_internal.h
index 456c8fcce..e9b689931 100644
--- a/src/script/lua_api/l_internal.h
+++ b/src/script/lua_api/l_internal.h
@@ -30,22 +30,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common/c_internal.h"
#define luamethod(class, name) {#name, class::l_##name}
-#define API_FCT(name) registerFunction(L, #name, l_##name,top)
-#define ASYNC_API_FCT(name) engine.registerFunction(#name, l_##name)
+#define luamethod_aliased(class, name, alias) {#name, class::l_##name}, {#alias, class::l_##name}
+#define API_FCT(name) registerFunction(L, #name, l_##name, top)
#define MAP_LOCK_REQUIRED
#define NO_MAP_LOCK_REQUIRED
-/*
-#if (defined(WIN32) || defined(_WIN32_WCE))
- #define NO_MAP_LOCK_REQUIRED
-#else
- #include "profiler.h"
- #define NO_MAP_LOCK_REQUIRED \
- ScopeProfiler nolocktime(g_profiler,"Scriptapi: unlockable time",SPT_ADD)
-#endif
-*/
-
#define GET_ENV_PTR_NO_MAP_LOCK \
ServerEnvironment *env = (ServerEnvironment *)getEnv(L); \
if (env == NULL) \
diff --git a/src/script/lua_api/l_inventory.cpp b/src/script/lua_api/l_inventory.cpp
index 38eade609..f5e76a7b6 100644
--- a/src/script/lua_api/l_inventory.cpp
+++ b/src/script/lua_api/l_inventory.cpp
@@ -194,7 +194,7 @@ int InvRef::l_set_stack(lua_State *L)
InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2);
int i = luaL_checknumber(L, 3) - 1;
- ItemStack newitem = read_item(L, 4, getServer(L));
+ ItemStack newitem = read_item(L, 4, getServer(L)->idef());
InventoryList *list = getlist(L, ref, listname);
if(list != NULL && i >= 0 && i < (int) list->getSize()){
list->changeItem(i, newitem);
@@ -295,7 +295,7 @@ int InvRef::l_add_item(lua_State *L)
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2);
- ItemStack item = read_item(L, 3, getServer(L));
+ ItemStack item = read_item(L, 3, getServer(L)->idef());
InventoryList *list = getlist(L, ref, listname);
if(list){
ItemStack leftover = list->addItem(item);
@@ -315,7 +315,7 @@ int InvRef::l_room_for_item(lua_State *L)
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2);
- ItemStack item = read_item(L, 3, getServer(L));
+ ItemStack item = read_item(L, 3, getServer(L)->idef());
InventoryList *list = getlist(L, ref, listname);
if(list){
lua_pushboolean(L, list->roomForItem(item));
@@ -332,7 +332,7 @@ int InvRef::l_contains_item(lua_State *L)
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2);
- ItemStack item = read_item(L, 3, getServer(L));
+ ItemStack item = read_item(L, 3, getServer(L)->idef());
InventoryList *list = getlist(L, ref, listname);
if(list){
lua_pushboolean(L, list->containsItem(item));
@@ -349,7 +349,7 @@ int InvRef::l_remove_item(lua_State *L)
NO_MAP_LOCK_REQUIRED;
InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2);
- ItemStack item = read_item(L, 3, getServer(L));
+ ItemStack item = read_item(L, 3, getServer(L)->idef());
InventoryList *list = getlist(L, ref, listname);
if(list){
ItemStack removed = list->removeItem(item);
@@ -463,7 +463,7 @@ void InvRef::Register(lua_State *L)
}
const char InvRef::className[] = "InvRef";
-const luaL_reg InvRef::methods[] = {
+const luaL_Reg InvRef::methods[] = {
luamethod(InvRef, is_empty),
luamethod(InvRef, get_size),
luamethod(InvRef, set_size),
diff --git a/src/script/lua_api/l_inventory.h b/src/script/lua_api/l_inventory.h
index cc5333965..91d41c0d0 100644
--- a/src/script/lua_api/l_inventory.h
+++ b/src/script/lua_api/l_inventory.h
@@ -36,7 +36,7 @@ private:
InventoryLocation m_loc;
static const char className[];
- static const luaL_reg methods[];
+ static const luaL_Reg methods[];
static InvRef *checkobject(lua_State *L, int narg);
diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp
index ff0baea14..0e4fc4ef0 100644
--- a/src/script/lua_api/l_item.cpp
+++ b/src/script/lua_api/l_item.cpp
@@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "lua_api/l_item.h"
+#include "lua_api/l_itemstackmeta.h"
#include "lua_api/l_internal.h"
#include "common/c_converter.h"
#include "common/c_content.h"
@@ -137,16 +138,28 @@ int LuaItemStack::l_set_wear(lua_State *L)
return 1;
}
+// get_meta(self) -> string
+int LuaItemStack::l_get_meta(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStackMetaRef::create(L, &o->m_stack);
+ return 1;
+}
+
+// DEPRECATED
// get_metadata(self) -> string
int LuaItemStack::l_get_metadata(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
- lua_pushlstring(L, item.metadata.c_str(), item.metadata.size());
+ const std::string &value = item.metadata.getString("");
+ lua_pushlstring(L, value.c_str(), value.size());
return 1;
}
+// DEPRECATED
// set_metadata(self, string)
int LuaItemStack::l_set_metadata(lua_State *L)
{
@@ -156,7 +169,7 @@ int LuaItemStack::l_set_metadata(lua_State *L)
size_t len = 0;
const char *ptr = luaL_checklstring(L, 2, &len);
- item.metadata.assign(ptr, len);
+ item.metadata.setString("", std::string(ptr, len));
lua_pushboolean(L, true);
return 1;
@@ -177,7 +190,7 @@ int LuaItemStack::l_replace(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
- o->m_stack = read_item(L,2,getServer(L));
+ o->m_stack = read_item(L, 2, getGameDef(L)->idef());
lua_pushboolean(L, true);
return 1;
}
@@ -211,8 +224,24 @@ int LuaItemStack::l_to_table(lua_State *L)
lua_setfield(L, -2, "count");
lua_pushinteger(L, item.wear);
lua_setfield(L, -2, "wear");
- lua_pushlstring(L, item.metadata.c_str(), item.metadata.size());
+
+ const std::string &metadata_str = item.metadata.getString("");
+ lua_pushlstring(L, metadata_str.c_str(), metadata_str.size());
lua_setfield(L, -2, "metadata");
+
+ lua_newtable(L);
+ const StringMap &fields = item.metadata.getStrings();
+ for (StringMap::const_iterator it = fields.begin();
+ it != fields.end(); ++it) {
+ const std::string &name = it->first;
+ if (name.empty())
+ continue;
+ const std::string &value = it->second;
+ lua_pushlstring(L, name.c_str(), name.size());
+ lua_pushlstring(L, value.c_str(), value.size());
+ lua_settable(L, -3);
+ }
+ lua_setfield(L, -2, "meta");
}
return 1;
}
@@ -223,7 +252,7 @@ int LuaItemStack::l_get_stack_max(lua_State *L)
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
- lua_pushinteger(L, item.getStackMax(getServer(L)->idef()));
+ lua_pushinteger(L, item.getStackMax(getGameDef(L)->idef()));
return 1;
}
@@ -233,7 +262,7 @@ int LuaItemStack::l_get_free_space(lua_State *L)
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
- lua_pushinteger(L, item.freeSpace(getServer(L)->idef()));
+ lua_pushinteger(L, item.freeSpace(getGameDef(L)->idef()));
return 1;
}
@@ -244,7 +273,7 @@ int LuaItemStack::l_is_known(lua_State *L)
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
- bool is_known = item.isKnown(getServer(L)->idef());
+ bool is_known = item.isKnown(getGameDef(L)->idef());
lua_pushboolean(L, is_known);
return 1;
}
@@ -280,7 +309,7 @@ int LuaItemStack::l_get_tool_capabilities(lua_State *L)
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
const ToolCapabilities &prop =
- item.getToolCapabilities(getServer(L)->idef());
+ item.getToolCapabilities(getGameDef(L)->idef());
push_tool_capabilities(L, prop);
return 1;
}
@@ -295,7 +324,7 @@ int LuaItemStack::l_add_wear(lua_State *L)
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
int amount = lua_tointeger(L, 2);
- bool result = item.addWear(amount, getServer(L)->idef());
+ bool result = item.addWear(amount, getGameDef(L)->idef());
lua_pushboolean(L, result);
return 1;
}
@@ -307,8 +336,8 @@ int LuaItemStack::l_add_item(lua_State *L)
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
- ItemStack newitem = read_item(L,-1, getServer(L));
- ItemStack leftover = item.addItem(newitem, getServer(L)->idef());
+ ItemStack newitem = read_item(L, -1, getGameDef(L)->idef());
+ ItemStack leftover = item.addItem(newitem, getGameDef(L)->idef());
create(L, leftover);
return 1;
}
@@ -321,9 +350,9 @@ int LuaItemStack::l_item_fits(lua_State *L)
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
- ItemStack newitem = read_item(L, 2, getServer(L));
+ ItemStack newitem = read_item(L, 2, getGameDef(L)->idef());
ItemStack restitem;
- bool fits = item.itemFits(newitem, &restitem, getServer(L)->idef());
+ bool fits = item.itemFits(newitem, &restitem, getGameDef(L)->idef());
lua_pushboolean(L, fits); // first return value
create(L, restitem); // second return value
return 2;
@@ -380,7 +409,7 @@ ItemStack& LuaItemStack::getItem()
int LuaItemStack::create_object(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- ItemStack item = read_item(L, 1, getServer(L));
+ ItemStack item = read_item(L, 1, getGameDef(L)->idef());
LuaItemStack *o = new LuaItemStack(item);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
@@ -435,7 +464,7 @@ void LuaItemStack::Register(lua_State *L)
}
const char LuaItemStack::className[] = "ItemStack";
-const luaL_reg LuaItemStack::methods[] = {
+const luaL_Reg LuaItemStack::methods[] = {
luamethod(LuaItemStack, is_empty),
luamethod(LuaItemStack, get_name),
luamethod(LuaItemStack, set_name),
@@ -443,6 +472,7 @@ const luaL_reg LuaItemStack::methods[] = {
luamethod(LuaItemStack, set_count),
luamethod(LuaItemStack, get_wear),
luamethod(LuaItemStack, set_wear),
+ luamethod(LuaItemStack, get_meta),
luamethod(LuaItemStack, get_metadata),
luamethod(LuaItemStack, set_metadata),
luamethod(LuaItemStack, clear),
@@ -496,7 +526,7 @@ int ModApiItemMod::l_register_item_raw(lua_State *L)
def.node_placement_prediction = "__default";
// Read the item definition
- def = read_item_definition(L, table, def);
+ read_item_definition(L, table, def, def);
// Default to having client-side placement prediction for nodes
// ("" in item definition sets it off)
@@ -568,7 +598,7 @@ int ModApiItemMod::l_get_content_id(lua_State *L)
NO_MAP_LOCK_REQUIRED;
std::string name = luaL_checkstring(L, 1);
- INodeDefManager *ndef = getServer(L)->getNodeDefManager();
+ INodeDefManager *ndef = getGameDef(L)->getNodeDefManager();
content_t c = ndef->getId(name);
lua_pushinteger(L, c);
@@ -581,7 +611,7 @@ int ModApiItemMod::l_get_name_from_content_id(lua_State *L)
NO_MAP_LOCK_REQUIRED;
content_t c = luaL_checkint(L, 1);
- INodeDefManager *ndef = getServer(L)->getNodeDefManager();
+ INodeDefManager *ndef = getGameDef(L)->getNodeDefManager();
const char *name = ndef->get(c).name.c_str();
lua_pushstring(L, name);
diff --git a/src/script/lua_api/l_item.h b/src/script/lua_api/l_item.h
index be919b701..b4efaefc8 100644
--- a/src/script/lua_api/l_item.h
+++ b/src/script/lua_api/l_item.h
@@ -28,7 +28,7 @@ private:
ItemStack m_stack;
static const char className[];
- static const luaL_reg methods[];
+ static const luaL_Reg methods[];
// Exported functions
@@ -56,9 +56,14 @@ private:
// set_wear(self, number)
static int l_set_wear(lua_State *L);
+ // get_meta(self) -> string
+ static int l_get_meta(lua_State *L);
+
+ // DEPRECATED
// get_metadata(self) -> string
static int l_get_metadata(lua_State *L);
+ // DEPRECATED
// set_metadata(self, string)
static int l_set_metadata(lua_State *L);
diff --git a/src/script/lua_api/l_itemstackmeta.cpp b/src/script/lua_api/l_itemstackmeta.cpp
new file mode 100644
index 000000000..c37a82116
--- /dev/null
+++ b/src/script/lua_api/l_itemstackmeta.cpp
@@ -0,0 +1,120 @@
+/*
+Minetest
+Copyright (C) 2013 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 Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "lua_api/l_itemstackmeta.h"
+#include "lua_api/l_internal.h"
+#include "common/c_content.h"
+
+/*
+ NodeMetaRef
+*/
+ItemStackMetaRef* ItemStackMetaRef::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if (!ud)
+ luaL_typerror(L, narg, className);
+
+ return *(ItemStackMetaRef**)ud; // unbox pointer
+}
+
+Metadata* ItemStackMetaRef::getmeta(bool auto_create)
+{
+ return &istack->metadata;
+}
+
+void ItemStackMetaRef::clearMeta()
+{
+ istack->metadata.clear();
+}
+
+void ItemStackMetaRef::reportMetadataChange()
+{
+ // TODO
+}
+
+// Exported functions
+
+// garbage collector
+int ItemStackMetaRef::gc_object(lua_State *L) {
+ ItemStackMetaRef *o = *(ItemStackMetaRef **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+// Creates an NodeMetaRef and leaves it on top of stack
+// Not callable from Lua; all references are created on the C side.
+void ItemStackMetaRef::create(lua_State *L, ItemStack *istack)
+{
+ ItemStackMetaRef *o = new ItemStackMetaRef(istack);
+ //infostream<<"NodeMetaRef::create: o="<<o<<std::endl;
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+}
+
+void ItemStackMetaRef::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+
+ lua_pushliteral(L, "metadata_class");
+ lua_pushlstring(L, className, strlen(className));
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__eq");
+ lua_pushcfunction(L, l_equals);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1); // drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // drop methodtable
+
+ // Cannot be created from Lua
+ //lua_register(L, className, create_object);
+}
+
+const char ItemStackMetaRef::className[] = "ItemStackMetaRef";
+const luaL_Reg ItemStackMetaRef::methods[] = {
+ luamethod(MetaDataRef, get_string),
+ luamethod(MetaDataRef, set_string),
+ luamethod(MetaDataRef, get_int),
+ luamethod(MetaDataRef, set_int),
+ luamethod(MetaDataRef, get_float),
+ luamethod(MetaDataRef, set_float),
+ luamethod(MetaDataRef, to_table),
+ luamethod(MetaDataRef, from_table),
+ luamethod(MetaDataRef, equals),
+ {0,0}
+};
diff --git a/src/script/lua_api/l_itemstackmeta.h b/src/script/lua_api/l_itemstackmeta.h
new file mode 100644
index 000000000..4ef64a91e
--- /dev/null
+++ b/src/script/lua_api/l_itemstackmeta.h
@@ -0,0 +1,59 @@
+/*
+Minetest
+Copyright (C) 2013 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 Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 L_ITEMSTACKMETA_H_
+#define L_ITEMSTACKMETA_H_
+
+#include "lua_api/l_base.h"
+#include "lua_api/l_metadata.h"
+#include "irrlichttypes_bloated.h"
+#include "inventory.h"
+
+class ItemStackMetaRef : public MetaDataRef
+{
+private:
+ ItemStack *istack;
+
+ static const char className[];
+ static const luaL_Reg methods[];
+
+ static ItemStackMetaRef *checkobject(lua_State *L, int narg);
+
+ virtual Metadata* getmeta(bool auto_create);
+
+ virtual void clearMeta();
+
+ virtual void reportMetadataChange();
+
+ // Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L);
+public:
+ ItemStackMetaRef(ItemStack *istack): istack(istack) {}
+ ~ItemStackMetaRef() {}
+
+ // Creates an ItemStackMetaRef and leaves it on top of stack
+ // Not callable from Lua; all references are created on the C side.
+ static void create(lua_State *L, ItemStack *istack);
+
+ static void Register(lua_State *L);
+};
+
+#endif
diff --git a/src/script/lua_api/l_localplayer.cpp b/src/script/lua_api/l_localplayer.cpp
new file mode 100644
index 000000000..7ec4eaa62
--- /dev/null
+++ b/src/script/lua_api/l_localplayer.cpp
@@ -0,0 +1,358 @@
+/*
+Minetest
+Copyright (C) 2017 Dumbeldor, Vincent Glize <vincent.glize@live.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "l_localplayer.h"
+#include "l_internal.h"
+#include "script/common/c_converter.h"
+
+LuaLocalPlayer::LuaLocalPlayer(LocalPlayer *m)
+{
+ m_localplayer = m;
+}
+
+void LuaLocalPlayer::create(lua_State *L, LocalPlayer *m)
+{
+ LuaLocalPlayer *o = new LuaLocalPlayer(m);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+
+ // Keep localplayer object stack id
+ int localplayer_object = lua_gettop(L);
+
+ lua_getglobal(L, "core");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ int coretable = lua_gettop(L);
+
+ lua_pushvalue(L, localplayer_object);
+ lua_setfield(L, coretable, "localplayer");
+}
+
+int LuaLocalPlayer::l_get_velocity(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ push_v3f(L, player->getSpeed() / BS);
+ return 1;
+}
+
+int LuaLocalPlayer::l_get_hp(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_pushinteger(L, player->hp);
+ return 1;
+}
+
+int LuaLocalPlayer::l_get_name(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_pushstring(L, player->getName());
+ return 1;
+}
+
+int LuaLocalPlayer::l_is_attached(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_pushboolean(L, player->isAttached);
+ return 1;
+}
+
+int LuaLocalPlayer::l_is_touching_ground(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_pushboolean(L, player->touching_ground);
+ return 1;
+}
+
+int LuaLocalPlayer::l_is_in_liquid(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_pushboolean(L, player->in_liquid);
+ return 1;
+}
+
+int LuaLocalPlayer::l_is_in_liquid_stable(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_pushboolean(L, player->in_liquid_stable);
+ return 1;
+}
+
+int LuaLocalPlayer::l_get_liquid_viscosity(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_pushinteger(L, player->liquid_viscosity);
+ return 1;
+}
+
+int LuaLocalPlayer::l_is_climbing(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_pushboolean(L, player->is_climbing);
+ return 1;
+}
+
+int LuaLocalPlayer::l_swimming_vertical(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_pushboolean(L, player->swimming_vertical);
+ return 1;
+}
+
+int LuaLocalPlayer::l_get_physics_override(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_newtable(L);
+ lua_pushnumber(L, player->physics_override_speed);
+ lua_setfield(L, -2, "speed");
+
+ lua_pushnumber(L, player->physics_override_jump);
+ lua_setfield(L, -2, "jump");
+
+ lua_pushnumber(L, player->physics_override_gravity);
+ lua_setfield(L, -2, "gravity");
+
+ lua_pushboolean(L, player->physics_override_sneak);
+ lua_setfield(L, -2, "sneak");
+
+ lua_pushboolean(L, player->physics_override_sneak_glitch);
+ lua_setfield(L, -2, "sneak_glitch");
+
+ return 1;
+}
+
+int LuaLocalPlayer::l_get_override_pos(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ push_v3f(L, player->overridePosition);
+ return 1;
+}
+
+int LuaLocalPlayer::l_get_last_pos(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ push_v3f(L, player->last_position / BS);
+ return 1;
+}
+
+int LuaLocalPlayer::l_get_last_velocity(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ push_v3f(L, player->last_speed);
+ return 1;
+}
+
+int LuaLocalPlayer::l_get_last_look_vertical(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_pushnumber(L, -1.0 * player->last_pitch * core::DEGTORAD);
+ return 1;
+}
+
+int LuaLocalPlayer::l_get_last_look_horizontal(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_pushnumber(L, (player->last_yaw + 90.) * core::DEGTORAD);
+ return 1;
+}
+
+int LuaLocalPlayer::l_get_key_pressed(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_pushinteger(L, player->last_keyPressed);
+ return 1;
+}
+
+int LuaLocalPlayer::l_get_breath(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_pushinteger(L, player->getBreath());
+ return 1;
+}
+
+int LuaLocalPlayer::l_get_pos(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ push_v3f(L, player->getPosition() / BS);
+ return 1;
+}
+
+int LuaLocalPlayer::l_get_movement_acceleration(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_newtable(L);
+ lua_pushnumber(L, player->movement_acceleration_default);
+ lua_setfield(L, -2, "default");
+
+ lua_pushnumber(L, player->movement_acceleration_air);
+ lua_setfield(L, -2, "air");
+
+ lua_pushnumber(L, player->movement_acceleration_fast);
+ lua_setfield(L, -2, "fast");
+
+ return 1;
+}
+
+int LuaLocalPlayer::l_get_movement_speed(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_newtable(L);
+ lua_pushnumber(L, player->movement_speed_walk);
+ lua_setfield(L, -2, "walk");
+
+ lua_pushnumber(L, player->movement_speed_crouch);
+ lua_setfield(L, -2, "crouch");
+
+ lua_pushnumber(L, player->movement_speed_fast);
+ lua_setfield(L, -2, "fast");
+
+ lua_pushnumber(L, player->movement_speed_climb);
+ lua_setfield(L, -2, "climb");
+
+ lua_pushnumber(L, player->movement_speed_jump);
+ lua_setfield(L, -2, "jump");
+
+ return 1;
+}
+
+int LuaLocalPlayer::l_get_movement(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ lua_newtable(L);
+
+ lua_pushnumber(L, player->movement_liquid_fluidity);
+ lua_setfield(L, -2, "liquid_fluidity");
+
+ lua_pushnumber(L, player->movement_liquid_fluidity_smooth);
+ lua_setfield(L, -2, "liquid_fluidity_smooth");
+
+ lua_pushnumber(L, player->movement_liquid_sink);
+ lua_setfield(L, -2, "liquid_sink");
+
+ lua_pushnumber(L, player->movement_gravity);
+ lua_setfield(L, -2, "gravity");
+
+ return 1;
+}
+
+LuaLocalPlayer *LuaLocalPlayer::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+
+ void *ud = luaL_checkudata(L, narg, className);
+ if (!ud)
+ luaL_typerror(L, narg, className);
+
+ return *(LuaLocalPlayer **)ud;
+}
+
+LocalPlayer *LuaLocalPlayer::getobject(LuaLocalPlayer *ref)
+{
+ return ref->m_localplayer;
+}
+
+LocalPlayer *LuaLocalPlayer::getobject(lua_State *L, int narg)
+{
+ LuaLocalPlayer *ref = checkobject(L, narg);
+ assert(ref);
+ LocalPlayer *player = getobject(ref);
+ assert(player);
+ return player;
+}
+
+int LuaLocalPlayer::gc_object(lua_State *L)
+{
+ LuaLocalPlayer *o = *(LuaLocalPlayer **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+void LuaLocalPlayer::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable); // hide metatable from lua getmetatable()
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1); // Drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // Drop methodtable
+}
+
+const char LuaLocalPlayer::className[] = "LocalPlayer";
+const luaL_Reg LuaLocalPlayer::methods[] = {
+ luamethod(LuaLocalPlayer, get_velocity),
+ luamethod(LuaLocalPlayer, get_hp),
+ luamethod(LuaLocalPlayer, get_name),
+ luamethod(LuaLocalPlayer, is_attached),
+ luamethod(LuaLocalPlayer, is_touching_ground),
+ luamethod(LuaLocalPlayer, is_in_liquid),
+ luamethod(LuaLocalPlayer, is_in_liquid_stable),
+ luamethod(LuaLocalPlayer, get_liquid_viscosity),
+ luamethod(LuaLocalPlayer, is_climbing),
+ luamethod(LuaLocalPlayer, swimming_vertical),
+ luamethod(LuaLocalPlayer, get_physics_override),
+ luamethod(LuaLocalPlayer, get_override_pos),
+ luamethod(LuaLocalPlayer, get_last_pos),
+ luamethod(LuaLocalPlayer, get_last_velocity),
+ luamethod(LuaLocalPlayer, get_last_look_horizontal),
+ luamethod(LuaLocalPlayer, get_last_look_vertical),
+ luamethod(LuaLocalPlayer, get_key_pressed),
+ luamethod(LuaLocalPlayer, get_breath),
+ luamethod(LuaLocalPlayer, get_pos),
+ luamethod(LuaLocalPlayer, get_movement_acceleration),
+ luamethod(LuaLocalPlayer, get_movement_speed),
+ luamethod(LuaLocalPlayer, get_movement),
+
+ {0, 0}
+};
diff --git a/src/script/lua_api/l_localplayer.h b/src/script/lua_api/l_localplayer.h
new file mode 100644
index 000000000..e56ec808f
--- /dev/null
+++ b/src/script/lua_api/l_localplayer.h
@@ -0,0 +1,85 @@
+/*
+Minetest
+Copyright (C) 2017 Dumbeldor, Vincent Glize <vincent.glize@live.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 MINETEST_L_LOCALPLAYER_H
+#define MINETEST_L_LOCALPLAYER_H
+
+#include "l_base.h"
+
+class LocalPlayer;
+
+class LuaLocalPlayer : public ModApiBase
+{
+private:
+ static const char className[];
+ static const luaL_Reg methods[];
+
+ // garbage collector
+ static int gc_object(lua_State *L);
+
+ static int l_get_velocity(lua_State *L);
+
+ static int l_get_hp(lua_State *L);
+
+ static int l_get_name(lua_State *L);
+
+ static int l_is_attached(lua_State *L);
+ static int l_is_touching_ground(lua_State *L);
+ static int l_is_in_liquid(lua_State *L);
+ static int l_is_in_liquid_stable(lua_State *L);
+ static int l_get_liquid_viscosity(lua_State *L);
+ static int l_is_climbing(lua_State *L);
+ static int l_swimming_vertical(lua_State *L);
+
+ static int l_get_physics_override(lua_State *L);
+
+ static int l_get_override_pos(lua_State *L);
+
+ static int l_get_last_pos(lua_State *L);
+ static int l_get_last_velocity(lua_State *L);
+ static int l_get_last_look_vertical(lua_State *L);
+ static int l_get_last_look_horizontal(lua_State *L);
+ static int l_get_key_pressed(lua_State *L);
+
+ static int l_get_breath(lua_State *L);
+
+ static int l_get_pos(lua_State *L);
+
+ static int l_get_movement_acceleration(lua_State *L);
+
+ static int l_get_movement_speed(lua_State *L);
+
+ static int l_get_movement(lua_State *L);
+
+ LocalPlayer *m_localplayer;
+
+public:
+ LuaLocalPlayer(LocalPlayer *m);
+ ~LuaLocalPlayer() {}
+
+ static void create(lua_State *L, LocalPlayer *m);
+
+ static LuaLocalPlayer *checkobject(lua_State *L, int narg);
+ static LocalPlayer *getobject(LuaLocalPlayer *ref);
+ static LocalPlayer *getobject(lua_State *L, int narg);
+
+ static void Register(lua_State *L);
+};
+
+#endif // MINETEST_L_LOCALPLAYER_H
diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
index 4a2484613..dc8654960 100644
--- a/src/script/lua_api/l_mainmenu.cpp
+++ b/src/script/lua_api/l_mainmenu.cpp
@@ -32,14 +32,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "convert_json.h"
#include "serverlist.h"
#include "mapgen.h"
-#include "sound.h"
#include "settings.h"
-#include "log.h"
#include "EDriverTypes.h"
#include <IFileArchive.h>
#include <IFileSystem.h>
+
/******************************************************************************/
std::string ModApiMainMenu::getTextData(lua_State *L, std::string name)
{
@@ -299,7 +298,7 @@ int ModApiMainMenu::l_get_games(lua_State *L)
int table2 = lua_gettop(L);
int internal_index=1;
for (std::set<std::string>::iterator iter = games[i].addon_mods_paths.begin();
- iter != games[i].addon_mods_paths.end(); iter++) {
+ iter != games[i].addon_mods_paths.end(); ++iter) {
lua_pushnumber(L,internal_index);
lua_pushstring(L,(*iter).c_str());
lua_settable(L, table2);
@@ -577,6 +576,13 @@ int ModApiMainMenu::l_get_favorites(lua_State *L)
lua_settable(L, top_lvl2);
}
+ if (servers[i].isMember("ping")) {
+ float ping = servers[i]["ping"].asFloat();
+ lua_pushstring(L, "ping");
+ lua_pushnumber(L, ping);
+ lua_settable(L, top_lvl2);
+ }
+
lua_settable(L, top);
index++;
}
@@ -956,33 +962,6 @@ int ModApiMainMenu::l_show_file_open_dialog(lua_State *L)
}
/******************************************************************************/
-int ModApiMainMenu::l_sound_play(lua_State *L)
-{
- GUIEngine* engine = getGuiEngine(L);
-
- SimpleSoundSpec spec;
- read_soundspec(L, 1, spec);
- bool looped = lua_toboolean(L, 2);
-
- u32 handle = engine->playSound(spec, looped);
-
- lua_pushinteger(L, handle);
-
- return 1;
-}
-
-/******************************************************************************/
-int ModApiMainMenu::l_sound_stop(lua_State *L)
-{
- GUIEngine* engine = getGuiEngine(L);
-
- u32 handle = luaL_checkinteger(L, 1);
- engine->stopSound(handle);
-
- return 1;
-}
-
-/******************************************************************************/
int ModApiMainMenu::l_download_file(lua_State *L)
{
const char *url = luaL_checkstring(L, 1);
@@ -1153,8 +1132,6 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
API_FCT(download_file);
API_FCT(get_modstore_details);
API_FCT(get_modstore_list);
- API_FCT(sound_play);
- API_FCT(sound_stop);
API_FCT(gettext);
API_FCT(get_video_drivers);
API_FCT(get_video_modes);
@@ -1165,23 +1142,24 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
}
/******************************************************************************/
-void ModApiMainMenu::InitializeAsync(AsyncEngine& engine)
+void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
{
- ASYNC_API_FCT(get_worlds);
- ASYNC_API_FCT(get_games);
- ASYNC_API_FCT(get_favorites);
- ASYNC_API_FCT(get_mapgen_names);
- ASYNC_API_FCT(get_modpath);
- ASYNC_API_FCT(get_gamepath);
- ASYNC_API_FCT(get_texturepath);
- ASYNC_API_FCT(get_texturepath_share);
- ASYNC_API_FCT(create_dir);
- ASYNC_API_FCT(delete_dir);
- ASYNC_API_FCT(copy_dir);
- //ASYNC_API_FCT(extract_zip); //TODO remove dependency to GuiEngine
- ASYNC_API_FCT(download_file);
- ASYNC_API_FCT(get_modstore_details);
- ASYNC_API_FCT(get_modstore_list);
- //ASYNC_API_FCT(gettext); (gettext lib isn't threadsafe)
+ API_FCT(get_worlds);
+ API_FCT(get_games);
+ API_FCT(get_favorites);
+ API_FCT(get_mapgen_names);
+ API_FCT(get_modpath);
+ API_FCT(get_gamepath);
+ API_FCT(get_texturepath);
+ API_FCT(get_texturepath_share);
+ API_FCT(create_dir);
+ API_FCT(delete_dir);
+ API_FCT(copy_dir);
+ //API_FCT(extract_zip); //TODO remove dependency to GuiEngine
+ API_FCT(download_file);
+ API_FCT(get_modstore_details);
+ API_FCT(get_modstore_list);
+ //API_FCT(gettext); (gettext lib isn't threadsafe)
}
+
diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h
index ad5155ac6..d4946bab1 100644
--- a/src/script/lua_api/l_mainmenu.h
+++ b/src/script/lua_api/l_mainmenu.h
@@ -25,7 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class AsyncEngine;
/** Implementation of lua api support for mainmenu */
-class ModApiMainMenu : public ModApiBase {
+class ModApiMainMenu: public ModApiBase
+{
private:
/**
@@ -79,10 +80,6 @@ private:
static int l_delete_favorite(lua_State *L);
- static int l_sound_play(lua_State *L);
-
- static int l_sound_stop(lua_State *L);
-
static int l_gettext(lua_State *L);
//gui
@@ -145,6 +142,7 @@ private:
static int l_do_async_callback(lua_State *L);
public:
+
/**
* initialize this API module
* @param L lua stack to initialize
@@ -152,7 +150,7 @@ public:
*/
static void Initialize(lua_State *L, int top);
- static void InitializeAsync(AsyncEngine& engine);
+ static void InitializeAsync(lua_State *L, int top);
};
diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp
index bc1c32f03..32eb7af84 100644
--- a/src/script/lua_api/l_mapgen.cpp
+++ b/src/script/lua_api/l_mapgen.cpp
@@ -325,14 +325,22 @@ void read_schematic_replacements(lua_State *L, int index, StringMap *replace_nam
if (lua_istable(L, -1)) { // Old {{"x", "y"}, ...} format
lua_rawgeti(L, -1, 1);
+ if (!lua_isstring(L, -1))
+ throw LuaError("schematics: replace_from field is not a string");
replace_from = lua_tostring(L, -1);
lua_pop(L, 1);
lua_rawgeti(L, -1, 2);
+ if (!lua_isstring(L, -1))
+ throw LuaError("schematics: replace_to field is not a string");
replace_to = lua_tostring(L, -1);
lua_pop(L, 1);
} else { // New {x = "y", ...} format
+ if (!lua_isstring(L, -2))
+ throw LuaError("schematics: replace_from field is not a string");
replace_from = lua_tostring(L, -2);
+ if (!lua_isstring(L, -1))
+ throw LuaError("schematics: replace_to field is not a string");
replace_to = lua_tostring(L, -1);
}
@@ -419,7 +427,7 @@ size_t get_biome_list(lua_State *L, int index,
if (is_single) {
Biome *biome = get_or_load_biome(L, index, biomemgr);
if (!biome) {
- errorstream << "get_biome_list: failed to get biome '"
+ infostream << "get_biome_list: failed to get biome '"
<< (lua_isstring(L, index) ? lua_tostring(L, index) : "")
<< "'." << std::endl;
return 1;
@@ -438,7 +446,7 @@ size_t get_biome_list(lua_State *L, int index,
Biome *biome = get_or_load_biome(L, -1, biomemgr);
if (!biome) {
fail_count++;
- errorstream << "get_biome_list: failed to get biome '"
+ infostream << "get_biome_list: failed to get biome '"
<< (lua_isstring(L, -1) ? lua_tostring(L, -1) : "")
<< "'" << std::endl;
continue;
@@ -927,7 +935,7 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
//// Get biomes associated with this decoration (if any)
lua_getfield(L, index, "biomes");
if (get_biome_list(L, -1, biomemgr, &deco->biomes))
- errorstream << "register_decoration: couldn't get all biomes " << std::endl;
+ infostream << "register_decoration: couldn't get all biomes " << std::endl;
lua_pop(L, 1);
//// Get node name(s) to 'spawn by'
@@ -1092,7 +1100,7 @@ int ModApiMapgen::l_register_ore(lua_State *L)
//// Get biomes associated with this decoration (if any)
lua_getfield(L, index, "biomes");
if (get_biome_list(L, -1, bmgr, &ore->biomes))
- errorstream << "register_ore: couldn't get all biomes " << std::endl;
+ infostream << "register_ore: couldn't get all biomes " << std::endl;
lua_pop(L, 1);
//// Get noise parameters if needed
@@ -1357,7 +1365,9 @@ int ModApiMapgen::l_place_schematic(lua_State *L)
{
MAP_LOCK_REQUIRED;
- Map *map = &(getEnv(L)->getMap());
+ GET_ENV_PTR;
+
+ ServerMap *map = &(env->getServerMap());
SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
//// Read position
diff --git a/src/script/lua_api/l_mapgen.h b/src/script/lua_api/l_mapgen.h
index bb94575c7..a26c8b950 100644
--- a/src/script/lua_api/l_mapgen.h
+++ b/src/script/lua_api/l_mapgen.h
@@ -22,7 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_base.h"
-class ModApiMapgen : public ModApiBase {
+class ModApiMapgen : public ModApiBase
+{
private:
// get_biome_id(biomename)
// returns the biome id used in biomemap
diff --git a/src/script/lua_api/l_metadata.cpp b/src/script/lua_api/l_metadata.cpp
new file mode 100644
index 000000000..5f4e984cb
--- /dev/null
+++ b/src/script/lua_api/l_metadata.cpp
@@ -0,0 +1,266 @@
+/*
+Minetest
+Copyright (C) 2013 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 Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "lua_api/l_metadata.h"
+#include "lua_api/l_internal.h"
+#include "common/c_content.h"
+#include "serverenvironment.h"
+#include "map.h"
+#include "server.h"
+
+// LUALIB_API
+void *luaL_checkudata_is_metadataref(lua_State *L, int ud) {
+ void *p = lua_touserdata(L, ud);
+ if (p != NULL && // value is a userdata?
+ lua_getmetatable(L, ud)) { // does it have a metatable?
+ lua_getfield(L, -1, "metadata_class");
+ if (lua_type(L, -1) == LUA_TSTRING) { // does it have a metadata_class field?
+ return p;
+ }
+ }
+ luaL_typerror(L, ud, "MetaDataRef");
+ return NULL;
+}
+
+MetaDataRef* MetaDataRef::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata_is_metadataref(L, narg);
+ if (!ud)
+ luaL_typerror(L, narg, "MetaDataRef");
+
+ return *(MetaDataRef**)ud; // unbox pointer
+}
+
+// Exported functions
+
+// get_string(self, name)
+int MetaDataRef::l_get_string(lua_State *L)
+{
+ MAP_LOCK_REQUIRED;
+
+ MetaDataRef *ref = checkobject(L, 1);
+ std::string name = luaL_checkstring(L, 2);
+
+ Metadata *meta = ref->getmeta(false);
+ if (meta == NULL) {
+ lua_pushlstring(L, "", 0);
+ return 1;
+ }
+
+ const std::string &str = meta->getString(name);
+ lua_pushlstring(L, str.c_str(), str.size());
+ return 1;
+}
+
+// set_string(self, name, var)
+int MetaDataRef::l_set_string(lua_State *L)
+{
+ MAP_LOCK_REQUIRED;
+
+ MetaDataRef *ref = checkobject(L, 1);
+ std::string name = luaL_checkstring(L, 2);
+ size_t len = 0;
+ const char *s = lua_tolstring(L, 3, &len);
+ std::string str(s, len);
+
+ Metadata *meta = ref->getmeta(!str.empty());
+ if (meta == NULL || str == meta->getString(name))
+ return 0;
+
+ meta->setString(name, str);
+ ref->reportMetadataChange();
+ return 0;
+}
+
+// get_int(self, name)
+int MetaDataRef::l_get_int(lua_State *L)
+{
+ MAP_LOCK_REQUIRED;
+
+ MetaDataRef *ref = checkobject(L, 1);
+ std::string name = lua_tostring(L, 2);
+
+ Metadata *meta = ref->getmeta(false);
+ if (meta == NULL) {
+ lua_pushnumber(L, 0);
+ return 1;
+ }
+
+ const std::string &str = meta->getString(name);
+ lua_pushnumber(L, stoi(str));
+ return 1;
+}
+
+// set_int(self, name, var)
+int MetaDataRef::l_set_int(lua_State *L)
+{
+ MAP_LOCK_REQUIRED;
+
+ MetaDataRef *ref = checkobject(L, 1);
+ std::string name = lua_tostring(L, 2);
+ int a = lua_tointeger(L, 3);
+ std::string str = itos(a);
+
+ Metadata *meta = ref->getmeta(true);
+ if (meta == NULL || str == meta->getString(name))
+ return 0;
+
+ meta->setString(name, str);
+ ref->reportMetadataChange();
+ return 0;
+}
+
+// get_float(self, name)
+int MetaDataRef::l_get_float(lua_State *L)
+{
+ MAP_LOCK_REQUIRED;
+
+ MetaDataRef *ref = checkobject(L, 1);
+ std::string name = lua_tostring(L, 2);
+
+ Metadata *meta = ref->getmeta(false);
+ if (meta == NULL) {
+ lua_pushnumber(L, 0);
+ return 1;
+ }
+
+ const std::string &str = meta->getString(name);
+ lua_pushnumber(L, stof(str));
+ return 1;
+}
+
+// set_float(self, name, var)
+int MetaDataRef::l_set_float(lua_State *L)
+{
+ MAP_LOCK_REQUIRED;
+
+ MetaDataRef *ref = checkobject(L, 1);
+ std::string name = lua_tostring(L, 2);
+ float a = lua_tonumber(L, 3);
+ std::string str = ftos(a);
+
+ Metadata *meta = ref->getmeta(true);
+ if (meta == NULL || str == meta->getString(name))
+ return 0;
+
+ meta->setString(name, str);
+ ref->reportMetadataChange();
+ return 0;
+}
+
+// to_table(self)
+int MetaDataRef::l_to_table(lua_State *L)
+{
+ MAP_LOCK_REQUIRED;
+
+ MetaDataRef *ref = checkobject(L, 1);
+
+ Metadata *meta = ref->getmeta(true);
+ if (meta == NULL) {
+ lua_pushnil(L);
+ return 1;
+ }
+ lua_newtable(L);
+
+ ref->handleToTable(L, meta);
+
+ return 1;
+}
+
+// from_table(self, table)
+int MetaDataRef::l_from_table(lua_State *L)
+{
+ MAP_LOCK_REQUIRED;
+
+ MetaDataRef *ref = checkobject(L, 1);
+ int base = 2;
+
+ ref->clearMeta();
+
+ if (!lua_istable(L, base)) {
+ // No metadata
+ lua_pushboolean(L, true);
+ return 1;
+ }
+
+ // Create new metadata
+ Metadata *meta = ref->getmeta(true);
+ if (meta == NULL) {
+ lua_pushboolean(L, false);
+ return 1;
+ }
+
+ bool was_successful = ref->handleFromTable(L, base, meta);
+ ref->reportMetadataChange();
+ lua_pushboolean(L, was_successful);
+ return 1;
+}
+
+void MetaDataRef::handleToTable(lua_State *L, Metadata *meta)
+{
+ lua_newtable(L);
+ {
+ const StringMap &fields = meta->getStrings();
+ for (StringMap::const_iterator
+ it = fields.begin(); it != fields.end(); ++it) {
+ const std::string &name = it->first;
+ const std::string &value = it->second;
+ lua_pushlstring(L, name.c_str(), name.size());
+ lua_pushlstring(L, value.c_str(), value.size());
+ lua_settable(L, -3);
+ }
+ }
+ lua_setfield(L, -2, "fields");
+}
+
+bool MetaDataRef::handleFromTable(lua_State *L, int table, Metadata *meta)
+{
+ // Set fields
+ lua_getfield(L, table, "fields");
+ if (lua_istable(L, -1)) {
+ int fieldstable = lua_gettop(L);
+ lua_pushnil(L);
+ while (lua_next(L, fieldstable) != 0) {
+ // key at index -2 and value at index -1
+ std::string name = lua_tostring(L, -2);
+ size_t cl;
+ const char *cs = lua_tolstring(L, -1, &cl);
+ meta->setString(name, std::string(cs, cl));
+ lua_pop(L, 1); // Remove value, keep key for next iteration
+ }
+ lua_pop(L, 1);
+ }
+
+ return true;
+}
+
+// equals(self, other)
+int MetaDataRef::l_equals(lua_State *L)
+{
+ MetaDataRef *ref1 = checkobject(L, 1);
+ Metadata *data1 = ref1->getmeta(false);
+ MetaDataRef *ref2 = checkobject(L, 2);
+ Metadata *data2 = ref2->getmeta(false);
+ if (data1 == NULL || data2 == NULL)
+ lua_pushboolean(L, data1 == data2);
+ else
+ lua_pushboolean(L, *data1 == *data2);
+ return 1;
+}
diff --git a/src/script/lua_api/l_metadata.h b/src/script/lua_api/l_metadata.h
new file mode 100644
index 000000000..a4d8214d3
--- /dev/null
+++ b/src/script/lua_api/l_metadata.h
@@ -0,0 +1,75 @@
+/*
+Minetest
+Copyright (C) 2013 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 Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 L_METADATA_H_
+#define L_METADATA_H_
+
+#include "irrlichttypes_bloated.h"
+#include "lua_api/l_base.h"
+
+class Metadata;
+
+/*
+ NodeMetaRef
+*/
+
+class MetaDataRef : public ModApiBase
+{
+public:
+ virtual ~MetaDataRef() {}
+protected:
+ static MetaDataRef *checkobject(lua_State *L, int narg);
+
+ virtual void reportMetadataChange() {}
+ virtual Metadata *getmeta(bool auto_create) = 0;
+ virtual void clearMeta() = 0;
+
+ virtual void handleToTable(lua_State *L, Metadata *meta);
+ virtual bool handleFromTable(lua_State *L, int table, Metadata *meta);
+
+ // Exported functions
+
+ // get_string(self, name)
+ static int l_get_string(lua_State *L);
+
+ // set_string(self, name, var)
+ static int l_set_string(lua_State *L);
+
+ // get_int(self, name)
+ static int l_get_int(lua_State *L);
+
+ // set_int(self, name, var)
+ static int l_set_int(lua_State *L);
+
+ // get_float(self, name)
+ static int l_get_float(lua_State *L);
+
+ // set_float(self, name, var)
+ static int l_set_float(lua_State *L);
+
+ // to_table(self)
+ static int l_to_table(lua_State *L);
+
+ // from_table(self, table)
+ static int l_from_table(lua_State *L);
+
+ // equals(self, other)
+ static int l_equals(lua_State *L);
+};
+
+#endif /* L_NODEMETA_H_ */
diff --git a/src/script/lua_api/l_minimap.cpp b/src/script/lua_api/l_minimap.cpp
new file mode 100644
index 000000000..afb3766fb
--- /dev/null
+++ b/src/script/lua_api/l_minimap.cpp
@@ -0,0 +1,227 @@
+/*
+Minetest
+Copyright (C) 2017 Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "lua_api/l_minimap.h"
+#include "lua_api/l_internal.h"
+#include "common/c_converter.h"
+#include "minimap.h"
+#include "settings.h"
+
+LuaMinimap::LuaMinimap(Minimap *m)
+{
+ m_minimap = m;
+}
+
+void LuaMinimap::create(lua_State *L, Minimap *m)
+{
+ LuaMinimap *o = new LuaMinimap(m);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+
+ // Keep minimap object stack id
+ int minimap_object = lua_gettop(L);
+
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "ui");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ int uitable = lua_gettop(L);
+
+ lua_pushvalue(L, minimap_object); // Copy object to top of stack
+ lua_setfield(L, uitable, "minimap");
+}
+
+int LuaMinimap::l_get_pos(lua_State *L)
+{
+ LuaMinimap *ref = checkobject(L, 1);
+ Minimap *m = getobject(ref);
+
+ push_v3s16(L, m->getPos());
+ return 1;
+}
+
+int LuaMinimap::l_set_pos(lua_State *L)
+{
+ LuaMinimap *ref = checkobject(L, 1);
+ Minimap *m = getobject(ref);
+
+ m->setPos(read_v3s16(L, 2));
+ return 1;
+}
+
+int LuaMinimap::l_get_angle(lua_State *L)
+{
+ LuaMinimap *ref = checkobject(L, 1);
+ Minimap *m = getobject(ref);
+
+ lua_pushinteger(L, m->getAngle());
+ return 1;
+}
+
+int LuaMinimap::l_set_angle(lua_State *L)
+{
+ LuaMinimap *ref = checkobject(L, 1);
+ Minimap *m = getobject(ref);
+
+ m->setAngle(lua_tointeger(L, 2));
+ return 1;
+}
+
+int LuaMinimap::l_get_mode(lua_State *L)
+{
+ LuaMinimap *ref = checkobject(L, 1);
+ Minimap *m = getobject(ref);
+
+ lua_pushinteger(L, m->getMinimapMode());
+ return 1;
+}
+
+int LuaMinimap::l_set_mode(lua_State *L)
+{
+ LuaMinimap *ref = checkobject(L, 1);
+ Minimap *m = getobject(ref);
+
+ s32 mode = lua_tointeger(L, 2);
+ if (mode < MINIMAP_MODE_OFF ||
+ mode >= MINIMAP_MODE_COUNT) {
+ return 0;
+ }
+
+ m->setMinimapMode((MinimapMode) mode);
+ return 1;
+}
+
+int LuaMinimap::l_set_shape(lua_State *L)
+{
+ LuaMinimap *ref = checkobject(L, 1);
+ Minimap *m = getobject(ref);
+ if (!lua_isnumber(L, 2))
+ return 0;
+
+ m->setMinimapShape((MinimapShape)((int)lua_tonumber(L, 2)));
+ return 0;
+}
+
+int LuaMinimap::l_get_shape(lua_State *L)
+{
+ LuaMinimap *ref = checkobject(L, 1);
+ Minimap *m = getobject(ref);
+
+ lua_pushnumber(L, (int)m->getMinimapShape());
+ return 1;
+}
+
+int LuaMinimap::l_show(lua_State *L)
+{
+ // If minimap is disabled by config, don't show it.
+ if (!g_settings->getBool("enable_minimap"))
+ return 1;
+
+ Client *client = getClient(L);
+ assert(client);
+
+ LuaMinimap *ref = checkobject(L, 1);
+ Minimap *m = getobject(ref);
+
+ if (m->getMinimapMode() == MINIMAP_MODE_OFF)
+ m->setMinimapMode(MINIMAP_MODE_SURFACEx1);
+
+ client->showMinimap(true);
+ return 1;
+}
+
+int LuaMinimap::l_hide(lua_State *L)
+{
+ Client *client = getClient(L);
+ assert(client);
+
+ LuaMinimap *ref = checkobject(L, 1);
+ Minimap *m = getobject(ref);
+
+ if (m->getMinimapMode() != MINIMAP_MODE_OFF)
+ m->setMinimapMode(MINIMAP_MODE_OFF);
+
+ client->showMinimap(false);
+ return 1;
+}
+
+LuaMinimap *LuaMinimap::checkobject(lua_State *L, int narg)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+
+ void *ud = luaL_checkudata(L, narg, className);
+ if (!ud)
+ luaL_typerror(L, narg, className);
+
+ return *(LuaMinimap **)ud; // unbox pointer
+}
+
+Minimap* LuaMinimap::getobject(LuaMinimap *ref)
+{
+ return ref->m_minimap;
+}
+
+int LuaMinimap::gc_object(lua_State *L) {
+ LuaMinimap *o = *(LuaMinimap **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+void LuaMinimap::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1); // drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // drop methodtable
+}
+
+const char LuaMinimap::className[] = "Minimap";
+const luaL_Reg LuaMinimap::methods[] = {
+ luamethod(LuaMinimap, show),
+ luamethod(LuaMinimap, hide),
+ luamethod(LuaMinimap, get_pos),
+ luamethod(LuaMinimap, set_pos),
+ luamethod(LuaMinimap, get_angle),
+ luamethod(LuaMinimap, set_angle),
+ luamethod(LuaMinimap, get_mode),
+ luamethod(LuaMinimap, set_mode),
+ luamethod(LuaMinimap, set_shape),
+ luamethod(LuaMinimap, get_shape),
+ {0,0}
+};
diff --git a/src/script/lua_api/l_minimap.h b/src/script/lua_api/l_minimap.h
new file mode 100644
index 000000000..ba702b0b1
--- /dev/null
+++ b/src/script/lua_api/l_minimap.h
@@ -0,0 +1,65 @@
+/*
+Minetest
+Copyright (C) 2017 Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 L_MINIMAP_H_
+#define L_MINIMAP_H_
+
+#include "l_base.h"
+
+class Minimap;
+
+class LuaMinimap : public ModApiBase
+{
+private:
+ static const char className[];
+ static const luaL_Reg methods[];
+
+ // garbage collector
+ static int gc_object(lua_State *L);
+
+ static int l_get_pos(lua_State *L);
+ static int l_set_pos(lua_State *L);
+
+ static int l_get_angle(lua_State *L);
+ static int l_set_angle(lua_State *L);
+
+ static int l_get_mode(lua_State *L);
+ static int l_set_mode(lua_State *L);
+
+ static int l_show(lua_State *L);
+ static int l_hide(lua_State *L);
+
+ static int l_set_shape(lua_State *L);
+ static int l_get_shape(lua_State *L);
+
+ Minimap *m_minimap;
+
+public:
+ LuaMinimap(Minimap *m);
+ ~LuaMinimap() {}
+
+ static void create(lua_State *L, Minimap *object);
+
+ static LuaMinimap *checkobject(lua_State *L, int narg);
+ static Minimap *getobject(LuaMinimap *ref);
+
+ static void Register(lua_State *L);
+};
+
+#endif // L_MINIMAP_H_
diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp
index c8bc7d558..5dfa6d52e 100644
--- a/src/script/lua_api/l_nodemeta.cpp
+++ b/src/script/lua_api/l_nodemeta.cpp
@@ -20,14 +20,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_nodemeta.h"
#include "lua_api/l_internal.h"
#include "lua_api/l_inventory.h"
-#include "common/c_converter.h"
#include "common/c_content.h"
-#include "environment.h"
+#include "serverenvironment.h"
#include "map.h"
-#include "gamedef.h"
-#include "nodemetadata.h"
-
-
+#include "server.h"
/*
NodeMetaRef
@@ -40,12 +36,15 @@ NodeMetaRef* NodeMetaRef::checkobject(lua_State *L, int narg)
return *(NodeMetaRef**)ud; // unbox pointer
}
-NodeMetadata* NodeMetaRef::getmeta(NodeMetaRef *ref, bool auto_create)
+Metadata* NodeMetaRef::getmeta(bool auto_create)
{
- NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p);
- if(meta == NULL && auto_create) {
- meta = new NodeMetadata(ref->m_env->getGameDef()->idef());
- if(!ref->m_env->getMap().setNodeMetadata(ref->m_p, meta)) {
+ if (m_is_local)
+ return m_meta;
+
+ NodeMetadata *meta = m_env->getMap().getNodeMetadata(m_p);
+ if (meta == NULL && auto_create) {
+ meta = new NodeMetadata(m_env->getGameDef()->idef());
+ if (!m_env->getMap().setNodeMetadata(m_p, meta)) {
delete meta;
return NULL;
}
@@ -53,17 +52,22 @@ NodeMetadata* NodeMetaRef::getmeta(NodeMetaRef *ref, bool auto_create)
return meta;
}
-void NodeMetaRef::reportMetadataChange(NodeMetaRef *ref)
+void NodeMetaRef::clearMeta()
+{
+ m_env->getMap().removeNodeMetadata(m_p);
+}
+
+void NodeMetaRef::reportMetadataChange()
{
// NOTE: This same code is in rollback_interface.cpp
// Inform other things that the metadata has changed
- v3s16 blockpos = getNodeBlockPos(ref->m_p);
+ v3s16 blockpos = getNodeBlockPos(m_p);
MapEditEvent event;
event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
event.p = blockpos;
- ref->m_env->getMap().dispatchEvent(&event);
+ m_env->getMap().dispatchEvent(&event);
// Set the block to be saved
- MapBlock *block = ref->m_env->getMap().getBlockNoCreateNoEx(blockpos);
+ MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
if (block) {
block->raiseModified(MOD_STATE_WRITE_NEEDED,
MOD_REASON_REPORT_META_CHANGE);
@@ -79,154 +83,49 @@ int NodeMetaRef::gc_object(lua_State *L) {
return 0;
}
-// get_string(self, name)
-int NodeMetaRef::l_get_string(lua_State *L)
-{
- MAP_LOCK_REQUIRED;
-
- NodeMetaRef *ref = checkobject(L, 1);
- std::string name = luaL_checkstring(L, 2);
-
- NodeMetadata *meta = getmeta(ref, false);
- if(meta == NULL){
- lua_pushlstring(L, "", 0);
- return 1;
- }
- std::string str = meta->getString(name);
- lua_pushlstring(L, str.c_str(), str.size());
- return 1;
-}
-
-// set_string(self, name, var)
-int NodeMetaRef::l_set_string(lua_State *L)
-{
- MAP_LOCK_REQUIRED;
-
- NodeMetaRef *ref = checkobject(L, 1);
- std::string name = luaL_checkstring(L, 2);
- size_t len = 0;
- const char *s = lua_tolstring(L, 3, &len);
- std::string str(s, len);
-
- NodeMetadata *meta = getmeta(ref, !str.empty());
- if(meta == NULL || str == meta->getString(name))
- return 0;
- meta->setString(name, str);
- reportMetadataChange(ref);
- return 0;
-}
-
-// get_int(self, name)
-int NodeMetaRef::l_get_int(lua_State *L)
-{
- MAP_LOCK_REQUIRED;
-
- NodeMetaRef *ref = checkobject(L, 1);
- std::string name = lua_tostring(L, 2);
-
- NodeMetadata *meta = getmeta(ref, false);
- if(meta == NULL){
- lua_pushnumber(L, 0);
- return 1;
- }
- std::string str = meta->getString(name);
- lua_pushnumber(L, stoi(str));
- return 1;
-}
-
-// set_int(self, name, var)
-int NodeMetaRef::l_set_int(lua_State *L)
-{
- MAP_LOCK_REQUIRED;
-
- NodeMetaRef *ref = checkobject(L, 1);
- std::string name = lua_tostring(L, 2);
- int a = lua_tointeger(L, 3);
- std::string str = itos(a);
-
- NodeMetadata *meta = getmeta(ref, true);
- if(meta == NULL || str == meta->getString(name))
- return 0;
- meta->setString(name, str);
- reportMetadataChange(ref);
- return 0;
-}
-
-// get_float(self, name)
-int NodeMetaRef::l_get_float(lua_State *L)
-{
- MAP_LOCK_REQUIRED;
-
- NodeMetaRef *ref = checkobject(L, 1);
- std::string name = lua_tostring(L, 2);
-
- NodeMetadata *meta = getmeta(ref, false);
- if(meta == NULL){
- lua_pushnumber(L, 0);
- return 1;
- }
- std::string str = meta->getString(name);
- lua_pushnumber(L, stof(str));
- return 1;
-}
-
-// set_float(self, name, var)
-int NodeMetaRef::l_set_float(lua_State *L)
-{
- MAP_LOCK_REQUIRED;
-
- NodeMetaRef *ref = checkobject(L, 1);
- std::string name = lua_tostring(L, 2);
- float a = lua_tonumber(L, 3);
- std::string str = ftos(a);
-
- NodeMetadata *meta = getmeta(ref, true);
- if(meta == NULL || str == meta->getString(name))
- return 0;
- meta->setString(name, str);
- reportMetadataChange(ref);
- return 0;
-}
-
// get_inventory(self)
int NodeMetaRef::l_get_inventory(lua_State *L)
{
MAP_LOCK_REQUIRED;
NodeMetaRef *ref = checkobject(L, 1);
- getmeta(ref, true); // try to ensure the metadata exists
+ ref->getmeta(true); // try to ensure the metadata exists
InvRef::createNodeMeta(L, ref->m_p);
return 1;
}
-// to_table(self)
-int NodeMetaRef::l_to_table(lua_State *L)
+// mark_as_private(self, <string> or {<string>, <string>, ...})
+int NodeMetaRef::l_mark_as_private(lua_State *L)
{
MAP_LOCK_REQUIRED;
NodeMetaRef *ref = checkobject(L, 1);
+ NodeMetadata *meta = dynamic_cast<NodeMetadata*>(ref->getmeta(true));
+ assert(meta);
- NodeMetadata *meta = getmeta(ref, true);
- if (meta == NULL) {
+ if (lua_istable(L, 2)) {
lua_pushnil(L);
- return 1;
+ while (lua_next(L, 2) != 0) {
+ // key at index -2 and value at index -1
+ luaL_checktype(L, -1, LUA_TSTRING);
+ meta->markPrivate(lua_tostring(L, -1), true);
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ } else if (lua_isstring(L, 2)) {
+ meta->markPrivate(lua_tostring(L, 2), true);
}
- lua_newtable(L);
+ ref->reportMetadataChange();
+ return 0;
+}
+
+void NodeMetaRef::handleToTable(lua_State *L, Metadata *_meta)
+{
// fields
- lua_newtable(L);
- {
- StringMap fields = meta->getStrings();
- for (StringMap::const_iterator
- it = fields.begin(); it != fields.end(); ++it) {
- const std::string &name = it->first;
- const std::string &value = it->second;
- lua_pushlstring(L, name.c_str(), name.size());
- lua_pushlstring(L, value.c_str(), value.size());
- lua_settable(L, -3);
- }
- }
- lua_setfield(L, -2, "fields");
+ MetaDataRef::handleToTable(L, _meta);
+
+ NodeMetadata *meta = (NodeMetadata*) _meta;
// inventory
lua_newtable(L);
@@ -234,71 +133,52 @@ int NodeMetaRef::l_to_table(lua_State *L)
if (inv) {
std::vector<const InventoryList *> lists = inv->getLists();
for(std::vector<const InventoryList *>::const_iterator
- i = lists.begin(); i != lists.end(); i++) {
+ i = lists.begin(); i != lists.end(); ++i) {
push_inventory_list(L, inv, (*i)->getName().c_str());
lua_setfield(L, -2, (*i)->getName().c_str());
}
}
lua_setfield(L, -2, "inventory");
- return 1;
}
// from_table(self, table)
-int NodeMetaRef::l_from_table(lua_State *L)
+bool NodeMetaRef::handleFromTable(lua_State *L, int table, Metadata *_meta)
{
- MAP_LOCK_REQUIRED;
-
- NodeMetaRef *ref = checkobject(L, 1);
- int base = 2;
-
- // clear old metadata first
- ref->m_env->getMap().removeNodeMetadata(ref->m_p);
+ // fields
+ if (!MetaDataRef::handleFromTable(L, table, _meta))
+ return false;
- if(lua_isnil(L, base)){
- // No metadata
- lua_pushboolean(L, true);
- return 1;
- }
+ NodeMetadata *meta = (NodeMetadata*) _meta;
- // Create new metadata
- NodeMetadata *meta = getmeta(ref, true);
- if(meta == NULL){
- lua_pushboolean(L, false);
- return 1;
- }
- // Set fields
- lua_getfield(L, base, "fields");
- int fieldstable = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, fieldstable) != 0){
- // key at index -2 and value at index -1
- std::string name = lua_tostring(L, -2);
- size_t cl;
- const char *cs = lua_tolstring(L, -1, &cl);
- std::string value(cs, cl);
- meta->setString(name, value);
- lua_pop(L, 1); // removes value, keeps key for next iteration
- }
- // Set inventory
+ // inventory
Inventory *inv = meta->getInventory();
- lua_getfield(L, base, "inventory");
- int inventorytable = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, inventorytable) != 0){
- // key at index -2 and value at index -1
- std::string name = lua_tostring(L, -2);
- read_inventory_list(L, -1, inv, name.c_str(), getServer(L));
- lua_pop(L, 1); // removes value, keeps key for next iteration
+ lua_getfield(L, table, "inventory");
+ if (lua_istable(L, -1)) {
+ int inventorytable = lua_gettop(L);
+ lua_pushnil(L);
+ while (lua_next(L, inventorytable) != 0) {
+ // key at index -2 and value at index -1
+ std::string name = lua_tostring(L, -2);
+ read_inventory_list(L, -1, inv, name.c_str(), getServer(L));
+ lua_pop(L, 1); // Remove value, keep key for next iteration
+ }
+ lua_pop(L, 1);
}
- reportMetadataChange(ref);
- lua_pushboolean(L, true);
- return 1;
+
+ return true;
}
NodeMetaRef::NodeMetaRef(v3s16 p, ServerEnvironment *env):
m_p(p),
- m_env(env)
+ m_env(env),
+ m_is_local(false)
+{
+}
+
+NodeMetaRef::NodeMetaRef(Metadata *meta):
+ m_meta(meta),
+ m_is_local(true)
{
}
@@ -317,7 +197,17 @@ void NodeMetaRef::create(lua_State *L, v3s16 p, ServerEnvironment *env)
lua_setmetatable(L, -2);
}
-void NodeMetaRef::Register(lua_State *L)
+// Client-sided version of the above
+void NodeMetaRef::createClient(lua_State *L, Metadata *meta)
+{
+ NodeMetaRef *o = new NodeMetaRef(meta);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+}
+
+const char NodeMetaRef::className[] = "NodeMetaRef";
+void NodeMetaRef::RegisterCommon(lua_State *L)
{
lua_newtable(L);
int methodtable = lua_gettop(L);
@@ -328,6 +218,10 @@ void NodeMetaRef::Register(lua_State *L)
lua_pushvalue(L, methodtable);
lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+ lua_pushliteral(L, "metadata_class");
+ lua_pushlstring(L, className, strlen(className));
+ lua_settable(L, metatable);
+
lua_pushliteral(L, "__index");
lua_pushvalue(L, methodtable);
lua_settable(L, metatable);
@@ -336,25 +230,49 @@ void NodeMetaRef::Register(lua_State *L)
lua_pushcfunction(L, gc_object);
lua_settable(L, metatable);
+ lua_pushliteral(L, "__eq");
+ lua_pushcfunction(L, l_equals);
+ lua_settable(L, metatable);
+
lua_pop(L, 1); // drop metatable
+}
- luaL_openlib(L, 0, methods, 0); // fill methodtable
+void NodeMetaRef::Register(lua_State *L)
+{
+ RegisterCommon(L);
+ luaL_openlib(L, 0, methodsServer, 0); // fill methodtable
lua_pop(L, 1); // drop methodtable
-
- // Cannot be created from Lua
- //lua_register(L, className, create_object);
}
-const char NodeMetaRef::className[] = "NodeMetaRef";
-const luaL_reg NodeMetaRef::methods[] = {
- luamethod(NodeMetaRef, get_string),
- luamethod(NodeMetaRef, set_string),
- luamethod(NodeMetaRef, get_int),
- luamethod(NodeMetaRef, set_int),
- luamethod(NodeMetaRef, get_float),
- luamethod(NodeMetaRef, set_float),
+
+const luaL_Reg NodeMetaRef::methodsServer[] = {
+ luamethod(MetaDataRef, get_string),
+ luamethod(MetaDataRef, set_string),
+ luamethod(MetaDataRef, get_int),
+ luamethod(MetaDataRef, set_int),
+ luamethod(MetaDataRef, get_float),
+ luamethod(MetaDataRef, set_float),
+ luamethod(MetaDataRef, to_table),
+ luamethod(MetaDataRef, from_table),
luamethod(NodeMetaRef, get_inventory),
- luamethod(NodeMetaRef, to_table),
- luamethod(NodeMetaRef, from_table),
+ luamethod(NodeMetaRef, mark_as_private),
+ luamethod(MetaDataRef, equals),
+ {0,0}
+};
+
+
+void NodeMetaRef::RegisterClient(lua_State *L)
+{
+ RegisterCommon(L);
+ luaL_openlib(L, 0, methodsClient, 0); // fill methodtable
+ lua_pop(L, 1); // drop methodtable
+}
+
+
+const luaL_Reg NodeMetaRef::methodsClient[] = {
+ luamethod(MetaDataRef, get_string),
+ luamethod(MetaDataRef, get_int),
+ luamethod(MetaDataRef, get_float),
+ luamethod(MetaDataRef, to_table),
{0,0}
};
diff --git a/src/script/lua_api/l_nodemeta.h b/src/script/lua_api/l_nodemeta.h
index e39ac3931..dd4260ff9 100644
--- a/src/script/lua_api/l_nodemeta.h
+++ b/src/script/lua_api/l_nodemeta.h
@@ -20,7 +20,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define L_NODEMETA_H_
#include "lua_api/l_base.h"
+#include "lua_api/l_metadata.h"
#include "irrlichttypes_bloated.h"
+#include "nodemetadata.h"
class ServerEnvironment;
class NodeMetadata;
@@ -29,13 +31,16 @@ class NodeMetadata;
NodeMetaRef
*/
-class NodeMetaRef : public ModApiBase {
+class NodeMetaRef : public MetaDataRef {
private:
v3s16 m_p;
ServerEnvironment *m_env;
+ Metadata *m_meta;
+ bool m_is_local;
static const char className[];
- static const luaL_reg methods[];
+ static const luaL_Reg methodsServer[];
+ static const luaL_Reg methodsClient[];
static NodeMetaRef *checkobject(lua_State *L, int narg);
@@ -52,44 +57,28 @@ private:
* @param auto_create when true, try to create metadata information for the node if it has none.
* @return pointer to a @c NodeMetadata object or @c NULL in case of error.
*/
- static NodeMetadata* getmeta(NodeMetaRef *ref, bool auto_create);
+ virtual Metadata* getmeta(bool auto_create);
+ virtual void clearMeta();
- static void reportMetadataChange(NodeMetaRef *ref);
+ virtual void reportMetadataChange();
+
+ virtual void handleToTable(lua_State *L, Metadata *_meta);
+ virtual bool handleFromTable(lua_State *L, int table, Metadata *_meta);
// Exported functions
// garbage collector
static int gc_object(lua_State *L);
- // get_string(self, name)
- static int l_get_string(lua_State *L);
-
- // set_string(self, name, var)
- static int l_set_string(lua_State *L);
-
- // get_int(self, name)
- static int l_get_int(lua_State *L);
-
- // set_int(self, name, var)
- static int l_set_int(lua_State *L);
-
- // get_float(self, name)
- static int l_get_float(lua_State *L);
-
- // set_float(self, name, var)
- static int l_set_float(lua_State *L);
-
// get_inventory(self)
static int l_get_inventory(lua_State *L);
- // to_table(self)
- static int l_to_table(lua_State *L);
-
- // from_table(self, table)
- static int l_from_table(lua_State *L);
+ // mark_as_private(self, <string> or {<string>, <string>, ...})
+ static int l_mark_as_private(lua_State *L);
public:
NodeMetaRef(v3s16 p, ServerEnvironment *env);
+ NodeMetaRef(Metadata *meta);
~NodeMetaRef();
@@ -97,7 +86,12 @@ public:
// Not callable from Lua; all references are created on the C side.
static void create(lua_State *L, v3s16 p, ServerEnvironment *env);
+ // Client-sided version of the above
+ static void createClient(lua_State *L, Metadata *meta);
+
+ static void RegisterCommon(lua_State *L);
static void Register(lua_State *L);
+ static void RegisterClient(lua_State *L);
};
#endif /* L_NODEMETA_H_ */
diff --git a/src/script/lua_api/l_nodetimer.cpp b/src/script/lua_api/l_nodetimer.cpp
index 3242d6ea5..17b275c46 100644
--- a/src/script/lua_api/l_nodetimer.cpp
+++ b/src/script/lua_api/l_nodetimer.cpp
@@ -19,7 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_nodetimer.h"
#include "lua_api/l_internal.h"
-#include "environment.h"
+#include "serverenvironment.h"
#include "map.h"
@@ -162,7 +162,7 @@ void NodeTimerRef::Register(lua_State *L)
}
const char NodeTimerRef::className[] = "NodeTimerRef";
-const luaL_reg NodeTimerRef::methods[] = {
+const luaL_Reg NodeTimerRef::methods[] = {
luamethod(NodeTimerRef, start),
luamethod(NodeTimerRef, set),
luamethod(NodeTimerRef, stop),
diff --git a/src/script/lua_api/l_nodetimer.h b/src/script/lua_api/l_nodetimer.h
index 9f8dd21c8..ae362d8b3 100644
--- a/src/script/lua_api/l_nodetimer.h
+++ b/src/script/lua_api/l_nodetimer.h
@@ -20,18 +20,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef L_NODETIMER_H_
#define L_NODETIMER_H_
-#include "lua_api/l_base.h"
#include "irr_v3d.h"
+#include "lua_api/l_base.h"
class ServerEnvironment;
-class NodeTimerRef : public ModApiBase {
+class NodeTimerRef : public ModApiBase
+{
private:
v3s16 m_p;
ServerEnvironment *m_env;
static const char className[];
- static const luaL_reg methods[];
+ static const luaL_Reg methods[];
static int gc_object(lua_State *L);
@@ -62,6 +63,4 @@ public:
static void Register(lua_State *L);
};
-
-
#endif /* L_NODETIMER_H_ */
diff --git a/src/script/lua_api/l_noise.cpp b/src/script/lua_api/l_noise.cpp
index e0039371f..e3e76191f 100644
--- a/src/script/lua_api/l_noise.cpp
+++ b/src/script/lua_api/l_noise.cpp
@@ -135,7 +135,7 @@ void LuaPerlinNoise::Register(lua_State *L)
const char LuaPerlinNoise::className[] = "PerlinNoise";
-const luaL_reg LuaPerlinNoise::methods[] = {
+const luaL_Reg LuaPerlinNoise::methods[] = {
luamethod(LuaPerlinNoise, get2d),
luamethod(LuaPerlinNoise, get3d),
{0,0}
@@ -393,7 +393,7 @@ void LuaPerlinNoiseMap::Register(lua_State *L)
const char LuaPerlinNoiseMap::className[] = "PerlinNoiseMap";
-const luaL_reg LuaPerlinNoiseMap::methods[] = {
+const luaL_Reg LuaPerlinNoiseMap::methods[] = {
luamethod(LuaPerlinNoiseMap, get2dMap),
luamethod(LuaPerlinNoiseMap, get2dMap_flat),
luamethod(LuaPerlinNoiseMap, calc2dMap),
@@ -498,7 +498,7 @@ void LuaPseudoRandom::Register(lua_State *L)
const char LuaPseudoRandom::className[] = "PseudoRandom";
-const luaL_reg LuaPseudoRandom::methods[] = {
+const luaL_Reg LuaPseudoRandom::methods[] = {
luamethod(LuaPseudoRandom, next),
{0,0}
};
@@ -597,7 +597,7 @@ void LuaPcgRandom::Register(lua_State *L)
const char LuaPcgRandom::className[] = "PcgRandom";
-const luaL_reg LuaPcgRandom::methods[] = {
+const luaL_Reg LuaPcgRandom::methods[] = {
luamethod(LuaPcgRandom, next),
luamethod(LuaPcgRandom, rand_normal_dist),
{0,0}
@@ -711,7 +711,7 @@ void LuaSecureRandom::Register(lua_State *L)
}
const char LuaSecureRandom::className[] = "SecureRandom";
-const luaL_reg LuaSecureRandom::methods[] = {
+const luaL_Reg LuaSecureRandom::methods[] = {
luamethod(LuaSecureRandom, next_bytes),
{0,0}
};
diff --git a/src/script/lua_api/l_noise.h b/src/script/lua_api/l_noise.h
index 40bfd1315..f252b5ba2 100644
--- a/src/script/lua_api/l_noise.h
+++ b/src/script/lua_api/l_noise.h
@@ -20,18 +20,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef L_NOISE_H_
#define L_NOISE_H_
-#include "lua_api/l_base.h"
#include "irr_v3d.h"
+#include "lua_api/l_base.h"
#include "noise.h"
/*
LuaPerlinNoise
*/
-class LuaPerlinNoise : public ModApiBase {
+class LuaPerlinNoise : public ModApiBase
+{
private:
NoiseParams np;
static const char className[];
- static const luaL_reg methods[];
+ static const luaL_Reg methods[];
// Exported functions
@@ -57,12 +58,13 @@ public:
/*
LuaPerlinNoiseMap
*/
-class LuaPerlinNoiseMap : public ModApiBase {
+class LuaPerlinNoiseMap : public ModApiBase
+{
NoiseParams np;
Noise *noise;
bool m_is3d;
static const char className[];
- static const luaL_reg methods[];
+ static const luaL_Reg methods[];
// Exported functions
@@ -95,12 +97,13 @@ public:
/*
LuaPseudoRandom
*/
-class LuaPseudoRandom : public ModApiBase {
+class LuaPseudoRandom : public ModApiBase
+{
private:
PseudoRandom m_pseudo;
static const char className[];
- static const luaL_reg methods[];
+ static const luaL_Reg methods[];
// Exported functions
@@ -111,8 +114,7 @@ private:
static int l_next(lua_State *L);
public:
- LuaPseudoRandom(s32 seed) :
- m_pseudo(seed) {}
+ LuaPseudoRandom(s32 seed) : m_pseudo(seed) {}
// LuaPseudoRandom(seed)
// Creates an LuaPseudoRandom and leaves it on top of stack
@@ -126,12 +128,13 @@ public:
/*
LuaPcgRandom
*/
-class LuaPcgRandom : public ModApiBase {
+class LuaPcgRandom : public ModApiBase
+{
private:
PcgRandom m_rnd;
static const char className[];
- static const luaL_reg methods[];
+ static const luaL_Reg methods[];
// Exported functions
@@ -146,10 +149,8 @@ private:
static int l_rand_normal_dist(lua_State *L);
public:
- LuaPcgRandom(u64 seed) :
- m_rnd(seed) {}
- LuaPcgRandom(u64 seed, u64 seq) :
- m_rnd(seed, seq) {}
+ LuaPcgRandom(u64 seed) : m_rnd(seed) {}
+ LuaPcgRandom(u64 seed, u64 seq) : m_rnd(seed, seq) {}
// LuaPcgRandom(seed)
// Creates an LuaPcgRandom and leaves it on top of stack
@@ -160,15 +161,15 @@ public:
static void Register(lua_State *L);
};
-
/*
LuaSecureRandom
*/
-class LuaSecureRandom : public ModApiBase {
+class LuaSecureRandom : public ModApiBase
+{
private:
static const size_t RAND_BUF_SIZE = 2048;
static const char className[];
- static const luaL_reg methods[];
+ static const luaL_Reg methods[];
u32 m_rand_idx;
char m_rand_buf[RAND_BUF_SIZE];
diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp
index 2a8b8a64e..aaab0d98e 100644
--- a/src/script/lua_api/l_object.cpp
+++ b/src/script/lua_api/l_object.cpp
@@ -29,7 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_sao.h"
#include "server.h"
#include "hud.h"
-#include "scripting_game.h"
+#include "scripting_server.h"
struct EnumString es_HudElementType[] =
{
@@ -137,8 +137,8 @@ int ObjectRef::l_remove(lua_State *L)
if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
return 0;
- UNORDERED_SET<int> child_ids = co->getAttachmentChildIds();
- UNORDERED_SET<int>::iterator it;
+ const UNORDERED_SET<int> &child_ids = co->getAttachmentChildIds();
+ UNORDERED_SET<int>::const_iterator it;
for (it = child_ids.begin(); it != child_ids.end(); ++it) {
// Child can be NULL if it was deleted earlier
if (ServerActiveObject *child = env->getActiveObject(*it))
@@ -150,9 +150,9 @@ int ObjectRef::l_remove(lua_State *L)
return 0;
}
-// getpos(self)
+// get_pos(self)
// returns: {x=num, y=num, z=num}
-int ObjectRef::l_getpos(lua_State *L)
+int ObjectRef::l_get_pos(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
@@ -169,8 +169,8 @@ int ObjectRef::l_getpos(lua_State *L)
return 1;
}
-// setpos(self, pos)
-int ObjectRef::l_setpos(lua_State *L)
+// set_pos(self, pos)
+int ObjectRef::l_set_pos(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
@@ -184,8 +184,8 @@ int ObjectRef::l_setpos(lua_State *L)
return 0;
}
-// moveto(self, pos, continuous=false)
-int ObjectRef::l_moveto(lua_State *L)
+// move_to(self, pos, continuous=false)
+int ObjectRef::l_move_to(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
@@ -364,7 +364,7 @@ int ObjectRef::l_set_wielded_item(lua_State *L)
ServerActiveObject *co = getobject(ref);
if (co == NULL) return 0;
// Do it
- ItemStack item = read_item(L, 2, getServer(L));
+ ItemStack item = read_item(L, 2, getServer(L)->idef());
bool success = co->setWieldedItem(item);
if (success && co->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
getServer(L)->SendInventory(((PlayerSAO*)co));
@@ -396,13 +396,12 @@ int ObjectRef::l_get_armor_groups(lua_State *L)
if (co == NULL)
return 0;
// Do it
- ItemGroupList groups = co->getArmorGroups();
- push_groups(L, groups);
+ push_groups(L, co->getArmorGroups());
return 1;
}
// set_physics_override(self, physics_override_speed, physics_override_jump,
-// physics_override_gravity, sneak, sneak_glitch)
+// physics_override_gravity, sneak, sneak_glitch, new_move)
int ObjectRef::l_set_physics_override(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -411,11 +410,18 @@ int ObjectRef::l_set_physics_override(lua_State *L)
if (co == NULL) return 0;
// Do it
if (lua_istable(L, 2)) {
- co->m_physics_override_speed = getfloatfield_default(L, 2, "speed", co->m_physics_override_speed);
- co->m_physics_override_jump = getfloatfield_default(L, 2, "jump", co->m_physics_override_jump);
- co->m_physics_override_gravity = getfloatfield_default(L, 2, "gravity", co->m_physics_override_gravity);
- co->m_physics_override_sneak = getboolfield_default(L, 2, "sneak", co->m_physics_override_sneak);
- co->m_physics_override_sneak_glitch = getboolfield_default(L, 2, "sneak_glitch", co->m_physics_override_sneak_glitch);
+ co->m_physics_override_speed = getfloatfield_default(
+ L, 2, "speed", co->m_physics_override_speed);
+ co->m_physics_override_jump = getfloatfield_default(
+ L, 2, "jump", co->m_physics_override_jump);
+ co->m_physics_override_gravity = getfloatfield_default(
+ L, 2, "gravity", co->m_physics_override_gravity);
+ co->m_physics_override_sneak = getboolfield_default(
+ L, 2, "sneak", co->m_physics_override_sneak);
+ co->m_physics_override_sneak_glitch = getboolfield_default(
+ L, 2, "sneak_glitch", co->m_physics_override_sneak_glitch);
+ co->m_physics_override_new_move = getboolfield_default(
+ L, 2, "new_move", co->m_physics_override_new_move);
co->m_physics_override_sent = false;
} else {
// old, non-table format
@@ -455,6 +461,8 @@ int ObjectRef::l_get_physics_override(lua_State *L)
lua_setfield(L, -2, "sneak");
lua_pushboolean(L, co->m_physics_override_sneak_glitch);
lua_setfield(L, -2, "sneak_glitch");
+ lua_pushboolean(L, co->m_physics_override_new_move);
+ lua_setfield(L, -2, "new_move");
return 1;
}
@@ -718,11 +726,13 @@ int ObjectRef::l_set_detach(lua_State *L)
v3f rotation;
co->getAttachment(&parent_id, &bone, &position, &rotation);
ServerActiveObject *parent = NULL;
- if (parent_id)
+ if (parent_id) {
parent = env->getActiveObject(parent_id);
-
+ co->setAttachment(0, "", position, rotation);
+ } else {
+ co->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0));
+ }
// Do it
- co->setAttachment(0, "", v3f(0,0,0), v3f(0,0,0));
if (parent != NULL)
parent->removeAttachmentChild(co->getId());
return 0;
@@ -738,7 +748,7 @@ int ObjectRef::l_set_properties(lua_State *L)
ObjectProperties *prop = co->accessObjectProperties();
if (!prop)
return 0;
- read_object_properties(L, 2, prop);
+ read_object_properties(L, 2, prop, getServer(L)->idef());
co->notifyObjectPropertiesModified();
return 0;
}
@@ -790,8 +800,7 @@ int ObjectRef::l_set_nametag_attributes(lua_State *L)
lua_pop(L, 1);
std::string nametag = getstringfield_default(L, 2, "text", "");
- if (nametag != "")
- prop->nametag = nametag;
+ prop->nametag = nametag;
co->notifyObjectPropertiesModified();
lua_pushboolean(L, true);
@@ -823,8 +832,8 @@ int ObjectRef::l_get_nametag_attributes(lua_State *L)
/* LuaEntitySAO-only */
-// setvelocity(self, {x=num, y=num, z=num})
-int ObjectRef::l_setvelocity(lua_State *L)
+// set_velocity(self, {x=num, y=num, z=num})
+int ObjectRef::l_set_velocity(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
@@ -836,8 +845,8 @@ int ObjectRef::l_setvelocity(lua_State *L)
return 0;
}
-// getvelocity(self)
-int ObjectRef::l_getvelocity(lua_State *L)
+// get_velocity(self)
+int ObjectRef::l_get_velocity(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
@@ -849,8 +858,8 @@ int ObjectRef::l_getvelocity(lua_State *L)
return 1;
}
-// setacceleration(self, {x=num, y=num, z=num})
-int ObjectRef::l_setacceleration(lua_State *L)
+// set_acceleration(self, {x=num, y=num, z=num})
+int ObjectRef::l_set_acceleration(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
@@ -863,8 +872,8 @@ int ObjectRef::l_setacceleration(lua_State *L)
return 0;
}
-// getacceleration(self)
-int ObjectRef::l_getacceleration(lua_State *L)
+// get_acceleration(self)
+int ObjectRef::l_get_acceleration(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
@@ -876,8 +885,8 @@ int ObjectRef::l_getacceleration(lua_State *L)
return 1;
}
-// setyaw(self, radians)
-int ObjectRef::l_setyaw(lua_State *L)
+// set_yaw(self, radians)
+int ObjectRef::l_set_yaw(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
@@ -889,8 +898,8 @@ int ObjectRef::l_setyaw(lua_State *L)
return 0;
}
-// getyaw(self)
-int ObjectRef::l_getyaw(lua_State *L)
+// get_yaw(self)
+int ObjectRef::l_get_yaw(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
@@ -902,8 +911,8 @@ int ObjectRef::l_getyaw(lua_State *L)
return 1;
}
-// settexturemod(self, mod)
-int ObjectRef::l_settexturemod(lua_State *L)
+// set_texture_mod(self, mod)
+int ObjectRef::l_set_texture_mod(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
@@ -915,9 +924,22 @@ int ObjectRef::l_settexturemod(lua_State *L)
return 0;
}
-// setsprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2,
+// get_texture_mod(self)
+int ObjectRef::l_get_texture_mod(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ LuaEntitySAO *co = getluaobject(ref);
+ if (co == NULL) return 0;
+ // Do it
+ std::string mod = co->getTextureMod();
+ lua_pushstring(L, mod.c_str());
+ return 1;
+}
+
+// set_sprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2,
// select_horiz_by_yawpitch=false)
-int ObjectRef::l_setsprite(lua_State *L)
+int ObjectRef::l_set_sprite(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
@@ -1152,13 +1174,8 @@ int ObjectRef::l_set_breath(lua_State *L)
PlayerSAO* co = getplayersao(ref);
if (co == NULL) return 0;
u16 breath = luaL_checknumber(L, 2);
- // Do it
co->setBreath(breath);
- // If the object is a player sent the breath to client
- if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
- getServer(L)->SendPlayerBreath(((PlayerSAO*)co)->getPeerID());
-
return 0;
}
@@ -1175,6 +1192,46 @@ int ObjectRef::l_get_breath(lua_State *L)
return 1;
}
+// set_attribute(self, attribute, value)
+int ObjectRef::l_set_attribute(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ PlayerSAO* co = getplayersao(ref);
+ if (co == NULL) {
+ return 0;
+ }
+
+ std::string attr = luaL_checkstring(L, 2);
+ if (lua_isnil(L, 3)) {
+ co->removeExtendedAttribute(attr);
+ } else {
+ std::string value = luaL_checkstring(L, 3);
+ co->setExtendedAttribute(attr, value);
+ }
+ return 1;
+}
+
+// get_attribute(self, attribute)
+int ObjectRef::l_get_attribute(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ PlayerSAO* co = getplayersao(ref);
+ if (co == NULL) {
+ return 0;
+ }
+
+ std::string attr = luaL_checkstring(L, 2);
+
+ std::string value = "";
+ if (co->getExtendedAttribute(attr, &value)) {
+ lua_pushstring(L, value.c_str());
+ return 1;
+ }
+
+ return 0;
+}
+
+
// set_inventory_formspec(self, formspec)
int ObjectRef::l_set_inventory_formspec(lua_State *L)
{
@@ -1606,7 +1663,7 @@ int ObjectRef::l_hud_get_hotbar_selected_image(lua_State *L)
return 1;
}
-// set_sky(self, bgcolor, type, list)
+// set_sky(self, bgcolor, type, list, clouds = true)
int ObjectRef::l_set_sky(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -1622,9 +1679,8 @@ int ObjectRef::l_set_sky(lua_State *L)
std::vector<std::string> params;
if (lua_istable(L, 4)) {
- int table = lua_gettop(L);
lua_pushnil(L);
- while (lua_next(L, table) != 0) {
+ while (lua_next(L, 4) != 0) {
// key at index -2 and value at index -1
if (lua_isstring(L, -1))
params.push_back(lua_tostring(L, -1));
@@ -1638,7 +1694,11 @@ int ObjectRef::l_set_sky(lua_State *L)
if (type == "skybox" && params.size() != 6)
throw LuaError("skybox expects 6 textures");
- if (!getServer(L)->setSky(player, bgcolor, type, params))
+ bool clouds = true;
+ if (lua_isboolean(L, 5))
+ clouds = lua_toboolean(L, 5);
+
+ if (!getServer(L)->setSky(player, bgcolor, type, params, clouds))
return 0;
lua_pushboolean(L, true);
@@ -1656,8 +1716,9 @@ int ObjectRef::l_get_sky(lua_State *L)
video::SColor bgcolor(255, 255, 255, 255);
std::string type;
std::vector<std::string> params;
+ bool clouds;
- player->getSky(&bgcolor, &type, &params);
+ player->getSky(&bgcolor, &type, &params, &clouds);
type = type == "" ? "regular" : type;
push_ARGB8(L, bgcolor);
@@ -1670,9 +1731,89 @@ int ObjectRef::l_get_sky(lua_State *L)
lua_rawseti(L, -2, i);
i++;
}
- return 3;
+ lua_pushboolean(L, clouds);
+ return 4;
}
+// set_clouds(self, {density=, color=, ambient=, height=, thickness=, speed=})
+int ObjectRef::l_set_clouds(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ RemotePlayer *player = getplayer(ref);
+ if (!player)
+ return 0;
+ if (!lua_istable(L, 2))
+ return 0;
+
+ CloudParams cloud_params = player->getCloudParams();
+
+ cloud_params.density = getfloatfield_default(L, 2, "density", cloud_params.density);
+
+ lua_getfield(L, 2, "color");
+ if (!lua_isnil(L, -1))
+ read_color(L, -1, &cloud_params.color_bright);
+ lua_pop(L, 1);
+ lua_getfield(L, 2, "ambient");
+ if (!lua_isnil(L, -1))
+ read_color(L, -1, &cloud_params.color_ambient);
+ lua_pop(L, 1);
+
+ cloud_params.height = getfloatfield_default(L, 2, "height", cloud_params.height );
+ cloud_params.thickness = getfloatfield_default(L, 2, "thickness", cloud_params.thickness);
+
+ lua_getfield(L, 2, "speed");
+ if (lua_istable(L, -1)) {
+ v2f new_speed;
+ new_speed.X = getfloatfield_default(L, -1, "x", 0);
+ new_speed.Y = getfloatfield_default(L, -1, "y", 0);
+ cloud_params.speed = new_speed;
+ }
+ lua_pop(L, 1);
+
+ if (!getServer(L)->setClouds(player, cloud_params.density,
+ cloud_params.color_bright, cloud_params.color_ambient,
+ cloud_params.height, cloud_params.thickness,
+ cloud_params.speed))
+ return 0;
+
+ player->setCloudParams(cloud_params);
+
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+int ObjectRef::l_get_clouds(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ RemotePlayer *player = getplayer(ref);
+ if (!player)
+ return 0;
+ const CloudParams &cloud_params = player->getCloudParams();
+
+ lua_newtable(L);
+ lua_pushnumber(L, cloud_params.density);
+ lua_setfield(L, -2, "density");
+ push_ARGB8(L, cloud_params.color_bright);
+ lua_setfield(L, -2, "color");
+ push_ARGB8(L, cloud_params.color_ambient);
+ lua_setfield(L, -2, "ambient");
+ lua_pushnumber(L, cloud_params.height);
+ lua_setfield(L, -2, "height");
+ lua_pushnumber(L, cloud_params.thickness);
+ lua_setfield(L, -2, "thickness");
+ lua_newtable(L);
+ lua_pushnumber(L, cloud_params.speed.X);
+ lua_setfield(L, -2, "x");
+ lua_pushnumber(L, cloud_params.speed.Y);
+ lua_setfield(L, -2, "y");
+ lua_setfield(L, -2, "speed");
+
+ return 1;
+}
+
+
// override_day_night_ratio(self, brightness=0...1)
int ObjectRef::l_override_day_night_ratio(lua_State *L)
{
@@ -1778,12 +1919,12 @@ void ObjectRef::Register(lua_State *L)
}
const char ObjectRef::className[] = "ObjectRef";
-const luaL_reg ObjectRef::methods[] = {
+const luaL_Reg ObjectRef::methods[] = {
// ServerActiveObject
luamethod(ObjectRef, remove),
- luamethod(ObjectRef, getpos),
- luamethod(ObjectRef, setpos),
- luamethod(ObjectRef, moveto),
+ luamethod_aliased(ObjectRef, get_pos, getpos),
+ luamethod_aliased(ObjectRef, set_pos, setpos),
+ luamethod_aliased(ObjectRef, move_to, moveto),
luamethod(ObjectRef, punch),
luamethod(ObjectRef, right_click),
luamethod(ObjectRef, set_hp),
@@ -1807,14 +1948,14 @@ const luaL_reg ObjectRef::methods[] = {
luamethod(ObjectRef, set_nametag_attributes),
luamethod(ObjectRef, get_nametag_attributes),
// LuaEntitySAO-only
- luamethod(ObjectRef, setvelocity),
- luamethod(ObjectRef, getvelocity),
- luamethod(ObjectRef, setacceleration),
- luamethod(ObjectRef, getacceleration),
- luamethod(ObjectRef, setyaw),
- luamethod(ObjectRef, getyaw),
- luamethod(ObjectRef, settexturemod),
- luamethod(ObjectRef, setsprite),
+ luamethod_aliased(ObjectRef, set_velocity, setvelocity),
+ luamethod_aliased(ObjectRef, get_velocity, getvelocity),
+ luamethod_aliased(ObjectRef, set_acceleration, setacceleration),
+ luamethod_aliased(ObjectRef, get_acceleration, getacceleration),
+ luamethod_aliased(ObjectRef, set_yaw, setyaw),
+ luamethod_aliased(ObjectRef, get_yaw, getyaw),
+ luamethod_aliased(ObjectRef, set_texture_mod, settexturemod),
+ luamethod_aliased(ObjectRef, set_sprite, setsprite),
luamethod(ObjectRef, get_entity_name),
luamethod(ObjectRef, get_luaentity),
// Player-only
@@ -1833,6 +1974,8 @@ const luaL_reg ObjectRef::methods[] = {
luamethod(ObjectRef, set_look_pitch),
luamethod(ObjectRef, get_breath),
luamethod(ObjectRef, set_breath),
+ luamethod(ObjectRef, get_attribute),
+ luamethod(ObjectRef, set_attribute),
luamethod(ObjectRef, set_inventory_formspec),
luamethod(ObjectRef, get_inventory_formspec),
luamethod(ObjectRef, get_player_control),
@@ -1853,6 +1996,8 @@ const luaL_reg ObjectRef::methods[] = {
luamethod(ObjectRef, hud_get_hotbar_selected_image),
luamethod(ObjectRef, set_sky),
luamethod(ObjectRef, get_sky),
+ luamethod(ObjectRef, set_clouds),
+ luamethod(ObjectRef, get_clouds),
luamethod(ObjectRef, override_day_night_ratio),
luamethod(ObjectRef, get_day_night_ratio),
luamethod(ObjectRef, set_local_animation),
diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h
index 09f10e417..9801ce02b 100644
--- a/src/script/lua_api/l_object.h
+++ b/src/script/lua_api/l_object.h
@@ -37,7 +37,7 @@ private:
ServerActiveObject *m_object;
static const char className[];
- static const luaL_reg methods[];
+ static const luaL_Reg methods[];
public:
static ObjectRef *checkobject(lua_State *L, int narg);
@@ -57,15 +57,15 @@ private:
// remove(self)
static int l_remove(lua_State *L);
- // getpos(self)
+ // get_pos(self)
// returns: {x=num, y=num, z=num}
- static int l_getpos(lua_State *L);
+ static int l_get_pos(lua_State *L);
- // setpos(self, pos)
- static int l_setpos(lua_State *L);
+ // set_pos(self, pos)
+ static int l_set_pos(lua_State *L);
- // moveto(self, pos, continuous=false)
- static int l_moveto(lua_State *L);
+ // move_to(self, pos, continuous=false)
+ static int l_move_to(lua_State *L);
// punch(self, puncher, time_from_last_punch, tool_capabilities, dir)
static int l_punch(lua_State *L);
@@ -105,7 +105,7 @@ private:
static int l_get_armor_groups(lua_State *L);
// set_physics_override(self, physics_override_speed, physics_override_jump,
- // physics_override_gravity, sneak, sneak_glitch)
+ // physics_override_gravity, sneak, sneak_glitch, new_move)
static int l_set_physics_override(lua_State *L);
// get_physics_override(self)
@@ -143,30 +143,33 @@ private:
/* LuaEntitySAO-only */
- // setvelocity(self, {x=num, y=num, z=num})
- static int l_setvelocity(lua_State *L);
+ // set_velocity(self, {x=num, y=num, z=num})
+ static int l_set_velocity(lua_State *L);
- // getvelocity(self)
- static int l_getvelocity(lua_State *L);
+ // get_velocity(self)
+ static int l_get_velocity(lua_State *L);
- // setacceleration(self, {x=num, y=num, z=num})
- static int l_setacceleration(lua_State *L);
+ // set_acceleration(self, {x=num, y=num, z=num})
+ static int l_set_acceleration(lua_State *L);
- // getacceleration(self)
- static int l_getacceleration(lua_State *L);
+ // get_acceleration(self)
+ static int l_get_acceleration(lua_State *L);
- // setyaw(self, radians)
- static int l_setyaw(lua_State *L);
+ // set_yaw(self, radians)
+ static int l_set_yaw(lua_State *L);
- // getyaw(self)
- static int l_getyaw(lua_State *L);
+ // get_yaw(self)
+ static int l_get_yaw(lua_State *L);
- // settexturemod(self, mod)
- static int l_settexturemod(lua_State *L);
+ // set_texture_mod(self, mod)
+ static int l_set_texture_mod(lua_State *L);
- // setsprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2,
+ // l_get_texture_mod(self)
+ static int l_get_texture_mod(lua_State *L);
+
+ // set_sprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2,
// select_horiz_by_yawpitch=false)
- static int l_setsprite(lua_State *L);
+ static int l_set_sprite(lua_State *L);
// DEPRECATED
// get_entity_name(self)
@@ -223,6 +226,12 @@ private:
// get_breath(self, breath)
static int l_get_breath(lua_State *L);
+ // set_attribute(self, attribute, value)
+ static int l_set_attribute(lua_State *L);
+
+ // get_attribute(self, attribute)
+ static int l_get_attribute(lua_State *L);
+
// set_inventory_formspec(self, formspec)
static int l_set_inventory_formspec(lua_State *L);
@@ -274,12 +283,18 @@ private:
// hud_get_hotbar_selected_image(self)
static int l_hud_get_hotbar_selected_image(lua_State *L);
- // set_sky(self, type, list)
+ // set_sky(self, bgcolor, type, list, clouds = true)
static int l_set_sky(lua_State *L);
- // get_sky(self, type, list)
+ // get_sky(self)
static int l_get_sky(lua_State *L);
+ // set_clouds(self, {density=, color=, ambient=, height=, thickness=, speed=})
+ static int l_set_clouds(lua_State *L);
+
+ // get_clouds(self)
+ static int l_get_clouds(lua_State *L);
+
// override_day_night_ratio(self, type)
static int l_override_day_night_ratio(lua_State *L);
diff --git a/src/script/lua_api/l_particles.cpp b/src/script/lua_api/l_particles.cpp
index 667ac7272..2f3e9a58d 100644
--- a/src/script/lua_api/l_particles.cpp
+++ b/src/script/lua_api/l_particles.cpp
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_object.h"
#include "lua_api/l_internal.h"
#include "common/c_converter.h"
+#include "common/c_content.h"
#include "server.h"
#include "particles.h"
@@ -34,6 +35,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// collision_removal = bool
// vertical = bool
// texture = e.g."default_wood.png"
+// animation = TileAnimation definition
+// glow = num
int ModApiParticles::l_add_particle(lua_State *L)
{
MAP_LOCK_REQUIRED;
@@ -47,10 +50,14 @@ int ModApiParticles::l_add_particle(lua_State *L)
bool collisiondetection, vertical, collision_removal;
collisiondetection = vertical = collision_removal = false;
+ struct TileAnimationParams animation;
+ animation.type = TAT_NONE;
std::string texture = "";
std::string playername = "";
+ u8 glow = 0;
+
if (lua_gettop(L) > 1) // deprecated
{
log_deprecated(L, "Deprecated add_particle call with individual parameters instead of definition");
@@ -101,11 +108,18 @@ int ModApiParticles::l_add_particle(lua_State *L)
collision_removal = getboolfield_default(L, 1,
"collision_removal", collision_removal);
vertical = getboolfield_default(L, 1, "vertical", vertical);
+
+ lua_getfield(L, 1, "animation");
+ animation = read_animation_definition(L, -1);
+ lua_pop(L, 1);
+
texture = getstringfield_default(L, 1, "texture", "");
playername = getstringfield_default(L, 1, "playername", "");
+
+ glow = getintfield_default(L, 1, "glow", 0);
}
getServer(L)->spawnParticle(playername, pos, vel, acc, expirationtime, size,
- collisiondetection, collision_removal, vertical, texture);
+ collisiondetection, collision_removal, vertical, texture, animation, glow);
return 1;
}
@@ -127,6 +141,8 @@ int ModApiParticles::l_add_particle(lua_State *L)
// collision_removal = bool
// vertical = bool
// texture = e.g."default_wood.png"
+// animation = TileAnimation definition
+// glow = num
int ModApiParticles::l_add_particlespawner(lua_State *L)
{
MAP_LOCK_REQUIRED;
@@ -139,9 +155,12 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
time= minexptime= maxexptime= minsize= maxsize= 1;
bool collisiondetection, vertical, collision_removal;
collisiondetection = vertical = collision_removal = false;
+ struct TileAnimationParams animation;
+ animation.type = TAT_NONE;
ServerActiveObject *attached = NULL;
std::string texture = "";
std::string playername = "";
+ u8 glow = 0;
if (lua_gettop(L) > 1) //deprecated
{
@@ -201,6 +220,10 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
collision_removal = getboolfield_default(L, 1,
"collision_removal", collision_removal);
+ lua_getfield(L, 1, "animation");
+ animation = read_animation_definition(L, -1);
+ lua_pop(L, 1);
+
lua_getfield(L, 1, "attached");
if (!lua_isnil(L, -1)) {
ObjectRef *ref = ObjectRef::checkobject(L, -1);
@@ -211,6 +234,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
vertical = getboolfield_default(L, 1, "vertical", vertical);
texture = getstringfield_default(L, 1, "texture", "");
playername = getstringfield_default(L, 1, "playername", "");
+ glow = getintfield_default(L, 1, "glow", 0);
}
u32 id = getServer(L)->addParticleSpawner(amount, time,
@@ -223,7 +247,8 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
collision_removal,
attached,
vertical,
- texture, playername);
+ texture, playername,
+ animation, glow);
lua_pushnumber(L, id);
return 1;
diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp
index b6d44e0ff..a0e475dec 100644
--- a/src/script/lua_api/l_server.cpp
+++ b/src/script/lua_api/l_server.cpp
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "environment.h"
#include "player.h"
#include "log.h"
+#include <algorithm>
// request_shutdown()
int ModApiServer::l_request_shutdown(lua_State *L)
@@ -33,7 +34,8 @@ int ModApiServer::l_request_shutdown(lua_State *L)
NO_MAP_LOCK_REQUIRED;
const char *msg = lua_tolstring(L, 1, NULL);
bool reconnect = lua_toboolean(L, 2);
- getServer(L)->requestShutdown(msg ? msg : "", reconnect);
+ float seconds_before_shutdown = lua_tonumber(L, 3);
+ getServer(L)->requestShutdown(msg ? msg : "", reconnect, seconds_before_shutdown);
return 0;
}
@@ -102,7 +104,7 @@ int ModApiServer::l_get_player_privs(lua_State *L)
int table = lua_gettop(L);
std::set<std::string> privs_s = server->getPlayerEffectivePrivs(name);
for(std::set<std::string>::const_iterator
- i = privs_s.begin(); i != privs_s.end(); i++){
+ i = privs_s.begin(); i != privs_s.end(); ++i){
lua_pushboolean(L, true);
lua_setfield(L, table, i->c_str());
}
@@ -136,7 +138,7 @@ int ModApiServer::l_get_player_ip(lua_State *L)
}
}
-// get_player_information()
+// get_player_information(name)
int ModApiServer::l_get_player_information(lua_State *L)
{
@@ -230,15 +232,15 @@ int ModApiServer::l_get_player_information(lua_State *L)
lua_pushnumber(L, uptime);
lua_settable(L, table);
+ lua_pushstring(L,"protocol_version");
+ lua_pushnumber(L, prot_vers);
+ lua_settable(L, table);
+
#ifndef NDEBUG
lua_pushstring(L,"serialization_version");
lua_pushnumber(L, ser_vers);
lua_settable(L, table);
- lua_pushstring(L,"protocol_version");
- lua_pushnumber(L, prot_vers);
- lua_settable(L, table);
-
lua_pushstring(L,"major");
lua_pushnumber(L, major);
lua_settable(L, table);
@@ -333,6 +335,22 @@ int ModApiServer::l_kick_player(lua_State *L)
return 1;
}
+int ModApiServer::l_remove_player(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ std::string name = luaL_checkstring(L, 1);
+ ServerEnvironment *s_env = dynamic_cast<ServerEnvironment *>(getEnv(L));
+ assert(s_env);
+
+ RemotePlayer *player = s_env->getPlayer(name.c_str());
+ if (!player)
+ lua_pushinteger(L, s_env->removePlayerFromDatabase(name) ? 0 : 1);
+ else
+ lua_pushinteger(L, 2);
+
+ return 1;
+}
+
// unban_player_or_ip()
int ModApiServer::l_unban_player_or_ip(lua_State *L)
{
@@ -400,7 +418,7 @@ int ModApiServer::l_get_modnames(lua_State *L)
// Package them up for Lua
lua_createtable(L, modlist.size(), 0);
std::vector<std::string>::iterator iter = modlist.begin();
- for (u16 i = 0; iter != modlist.end(); iter++) {
+ for (u16 i = 0; iter != modlist.end(); ++iter) {
lua_pushstring(L, iter->c_str());
lua_rawseti(L, -2, ++i);
}
@@ -438,6 +456,16 @@ int ModApiServer::l_sound_stop(lua_State *L)
return 0;
}
+int ModApiServer::l_sound_fade(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ s32 handle = luaL_checkinteger(L, 1);
+ float step = luaL_checknumber(L, 2);
+ float gain = luaL_checknumber(L, 3);
+ getServer(L)->fadeSound(handle, step, gain);
+ return 0;
+}
+
// is_singleplayer()
int ModApiServer::l_is_singleplayer(lua_State *L)
{
@@ -482,36 +510,6 @@ int ModApiServer::l_set_last_run_mod(lua_State *L)
return 0;
}
-#ifndef NDEBUG
-// cause_error(type_of_error)
-int ModApiServer::l_cause_error(lua_State *L)
-{
- NO_MAP_LOCK_REQUIRED;
- std::string type_of_error = "none";
- if(lua_isstring(L, 1))
- type_of_error = lua_tostring(L, 1);
-
- errorstream << "Error handler test called, errortype=" << type_of_error << std::endl;
-
- if(type_of_error == "segv") {
- volatile int* some_pointer = 0;
- errorstream << "Cause a sigsegv now: " << (*some_pointer) << std::endl;
-
- } else if (type_of_error == "zerodivision") {
-
- unsigned int some_number = porting::getTimeS();
- unsigned int zerovalue = 0;
- unsigned int result = some_number / zerovalue;
- errorstream << "Well this shouldn't ever be shown: " << result << std::endl;
-
- } else if (type_of_error == "exception") {
- throw BaseException("Errorhandler test fct called");
- }
-
- return 0;
-}
-#endif
-
void ModApiServer::Initialize(lua_State *L, int top)
{
API_FCT(request_shutdown);
@@ -531,6 +529,7 @@ void ModApiServer::Initialize(lua_State *L, int top)
API_FCT(show_formspec);
API_FCT(sound_play);
API_FCT(sound_stop);
+ API_FCT(sound_fade);
API_FCT(get_player_information);
API_FCT(get_player_privs);
@@ -539,12 +538,10 @@ void ModApiServer::Initialize(lua_State *L, int top)
API_FCT(get_ban_description);
API_FCT(ban_player);
API_FCT(kick_player);
+ API_FCT(remove_player);
API_FCT(unban_player_or_ip);
API_FCT(notify_authentication_modified);
API_FCT(get_last_run_mod);
API_FCT(set_last_run_mod);
-#ifndef NDEBUG
- API_FCT(cause_error);
-#endif
}
diff --git a/src/script/lua_api/l_server.h b/src/script/lua_api/l_server.h
index 1ad46d440..251a0ce89 100644
--- a/src/script/lua_api/l_server.h
+++ b/src/script/lua_api/l_server.h
@@ -22,7 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_base.h"
-class ModApiServer : public ModApiBase {
+class ModApiServer : public ModApiBase
+{
private:
// request_shutdown([message], [reconnect])
static int l_request_shutdown(lua_State *L);
@@ -67,13 +68,16 @@ private:
// sound_stop(handle)
static int l_sound_stop(lua_State *L);
+ // sound_fade(handle, step, gain)
+ static int l_sound_fade(lua_State *L);
+
// get_player_privs(name, text)
static int l_get_player_privs(lua_State *L);
// get_player_ip()
static int l_get_player_ip(lua_State *L);
- // get_player_information()
+ // get_player_information(name)
static int l_get_player_information(lua_State *L);
// get_ban_list()
@@ -91,6 +95,9 @@ private:
// kick_player(name, [message]) -> success
static int l_kick_player(lua_State *L);
+ // remove_player(name)
+ static int l_remove_player(lua_State *L);
+
// notify_authentication_modified(name)
static int l_notify_authentication_modified(lua_State *L);
@@ -100,14 +107,8 @@ private:
// set_last_run_mod(modname)
static int l_set_last_run_mod(lua_State *L);
-#ifndef NDEBUG
- // cause_error(type_of_error)
- static int l_cause_error(lua_State *L);
-#endif
-
public:
static void Initialize(lua_State *L, int top);
-
};
#endif /* L_SERVER_H_ */
diff --git a/src/script/lua_api/l_settings.cpp b/src/script/lua_api/l_settings.cpp
index d3fe03005..70807f3d2 100644
--- a/src/script/lua_api/l_settings.cpp
+++ b/src/script/lua_api/l_settings.cpp
@@ -23,6 +23,47 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "log.h"
+
+#define SET_SECURITY_CHECK(L, name) \
+ if (o->m_settings == g_settings && ScriptApiSecurity::isSecure(L) && \
+ name.compare(0, 7, "secure.") == 0) { \
+ throw LuaError("Attempt to set secure setting."); \
+ }
+
+LuaSettings::LuaSettings(Settings *settings, const std::string &filename) :
+ m_settings(settings),
+ m_filename(filename),
+ m_is_own_settings(false),
+ m_write_allowed(true)
+{
+}
+
+LuaSettings::LuaSettings(const std::string &filename, bool write_allowed) :
+ m_filename(filename),
+ m_is_own_settings(true),
+ m_write_allowed(write_allowed)
+{
+ m_settings = new Settings();
+ m_settings->readConfigFile(filename.c_str());
+}
+
+LuaSettings::~LuaSettings()
+{
+ if (m_is_own_settings)
+ delete m_settings;
+}
+
+
+void LuaSettings::create(lua_State *L, Settings *settings,
+ const std::string &filename)
+{
+ LuaSettings *o = new LuaSettings(settings, filename);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+}
+
+
// garbage collector
int LuaSettings::gc_object(lua_State* L)
{
@@ -31,6 +72,7 @@ int LuaSettings::gc_object(lua_State* L)
return 0;
}
+
// get(self, key) -> value
int LuaSettings::l_get(lua_State* L)
{
@@ -74,12 +116,30 @@ int LuaSettings::l_set(lua_State* L)
std::string key = std::string(luaL_checkstring(L, 2));
const char* value = luaL_checkstring(L, 3);
+ SET_SECURITY_CHECK(L, key);
+
if (!o->m_settings->set(key, value))
throw LuaError("Invalid sequence found in setting parameters");
return 0;
}
+// set_bool(self, key, value)
+int LuaSettings::l_set_bool(lua_State* L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ LuaSettings* o = checkobject(L, 1);
+
+ std::string key = std::string(luaL_checkstring(L, 2));
+ bool value = lua_toboolean(L, 3);
+
+ SET_SECURITY_CHECK(L, key);
+
+ o->m_settings->setBool(key, value);
+
+ return 1;
+}
+
// remove(self, key) -> success
int LuaSettings::l_remove(lua_State* L)
{
@@ -88,6 +148,8 @@ int LuaSettings::l_remove(lua_State* L)
std::string key = std::string(luaL_checkstring(L, 2));
+ SET_SECURITY_CHECK(L, key);
+
bool success = o->m_settings->remove(key);
lua_pushboolean(L, success);
@@ -147,19 +209,6 @@ int LuaSettings::l_to_table(lua_State* L)
return 1;
}
-LuaSettings::LuaSettings(const char* filename, bool write_allowed)
-{
- m_write_allowed = write_allowed;
- m_filename = std::string(filename);
-
- m_settings = new Settings();
- m_settings->readConfigFile(m_filename.c_str());
-}
-
-LuaSettings::~LuaSettings()
-{
- delete m_settings;
-}
void LuaSettings::Register(lua_State* L)
{
@@ -190,7 +239,7 @@ void LuaSettings::Register(lua_State* L)
}
// LuaSettings(filename)
-// Creates an LuaSettings and leaves it on top of stack
+// Creates a LuaSettings and leaves it on top of the stack
int LuaSettings::create_object(lua_State* L)
{
NO_MAP_LOCK_REQUIRED;
@@ -209,15 +258,17 @@ LuaSettings* LuaSettings::checkobject(lua_State* L, int narg)
NO_MAP_LOCK_REQUIRED;
luaL_checktype(L, narg, LUA_TUSERDATA);
void *ud = luaL_checkudata(L, narg, className);
- if(!ud) luaL_typerror(L, narg, className);
- return *(LuaSettings**)ud; // unbox pointer
+ if (!ud)
+ luaL_typerror(L, narg, className);
+ return *(LuaSettings**) ud; // unbox pointer
}
const char LuaSettings::className[] = "Settings";
-const luaL_reg LuaSettings::methods[] = {
+const luaL_Reg LuaSettings::methods[] = {
luamethod(LuaSettings, get),
luamethod(LuaSettings, get_bool),
luamethod(LuaSettings, set),
+ luamethod(LuaSettings, set_bool),
luamethod(LuaSettings, remove),
luamethod(LuaSettings, get_names),
luamethod(LuaSettings, write),
diff --git a/src/script/lua_api/l_settings.h b/src/script/lua_api/l_settings.h
index bca333e31..54b003ab3 100644
--- a/src/script/lua_api/l_settings.h
+++ b/src/script/lua_api/l_settings.h
@@ -24,51 +24,58 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Settings;
-class LuaSettings : public ModApiBase {
+class LuaSettings : public ModApiBase
+{
private:
static const char className[];
- static const luaL_reg methods[];
+ static const luaL_Reg methods[];
// garbage collector
- static int gc_object(lua_State* L);
+ static int gc_object(lua_State *L);
// get(self, key) -> value
- static int l_get(lua_State* L);
+ static int l_get(lua_State *L);
// get_bool(self, key) -> boolean
- static int l_get_bool(lua_State* L);
+ static int l_get_bool(lua_State *L);
// set(self, key, value)
- static int l_set(lua_State* L);
+ static int l_set(lua_State *L);
+
+ // set_bool(self, key, value)
+ static int l_set_bool(lua_State *L);
// remove(self, key) -> success
- static int l_remove(lua_State* L);
+ static int l_remove(lua_State *L);
// get_names(self) -> {key1, ...}
- static int l_get_names(lua_State* L);
+ static int l_get_names(lua_State *L);
// write(self) -> success
- static int l_write(lua_State* L);
+ static int l_write(lua_State *L);
// to_table(self) -> {[key1]=value1,...}
- static int l_to_table(lua_State* L);
+ static int l_to_table(lua_State *L);
- bool m_write_allowed;
- Settings* m_settings;
+ Settings *m_settings;
std::string m_filename;
+ bool m_is_own_settings;
+ bool m_write_allowed;
public:
- LuaSettings(const char* filename, bool write_allowed);
+ LuaSettings(Settings *settings, const std::string &filename);
+ LuaSettings(const std::string &filename, bool write_allowed);
~LuaSettings();
- // LuaSettings(filename)
- // Creates an LuaSettings and leaves it on top of stack
- static int create_object(lua_State* L);
+ static void create(lua_State *L, Settings *settings, const std::string &filename);
- static LuaSettings* checkobject(lua_State* L, int narg);
+ // LuaSettings(filename)
+ // Creates a LuaSettings and leaves it on top of the stack
+ static int create_object(lua_State *L);
- static void Register(lua_State* L);
+ static LuaSettings *checkobject(lua_State *L, int narg);
+ static void Register(lua_State *L);
};
#endif
diff --git a/src/script/lua_api/l_sound.cpp b/src/script/lua_api/l_sound.cpp
new file mode 100644
index 000000000..07ce36daa
--- /dev/null
+++ b/src/script/lua_api/l_sound.cpp
@@ -0,0 +1,53 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "l_sound.h"
+#include "l_internal.h"
+#include "common/c_content.h"
+#include "guiEngine.h"
+
+
+int ModApiSound::l_sound_play(lua_State *L)
+{
+ SimpleSoundSpec spec;
+ read_soundspec(L, 1, spec);
+ bool looped = lua_toboolean(L, 2);
+
+ s32 handle = getGuiEngine(L)->playSound(spec, looped);
+
+ lua_pushinteger(L, handle);
+
+ return 1;
+}
+
+int ModApiSound::l_sound_stop(lua_State *L)
+{
+ u32 handle = luaL_checkinteger(L, 1);
+
+ getGuiEngine(L)->stopSound(handle);
+
+ return 1;
+}
+
+void ModApiSound::Initialize(lua_State *L, int top)
+{
+ API_FCT(sound_play);
+ API_FCT(sound_stop);
+}
diff --git a/src/script/lua_api/l_sound.h b/src/script/lua_api/l_sound.h
new file mode 100644
index 000000000..1f0c1eba1
--- /dev/null
+++ b/src/script/lua_api/l_sound.h
@@ -0,0 +1,36 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 L_SOUND_H_
+#define L_SOUND_H_
+
+#include "lua_api/l_base.h"
+
+class ModApiSound : public ModApiBase
+{
+private:
+ static int l_sound_play(lua_State *L);
+ static int l_sound_stop(lua_State *L);
+
+public:
+ static void Initialize(lua_State *L, int top);
+};
+
+#endif
diff --git a/src/script/lua_api/l_storage.cpp b/src/script/lua_api/l_storage.cpp
new file mode 100644
index 000000000..4c6b2a182
--- /dev/null
+++ b/src/script/lua_api/l_storage.cpp
@@ -0,0 +1,147 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "lua_api/l_storage.h"
+#include "l_internal.h"
+#include "mods.h"
+#include "server.h"
+
+int ModApiStorage::l_get_mod_storage(lua_State *L)
+{
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
+ if (!lua_isstring(L, -1)) {
+ return 0;
+ }
+
+ std::string mod_name = lua_tostring(L, -1);
+
+ ModMetadata *store = new ModMetadata(mod_name);
+ if (IGameDef *gamedef = getGameDef(L)) {
+ store->load(gamedef->getModStoragePath());
+ gamedef->registerModStorage(store);
+ } else {
+ assert(false); // this should not happen
+ }
+
+ StorageRef::create(L, store);
+ int object = lua_gettop(L);
+
+ lua_pushvalue(L, object);
+ return 1;
+}
+
+void ModApiStorage::Initialize(lua_State *L, int top)
+{
+ API_FCT(get_mod_storage);
+}
+
+StorageRef::StorageRef(ModMetadata *object):
+ m_object(object)
+{
+}
+
+void StorageRef::create(lua_State *L, ModMetadata *object)
+{
+ StorageRef *o = new StorageRef(object);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+}
+
+int StorageRef::gc_object(lua_State *L)
+{
+ StorageRef *o = *(StorageRef **)(lua_touserdata(L, 1));
+ // Server side
+ if (IGameDef *gamedef = getGameDef(L))
+ gamedef->unregisterModStorage(getobject(o)->getModName());
+ delete o;
+ return 0;
+}
+
+void StorageRef::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+
+ lua_pushliteral(L, "metadata_class");
+ lua_pushlstring(L, className, strlen(className));
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__eq");
+ lua_pushcfunction(L, l_equals);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1); // drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // drop methodtable
+}
+
+StorageRef* StorageRef::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if (!ud) luaL_typerror(L, narg, className);
+ return *(StorageRef**)ud; // unbox pointer
+}
+
+ModMetadata* StorageRef::getobject(StorageRef *ref)
+{
+ ModMetadata *co = ref->m_object;
+ return co;
+}
+
+Metadata* StorageRef::getmeta(bool auto_create)
+{
+ return m_object;
+}
+
+void StorageRef::clearMeta()
+{
+ m_object->clear();
+}
+
+const char StorageRef::className[] = "StorageRef";
+const luaL_Reg StorageRef::methods[] = {
+ luamethod(MetaDataRef, get_string),
+ luamethod(MetaDataRef, set_string),
+ luamethod(MetaDataRef, get_int),
+ luamethod(MetaDataRef, set_int),
+ luamethod(MetaDataRef, get_float),
+ luamethod(MetaDataRef, set_float),
+ luamethod(MetaDataRef, to_table),
+ luamethod(MetaDataRef, from_table),
+ luamethod(MetaDataRef, equals),
+ {0,0}
+};
diff --git a/src/script/lua_api/l_storage.h b/src/script/lua_api/l_storage.h
new file mode 100644
index 000000000..ec6f8d941
--- /dev/null
+++ b/src/script/lua_api/l_storage.h
@@ -0,0 +1,63 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 __L_STORAGE_H__
+#define __L_STORAGE_H__
+
+#include "l_metadata.h"
+#include "lua_api/l_base.h"
+
+class ModMetadata;
+
+class ModApiStorage : public ModApiBase
+{
+protected:
+ static int l_get_mod_storage(lua_State *L);
+
+public:
+ static void Initialize(lua_State *L, int top);
+};
+
+class StorageRef : public MetaDataRef
+{
+private:
+ ModMetadata *m_object;
+
+ static const char className[];
+ static const luaL_Reg methods[];
+
+ virtual Metadata *getmeta(bool auto_create);
+ virtual void clearMeta();
+
+ // garbage collector
+ static int gc_object(lua_State *L);
+
+public:
+ StorageRef(ModMetadata *object);
+ ~StorageRef() {}
+
+ static void Register(lua_State *L);
+ static void create(lua_State *L, ModMetadata *object);
+
+ static StorageRef *checkobject(lua_State *L, int narg);
+ static ModMetadata *getobject(StorageRef *ref);
+};
+
+#endif /* __L_STORAGE_H__ */
diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp
index 26e2b985c..c4a988e07 100644
--- a/src/script/lua_api/l_util.cpp
+++ b/src/script/lua_api/l_util.cpp
@@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_util.h"
#include "lua_api/l_internal.h"
+#include "lua_api/l_settings.h"
#include "common/c_converter.h"
#include "common/c_content.h"
#include "cpp_api/s_async.h"
@@ -77,71 +78,6 @@ int ModApiUtil::l_get_us_time(lua_State *L)
return 1;
}
-#define CHECK_SECURE_SETTING(L, name) \
- if (ScriptApiSecurity::isSecure(L) && \
- name.compare(0, 7, "secure.") == 0) { \
- throw LuaError("Attempt to set secure setting."); \
- }
-
-// setting_set(name, value)
-int ModApiUtil::l_setting_set(lua_State *L)
-{
- NO_MAP_LOCK_REQUIRED;
- std::string name = luaL_checkstring(L, 1);
- std::string value = luaL_checkstring(L, 2);
- CHECK_SECURE_SETTING(L, name);
- g_settings->set(name, value);
- return 0;
-}
-
-// setting_get(name)
-int ModApiUtil::l_setting_get(lua_State *L)
-{
- NO_MAP_LOCK_REQUIRED;
- const char *name = luaL_checkstring(L, 1);
- try{
- std::string value = g_settings->get(name);
- lua_pushstring(L, value.c_str());
- } catch(SettingNotFoundException &e){
- lua_pushnil(L);
- }
- return 1;
-}
-
-// setting_setbool(name)
-int ModApiUtil::l_setting_setbool(lua_State *L)
-{
- NO_MAP_LOCK_REQUIRED;
- std::string name = luaL_checkstring(L, 1);
- bool value = lua_toboolean(L, 2);
- CHECK_SECURE_SETTING(L, name);
- g_settings->setBool(name, value);
- return 0;
-}
-
-// setting_getbool(name)
-int ModApiUtil::l_setting_getbool(lua_State *L)
-{
- NO_MAP_LOCK_REQUIRED;
- const char *name = luaL_checkstring(L, 1);
- try{
- bool value = g_settings->getBool(name);
- lua_pushboolean(L, value);
- } catch(SettingNotFoundException &e){
- lua_pushnil(L);
- }
- return 1;
-}
-
-// setting_save()
-int ModApiUtil::l_setting_save(lua_State *L)
-{
- NO_MAP_LOCK_REQUIRED;
- if(g_settings_path != "")
- g_settings->updateConfigFile(g_settings_path.c_str());
- return 0;
-}
-
// parse_json(str[, nullvalue])
int ModApiUtil::l_parse_json(lua_State *L)
{
@@ -398,7 +334,8 @@ int ModApiUtil::l_get_dir_list(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
const char *path = luaL_checkstring(L, 1);
- short is_dir = lua_isboolean(L, 2) ? lua_toboolean(L, 2) : -1;
+ bool list_all = !lua_isboolean(L, 2); // if its not a boolean list all
+ bool list_dirs = lua_toboolean(L, 2); // true: list dirs, false: list files
CHECK_SECURE_PATH(L, path, false);
@@ -408,7 +345,7 @@ int ModApiUtil::l_get_dir_list(lua_State *L)
lua_newtable(L);
for (size_t i = 0; i < list.size(); i++) {
- if (is_dir == -1 || is_dir == list[i].dir) {
+ if (list_all || list_dirs == list[i].dir) {
lua_pushstring(L, list[i].name.c_str());
lua_rawseti(L, -2, ++index);
}
@@ -492,12 +429,6 @@ void ModApiUtil::Initialize(lua_State *L, int top)
API_FCT(get_us_time);
- API_FCT(setting_set);
- API_FCT(setting_get);
- API_FCT(setting_setbool);
- API_FCT(setting_getbool);
- API_FCT(setting_save);
-
API_FCT(parse_json);
API_FCT(write_json);
@@ -523,36 +454,58 @@ void ModApiUtil::Initialize(lua_State *L, int top)
API_FCT(decode_base64);
API_FCT(get_version);
+
+ LuaSettings::create(L, g_settings, g_settings_path);
+ lua_setfield(L, top, "settings");
}
-void ModApiUtil::InitializeAsync(AsyncEngine& engine)
+void ModApiUtil::InitializeClient(lua_State *L, int top)
{
- ASYNC_API_FCT(log);
+ API_FCT(log);
+
+ API_FCT(get_us_time);
+
+ API_FCT(parse_json);
+ API_FCT(write_json);
+
+ API_FCT(is_yes);
+
+ API_FCT(get_builtin_path);
+
+ API_FCT(compress);
+ API_FCT(decompress);
+
+ API_FCT(encode_base64);
+ API_FCT(decode_base64);
+
+ API_FCT(get_version);
+}
- ASYNC_API_FCT(get_us_time);
+void ModApiUtil::InitializeAsync(lua_State *L, int top)
+{
+ API_FCT(log);
- //ASYNC_API_FCT(setting_set);
- ASYNC_API_FCT(setting_get);
- //ASYNC_API_FCT(setting_setbool);
- ASYNC_API_FCT(setting_getbool);
- //ASYNC_API_FCT(setting_save);
+ API_FCT(get_us_time);
- ASYNC_API_FCT(parse_json);
- ASYNC_API_FCT(write_json);
+ API_FCT(parse_json);
+ API_FCT(write_json);
- ASYNC_API_FCT(is_yes);
+ API_FCT(is_yes);
- ASYNC_API_FCT(get_builtin_path);
+ API_FCT(get_builtin_path);
- ASYNC_API_FCT(compress);
- ASYNC_API_FCT(decompress);
+ API_FCT(compress);
+ API_FCT(decompress);
+
+ API_FCT(mkdir);
+ API_FCT(get_dir_list);
- ASYNC_API_FCT(mkdir);
- ASYNC_API_FCT(get_dir_list);
+ API_FCT(encode_base64);
+ API_FCT(decode_base64);
- ASYNC_API_FCT(encode_base64);
- ASYNC_API_FCT(decode_base64);
+ API_FCT(get_version);
- ASYNC_API_FCT(get_version);
+ LuaSettings::create(L, g_settings, g_settings_path);
+ lua_setfield(L, top, "settings");
}
diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h
index 9910704b3..b75d9db29 100644
--- a/src/script/lua_api/l_util.h
+++ b/src/script/lua_api/l_util.h
@@ -24,7 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class AsyncEngine;
-class ModApiUtil : public ModApiBase {
+class ModApiUtil : public ModApiBase
+{
private:
/*
NOTE:
@@ -44,21 +45,6 @@ private:
// get us precision time
static int l_get_us_time(lua_State *L);
- // setting_set(name, value)
- static int l_setting_set(lua_State *L);
-
- // setting_get(name)
- static int l_setting_get(lua_State *L);
-
- // setting_setbool(name, value)
- static int l_setting_setbool(lua_State *L);
-
- // setting_getbool(name)
- static int l_setting_getbool(lua_State *L);
-
- // setting_save()
- static int l_setting_save(lua_State *L);
-
// parse_json(str[, nullvalue])
static int l_parse_json(lua_State *L);
@@ -109,10 +95,10 @@ private:
public:
static void Initialize(lua_State *L, int top);
+ static void InitializeAsync(lua_State *L, int top);
+ static void InitializeClient(lua_State *L, int top);
- static void InitializeAsync(AsyncEngine& engine);
-
+ static void InitializeAsync(AsyncEngine &engine);
};
#endif /* L_UTIL_H_ */
-
diff --git a/src/script/lua_api/l_vmanip.cpp b/src/script/lua_api/l_vmanip.cpp
index bdf720f0a..254a7e5a6 100644
--- a/src/script/lua_api/l_vmanip.cpp
+++ b/src/script/lua_api/l_vmanip.cpp
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h"
#include "server.h"
#include "mapgen.h"
+#include "voxelalgorithms.h"
// garbage collector
int LuaVoxelManip::gc_object(lua_State *L)
@@ -109,10 +110,25 @@ int LuaVoxelManip::l_write_to_map(lua_State *L)
MAP_LOCK_REQUIRED;
LuaVoxelManip *o = checkobject(L, 1);
- MMVManip *vm = o->vm;
+ bool update_light = lua_isboolean(L, 2) ? lua_toboolean(L, 2) : true;
+ GET_ENV_PTR;
+ ServerMap *map = &(env->getServerMap());
+ if (o->is_mapgen_vm || !update_light) {
+ o->vm->blitBackAll(&(o->modified_blocks));
+ } else {
+ voxalgo::blit_back_with_light(map, o->vm,
+ &(o->modified_blocks));
+ }
- vm->blitBackAll(&o->modified_blocks);
+ MapEditEvent event;
+ event.type = MEET_OTHER;
+ for (std::map<v3s16, MapBlock *>::iterator it = o->modified_blocks.begin();
+ it != o->modified_blocks.end(); ++it)
+ event.modified_blocks.insert(it->first);
+ map->dispatchEvent(&event);
+
+ o->modified_blocks.clear();
return 0;
}
@@ -322,33 +338,6 @@ int LuaVoxelManip::l_set_param2_data(lua_State *L)
int LuaVoxelManip::l_update_map(lua_State *L)
{
- GET_ENV_PTR;
-
- LuaVoxelManip *o = checkobject(L, 1);
- if (o->is_mapgen_vm)
- return 0;
-
- Map *map = &(env->getMap());
-
- // TODO: Optimize this by using Mapgen::calcLighting() instead
- std::map<v3s16, MapBlock *> lighting_mblocks;
- std::map<v3s16, MapBlock *> *mblocks = &o->modified_blocks;
-
- lighting_mblocks.insert(mblocks->begin(), mblocks->end());
-
- map->updateLighting(lighting_mblocks, *mblocks);
-
- MapEditEvent event;
- event.type = MEET_OTHER;
- for (std::map<v3s16, MapBlock *>::iterator
- it = mblocks->begin();
- it != mblocks->end(); ++it)
- event.modified_blocks.insert(it->first);
-
- map->dispatchEvent(&event);
-
- mblocks->clear();
-
return 0;
}
@@ -464,7 +453,7 @@ void LuaVoxelManip::Register(lua_State *L)
}
const char LuaVoxelManip::className[] = "VoxelManip";
-const luaL_reg LuaVoxelManip::methods[] = {
+const luaL_Reg LuaVoxelManip::methods[] = {
luamethod(LuaVoxelManip, read_from_map),
luamethod(LuaVoxelManip, get_data),
luamethod(LuaVoxelManip, set_data),
diff --git a/src/script/lua_api/l_vmanip.h b/src/script/lua_api/l_vmanip.h
index 1adb78c4e..b6a69f36a 100644
--- a/src/script/lua_api/l_vmanip.h
+++ b/src/script/lua_api/l_vmanip.h
@@ -20,9 +20,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef L_VMANIP_H_
#define L_VMANIP_H_
-#include "lua_api/l_base.h"
-#include "irr_v3d.h"
#include <map>
+#include "irr_v3d.h"
+#include "lua_api/l_base.h"
class Map;
class MapBlock;
@@ -31,13 +31,14 @@ class MMVManip;
/*
VoxelManip
*/
-class LuaVoxelManip : public ModApiBase {
+class LuaVoxelManip : public ModApiBase
+{
private:
std::map<v3s16, MapBlock *> modified_blocks;
bool is_mapgen_vm;
static const char className[];
- static const luaL_reg methods[];
+ static const luaL_Reg methods[];
static int gc_object(lua_State *L);
diff --git a/src/script/scripting_client.cpp b/src/script/scripting_client.cpp
new file mode 100644
index 000000000..da289e564
--- /dev/null
+++ b/src/script/scripting_client.cpp
@@ -0,0 +1,88 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "scripting_client.h"
+#include "client.h"
+#include "cpp_api/s_internal.h"
+#include "lua_api/l_client.h"
+#include "lua_api/l_env.h"
+#include "lua_api/l_minimap.h"
+#include "lua_api/l_storage.h"
+#include "lua_api/l_sound.h"
+#include "lua_api/l_util.h"
+#include "lua_api/l_item.h"
+#include "lua_api/l_nodemeta.h"
+#include "lua_api/l_localplayer.h"
+#include "lua_api/l_camera.h"
+
+ClientScripting::ClientScripting(Client *client):
+ ScriptApiBase()
+{
+ setGameDef(client);
+
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Security is mandatory client side
+ initializeSecurityClient();
+
+ lua_getglobal(L, "core");
+ int top = lua_gettop(L);
+
+ lua_newtable(L);
+ lua_setfield(L, -2, "ui");
+
+ InitializeModApi(L, top);
+ lua_pop(L, 1);
+
+ if (client->getMinimap())
+ LuaMinimap::create(L, client->getMinimap());
+
+ // Push builtin initialization type
+ lua_pushstring(L, "client");
+ lua_setglobal(L, "INIT");
+
+ infostream << "SCRIPTAPI: Initialized client game modules" << std::endl;
+}
+
+void ClientScripting::InitializeModApi(lua_State *L, int top)
+{
+ LuaItemStack::Register(L);
+ StorageRef::Register(L);
+ LuaMinimap::Register(L);
+ NodeMetaRef::RegisterClient(L);
+ LuaLocalPlayer::Register(L);
+ LuaCamera::Register(L);
+
+ ModApiUtil::InitializeClient(L, top);
+ ModApiClient::Initialize(L, top);
+ ModApiStorage::Initialize(L, top);
+ ModApiEnvMod::InitializeClient(L, top);
+}
+
+void ClientScripting::on_client_ready(LocalPlayer *localplayer)
+{
+ lua_State *L = getStack();
+ LuaLocalPlayer::create(L, localplayer);
+}
+
+void ClientScripting::on_camera_ready(Camera *camera)
+{
+ LuaCamera::create(getStack(), camera);
+}
diff --git a/src/script/scripting_client.h b/src/script/scripting_client.h
new file mode 100644
index 000000000..c13fde607
--- /dev/null
+++ b/src/script/scripting_client.h
@@ -0,0 +1,46 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 CLIENT_SCRIPTING_H_
+#define CLIENT_SCRIPTING_H_
+
+#include "cpp_api/s_base.h"
+#include "cpp_api/s_client.h"
+#include "cpp_api/s_security.h"
+#include "util/basic_macros.h"
+
+class Client;
+class LocalPlayer;
+class Camera;
+class ClientScripting:
+ virtual public ScriptApiBase,
+ public ScriptApiSecurity,
+ public ScriptApiClient
+{
+public:
+ ClientScripting(Client *client);
+ void on_client_ready(LocalPlayer *localplayer);
+ void on_camera_ready(Camera *camera);
+
+private:
+ virtual void InitializeModApi(lua_State *L, int top);
+ DISABLE_CLASS_COPY(ClientScripting);
+};
+#endif
diff --git a/src/script/scripting_mainmenu.cpp b/src/script/scripting_mainmenu.cpp
index b1e50c94b..48957b472 100644
--- a/src/script/scripting_mainmenu.cpp
+++ b/src/script/scripting_mainmenu.cpp
@@ -19,11 +19,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "scripting_mainmenu.h"
#include "mods.h"
-#include "porting.h"
-#include "log.h"
#include "cpp_api/s_internal.h"
#include "lua_api/l_base.h"
#include "lua_api/l_mainmenu.h"
+#include "lua_api/l_sound.h"
#include "lua_api/l_util.h"
#include "lua_api/l_settings.h"
@@ -60,16 +59,16 @@ MainMenuScripting::MainMenuScripting(GUIEngine* guiengine)
/******************************************************************************/
void MainMenuScripting::initializeModApi(lua_State *L, int top)
{
+ registerLuaClasses(L, top);
+
// Initialize mod API modules
ModApiMainMenu::Initialize(L, top);
ModApiUtil::Initialize(L, top);
+ ModApiSound::Initialize(L, top);
- // Register reference classes (userdata)
- LuaSettings::Register(L);
-
- // Register functions to async environment
- ModApiMainMenu::InitializeAsync(asyncEngine);
- ModApiUtil::InitializeAsync(asyncEngine);
+ asyncEngine.registerStateInitializer(registerLuaClasses);
+ asyncEngine.registerStateInitializer(ModApiMainMenu::InitializeAsync);
+ asyncEngine.registerStateInitializer(ModApiUtil::InitializeAsync);
// Initialize async environment
//TODO possibly make number of async threads configurable
@@ -77,13 +76,21 @@ void MainMenuScripting::initializeModApi(lua_State *L, int top)
}
/******************************************************************************/
-void MainMenuScripting::step() {
+void MainMenuScripting::registerLuaClasses(lua_State *L, int top)
+{
+ LuaSettings::Register(L);
+}
+
+/******************************************************************************/
+void MainMenuScripting::step()
+{
asyncEngine.step(getStack());
}
/******************************************************************************/
-unsigned int MainMenuScripting::queueAsync(std::string serialized_func,
- std::string serialized_param) {
+unsigned int MainMenuScripting::queueAsync(const std::string &serialized_func,
+ const std::string &serialized_param)
+{
return asyncEngine.queueAsyncJob(serialized_func, serialized_param);
}
diff --git a/src/script/scripting_mainmenu.h b/src/script/scripting_mainmenu.h
index 3a0795df4..7b3a6eba8 100644
--- a/src/script/scripting_mainmenu.h
+++ b/src/script/scripting_mainmenu.h
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "cpp_api/s_base.h"
#include "cpp_api/s_mainmenu.h"
#include "cpp_api/s_async.h"
+#include "util/basic_macros.h"
/*****************************************************************************/
/* Scripting <-> Main Menu Interface */
@@ -39,12 +40,14 @@ public:
void step();
// Pass async events from engine to async threads
- unsigned int queueAsync(std::string serialized_func,
- std::string serialized_params);
+ unsigned int queueAsync(const std::string &serialized_func,
+ const std::string &serialized_params);
private:
void initializeModApi(lua_State *L, int top);
+ static void registerLuaClasses(lua_State *L, int top);
AsyncEngine asyncEngine;
+ DISABLE_CLASS_COPY(MainMenuScripting);
};
diff --git a/src/script/scripting_game.cpp b/src/script/scripting_server.cpp
index e313d55f8..cd01b0773 100644
--- a/src/script/scripting_game.cpp
+++ b/src/script/scripting_server.cpp
@@ -17,7 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include "scripting_game.h"
+#include "scripting_server.h"
#include "server.h"
#include "log.h"
#include "settings.h"
@@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_env.h"
#include "lua_api/l_inventory.h"
#include "lua_api/l_item.h"
+#include "lua_api/l_itemstackmeta.h"
#include "lua_api/l_mapgen.h"
#include "lua_api/l_nodemeta.h"
#include "lua_api/l_nodetimer.h"
@@ -40,14 +41,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_vmanip.h"
#include "lua_api/l_settings.h"
#include "lua_api/l_http.h"
+#include "lua_api/l_storage.h"
extern "C" {
#include "lualib.h"
}
-GameScripting::GameScripting(Server* server)
+ServerScripting::ServerScripting(Server* server)
{
- setServer(server);
+ setGameDef(server);
// setEnv(env) is called by ScriptApiEnv::initializeEnvironment()
// once the environment has been created
@@ -78,22 +80,11 @@ GameScripting::GameScripting(Server* server)
infostream << "SCRIPTAPI: Initialized game modules" << std::endl;
}
-void GameScripting::InitializeModApi(lua_State *L, int top)
+void ServerScripting::InitializeModApi(lua_State *L, int top)
{
- // Initialize mod api modules
- ModApiCraft::Initialize(L, top);
- ModApiEnvMod::Initialize(L, top);
- ModApiInventory::Initialize(L, top);
- ModApiItemMod::Initialize(L, top);
- ModApiMapgen::Initialize(L, top);
- ModApiParticles::Initialize(L, top);
- ModApiRollback::Initialize(L, top);
- ModApiServer::Initialize(L, top);
- ModApiUtil::Initialize(L, top);
- ModApiHttp::Initialize(L, top);
-
// Register reference classes (userdata)
InvRef::Register(L);
+ ItemStackMetaRef::Register(L);
LuaAreaStore::Register(L);
LuaItemStack::Register(L);
LuaPerlinNoise::Register(L);
@@ -106,6 +97,20 @@ void GameScripting::InitializeModApi(lua_State *L, int top)
NodeTimerRef::Register(L);
ObjectRef::Register(L);
LuaSettings::Register(L);
+ StorageRef::Register(L);
+
+ // Initialize mod api modules
+ ModApiCraft::Initialize(L, top);
+ ModApiEnvMod::Initialize(L, top);
+ ModApiInventory::Initialize(L, top);
+ ModApiItemMod::Initialize(L, top);
+ ModApiMapgen::Initialize(L, top);
+ ModApiParticles::Initialize(L, top);
+ ModApiRollback::Initialize(L, top);
+ ModApiServer::Initialize(L, top);
+ ModApiUtil::Initialize(L, top);
+ ModApiHttp::Initialize(L, top);
+ ModApiStorage::Initialize(L, top);
}
void log_deprecated(const std::string &message)
diff --git a/src/script/scripting_game.h b/src/script/scripting_server.h
index 970b3e80d..1b335406e 100644
--- a/src/script/scripting_game.h
+++ b/src/script/scripting_server.h
@@ -17,8 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef SCRIPTING_GAME_H_
-#define SCRIPTING_GAME_H_
+#ifndef SERVER_SCRIPTING_H_
+#define SERVER_SCRIPTING_H_
#include "cpp_api/s_base.h"
#include "cpp_api/s_entity.h"
@@ -28,12 +28,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "cpp_api/s_player.h"
#include "cpp_api/s_server.h"
#include "cpp_api/s_security.h"
+#include "util/basic_macros.h"
/*****************************************************************************/
-/* Scripting <-> Game Interface */
+/* Scripting <-> Server Game Interface */
/*****************************************************************************/
-class GameScripting :
+class ServerScripting:
virtual public ScriptApiBase,
public ScriptApiDetached,
public ScriptApiEntity,
@@ -44,12 +45,13 @@ class GameScripting :
public ScriptApiSecurity
{
public:
- GameScripting(Server* server);
+ ServerScripting(Server* server);
// use ScriptApiBase::loadMod() to load mods
private:
void InitializeModApi(lua_State *L, int top);
+ DISABLE_CLASS_COPY(ServerScripting);
};
void log_deprecated(const std::string &message);
diff --git a/src/serialization.h b/src/serialization.h
index 01d37d363..c91c3241f 100644
--- a/src/serialization.h
+++ b/src/serialization.h
@@ -62,13 +62,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
24: 16-bit node ids and node timers (never released as stable)
25: Improved node timer format
26: Never written; read the same as 25
+ 27: Added light spreading flags to blocks
+ 28: Added "private" flag to NodeMetadata
*/
// This represents an uninitialized or invalid format
#define SER_FMT_VER_INVALID 255
// Highest supported serialization version
-#define SER_FMT_VER_HIGHEST_READ 26
+#define SER_FMT_VER_HIGHEST_READ 28
// Saved on disk version
-#define SER_FMT_VER_HIGHEST_WRITE 25
+#define SER_FMT_VER_HIGHEST_WRITE 28
// Lowest supported serialization version
#define SER_FMT_VER_LOWEST_READ 0
// Lowest serialization version for writing
diff --git a/src/server.cpp b/src/server.cpp
index c9d5c7129..1e8e6a5d2 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -38,7 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "profiler.h"
#include "log.h"
-#include "scripting_game.h"
+#include "scripting_server.h"
#include "nodedef.h"
#include "itemdef.h"
#include "craftdef.h"
@@ -50,11 +50,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_abm.h"
#include "content_sao.h"
#include "mods.h"
-#include "sound.h" // dummySoundManager
#include "event_manager.h"
#include "serverlist.h"
#include "util/string.h"
-#include "util/mathconstants.h"
#include "rollback.h"
#include "util/serialize.h"
#include "util/thread.h"
@@ -62,6 +60,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/base64.h"
#include "util/sha1.h"
#include "util/hex.h"
+#include "database.h"
class ClientNotFoundException : public BaseException
{
@@ -108,7 +107,8 @@ void *ServerThread::run()
} catch (con::ConnectionBindFailed &e) {
m_server->setAsyncFatalError(e.what());
} catch (LuaError &e) {
- m_server->setAsyncFatalError("Lua: " + std::string(e.what()));
+ m_server->setAsyncFatalError(
+ "ServerThread::run Lua: " + std::string(e.what()));
}
}
@@ -149,11 +149,13 @@ Server::Server(
const SubgameSpec &gamespec,
bool simple_singleplayer_mode,
bool ipv6,
+ bool dedicated,
ChatInterface *iface
):
m_path_world(path_world),
m_gamespec(gamespec),
m_simple_singleplayer_mode(simple_singleplayer_mode),
+ m_dedicated(dedicated),
m_async_fatal_error(""),
m_env(NULL),
m_con(PROTOCOL_ID,
@@ -176,11 +178,12 @@ Server::Server(
m_clients(&m_con),
m_shutdown_requested(false),
m_shutdown_ask_reconnect(false),
+ m_shutdown_timer(0.0f),
m_admin_chat(iface),
m_ignore_map_edit_events(false),
m_ignore_map_edit_events_peer_id(0),
- m_next_sound_id(0)
-
+ m_next_sound_id(0),
+ m_mod_storage_save_timer(10.0f)
{
m_liquid_transform_timer = 0.0;
m_liquid_transform_every = 1.0;
@@ -219,46 +222,12 @@ Server::Server(
std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
m_banmanager = new BanManager(ban_path);
- ModConfiguration modconf(m_path_world);
+ ServerModConfiguration modconf(m_path_world);
m_mods = modconf.getMods();
std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
// complain about mods with unsatisfied dependencies
- if(!modconf.isConsistent()) {
- for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
- it != unsatisfied_mods.end(); ++it) {
- ModSpec mod = *it;
- errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
- for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
- dep_it != mod.unsatisfied_depends.end(); ++dep_it)
- errorstream << " \"" << *dep_it << "\"";
- errorstream << std::endl;
- }
- }
-
- Settings worldmt_settings;
- std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
- worldmt_settings.readConfigFile(worldmt.c_str());
- std::vector<std::string> names = worldmt_settings.getNames();
- std::set<std::string> load_mod_names;
- for(std::vector<std::string>::iterator it = names.begin();
- it != names.end(); ++it) {
- std::string name = *it;
- if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
- load_mod_names.insert(name.substr(9));
- }
- // complain about mods declared to be loaded, but not found
- for(std::vector<ModSpec>::iterator it = m_mods.begin();
- it != m_mods.end(); ++it)
- load_mod_names.erase((*it).name);
- for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
- it != unsatisfied_mods.end(); ++it)
- load_mod_names.erase((*it).name);
- if(!load_mod_names.empty()) {
- errorstream << "The following mods could not be found:";
- for(std::set<std::string>::iterator it = load_mod_names.begin();
- it != load_mod_names.end(); ++it)
- errorstream << " \"" << (*it) << "\"";
- errorstream << std::endl;
+ if (!modconf.isConsistent()) {
+ modconf.printUnsatisfiedModsError();
}
//lock environment
@@ -270,28 +239,25 @@ Server::Server(
// Initialize scripting
infostream<<"Server: Initializing Lua"<<std::endl;
- m_script = new GameScripting(this);
-
- std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
+ m_script = new ServerScripting(this);
- m_script->loadMod(script_path, BUILTIN_MOD_NAME);
+ m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
// Print mods
infostream << "Server: Loading mods: ";
- for(std::vector<ModSpec>::iterator i = m_mods.begin();
+ for (std::vector<ModSpec>::const_iterator i = m_mods.begin();
i != m_mods.end(); ++i) {
- const ModSpec &mod = *i;
- infostream << mod.name << " ";
+ infostream << (*i).name << " ";
}
infostream << std::endl;
// Load and run "mod" scripts
- for (std::vector<ModSpec>::iterator it = m_mods.begin();
+ for (std::vector<ModSpec>::const_iterator it = m_mods.begin();
it != m_mods.end(); ++it) {
const ModSpec &mod = *it;
if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
throw ModError("Error loading mod \"" + mod.name +
"\": Mod name does not follow naming conventions: "
- "Only chararacters [a-z0-9_] are allowed.");
+ "Only characters [a-z0-9_] are allowed.");
}
std::string script_path = mod.path + DIR_DELIM + "init.lua";
infostream << " [" << padStringRight(mod.name, 12) << "] [\""
@@ -488,7 +454,7 @@ void Server::step(float dtime)
g_settings->get("kick_msg_crash"),
g_settings->getBool("ask_reconnect_on_crash"));
}
- throw ServerError(async_err);
+ throw ServerError("AsyncErr: " + async_err);
}
}
@@ -608,7 +574,7 @@ void Server::AsyncRunStep(bool initial_step)
ScopeProfiler sp(g_profiler, "Server: liquid transform");
std::map<v3s16, MapBlock*> modified_blocks;
- m_env->getMap().transformLiquids(modified_blocks);
+ m_env->getMap().transformLiquids(modified_blocks, m_env);
#if 0
/*
Update lighting
@@ -641,10 +607,10 @@ void Server::AsyncRunStep(bool initial_step)
// send masterserver announce
{
float &counter = m_masterserver_timer;
- if(!isSingleplayer() && (!counter || counter >= 300.0) &&
- g_settings->getBool("server_announce"))
- {
- ServerList::sendAnnounce(counter ? "update" : "start",
+ if (!isSingleplayer() && (!counter || counter >= 300.0) &&
+ g_settings->getBool("server_announce")) {
+ ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
+ ServerList::AA_START,
m_bind_addr.getPort(),
m_clients.getPlayerNames(),
m_uptime.get(),
@@ -652,7 +618,8 @@ void Server::AsyncRunStep(bool initial_step)
m_lag,
m_gamespec.id,
Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
- m_mods);
+ m_mods,
+ m_dedicated);
counter = 0.01;
}
counter += dtime;
@@ -789,6 +756,18 @@ void Server::AsyncRunStep(bool initial_step)
<< "packet size is " << pktSize << std::endl;
}
m_clients.unlock();
+
+ m_mod_storage_save_timer -= dtime;
+ if (m_mod_storage_save_timer <= 0.0f) {
+ infostream << "Saving registered mod storages." << std::endl;
+ m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
+ for (UNORDERED_MAP<std::string, ModMetadata *>::const_iterator
+ it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
+ if (it->second->isModified()) {
+ it->second->save(getModStoragePath());
+ }
+ }
+ }
}
/*
@@ -1026,6 +1005,39 @@ void Server::AsyncRunStep(bool initial_step)
m_env->saveMeta();
}
}
+
+ // Timed shutdown
+ static const float shutdown_msg_times[] =
+ {
+ 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600
+ };
+
+ if (m_shutdown_timer > 0.0f) {
+ // Automated messages
+ if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
+ for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) {
+ // If shutdown timer matches an automessage, shot it
+ if (m_shutdown_timer > shutdown_msg_times[i] &&
+ m_shutdown_timer - dtime < shutdown_msg_times[i]) {
+ std::wstringstream ws;
+
+ ws << L"*** Server shutting down in "
+ << duration_to_string(myround(m_shutdown_timer - dtime)).c_str()
+ << ".";
+
+ infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
+ SendChatMessage(PEER_ID_INEXISTENT, ws.str());
+ break;
+ }
+ }
+ }
+
+ m_shutdown_timer -= dtime;
+ if (m_shutdown_timer < 0.0f) {
+ m_shutdown_timer = 0.0f;
+ m_shutdown_requested = true;
+ }
+ }
}
void Server::Receive()
@@ -1076,8 +1088,7 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
}
m_clients.unlock();
- RemotePlayer *player =
- static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
+ RemotePlayer *player = m_env->getPlayer(playername.c_str());
// If failed, cancel
if ((playersao == NULL) || (player == NULL)) {
@@ -1109,18 +1120,17 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
// Send inventory
SendInventory(playersao);
- // Send HP
- SendPlayerHPOrDie(playersao);
-
- // Send Breath
- SendPlayerBreath(peer_id);
-
- // Show death screen if necessary
+ // Send HP or death screen
if (playersao->isDead())
SendDeathscreen(peer_id, false, v3f(0,0,0));
+ else
+ SendPlayerHPOrDie(playersao);
+
+ // Send Breath
+ SendPlayerBreath(playersao);
// Note things in chat if not in simple singleplayer mode
- if(!m_simple_singleplayer_mode) {
+ if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
// Send information about server to player in chat
SendChatMessage(peer_id, getStatusString());
}
@@ -1641,7 +1651,7 @@ void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
Send(&pkt);
}
else {
- m_clients.sendToAll(0, &pkt, true);
+ m_clients.sendToAll(&pkt);
}
}
@@ -1663,12 +1673,40 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
}
// Spawns a particle on peer with peer_id
-void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
+void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
+ v3f pos, v3f velocity, v3f acceleration,
float expirationtime, float size, bool collisiondetection,
bool collision_removal,
- bool vertical, const std::string &texture)
+ bool vertical, const std::string &texture,
+ const struct TileAnimationParams &animation, u8 glow)
{
DSTACK(FUNCTION_NAME);
+ static const float radius =
+ g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
+
+ if (peer_id == PEER_ID_INEXISTENT) {
+ std::vector<u16> clients = m_clients.getClientIDs();
+
+ for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
+ RemotePlayer *player = m_env->getPlayer(*i);
+ if (!player)
+ continue;
+
+ PlayerSAO *sao = player->getPlayerSAO();
+ if (!sao)
+ continue;
+
+ // Do not send to distant clients
+ if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
+ continue;
+
+ SendSpawnParticle(*i, player->protocol_version,
+ pos, velocity, acceleration,
+ expirationtime, size, collisiondetection,
+ collision_removal, vertical, texture, animation, glow);
+ }
+ return;
+ }
NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
@@ -1677,22 +1715,39 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat
pkt.putLongString(texture);
pkt << vertical;
pkt << collision_removal;
+ // This is horrible but required (why are there two ways to serialize pkts?)
+ std::ostringstream os(std::ios_base::binary);
+ animation.serialize(os, protocol_version);
+ pkt.putRawString(os.str());
+ pkt << glow;
- if (peer_id != PEER_ID_INEXISTENT) {
- Send(&pkt);
- }
- else {
- m_clients.sendToAll(0, &pkt, true);
- }
+ Send(&pkt);
}
// Adds a ParticleSpawner on peer with peer_id
-void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
+void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
+ u16 amount, float spawntime, v3f minpos, v3f maxpos,
v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
float minsize, float maxsize, bool collisiondetection, bool collision_removal,
- u16 attached_id, bool vertical, const std::string &texture, u32 id)
+ u16 attached_id, bool vertical, const std::string &texture, u32 id,
+ const struct TileAnimationParams &animation, u8 glow)
{
DSTACK(FUNCTION_NAME);
+ if (peer_id == PEER_ID_INEXISTENT) {
+ // This sucks and should be replaced:
+ std::vector<u16> clients = m_clients.getClientIDs();
+ for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
+ RemotePlayer *player = m_env->getPlayer(*i);
+ if (!player)
+ continue;
+ SendAddParticleSpawner(*i, player->protocol_version,
+ amount, spawntime, minpos, maxpos,
+ minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
+ minsize, maxsize, collisiondetection, collision_removal,
+ attached_id, vertical, texture, id, animation, glow);
+ }
+ return;
+ }
NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
@@ -1705,13 +1760,13 @@ void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3
pkt << id << vertical;
pkt << collision_removal;
pkt << attached_id;
+ // This is horrible but required
+ std::ostringstream os(std::ios_base::binary);
+ animation.serialize(os, protocol_version);
+ pkt.putRawString(os.str());
+ pkt << glow;
- if (peer_id != PEER_ID_INEXISTENT) {
- Send(&pkt);
- }
- else {
- m_clients.sendToAll(0, &pkt, true);
- }
+ Send(&pkt);
}
void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
@@ -1727,7 +1782,7 @@ void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
Send(&pkt);
}
else {
- m_clients.sendToAll(0, &pkt, true);
+ m_clients.sendToAll(&pkt);
}
}
@@ -1802,7 +1857,8 @@ void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
}
void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
- const std::string &type, const std::vector<std::string> &params)
+ const std::string &type, const std::vector<std::string> &params,
+ bool &clouds)
{
NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
pkt << bgcolor << type << (u16) params.size();
@@ -1810,6 +1866,22 @@ void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
for(size_t i=0; i<params.size(); i++)
pkt << params[i];
+ pkt << clouds;
+
+ Send(&pkt);
+}
+
+void Server::SendCloudParams(u16 peer_id, float density,
+ const video::SColor &color_bright,
+ const video::SColor &color_ambient,
+ float height,
+ float thickness,
+ const v2f &speed)
+{
+ NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
+ pkt << density << color_bright << color_ambient
+ << height << thickness << speed;
+
Send(&pkt);
}
@@ -1832,7 +1904,7 @@ void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
pkt << time << time_speed;
if (peer_id == PEER_ID_INEXISTENT) {
- m_clients.sendToAll(0, &pkt, true);
+ m_clients.sendToAll(&pkt);
}
else {
Send(&pkt);
@@ -1857,14 +1929,13 @@ void Server::SendPlayerHP(u16 peer_id)
playersao->m_messages_out.push(aom);
}
-void Server::SendPlayerBreath(u16 peer_id)
+void Server::SendPlayerBreath(PlayerSAO *sao)
{
DSTACK(FUNCTION_NAME);
- PlayerSAO *playersao = getPlayerSAO(peer_id);
- assert(playersao);
+ assert(sao);
- m_script->player_event(playersao, "breath_changed");
- SendBreath(peer_id, playersao->getBreath());
+ m_script->player_event(sao, "breath_changed");
+ SendBreath(sao->getPeerID(), sao->getBreath());
}
void Server::SendMovePlayer(u16 peer_id)
@@ -2018,15 +2089,23 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
m_playing_sounds[id] = ServerPlayingSound();
ServerPlayingSound &psound = m_playing_sounds[id];
psound.params = params;
+ psound.spec = spec;
+ float gain = params.gain * spec.gain;
NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
- pkt << id << spec.name << (float) (spec.gain * params.gain)
- << (u8) params.type << pos << params.object << params.loop;
+ pkt << id << spec.name << gain
+ << (u8) params.type << pos << params.object
+ << params.loop << params.fade;
+
+ // Backwards compability
+ bool play_sound = gain > 0;
- for(std::vector<u16>::iterator i = dst_clients.begin();
+ for (std::vector<u16>::iterator i = dst_clients.begin();
i != dst_clients.end(); ++i) {
- psound.clients.insert(*i);
- m_clients.send(*i, 0, &pkt, true);
+ if (play_sound || m_clients.getProtocolVersion(*i) >= 32) {
+ psound.clients.insert(*i);
+ m_clients.send(*i, 0, &pkt, true);
+ }
}
return id;
}
@@ -2050,6 +2129,52 @@ void Server::stopSound(s32 handle)
m_playing_sounds.erase(i);
}
+void Server::fadeSound(s32 handle, float step, float gain)
+{
+ // Get sound reference
+ UNORDERED_MAP<s32, ServerPlayingSound>::iterator i =
+ m_playing_sounds.find(handle);
+ if (i == m_playing_sounds.end())
+ return;
+
+ ServerPlayingSound &psound = i->second;
+ psound.params.gain = gain;
+
+ NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
+ pkt << handle << step << gain;
+
+ // Backwards compability
+ bool play_sound = gain > 0;
+ ServerPlayingSound compat_psound = psound;
+ compat_psound.clients.clear();
+
+ NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
+ compat_pkt << handle;
+
+ for (UNORDERED_SET<u16>::iterator it = psound.clients.begin();
+ it != psound.clients.end();) {
+ if (m_clients.getProtocolVersion(*it) >= 32) {
+ // Send as reliable
+ m_clients.send(*it, 0, &pkt, true);
+ ++it;
+ } else {
+ compat_psound.clients.insert(*it);
+ // Stop old sound
+ m_clients.send(*it, 0, &compat_pkt, true);
+ psound.clients.erase(it++);
+ }
+ }
+
+ // Remove sound reference
+ if (!play_sound || psound.clients.size() == 0)
+ m_playing_sounds.erase(i);
+
+ if (play_sound && compat_psound.clients.size() > 0) {
+ // Play new sound volume on older clients
+ playSound(compat_psound.spec, compat_psound.params);
+ }
+}
+
void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
std::vector<u16> *far_players, float far_d_nodes)
{
@@ -2113,14 +2238,6 @@ void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
if (client != 0) {
pkt << p << n.param0 << n.param1 << n.param2
<< (u8) (remove_metadata ? 0 : 1);
-
- if (!remove_metadata) {
- if (client->net_proto_version <= 21) {
- // Old clients always clear metadata; fix it
- // by sending the full block again.
- client->SetBlockNotSent(getNodeBlockPos(p));
- }
- }
}
m_clients.unlock();
@@ -2154,7 +2271,7 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto
std::ostringstream os(std::ios_base::binary);
block->serialize(os, ver, false);
- block->serializeNetworkSpecific(os, net_proto_version);
+ block->serializeNetworkSpecific(os);
std::string s = os.str();
NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
@@ -2494,7 +2611,7 @@ void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
const std::string &check = m_detached_inventories_player[name];
if (peer_id == PEER_ID_INEXISTENT) {
if (check == "")
- return m_clients.sendToAll(0, &pkt, true);
+ return m_clients.sendToAll(&pkt);
RemotePlayer *p = m_env->getPlayer(check.c_str());
if (p)
m_clients.send(p->peer_id, 0, &pkt, true);
@@ -2557,15 +2674,13 @@ void Server::RespawnPlayer(u16 peer_id)
playersao->setHP(PLAYER_MAX_HP);
playersao->setBreath(PLAYER_MAX_BREATH);
- SendPlayerHP(peer_id);
- SendPlayerBreath(peer_id);
-
bool repositioned = m_script->on_respawnplayer(playersao);
- if(!repositioned){
- v3f pos = findSpawnPos();
+ if (!repositioned) {
// setPos will send the new position to client
- playersao->setPos(pos);
+ playersao->setPos(findSpawnPos());
}
+
+ SendPlayerHP(peer_id);
}
@@ -2761,59 +2876,49 @@ std::wstring Server::handleChat(const std::string &name, const std::wstring &wna
RollbackScopeActor rollback_scope(m_rollback,
std::string("player:") + name);
- // Line to send
- std::wstring line;
- // Whether to send line to the player that sent the message, or to all players
- bool broadcast_line = true;
-
- // Run script hook
- bool ate = m_script->on_chat_message(name,
- wide_to_utf8(wmessage));
- // If script ate the message, don't proceed
- if (ate)
- return L"";
-
if (player) {
switch (player->canSendChatMessage()) {
case RPLAYER_CHATRESULT_FLOODING: {
std::wstringstream ws;
ws << L"You cannot send more messages. You are limited to "
- << g_settings->getFloat("chat_message_limit_per_10sec")
- << L" messages per 10 seconds.";
+ << g_settings->getFloat("chat_message_limit_per_10sec")
+ << L" messages per 10 seconds.";
return ws.str();
}
case RPLAYER_CHATRESULT_KICK:
- DenyAccess_Legacy(player->peer_id, L"You have been kicked due to message flooding.");
+ DenyAccess_Legacy(player->peer_id,
+ L"You have been kicked due to message flooding.");
return L"";
- case RPLAYER_CHATRESULT_OK: break;
- default: FATAL_ERROR("Unhandled chat filtering result found.");
+ case RPLAYER_CHATRESULT_OK:
+ break;
+ default:
+ FATAL_ERROR("Unhandled chat filtering result found.");
}
}
- if (m_max_chatmessage_length > 0 && wmessage.length() > m_max_chatmessage_length) {
+ if (m_max_chatmessage_length > 0
+ && wmessage.length() > m_max_chatmessage_length) {
return L"Your message exceed the maximum chat message limit set on the server. "
- L"It was refused. Send a shorter message";
+ L"It was refused. Send a shorter message";
}
- // Commands are implemented in Lua, so only catch invalid
- // commands that were not "eaten" and send an error back
- if (wmessage[0] == L'/') {
- std::wstring wcmd = wmessage.substr(1);
+ // Run script hook, exit if script ate the chat message
+ if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
+ return L"";
+
+ // Line to send
+ std::wstring line;
+ // Whether to send line to the player that sent the message, or to all players
+ bool broadcast_line = true;
+
+ if (check_shout_priv && !checkPriv(name, "shout")) {
+ line += L"-!- You don't have permission to shout.";
broadcast_line = false;
- if (wcmd.length() == 0)
- line += L"-!- Empty command";
- else
- line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0];
} else {
- if (check_shout_priv && !checkPriv(name, "shout")) {
- line += L"-!- You don't have permission to shout.";
- broadcast_line = false;
- } else {
- line += L"<";
- line += wname;
- line += L"> ";
- line += wmessage;
- }
+ line += L"<";
+ line += wname;
+ line += L"> ";
+ line += wmessage;
}
/*
@@ -2829,7 +2934,15 @@ std::wstring Server::handleChat(const std::string &name, const std::wstring &wna
std::vector<u16> clients = m_clients.getClientIDs();
+ /*
+ Send the message back to the inital sender
+ if they are using protocol version >= 29
+ */
+
u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT);
+ if (player && player->protocol_version >= 29)
+ peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
+
for (u16 i = 0; i < clients.size(); i++) {
u16 cid = clients[i];
if (cid != peer_id_to_avoid_sending)
@@ -3130,13 +3243,30 @@ bool Server::setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third)
}
bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
- const std::string &type, const std::vector<std::string> &params)
+ const std::string &type, const std::vector<std::string> &params,
+ bool &clouds)
+{
+ if (!player)
+ return false;
+
+ player->setSky(bgcolor, type, params, clouds);
+ SendSetSky(player->peer_id, bgcolor, type, params, clouds);
+ return true;
+}
+
+bool Server::setClouds(RemotePlayer *player, float density,
+ const video::SColor &color_bright,
+ const video::SColor &color_ambient,
+ float height,
+ float thickness,
+ const v2f &speed)
{
if (!player)
return false;
- player->setSky(bgcolor, type, params);
- SendSetSky(player->peer_id, bgcolor, type, params);
+ SendCloudParams(player->peer_id, density,
+ color_bright, color_ambient, height,
+ thickness, speed);
return true;
}
@@ -3160,23 +3290,25 @@ void Server::spawnParticle(const std::string &playername, v3f pos,
v3f velocity, v3f acceleration,
float expirationtime, float size, bool
collisiondetection, bool collision_removal,
- bool vertical, const std::string &texture)
+ bool vertical, const std::string &texture,
+ const struct TileAnimationParams &animation, u8 glow)
{
// m_env will be NULL if the server is initializing
if (!m_env)
return;
- u16 peer_id = PEER_ID_INEXISTENT;
+ u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
if (playername != "") {
RemotePlayer *player = m_env->getPlayer(playername.c_str());
if (!player)
return;
peer_id = player->peer_id;
+ proto_ver = player->protocol_version;
}
- SendSpawnParticle(peer_id, pos, velocity, acceleration,
+ SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
expirationtime, size, collisiondetection,
- collision_removal, vertical, texture);
+ collision_removal, vertical, texture, animation, glow);
}
u32 Server::addParticleSpawner(u16 amount, float spawntime,
@@ -3184,18 +3316,20 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime,
float minexptime, float maxexptime, float minsize, float maxsize,
bool collisiondetection, bool collision_removal,
ServerActiveObject *attached, bool vertical, const std::string &texture,
- const std::string &playername)
+ const std::string &playername, const struct TileAnimationParams &animation,
+ u8 glow)
{
// m_env will be NULL if the server is initializing
if (!m_env)
return -1;
- u16 peer_id = PEER_ID_INEXISTENT;
+ u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
if (playername != "") {
RemotePlayer *player = m_env->getPlayer(playername.c_str());
if (!player)
return -1;
peer_id = player->peer_id;
+ proto_ver = player->protocol_version;
}
u16 attached_id = attached ? attached->getId() : 0;
@@ -3206,11 +3340,11 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime,
else
id = m_env->addParticleSpawner(spawntime, attached_id);
- SendAddParticleSpawner(peer_id, amount, spawntime,
+ SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
minpos, maxpos, minvel, maxvel, minacc, maxacc,
minexptime, maxexptime, minsize, maxsize,
collisiondetection, collision_removal, attached_id, vertical,
- texture, id);
+ texture, id, animation, glow);
return id;
}
@@ -3313,29 +3447,12 @@ ICraftDefManager *Server::getCraftDefManager()
{
return m_craftdef;
}
-ITextureSource *Server::getTextureSource()
-{
- return NULL;
-}
-IShaderSource *Server::getShaderSource()
-{
- return NULL;
-}
-scene::ISceneManager *Server::getSceneManager()
-{
- return NULL;
-}
u16 Server::allocateUnknownNodeId(const std::string &name)
{
return m_nodedef->allocateDummy(name);
}
-ISoundManager *Server::getSoundManager()
-{
- return &dummySoundManager;
-}
-
MtEventManager *Server::getEventManager()
{
return m_event;
@@ -3379,6 +3496,11 @@ std::string Server::getBuiltinLuaPath()
return porting::path_share + DIR_DELIM + "builtin";
}
+std::string Server::getModStoragePath() const
+{
+ return m_path_world + DIR_DELIM + "mod_storage";
+}
+
v3f Server::findSpawnPos()
{
ServerMap &map = m_env->getServerMap();
@@ -3394,8 +3516,8 @@ v3f Server::findSpawnPos()
s32 range = 1 + i;
// We're going to try to throw the player to this position
v2s16 nodepos2d = v2s16(
- -range + (myrand() % (range * 2)),
- -range + (myrand() % (range * 2)));
+ -range + (myrand() % (range * 2)),
+ -range + (myrand() % (range * 2)));
// Get spawn level at point
s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
@@ -3429,10 +3551,45 @@ v3f Server::findSpawnPos()
return nodeposf;
}
-PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
+void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
{
- bool newplayer = false;
+ m_shutdown_timer = delay;
+ m_shutdown_msg = msg;
+ m_shutdown_ask_reconnect = reconnect;
+
+ if (delay == 0.0f) {
+ // No delay, shutdown immediately
+ m_shutdown_requested = true;
+ // only print to the infostream, a chat message saying
+ // "Server Shutting Down" is sent when the server destructs.
+ infostream << "*** Immediate Server shutdown requested." << std::endl;
+ } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
+ // Negative delay, cancel shutdown if requested
+ m_shutdown_timer = 0.0f;
+ m_shutdown_msg = "";
+ m_shutdown_ask_reconnect = false;
+ m_shutdown_requested = false;
+ std::wstringstream ws;
+
+ ws << L"*** Server shutdown canceled.";
+
+ infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
+ SendChatMessage(PEER_ID_INEXISTENT, ws.str());
+ } else if (delay > 0.0f) {
+ // Positive delay, tell the clients when the server will shut down
+ std::wstringstream ws;
+
+ ws << L"*** Server shutting down in "
+ << duration_to_string(myround(m_shutdown_timer)).c_str()
+ << ".";
+
+ infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
+ SendChatMessage(PEER_ID_INEXISTENT, ws.str());
+ }
+}
+PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
+{
/*
Try to get an existing player
*/
@@ -3453,44 +3610,18 @@ PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version
return NULL;
}
- // Create a new player active object
- PlayerSAO *playersao = new PlayerSAO(m_env, peer_id, isSingleplayer());
- player = m_env->loadPlayer(name, playersao);
-
- // Create player if it doesn't exist
if (!player) {
- newplayer = true;
- player = new RemotePlayer(name, this->idef());
- // Set player position
- infostream<<"Server: Finding spawn place for player \""
- <<name<<"\""<<std::endl;
- playersao->setBasePosition(findSpawnPos());
-
- // Make sure the player is saved
- player->setModified(true);
-
- // Add player to environment
- m_env->addPlayer(player);
- } else {
- // If the player exists, ensure that they respawn inside legal bounds
- // This fixes an assert crash when the player can't be added
- // to the environment
- if (objectpos_over_limit(playersao->getBasePosition())) {
- actionstream << "Respawn position for player \""
- << name << "\" outside limits, resetting" << std::endl;
- playersao->setBasePosition(findSpawnPos());
- }
+ player = new RemotePlayer(name, idef());
}
- playersao->initialize(player, getPlayerEffectivePrivs(player->getName()));
-
- player->protocol_version = proto_version;
+ bool newplayer = false;
- /* Clean up old HUD elements from previous sessions */
- player->clearHud();
+ // Load player
+ PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
- /* Add object to environment */
- m_env->addActiveObject(playersao);
+ // Complete init with server parts
+ playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
+ player->protocol_version = proto_version;
/* Run scripts */
if (newplayer) {
@@ -3500,6 +3631,28 @@ PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version
return playersao;
}
+bool Server::registerModStorage(ModMetadata *storage)
+{
+ if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
+ errorstream << "Unable to register same mod storage twice. Storage name: "
+ << storage->getModName() << std::endl;
+ return false;
+ }
+
+ m_mod_storages[storage->getModName()] = storage;
+ return true;
+}
+
+void Server::unregisterModStorage(const std::string &name)
+{
+ UNORDERED_MAP<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
+ if (it != m_mod_storages.end()) {
+ // Save unconditionaly on unregistration
+ it->second->save(getModStoragePath());
+ m_mod_storages.erase(name);
+ }
+}
+
void dedicated_server_loop(Server &server, bool &kill)
{
DSTACK(FUNCTION_NAME);
@@ -3521,15 +3674,8 @@ void dedicated_server_loop(Server &server, bool &kill)
}
server.step(steplen);
- if(server.getShutdownRequested() || kill)
- {
- infostream<<"Dedicated server quitting"<<std::endl;
-#if USE_CURL
- if(g_settings->getBool("server_announce"))
- ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
-#endif
+ if (server.getShutdownRequested() || kill)
break;
- }
/*
Profiler
@@ -3543,4 +3689,11 @@ void dedicated_server_loop(Server &server, bool &kill)
}
}
}
+
+ infostream << "Dedicated server quitting" << std::endl;
+#if USE_CURL
+ if (g_settings->getBool("server_announce"))
+ ServerList::sendAnnounce(ServerList::AA_DELETE,
+ server.m_bind_addr.getPort());
+#endif
}
diff --git a/src/server.h b/src/server.h
index 4425d139b..2e735e77c 100644
--- a/src/server.h
+++ b/src/server.h
@@ -29,9 +29,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mods.h"
#include "inventorymanager.h"
#include "subgame.h"
+#include "tileanimation.h" // struct TileAnimationParams
#include "util/numeric.h"
#include "util/thread.h"
-#include "environment.h"
+#include "util/basic_macros.h"
+#include "serverenvironment.h"
#include "chat_interface.h"
#include "clientiface.h"
#include "remoteplayer.h"
@@ -41,8 +43,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <map>
#include <vector>
-#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
-
class IWritableItemDefManager;
class IWritableNodeDefManager;
class IWritableCraftDefManager;
@@ -53,7 +53,7 @@ class PlayerSAO;
class IRollbackManager;
struct RollbackAction;
class EmergeManager;
-class GameScripting;
+class ServerScripting;
class ServerEnvironment;
struct SimpleSoundSpec;
class ServerThread;
@@ -115,6 +115,7 @@ struct ServerSoundParams
u16 object;
float max_hear_distance;
bool loop;
+ float fade;
ServerSoundParams():
gain(1.0),
@@ -123,7 +124,8 @@ struct ServerSoundParams
pos(0,0,0),
object(0),
max_hear_distance(32*BS),
- loop(false)
+ loop(false),
+ fade(0)
{}
v3f getPos(ServerEnvironment *env, bool *pos_exists) const;
@@ -132,6 +134,7 @@ struct ServerSoundParams
struct ServerPlayingSound
{
ServerSoundParams params;
+ SimpleSoundSpec spec;
UNORDERED_SET<u16> clients; // peer ids
};
@@ -148,6 +151,7 @@ public:
const SubgameSpec &gamespec,
bool simple_singleplayer_mode,
bool ipv6,
+ bool dedicated,
ChatInterface *iface = NULL
);
~Server();
@@ -173,7 +177,6 @@ public:
void handleCommand_Init_Legacy(NetworkPacket* pkt);
void handleCommand_Init2(NetworkPacket* pkt);
void handleCommand_RequestMedia(NetworkPacket* pkt);
- void handleCommand_ReceivedMedia(NetworkPacket* pkt);
void handleCommand_ClientReady(NetworkPacket* pkt);
void handleCommand_GotBlocks(NetworkPacket* pkt);
void handleCommand_PlayerPos(NetworkPacket* pkt);
@@ -181,7 +184,6 @@ public:
void handleCommand_InventoryAction(NetworkPacket* pkt);
void handleCommand_ChatMessage(NetworkPacket* pkt);
void handleCommand_Damage(NetworkPacket* pkt);
- void handleCommand_Breath(NetworkPacket* pkt);
void handleCommand_Password(NetworkPacket* pkt);
void handleCommand_PlayerItem(NetworkPacket* pkt);
void handleCommand_Respawn(NetworkPacket* pkt);
@@ -226,17 +228,13 @@ public:
inline bool getShutdownRequested() const { return m_shutdown_requested; }
// request server to shutdown
- void requestShutdown(const std::string &msg, bool reconnect)
- {
- m_shutdown_requested = true;
- m_shutdown_msg = msg;
- m_shutdown_ask_reconnect = reconnect;
- }
+ void requestShutdown(const std::string &msg, bool reconnect, float delay = 0.0f);
// Returns -1 if failed, sound handle on success
// Envlock
s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams &params);
void stopSound(s32 handle);
+ void fadeSound(s32 handle, float step, float gain);
// Envlock
std::set<std::string> getPlayerEffectivePrivs(const std::string &name);
@@ -254,7 +252,8 @@ public:
v3f pos, v3f velocity, v3f acceleration,
float expirationtime, float size,
bool collisiondetection, bool collision_removal,
- bool vertical, const std::string &texture);
+ bool vertical, const std::string &texture,
+ const struct TileAnimationParams &animation, u8 glow);
u32 addParticleSpawner(u16 amount, float spawntime,
v3f minpos, v3f maxpos,
@@ -265,7 +264,8 @@ public:
bool collisiondetection, bool collision_removal,
ServerActiveObject *attached,
bool vertical, const std::string &texture,
- const std::string &playername);
+ const std::string &playername, const struct TileAnimationParams &animation,
+ u8 glow);
void deleteParticleSpawner(const std::string &playername, u32 id);
@@ -273,7 +273,7 @@ public:
Inventory* createDetachedInventory(const std::string &name, const std::string &player="");
// Envlock and conlock should be locked when using scriptapi
- GameScripting *getScriptIface(){ return m_script; }
+ ServerScripting *getScriptIface(){ return m_script; }
// actions: time-reversed list
// Return value: success/failure
@@ -285,24 +285,21 @@ public:
virtual IItemDefManager* getItemDefManager();
virtual INodeDefManager* getNodeDefManager();
virtual ICraftDefManager* getCraftDefManager();
- virtual ITextureSource* getTextureSource();
- virtual IShaderSource* getShaderSource();
virtual u16 allocateUnknownNodeId(const std::string &name);
- virtual ISoundManager* getSoundManager();
virtual MtEventManager* getEventManager();
- virtual scene::ISceneManager* getSceneManager();
- virtual IRollbackManager *getRollbackManager() { return m_rollback; }
+ IRollbackManager *getRollbackManager() { return m_rollback; }
virtual EmergeManager *getEmergeManager() { return m_emerge; }
IWritableItemDefManager* getWritableItemDefManager();
IWritableNodeDefManager* getWritableNodeDefManager();
IWritableCraftDefManager* getWritableCraftDefManager();
- const std::vector<ModSpec> &getMods() const { return m_mods; }
- const ModSpec* getModSpec(const std::string &modname) const;
+ virtual const std::vector<ModSpec> &getMods() const { return m_mods; }
+ virtual const ModSpec* getModSpec(const std::string &modname) const;
void getModNames(std::vector<std::string> &modlist);
std::string getBuiltinLuaPath();
- inline std::string getWorldPath() const { return m_path_world; }
+ virtual std::string getWorldPath() const { return m_path_world; }
+ virtual std::string getModStoragePath() const;
inline bool isSingleplayer()
{ return m_simple_singleplayer_mode; }
@@ -313,6 +310,7 @@ public:
bool showFormspec(const char *name, const std::string &formspec, const std::string &formname);
Map & getMap() { return m_env->getMap(); }
ServerEnvironment & getEnv() { return *m_env; }
+ v3f findSpawnPos();
u32 hudAdd(RemotePlayer *player, HudElement *element);
bool hudRemove(RemotePlayer *player, u32 id);
@@ -337,7 +335,14 @@ public:
bool setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third);
bool setSky(RemotePlayer *player, const video::SColor &bgcolor,
- const std::string &type, const std::vector<std::string> &params);
+ const std::string &type, const std::vector<std::string> &params,
+ bool &clouds);
+ bool setClouds(RemotePlayer *player, float density,
+ const video::SColor &color_bright,
+ const video::SColor &color_ambient,
+ float height,
+ float thickness,
+ const v2f &speed);
bool overrideDayNightRatio(RemotePlayer *player, bool do_override, float brightness);
@@ -359,10 +364,13 @@ public:
void printToConsoleOnly(const std::string &text);
void SendPlayerHPOrDie(PlayerSAO *player);
- void SendPlayerBreath(u16 peer_id);
+ void SendPlayerBreath(PlayerSAO *sao);
void SendInventory(PlayerSAO* playerSAO);
void SendMovePlayer(u16 peer_id);
+ virtual bool registerModStorage(ModMetadata *storage);
+ virtual void unregisterModStorage(const std::string &name);
+
// Bind address
Address m_bind_addr;
@@ -403,7 +411,14 @@ private:
void SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask);
void SendHUDSetParam(u16 peer_id, u16 param, const std::string &value);
void SendSetSky(u16 peer_id, const video::SColor &bgcolor,
- const std::string &type, const std::vector<std::string> &params);
+ const std::string &type, const std::vector<std::string> &params,
+ bool &clouds);
+ void SendCloudParams(u16 peer_id, float density,
+ const video::SColor &color_bright,
+ const video::SColor &color_ambient,
+ float height,
+ float thickness,
+ const v2f &speed);
void SendOverrideDayNightRatio(u16 peer_id, bool do_override, float ratio);
/*
@@ -434,7 +449,8 @@ private:
void sendDetachedInventories(u16 peer_id);
// Adds a ParticleSpawner on peer with peer_id (PEER_ID_INEXISTENT == all)
- void SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime,
+ void SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
+ u16 amount, float spawntime,
v3f minpos, v3f maxpos,
v3f minvel, v3f maxvel,
v3f minacc, v3f maxacc,
@@ -442,16 +458,18 @@ private:
float minsize, float maxsize,
bool collisiondetection, bool collision_removal,
u16 attached_id,
- bool vertical, const std::string &texture, u32 id);
+ bool vertical, const std::string &texture, u32 id,
+ const struct TileAnimationParams &animation, u8 glow);
void SendDeleteParticleSpawner(u16 peer_id, u32 id);
// Spawns particle on peer with peer_id (PEER_ID_INEXISTENT == all)
- void SendSpawnParticle(u16 peer_id,
+ void SendSpawnParticle(u16 peer_id, u16 protocol_version,
v3f pos, v3f velocity, v3f acceleration,
float expirationtime, float size,
bool collisiondetection, bool collision_removal,
- bool vertical, const std::string &texture);
+ bool vertical, const std::string &texture,
+ const struct TileAnimationParams &animation, u8 glow);
u32 SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas);
void SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable = true);
@@ -473,8 +491,6 @@ private:
RemotePlayer *player = NULL);
void handleAdminChat(const ChatEventChat *evt);
- v3f findSpawnPos();
-
// When called, connection mutex should be locked
RemoteClient* getClient(u16 peer_id,ClientState state_min=CS_Active);
RemoteClient* getClientNoEx(u16 peer_id,ClientState state_min=CS_Active);
@@ -506,6 +522,8 @@ private:
// functionality
bool m_simple_singleplayer_mode;
u16 m_max_chatmessage_length;
+ // For "dedicated" server list flag
+ bool m_dedicated;
// Thread can set; step() will throw as ServerError
MutexedVariable<std::string> m_async_fatal_error;
@@ -536,7 +554,7 @@ private:
// Scripting
// Envlock and conlock should be locked when using Lua
- GameScripting *m_script;
+ ServerScripting *m_script;
// Item definition manager
IWritableItemDefManager *m_itemdef;
@@ -576,7 +594,6 @@ private:
float m_time_of_day_send_timer;
// Uptime of server in seconds
MutexedVariable<double> m_uptime;
-
/*
Client interface
*/
@@ -596,6 +613,7 @@ private:
bool m_shutdown_requested;
std::string m_shutdown_msg;
bool m_shutdown_ask_reconnect;
+ float m_shutdown_timer;
ChatInterface *m_admin_chat;
std::string m_admin_nick;
@@ -651,6 +669,9 @@ private:
// value = "" (visible to all players) or player name
std::map<std::string, std::string> m_detached_inventories_player;
+ UNORDERED_MAP<std::string, ModMetadata *> m_mod_storages;
+ float m_mod_storage_save_timer;
+
DISABLE_CLASS_COPY(Server);
};
diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp
new file mode 100644
index 000000000..cbdc747d1
--- /dev/null
+++ b/src/serverenvironment.cpp
@@ -0,0 +1,2317 @@
+/*
+Minetest
+Copyright (C) 2010-2017 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 Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "serverenvironment.h"
+#include "content_sao.h"
+#include "settings.h"
+#include "log.h"
+#include "nodedef.h"
+#include "nodemetadata.h"
+#include "gamedef.h"
+#include "map.h"
+#include "profiler.h"
+#include "raycast.h"
+#include "remoteplayer.h"
+#include "scripting_server.h"
+#include "server.h"
+#include "voxelalgorithms.h"
+#include "util/serialize.h"
+#include "util/basic_macros.h"
+#include "util/pointedthing.h"
+#include "threading/mutex_auto_lock.h"
+#include "filesys.h"
+#include "gameparams.h"
+#include "database-dummy.h"
+#include "database-files.h"
+#include "database-sqlite3.h"
+#if USE_POSTGRESQL
+#include "database-postgresql.h"
+#endif
+
+#define LBM_NAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_:"
+
+// A number that is much smaller than the timeout for particle spawners should/could ever be
+#define PARTICLE_SPAWNER_NO_EXPIRY -1024.f
+
+/*
+ ABMWithState
+*/
+
+ABMWithState::ABMWithState(ActiveBlockModifier *abm_):
+ abm(abm_),
+ timer(0)
+{
+ // Initialize timer to random value to spread processing
+ float itv = abm->getTriggerInterval();
+ itv = MYMAX(0.001, itv); // No less than 1ms
+ int minval = MYMAX(-0.51*itv, -60); // Clamp to
+ int maxval = MYMIN(0.51*itv, 60); // +-60 seconds
+ timer = myrand_range(minval, maxval);
+}
+
+/*
+ LBMManager
+*/
+
+void LBMContentMapping::deleteContents()
+{
+ for (std::vector<LoadingBlockModifierDef *>::iterator it = lbm_list.begin();
+ it != lbm_list.end(); ++it) {
+ delete *it;
+ }
+}
+
+void LBMContentMapping::addLBM(LoadingBlockModifierDef *lbm_def, IGameDef *gamedef)
+{
+ // Add the lbm_def to the LBMContentMapping.
+ // Unknown names get added to the global NameIdMapping.
+ INodeDefManager *nodedef = gamedef->ndef();
+
+ lbm_list.push_back(lbm_def);
+
+ for (std::set<std::string>::const_iterator it = lbm_def->trigger_contents.begin();
+ it != lbm_def->trigger_contents.end(); ++it) {
+ std::set<content_t> c_ids;
+ bool found = nodedef->getIds(*it, c_ids);
+ if (!found) {
+ content_t c_id = gamedef->allocateUnknownNodeId(*it);
+ if (c_id == CONTENT_IGNORE) {
+ // Seems it can't be allocated.
+ warningstream << "Could not internalize node name \"" << *it
+ << "\" while loading LBM \"" << lbm_def->name << "\"." << std::endl;
+ continue;
+ }
+ c_ids.insert(c_id);
+ }
+
+ for (std::set<content_t>::const_iterator iit =
+ c_ids.begin(); iit != c_ids.end(); ++iit) {
+ content_t c_id = *iit;
+ map[c_id].push_back(lbm_def);
+ }
+ }
+}
+
+const std::vector<LoadingBlockModifierDef *> *
+LBMContentMapping::lookup(content_t c) const
+{
+ container_map::const_iterator it = map.find(c);
+ if (it == map.end())
+ return NULL;
+ // This first dereferences the iterator, returning
+ // a std::vector<LoadingBlockModifierDef *>
+ // reference, then we convert it to a pointer.
+ return &(it->second);
+}
+
+LBMManager::~LBMManager()
+{
+ for (std::map<std::string, LoadingBlockModifierDef *>::iterator it =
+ m_lbm_defs.begin(); it != m_lbm_defs.end(); ++it) {
+ delete it->second;
+ }
+ for (lbm_lookup_map::iterator it = m_lbm_lookup.begin();
+ it != m_lbm_lookup.end(); ++it) {
+ (it->second).deleteContents();
+ }
+}
+
+void LBMManager::addLBMDef(LoadingBlockModifierDef *lbm_def)
+{
+ // Precondition, in query mode the map isn't used anymore
+ FATAL_ERROR_IF(m_query_mode == true,
+ "attempted to modify LBMManager in query mode");
+
+ if (!string_allowed(lbm_def->name, LBM_NAME_ALLOWED_CHARS)) {
+ throw ModError("Error adding LBM \"" + lbm_def->name +
+ "\": Does not follow naming conventions: "
+ "Only characters [a-z0-9_:] are allowed.");
+ }
+
+ m_lbm_defs[lbm_def->name] = lbm_def;
+}
+
+void LBMManager::loadIntroductionTimes(const std::string &times,
+ IGameDef *gamedef, u32 now)
+{
+ m_query_mode = true;
+
+ // name -> time map.
+ // Storing it in a map first instead of
+ // handling the stuff directly in the loop
+ // removes all duplicate entries.
+ // TODO make this std::unordered_map
+ std::map<std::string, u32> introduction_times;
+
+ /*
+ The introduction times string consists of name~time entries,
+ with each entry terminated by a semicolon. The time is decimal.
+ */
+
+ size_t idx = 0;
+ size_t idx_new;
+ while ((idx_new = times.find(";", idx)) != std::string::npos) {
+ std::string entry = times.substr(idx, idx_new - idx);
+ std::vector<std::string> components = str_split(entry, '~');
+ if (components.size() != 2)
+ throw SerializationError("Introduction times entry \""
+ + entry + "\" requires exactly one '~'!");
+ const std::string &name = components[0];
+ u32 time = from_string<u32>(components[1]);
+ introduction_times[name] = time;
+ idx = idx_new + 1;
+ }
+
+ // Put stuff from introduction_times into m_lbm_lookup
+ for (std::map<std::string, u32>::const_iterator it = introduction_times.begin();
+ it != introduction_times.end(); ++it) {
+ const std::string &name = it->first;
+ u32 time = it->second;
+
+ std::map<std::string, LoadingBlockModifierDef *>::iterator def_it =
+ m_lbm_defs.find(name);
+ if (def_it == m_lbm_defs.end()) {
+ // This seems to be an LBM entry for
+ // an LBM we haven't loaded. Discard it.
+ continue;
+ }
+ LoadingBlockModifierDef *lbm_def = def_it->second;
+ if (lbm_def->run_at_every_load) {
+ // This seems to be an LBM entry for
+ // an LBM that runs at every load.
+ // Don't add it just yet.
+ continue;
+ }
+
+ m_lbm_lookup[time].addLBM(lbm_def, gamedef);
+
+ // Erase the entry so that we know later
+ // what elements didn't get put into m_lbm_lookup
+ m_lbm_defs.erase(name);
+ }
+
+ // Now also add the elements from m_lbm_defs to m_lbm_lookup
+ // that weren't added in the previous step.
+ // They are introduced first time to this world,
+ // or are run at every load (introducement time hardcoded to U32_MAX).
+
+ LBMContentMapping &lbms_we_introduce_now = m_lbm_lookup[now];
+ LBMContentMapping &lbms_running_always = m_lbm_lookup[U32_MAX];
+
+ for (std::map<std::string, LoadingBlockModifierDef *>::iterator it =
+ m_lbm_defs.begin(); it != m_lbm_defs.end(); ++it) {
+ if (it->second->run_at_every_load) {
+ lbms_running_always.addLBM(it->second, gamedef);
+ } else {
+ lbms_we_introduce_now.addLBM(it->second, gamedef);
+ }
+ }
+
+ // Clear the list, so that we don't delete remaining elements
+ // twice in the destructor
+ m_lbm_defs.clear();
+}
+
+std::string LBMManager::createIntroductionTimesString()
+{
+ // Precondition, we must be in query mode
+ FATAL_ERROR_IF(m_query_mode == false,
+ "attempted to query on non fully set up LBMManager");
+
+ std::ostringstream oss;
+ for (lbm_lookup_map::iterator it = m_lbm_lookup.begin();
+ it != m_lbm_lookup.end(); ++it) {
+ u32 time = it->first;
+ std::vector<LoadingBlockModifierDef *> &lbm_list = it->second.lbm_list;
+ for (std::vector<LoadingBlockModifierDef *>::iterator iit = lbm_list.begin();
+ iit != lbm_list.end(); ++iit) {
+ // Don't add if the LBM runs at every load,
+ // then introducement time is hardcoded
+ // and doesn't need to be stored
+ if ((*iit)->run_at_every_load)
+ continue;
+ oss << (*iit)->name << "~" << time << ";";
+ }
+ }
+ return oss.str();
+}
+
+void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, u32 stamp)
+{
+ // Precondition, we need m_lbm_lookup to be initialized
+ FATAL_ERROR_IF(m_query_mode == false,
+ "attempted to query on non fully set up LBMManager");
+ v3s16 pos_of_block = block->getPosRelative();
+ v3s16 pos;
+ MapNode n;
+ content_t c;
+ lbm_lookup_map::const_iterator it = getLBMsIntroducedAfter(stamp);
+ for (pos.X = 0; pos.X < MAP_BLOCKSIZE; pos.X++)
+ for (pos.Y = 0; pos.Y < MAP_BLOCKSIZE; pos.Y++)
+ for (pos.Z = 0; pos.Z < MAP_BLOCKSIZE; pos.Z++)
+ {
+ n = block->getNodeNoEx(pos);
+ c = n.getContent();
+ for (LBMManager::lbm_lookup_map::const_iterator iit = it;
+ iit != m_lbm_lookup.end(); ++iit) {
+ const std::vector<LoadingBlockModifierDef *> *lbm_list =
+ iit->second.lookup(c);
+ if (!lbm_list)
+ continue;
+ for (std::vector<LoadingBlockModifierDef *>::const_iterator iit =
+ lbm_list->begin(); iit != lbm_list->end(); ++iit) {
+ (*iit)->trigger(env, pos + pos_of_block, n);
+ }
+ }
+ }
+}
+
+/*
+ ActiveBlockList
+*/
+
+void fillRadiusBlock(v3s16 p0, s16 r, std::set<v3s16> &list)
+{
+ v3s16 p;
+ for(p.X=p0.X-r; p.X<=p0.X+r; p.X++)
+ for(p.Y=p0.Y-r; p.Y<=p0.Y+r; p.Y++)
+ for(p.Z=p0.Z-r; p.Z<=p0.Z+r; p.Z++)
+ {
+ // limit to a sphere
+ if (p.getDistanceFrom(p0) <= r) {
+ // Set in list
+ list.insert(p);
+ }
+ }
+}
+
+void ActiveBlockList::update(std::vector<v3s16> &active_positions,
+ s16 radius,
+ std::set<v3s16> &blocks_removed,
+ std::set<v3s16> &blocks_added)
+{
+ /*
+ Create the new list
+ */
+ std::set<v3s16> newlist = m_forceloaded_list;
+ for(std::vector<v3s16>::iterator i = active_positions.begin();
+ i != active_positions.end(); ++i)
+ {
+ fillRadiusBlock(*i, radius, newlist);
+ }
+
+ /*
+ Find out which blocks on the old list are not on the new list
+ */
+ // Go through old list
+ for(std::set<v3s16>::iterator i = m_list.begin();
+ i != m_list.end(); ++i)
+ {
+ v3s16 p = *i;
+ // If not on new list, it's been removed
+ if(newlist.find(p) == newlist.end())
+ blocks_removed.insert(p);
+ }
+
+ /*
+ Find out which blocks on the new list are not on the old list
+ */
+ // Go through new list
+ for(std::set<v3s16>::iterator i = newlist.begin();
+ i != newlist.end(); ++i)
+ {
+ v3s16 p = *i;
+ // If not on old list, it's been added
+ if(m_list.find(p) == m_list.end())
+ blocks_added.insert(p);
+ }
+
+ /*
+ Update m_list
+ */
+ m_list.clear();
+ for(std::set<v3s16>::iterator i = newlist.begin();
+ i != newlist.end(); ++i)
+ {
+ v3s16 p = *i;
+ m_list.insert(p);
+ }
+}
+
+/*
+ ServerEnvironment
+*/
+
+ServerEnvironment::ServerEnvironment(ServerMap *map,
+ ServerScripting *scriptIface, Server *server,
+ const std::string &path_world):
+ Environment(server),
+ m_map(map),
+ m_script(scriptIface),
+ m_server(server),
+ m_path_world(path_world),
+ m_send_recommended_timer(0),
+ m_active_block_interval_overload_skip(0),
+ m_game_time(0),
+ m_game_time_fraction_counter(0),
+ m_last_clear_objects_time(0),
+ m_recommended_send_interval(0.1),
+ m_max_lag_estimate(0.1),
+ m_player_database(NULL)
+{
+ // Determine which database backend to use
+ std::string conf_path = path_world + DIR_DELIM + "world.mt";
+ Settings conf;
+ bool succeeded = conf.readConfigFile(conf_path.c_str());
+ if (!succeeded || !conf.exists("player_backend")) {
+ // fall back to files
+ conf.set("player_backend", "files");
+ warningstream << "/!\\ You are using old player file backend. "
+ << "This backend is deprecated and will be removed in next release /!\\"
+ << std::endl << "Switching to SQLite3 or PostgreSQL is advised, "
+ << "please read http://wiki.minetest.net/Database_backends." << std::endl;
+
+ if (!conf.updateConfigFile(conf_path.c_str())) {
+ errorstream << "ServerEnvironment::ServerEnvironment(): "
+ << "Failed to update world.mt!" << std::endl;
+ }
+ }
+
+ std::string name = "";
+ conf.getNoEx("player_backend", name);
+ m_player_database = openPlayerDatabase(name, path_world, conf);
+}
+
+ServerEnvironment::~ServerEnvironment()
+{
+ // Clear active block list.
+ // This makes the next one delete all active objects.
+ m_active_blocks.clear();
+
+ // Convert all objects to static and delete the active objects
+ deactivateFarObjects(true);
+
+ // Drop/delete map
+ m_map->drop();
+
+ // Delete ActiveBlockModifiers
+ for (std::vector<ABMWithState>::iterator
+ i = m_abms.begin(); i != m_abms.end(); ++i){
+ delete i->abm;
+ }
+
+ // Deallocate players
+ for (std::vector<RemotePlayer *>::iterator i = m_players.begin();
+ i != m_players.end(); ++i) {
+ delete (*i);
+ }
+
+ delete m_player_database;
+}
+
+Map & ServerEnvironment::getMap()
+{
+ return *m_map;
+}
+
+ServerMap & ServerEnvironment::getServerMap()
+{
+ return *m_map;
+}
+
+RemotePlayer *ServerEnvironment::getPlayer(const u16 peer_id)
+{
+ for (std::vector<RemotePlayer *>::iterator i = m_players.begin();
+ i != m_players.end(); ++i) {
+ RemotePlayer *player = *i;
+ if (player->peer_id == peer_id)
+ return player;
+ }
+ return NULL;
+}
+
+RemotePlayer *ServerEnvironment::getPlayer(const char* name)
+{
+ for (std::vector<RemotePlayer *>::iterator i = m_players.begin();
+ i != m_players.end(); ++i) {
+ RemotePlayer *player = *i;
+ if (strcmp(player->getName(), name) == 0)
+ return player;
+ }
+ return NULL;
+}
+
+void ServerEnvironment::addPlayer(RemotePlayer *player)
+{
+ DSTACK(FUNCTION_NAME);
+ /*
+ Check that peer_ids are unique.
+ Also check that names are unique.
+ Exception: there can be multiple players with peer_id=0
+ */
+ // If peer id is non-zero, it has to be unique.
+ if (player->peer_id != 0)
+ FATAL_ERROR_IF(getPlayer(player->peer_id) != NULL, "Peer id not unique");
+ // Name has to be unique.
+ FATAL_ERROR_IF(getPlayer(player->getName()) != NULL, "Player name not unique");
+ // Add.
+ m_players.push_back(player);
+}
+
+void ServerEnvironment::removePlayer(RemotePlayer *player)
+{
+ for (std::vector<RemotePlayer *>::iterator it = m_players.begin();
+ it != m_players.end(); ++it) {
+ if ((*it) == player) {
+ delete *it;
+ m_players.erase(it);
+ return;
+ }
+ }
+}
+
+bool ServerEnvironment::removePlayerFromDatabase(const std::string &name)
+{
+ return m_player_database->removePlayer(name);
+}
+
+bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, float stepsize, v3s16 *p)
+{
+ float distance = pos1.getDistanceFrom(pos2);
+
+ //calculate normalized direction vector
+ v3f normalized_vector = v3f((pos2.X - pos1.X)/distance,
+ (pos2.Y - pos1.Y)/distance,
+ (pos2.Z - pos1.Z)/distance);
+
+ //find out if there's a node on path between pos1 and pos2
+ for (float i = 1; i < distance; i += stepsize) {
+ v3s16 pos = floatToInt(v3f(normalized_vector.X * i,
+ normalized_vector.Y * i,
+ normalized_vector.Z * i) +pos1,BS);
+
+ MapNode n = getMap().getNodeNoEx(pos);
+
+ if(n.param0 != CONTENT_AIR) {
+ if (p) {
+ *p = pos;
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
+void ServerEnvironment::kickAllPlayers(AccessDeniedCode reason,
+ const std::string &str_reason, bool reconnect)
+{
+ for (std::vector<RemotePlayer *>::iterator it = m_players.begin();
+ it != m_players.end(); ++it) {
+ RemotePlayer *player = dynamic_cast<RemotePlayer *>(*it);
+ m_server->DenyAccessVerCompliant(player->peer_id,
+ player->protocol_version, reason, str_reason, reconnect);
+ }
+}
+
+void ServerEnvironment::saveLoadedPlayers()
+{
+ std::string players_path = m_path_world + DIR_DELIM + "players";
+ fs::CreateDir(players_path);
+
+ for (std::vector<RemotePlayer *>::iterator it = m_players.begin();
+ it != m_players.end();
+ ++it) {
+ if ((*it)->checkModified() ||
+ ((*it)->getPlayerSAO() && (*it)->getPlayerSAO()->extendedAttributesModified())) {
+ try {
+ m_player_database->savePlayer(*it);
+ } catch (DatabaseException &e) {
+ errorstream << "Failed to save player " << (*it)->getName() << " exception: "
+ << e.what() << std::endl;
+ throw;
+ }
+ }
+ }
+}
+
+void ServerEnvironment::savePlayer(RemotePlayer *player)
+{
+ try {
+ m_player_database->savePlayer(player);
+ } catch (DatabaseException &e) {
+ errorstream << "Failed to save player " << player->getName() << " exception: "
+ << e.what() << std::endl;
+ throw;
+ }
+}
+
+PlayerSAO *ServerEnvironment::loadPlayer(RemotePlayer *player, bool *new_player,
+ u16 peer_id, bool is_singleplayer)
+{
+ PlayerSAO *playersao = new PlayerSAO(this, player, peer_id, is_singleplayer);
+ // Create player if it doesn't exist
+ if (!m_player_database->loadPlayer(player, playersao)) {
+ *new_player = true;
+ // Set player position
+ infostream << "Server: Finding spawn place for player \""
+ << player->getName() << "\"" << std::endl;
+ playersao->setBasePosition(m_server->findSpawnPos());
+
+ // Make sure the player is saved
+ player->setModified(true);
+ } else {
+ // If the player exists, ensure that they respawn inside legal bounds
+ // This fixes an assert crash when the player can't be added
+ // to the environment
+ if (objectpos_over_limit(playersao->getBasePosition())) {
+ actionstream << "Respawn position for player \""
+ << player->getName() << "\" outside limits, resetting" << std::endl;
+ playersao->setBasePosition(m_server->findSpawnPos());
+ }
+ }
+
+ // Add player to environment
+ addPlayer(player);
+
+ /* Clean up old HUD elements from previous sessions */
+ player->clearHud();
+
+ /* Add object to environment */
+ addActiveObject(playersao);
+
+ return playersao;
+}
+
+void ServerEnvironment::saveMeta()
+{
+ std::string path = m_path_world + DIR_DELIM "env_meta.txt";
+
+ // Open file and serialize
+ std::ostringstream ss(std::ios_base::binary);
+
+ Settings args;
+ args.setU64("game_time", m_game_time);
+ args.setU64("time_of_day", getTimeOfDay());
+ args.setU64("last_clear_objects_time", m_last_clear_objects_time);
+ args.setU64("lbm_introduction_times_version", 1);
+ args.set("lbm_introduction_times",
+ m_lbm_mgr.createIntroductionTimesString());
+ args.setU64("day_count", m_day_count);
+ args.writeLines(ss);
+ ss<<"EnvArgsEnd\n";
+
+ if(!fs::safeWriteToFile(path, ss.str()))
+ {
+ infostream<<"ServerEnvironment::saveMeta(): Failed to write "
+ <<path<<std::endl;
+ throw SerializationError("Couldn't save env meta");
+ }
+}
+
+void ServerEnvironment::loadMeta()
+{
+ std::string path = m_path_world + DIR_DELIM "env_meta.txt";
+
+ // Open file and deserialize
+ std::ifstream is(path.c_str(), std::ios_base::binary);
+ if (!is.good()) {
+ infostream << "ServerEnvironment::loadMeta(): Failed to open "
+ << path << std::endl;
+ throw SerializationError("Couldn't load env meta");
+ }
+
+ Settings args;
+
+ if (!args.parseConfigLines(is, "EnvArgsEnd")) {
+ throw SerializationError("ServerEnvironment::loadMeta(): "
+ "EnvArgsEnd not found!");
+ }
+
+ try {
+ m_game_time = args.getU64("game_time");
+ } catch (SettingNotFoundException &e) {
+ // Getting this is crucial, otherwise timestamps are useless
+ throw SerializationError("Couldn't load env meta game_time");
+ }
+
+ setTimeOfDay(args.exists("time_of_day") ?
+ // set day to morning by default
+ args.getU64("time_of_day") : 9000);
+
+ m_last_clear_objects_time = args.exists("last_clear_objects_time") ?
+ // If missing, do as if clearObjects was never called
+ args.getU64("last_clear_objects_time") : 0;
+
+ std::string lbm_introduction_times = "";
+ try {
+ u64 ver = args.getU64("lbm_introduction_times_version");
+ if (ver == 1) {
+ lbm_introduction_times = args.get("lbm_introduction_times");
+ } else {
+ infostream << "ServerEnvironment::loadMeta(): Non-supported"
+ << " introduction time version " << ver << std::endl;
+ }
+ } catch (SettingNotFoundException &e) {
+ // No problem, this is expected. Just continue with an empty string
+ }
+ m_lbm_mgr.loadIntroductionTimes(lbm_introduction_times, m_server, m_game_time);
+
+ m_day_count = args.exists("day_count") ?
+ args.getU64("day_count") : 0;
+}
+
+void ServerEnvironment::loadDefaultMeta()
+{
+ m_lbm_mgr.loadIntroductionTimes("", m_server, m_game_time);
+}
+
+struct ActiveABM
+{
+ ActiveBlockModifier *abm;
+ int chance;
+ std::set<content_t> required_neighbors;
+};
+
+class ABMHandler
+{
+private:
+ ServerEnvironment *m_env;
+ std::vector<std::vector<ActiveABM> *> m_aabms;
+public:
+ ABMHandler(std::vector<ABMWithState> &abms,
+ float dtime_s, ServerEnvironment *env,
+ bool use_timers):
+ m_env(env)
+ {
+ if(dtime_s < 0.001)
+ return;
+ INodeDefManager *ndef = env->getGameDef()->ndef();
+ for(std::vector<ABMWithState>::iterator
+ i = abms.begin(); i != abms.end(); ++i) {
+ ActiveBlockModifier *abm = i->abm;
+ float trigger_interval = abm->getTriggerInterval();
+ if(trigger_interval < 0.001)
+ trigger_interval = 0.001;
+ float actual_interval = dtime_s;
+ if(use_timers){
+ i->timer += dtime_s;
+ if(i->timer < trigger_interval)
+ continue;
+ i->timer -= trigger_interval;
+ actual_interval = trigger_interval;
+ }
+ float chance = abm->getTriggerChance();
+ if(chance == 0)
+ chance = 1;
+ ActiveABM aabm;
+ aabm.abm = abm;
+ if (abm->getSimpleCatchUp()) {
+ float intervals = actual_interval / trigger_interval;
+ if(intervals == 0)
+ continue;
+ aabm.chance = chance / intervals;
+ if(aabm.chance == 0)
+ aabm.chance = 1;
+ } else {
+ aabm.chance = chance;
+ }
+
+ // Trigger neighbors
+ const std::set<std::string> &required_neighbors_s =
+ abm->getRequiredNeighbors();
+ for (std::set<std::string>::iterator rn = required_neighbors_s.begin();
+ rn != required_neighbors_s.end(); ++rn) {
+ ndef->getIds(*rn, aabm.required_neighbors);
+ }
+
+ // Trigger contents
+ const std::set<std::string> &contents_s = abm->getTriggerContents();
+ for (std::set<std::string>::iterator cs = contents_s.begin();
+ cs != contents_s.end(); ++cs) {
+ std::set<content_t> ids;
+ ndef->getIds(*cs, ids);
+ for (std::set<content_t>::const_iterator k = ids.begin();
+ k != ids.end(); ++k) {
+ content_t c = *k;
+ if (c >= m_aabms.size())
+ m_aabms.resize(c + 256, NULL);
+ if (!m_aabms[c])
+ m_aabms[c] = new std::vector<ActiveABM>;
+ m_aabms[c]->push_back(aabm);
+ }
+ }
+ }
+ }
+
+ ~ABMHandler()
+ {
+ for (size_t i = 0; i < m_aabms.size(); i++)
+ delete m_aabms[i];
+ }
+
+ // Find out how many objects the given block and its neighbours contain.
+ // Returns the number of objects in the block, and also in 'wider' the
+ // number of objects in the block and all its neighbours. The latter
+ // may an estimate if any neighbours are unloaded.
+ u32 countObjects(MapBlock *block, ServerMap * map, u32 &wider)
+ {
+ wider = 0;
+ u32 wider_unknown_count = 0;
+ for(s16 x=-1; x<=1; x++)
+ for(s16 y=-1; y<=1; y++)
+ for(s16 z=-1; z<=1; z++)
+ {
+ MapBlock *block2 = map->getBlockNoCreateNoEx(
+ block->getPos() + v3s16(x,y,z));
+ if(block2==NULL){
+ wider_unknown_count++;
+ continue;
+ }
+ wider += block2->m_static_objects.m_active.size()
+ + block2->m_static_objects.m_stored.size();
+ }
+ // Extrapolate
+ u32 active_object_count = block->m_static_objects.m_active.size();
+ u32 wider_known_count = 3*3*3 - wider_unknown_count;
+ wider += wider_unknown_count * wider / wider_known_count;
+ return active_object_count;
+
+ }
+ void apply(MapBlock *block)
+ {
+ if(m_aabms.empty() || block->isDummy())
+ return;
+
+ ServerMap *map = &m_env->getServerMap();
+
+ u32 active_object_count_wider;
+ u32 active_object_count = this->countObjects(block, map, active_object_count_wider);
+ m_env->m_added_objects = 0;
+
+ v3s16 p0;
+ for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
+ for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
+ for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
+ {
+ const MapNode &n = block->getNodeUnsafe(p0);
+ content_t c = n.getContent();
+
+ if (c >= m_aabms.size() || !m_aabms[c])
+ continue;
+
+ v3s16 p = p0 + block->getPosRelative();
+ for(std::vector<ActiveABM>::iterator
+ i = m_aabms[c]->begin(); i != m_aabms[c]->end(); ++i) {
+ if(myrand() % i->chance != 0)
+ continue;
+
+ // Check neighbors
+ if(!i->required_neighbors.empty())
+ {
+ v3s16 p1;
+ for(p1.X = p0.X-1; p1.X <= p0.X+1; p1.X++)
+ for(p1.Y = p0.Y-1; p1.Y <= p0.Y+1; p1.Y++)
+ for(p1.Z = p0.Z-1; p1.Z <= p0.Z+1; p1.Z++)
+ {
+ if(p1 == p0)
+ continue;
+ content_t c;
+ if (block->isValidPosition(p1)) {
+ // if the neighbor is found on the same map block
+ // get it straight from there
+ const MapNode &n = block->getNodeUnsafe(p1);
+ c = n.getContent();
+ } else {
+ // otherwise consult the map
+ MapNode n = map->getNodeNoEx(p1 + block->getPosRelative());
+ c = n.getContent();
+ }
+ std::set<content_t>::const_iterator k;
+ k = i->required_neighbors.find(c);
+ if(k != i->required_neighbors.end()){
+ goto neighbor_found;
+ }
+ }
+ // No required neighbor found
+ continue;
+ }
+ neighbor_found:
+
+ // Call all the trigger variations
+ i->abm->trigger(m_env, p, n);
+ i->abm->trigger(m_env, p, n,
+ active_object_count, active_object_count_wider);
+
+ // Count surrounding objects again if the abms added any
+ if(m_env->m_added_objects > 0) {
+ active_object_count = countObjects(block, map, active_object_count_wider);
+ m_env->m_added_objects = 0;
+ }
+ }
+ }
+ }
+};
+
+void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
+{
+ // Reset usage timer immediately, otherwise a block that becomes active
+ // again at around the same time as it would normally be unloaded will
+ // get unloaded incorrectly. (I think this still leaves a small possibility
+ // of a race condition between this and server::AsyncRunStep, which only
+ // some kind of synchronisation will fix, but it at least reduces the window
+ // of opportunity for it to break from seconds to nanoseconds)
+ block->resetUsageTimer();
+
+ // Get time difference
+ u32 dtime_s = 0;
+ u32 stamp = block->getTimestamp();
+ if (m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
+ dtime_s = m_game_time - stamp;
+ dtime_s += additional_dtime;
+
+ /*infostream<<"ServerEnvironment::activateBlock(): block timestamp: "
+ <<stamp<<", game time: "<<m_game_time<<std::endl;*/
+
+ // Remove stored static objects if clearObjects was called since block's timestamp
+ if (stamp == BLOCK_TIMESTAMP_UNDEFINED || stamp < m_last_clear_objects_time) {
+ block->m_static_objects.m_stored.clear();
+ // do not set changed flag to avoid unnecessary mapblock writes
+ }
+
+ // Set current time as timestamp
+ block->setTimestampNoChangedFlag(m_game_time);
+
+ /*infostream<<"ServerEnvironment::activateBlock(): block is "
+ <<dtime_s<<" seconds old."<<std::endl;*/
+
+ // Activate stored objects
+ activateObjects(block, dtime_s);
+
+ /* Handle LoadingBlockModifiers */
+ m_lbm_mgr.applyLBMs(this, block, stamp);
+
+ // Run node timers
+ std::vector<NodeTimer> elapsed_timers =
+ block->m_node_timers.step((float)dtime_s);
+ if (!elapsed_timers.empty()) {
+ MapNode n;
+ for (std::vector<NodeTimer>::iterator
+ i = elapsed_timers.begin();
+ i != elapsed_timers.end(); ++i){
+ n = block->getNodeNoEx(i->position);
+ v3s16 p = i->position + block->getPosRelative();
+ if (m_script->node_on_timer(p, n, i->elapsed))
+ block->setNodeTimer(NodeTimer(i->timeout, 0, i->position));
+ }
+ }
+
+ /* Handle ActiveBlockModifiers */
+ ABMHandler abmhandler(m_abms, dtime_s, this, false);
+ abmhandler.apply(block);
+}
+
+void ServerEnvironment::addActiveBlockModifier(ActiveBlockModifier *abm)
+{
+ m_abms.push_back(ABMWithState(abm));
+}
+
+void ServerEnvironment::addLoadingBlockModifierDef(LoadingBlockModifierDef *lbm)
+{
+ m_lbm_mgr.addLBMDef(lbm);
+}
+
+bool ServerEnvironment::setNode(v3s16 p, const MapNode &n)
+{
+ INodeDefManager *ndef = m_server->ndef();
+ MapNode n_old = m_map->getNodeNoEx(p);
+
+ // Call destructor
+ if (ndef->get(n_old).has_on_destruct)
+ m_script->node_on_destruct(p, n_old);
+
+ // Replace node
+ if (!m_map->addNodeWithEvent(p, n))
+ return false;
+
+ // Update active VoxelManipulator if a mapgen thread
+ m_map->updateVManip(p);
+
+ // Call post-destructor
+ if (ndef->get(n_old).has_after_destruct)
+ m_script->node_after_destruct(p, n_old);
+
+ // Call constructor
+ if (ndef->get(n).has_on_construct)
+ m_script->node_on_construct(p, n);
+
+ return true;
+}
+
+bool ServerEnvironment::removeNode(v3s16 p)
+{
+ INodeDefManager *ndef = m_server->ndef();
+ MapNode n_old = m_map->getNodeNoEx(p);
+
+ // Call destructor
+ if (ndef->get(n_old).has_on_destruct)
+ m_script->node_on_destruct(p, n_old);
+
+ // Replace with air
+ // This is slightly optimized compared to addNodeWithEvent(air)
+ if (!m_map->removeNodeWithEvent(p))
+ return false;
+
+ // Update active VoxelManipulator if a mapgen thread
+ m_map->updateVManip(p);
+
+ // Call post-destructor
+ if (ndef->get(n_old).has_after_destruct)
+ m_script->node_after_destruct(p, n_old);
+
+ // Air doesn't require constructor
+ return true;
+}
+
+bool ServerEnvironment::swapNode(v3s16 p, const MapNode &n)
+{
+ if (!m_map->addNodeWithEvent(p, n, false))
+ return false;
+
+ // Update active VoxelManipulator if a mapgen thread
+ m_map->updateVManip(p);
+
+ return true;
+}
+
+void ServerEnvironment::getObjectsInsideRadius(std::vector<u16> &objects, v3f pos, float radius)
+{
+ for (ActiveObjectMap::iterator i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i) {
+ ServerActiveObject* obj = i->second;
+ u16 id = i->first;
+ v3f objectpos = obj->getBasePosition();
+ if (objectpos.getDistanceFrom(pos) > radius)
+ continue;
+ objects.push_back(id);
+ }
+}
+
+void ServerEnvironment::clearObjects(ClearObjectsMode mode)
+{
+ infostream << "ServerEnvironment::clearObjects(): "
+ << "Removing all active objects" << std::endl;
+ std::vector<u16> objects_to_remove;
+ for (ActiveObjectMap::iterator i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i) {
+ ServerActiveObject* obj = i->second;
+ if (obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
+ continue;
+ u16 id = i->first;
+ // Delete static object if block is loaded
+ if (obj->m_static_exists) {
+ MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
+ if (block) {
+ block->m_static_objects.remove(id);
+ block->raiseModified(MOD_STATE_WRITE_NEEDED,
+ MOD_REASON_CLEAR_ALL_OBJECTS);
+ obj->m_static_exists = false;
+ }
+ }
+ // If known by some client, don't delete immediately
+ if (obj->m_known_by_count > 0) {
+ obj->m_pending_deactivation = true;
+ obj->m_removed = true;
+ continue;
+ }
+
+ // Tell the object about removal
+ obj->removingFromEnvironment();
+ // Deregister in scripting api
+ m_script->removeObjectReference(obj);
+
+ // Delete active object
+ if (obj->environmentDeletes())
+ delete obj;
+ // Id to be removed from m_active_objects
+ objects_to_remove.push_back(id);
+ }
+
+ // Remove references from m_active_objects
+ for (std::vector<u16>::iterator i = objects_to_remove.begin();
+ i != objects_to_remove.end(); ++i) {
+ m_active_objects.erase(*i);
+ }
+
+ // Get list of loaded blocks
+ std::vector<v3s16> loaded_blocks;
+ infostream << "ServerEnvironment::clearObjects(): "
+ << "Listing all loaded blocks" << std::endl;
+ m_map->listAllLoadedBlocks(loaded_blocks);
+ infostream << "ServerEnvironment::clearObjects(): "
+ << "Done listing all loaded blocks: "
+ << loaded_blocks.size()<<std::endl;
+
+ // Get list of loadable blocks
+ std::vector<v3s16> loadable_blocks;
+ if (mode == CLEAR_OBJECTS_MODE_FULL) {
+ infostream << "ServerEnvironment::clearObjects(): "
+ << "Listing all loadable blocks" << std::endl;
+ m_map->listAllLoadableBlocks(loadable_blocks);
+ infostream << "ServerEnvironment::clearObjects(): "
+ << "Done listing all loadable blocks: "
+ << loadable_blocks.size() << std::endl;
+ } else {
+ loadable_blocks = loaded_blocks;
+ }
+
+ infostream << "ServerEnvironment::clearObjects(): "
+ << "Now clearing objects in " << loadable_blocks.size()
+ << " blocks" << std::endl;
+
+ // Grab a reference on each loaded block to avoid unloading it
+ for (std::vector<v3s16>::iterator i = loaded_blocks.begin();
+ i != loaded_blocks.end(); ++i) {
+ v3s16 p = *i;
+ MapBlock *block = m_map->getBlockNoCreateNoEx(p);
+ assert(block != NULL);
+ block->refGrab();
+ }
+
+ // Remove objects in all loadable blocks
+ u32 unload_interval = U32_MAX;
+ if (mode == CLEAR_OBJECTS_MODE_FULL) {
+ unload_interval = g_settings->getS32("max_clearobjects_extra_loaded_blocks");
+ unload_interval = MYMAX(unload_interval, 1);
+ }
+ u32 report_interval = loadable_blocks.size() / 10;
+ u32 num_blocks_checked = 0;
+ u32 num_blocks_cleared = 0;
+ u32 num_objs_cleared = 0;
+ for (std::vector<v3s16>::iterator i = loadable_blocks.begin();
+ i != loadable_blocks.end(); ++i) {
+ v3s16 p = *i;
+ MapBlock *block = m_map->emergeBlock(p, false);
+ if (!block) {
+ errorstream << "ServerEnvironment::clearObjects(): "
+ << "Failed to emerge block " << PP(p) << std::endl;
+ continue;
+ }
+ u32 num_stored = block->m_static_objects.m_stored.size();
+ u32 num_active = block->m_static_objects.m_active.size();
+ if (num_stored != 0 || num_active != 0) {
+ block->m_static_objects.m_stored.clear();
+ block->m_static_objects.m_active.clear();
+ block->raiseModified(MOD_STATE_WRITE_NEEDED,
+ MOD_REASON_CLEAR_ALL_OBJECTS);
+ num_objs_cleared += num_stored + num_active;
+ num_blocks_cleared++;
+ }
+ num_blocks_checked++;
+
+ if (report_interval != 0 &&
+ num_blocks_checked % report_interval == 0) {
+ float percent = 100.0 * (float)num_blocks_checked /
+ loadable_blocks.size();
+ infostream << "ServerEnvironment::clearObjects(): "
+ << "Cleared " << num_objs_cleared << " objects"
+ << " in " << num_blocks_cleared << " blocks ("
+ << percent << "%)" << std::endl;
+ }
+ if (num_blocks_checked % unload_interval == 0) {
+ m_map->unloadUnreferencedBlocks();
+ }
+ }
+ m_map->unloadUnreferencedBlocks();
+
+ // Drop references that were added above
+ for (std::vector<v3s16>::iterator i = loaded_blocks.begin();
+ i != loaded_blocks.end(); ++i) {
+ v3s16 p = *i;
+ MapBlock *block = m_map->getBlockNoCreateNoEx(p);
+ assert(block);
+ block->refDrop();
+ }
+
+ m_last_clear_objects_time = m_game_time;
+
+ infostream << "ServerEnvironment::clearObjects(): "
+ << "Finished: Cleared " << num_objs_cleared << " objects"
+ << " in " << num_blocks_cleared << " blocks" << std::endl;
+}
+
+void ServerEnvironment::step(float dtime)
+{
+ DSTACK(FUNCTION_NAME);
+
+ //TimeTaker timer("ServerEnv step");
+
+ /* Step time of day */
+ stepTimeOfDay(dtime);
+
+ // Update this one
+ // NOTE: This is kind of funny on a singleplayer game, but doesn't
+ // really matter that much.
+ static const float server_step = g_settings->getFloat("dedicated_server_step");
+ m_recommended_send_interval = server_step;
+
+ /*
+ Increment game time
+ */
+ {
+ m_game_time_fraction_counter += dtime;
+ u32 inc_i = (u32)m_game_time_fraction_counter;
+ m_game_time += inc_i;
+ m_game_time_fraction_counter -= (float)inc_i;
+ }
+
+ /*
+ Handle players
+ */
+ {
+ ScopeProfiler sp(g_profiler, "SEnv: handle players avg", SPT_AVG);
+ for (std::vector<RemotePlayer *>::iterator i = m_players.begin();
+ i != m_players.end(); ++i) {
+ RemotePlayer *player = dynamic_cast<RemotePlayer *>(*i);
+ assert(player);
+
+ // Ignore disconnected players
+ if(player->peer_id == 0)
+ continue;
+
+ // Move
+ player->move(dtime, this, 100*BS);
+ }
+ }
+
+ /*
+ Manage active block list
+ */
+ if (m_active_blocks_management_interval.step(dtime, m_cache_active_block_mgmt_interval)) {
+ ScopeProfiler sp(g_profiler, "SEnv: manage act. block list avg per interval", SPT_AVG);
+ /*
+ Get player block positions
+ */
+ std::vector<v3s16> players_blockpos;
+ for (std::vector<RemotePlayer *>::iterator i = m_players.begin();
+ i != m_players.end(); ++i) {
+ RemotePlayer *player = dynamic_cast<RemotePlayer *>(*i);
+ assert(player);
+
+ // Ignore disconnected players
+ if (player->peer_id == 0)
+ continue;
+
+ PlayerSAO *playersao = player->getPlayerSAO();
+ assert(playersao);
+
+ v3s16 blockpos = getNodeBlockPos(
+ floatToInt(playersao->getBasePosition(), BS));
+ players_blockpos.push_back(blockpos);
+ }
+
+ /*
+ Update list of active blocks, collecting changes
+ */
+ static const s16 active_block_range = g_settings->getS16("active_block_range");
+ std::set<v3s16> blocks_removed;
+ std::set<v3s16> blocks_added;
+ m_active_blocks.update(players_blockpos, active_block_range,
+ blocks_removed, blocks_added);
+
+ /*
+ Handle removed blocks
+ */
+
+ // Convert active objects that are no more in active blocks to static
+ deactivateFarObjects(false);
+
+ for(std::set<v3s16>::iterator
+ i = blocks_removed.begin();
+ i != blocks_removed.end(); ++i) {
+ v3s16 p = *i;
+
+ /* infostream<<"Server: Block " << PP(p)
+ << " became inactive"<<std::endl; */
+
+ MapBlock *block = m_map->getBlockNoCreateNoEx(p);
+ if(block==NULL)
+ continue;
+
+ // Set current time as timestamp (and let it set ChangedFlag)
+ block->setTimestamp(m_game_time);
+ }
+
+ /*
+ Handle added blocks
+ */
+
+ for(std::set<v3s16>::iterator
+ i = blocks_added.begin();
+ i != blocks_added.end(); ++i)
+ {
+ v3s16 p = *i;
+
+ MapBlock *block = m_map->getBlockOrEmerge(p);
+ if(block==NULL){
+ m_active_blocks.m_list.erase(p);
+ continue;
+ }
+
+ activateBlock(block);
+ /* infostream<<"Server: Block " << PP(p)
+ << " became active"<<std::endl; */
+ }
+ }
+
+ /*
+ Mess around in active blocks
+ */
+ if (m_active_blocks_nodemetadata_interval.step(dtime, m_cache_nodetimer_interval)) {
+ ScopeProfiler sp(g_profiler, "SEnv: mess in act. blocks avg per interval", SPT_AVG);
+
+ float dtime = m_cache_nodetimer_interval;
+
+ for(std::set<v3s16>::iterator
+ i = m_active_blocks.m_list.begin();
+ i != m_active_blocks.m_list.end(); ++i)
+ {
+ v3s16 p = *i;
+
+ /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
+ <<") being handled"<<std::endl;*/
+
+ MapBlock *block = m_map->getBlockNoCreateNoEx(p);
+ if(block==NULL)
+ continue;
+
+ // Reset block usage timer
+ block->resetUsageTimer();
+
+ // Set current time as timestamp
+ block->setTimestampNoChangedFlag(m_game_time);
+ // If time has changed much from the one on disk,
+ // set block to be saved when it is unloaded
+ if(block->getTimestamp() > block->getDiskTimestamp() + 60)
+ block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
+ MOD_REASON_BLOCK_EXPIRED);
+
+ // Run node timers
+ std::vector<NodeTimer> elapsed_timers =
+ block->m_node_timers.step((float)dtime);
+ if (!elapsed_timers.empty()) {
+ MapNode n;
+ for (std::vector<NodeTimer>::iterator i = elapsed_timers.begin();
+ i != elapsed_timers.end(); ++i) {
+ n = block->getNodeNoEx(i->position);
+ p = i->position + block->getPosRelative();
+ if (m_script->node_on_timer(p, n, i->elapsed)) {
+ block->setNodeTimer(NodeTimer(
+ i->timeout, 0, i->position));
+ }
+ }
+ }
+ }
+ }
+
+ if (m_active_block_modifier_interval.step(dtime, m_cache_abm_interval))
+ do{ // breakable
+ if(m_active_block_interval_overload_skip > 0){
+ ScopeProfiler sp(g_profiler, "SEnv: ABM overload skips");
+ m_active_block_interval_overload_skip--;
+ break;
+ }
+ ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg per interval", SPT_AVG);
+ TimeTaker timer("modify in active blocks per interval");
+
+ // Initialize handling of ActiveBlockModifiers
+ ABMHandler abmhandler(m_abms, m_cache_abm_interval, this, true);
+
+ for(std::set<v3s16>::iterator
+ i = m_active_blocks.m_list.begin();
+ i != m_active_blocks.m_list.end(); ++i)
+ {
+ v3s16 p = *i;
+
+ /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
+ <<") being handled"<<std::endl;*/
+
+ MapBlock *block = m_map->getBlockNoCreateNoEx(p);
+ if(block == NULL)
+ continue;
+
+ // Set current time as timestamp
+ block->setTimestampNoChangedFlag(m_game_time);
+
+ /* Handle ActiveBlockModifiers */
+ abmhandler.apply(block);
+ }
+
+ u32 time_ms = timer.stop(true);
+ u32 max_time_ms = 200;
+ if(time_ms > max_time_ms){
+ warningstream<<"active block modifiers took "
+ <<time_ms<<"ms (longer than "
+ <<max_time_ms<<"ms)"<<std::endl;
+ m_active_block_interval_overload_skip = (time_ms / max_time_ms) + 1;
+ }
+ }while(0);
+
+ /*
+ Step script environment (run global on_step())
+ */
+ m_script->environment_Step(dtime);
+
+ /*
+ Step active objects
+ */
+ {
+ ScopeProfiler sp(g_profiler, "SEnv: step act. objs avg", SPT_AVG);
+ //TimeTaker timer("Step active objects");
+
+ g_profiler->avg("SEnv: num of objects", m_active_objects.size());
+
+ // This helps the objects to send data at the same time
+ bool send_recommended = false;
+ m_send_recommended_timer += dtime;
+ if(m_send_recommended_timer > getSendRecommendedInterval())
+ {
+ m_send_recommended_timer -= getSendRecommendedInterval();
+ send_recommended = true;
+ }
+
+ for(ActiveObjectMap::iterator i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i) {
+ ServerActiveObject* obj = i->second;
+ // Don't step if is to be removed or stored statically
+ if(obj->m_removed || obj->m_pending_deactivation)
+ continue;
+ // Step object
+ obj->step(dtime, send_recommended);
+ // Read messages from object
+ while(!obj->m_messages_out.empty())
+ {
+ m_active_object_messages.push(
+ obj->m_messages_out.front());
+ obj->m_messages_out.pop();
+ }
+ }
+ }
+
+ /*
+ Manage active objects
+ */
+ if(m_object_management_interval.step(dtime, 0.5))
+ {
+ ScopeProfiler sp(g_profiler, "SEnv: remove removed objs avg /.5s", SPT_AVG);
+ /*
+ Remove objects that satisfy (m_removed && m_known_by_count==0)
+ */
+ removeRemovedObjects();
+ }
+
+ /*
+ Manage particle spawner expiration
+ */
+ if (m_particle_management_interval.step(dtime, 1.0)) {
+ for (UNORDERED_MAP<u32, float>::iterator i = m_particle_spawners.begin();
+ i != m_particle_spawners.end(); ) {
+ //non expiring spawners
+ if (i->second == PARTICLE_SPAWNER_NO_EXPIRY) {
+ ++i;
+ continue;
+ }
+
+ i->second -= 1.0f;
+ if (i->second <= 0.f)
+ m_particle_spawners.erase(i++);
+ else
+ ++i;
+ }
+ }
+}
+
+u32 ServerEnvironment::addParticleSpawner(float exptime)
+{
+ // Timers with lifetime 0 do not expire
+ float time = exptime > 0.f ? exptime : PARTICLE_SPAWNER_NO_EXPIRY;
+
+ u32 id = 0;
+ for (;;) { // look for unused particlespawner id
+ id++;
+ UNORDERED_MAP<u32, float>::iterator f = m_particle_spawners.find(id);
+ if (f == m_particle_spawners.end()) {
+ m_particle_spawners[id] = time;
+ break;
+ }
+ }
+ return id;
+}
+
+u32 ServerEnvironment::addParticleSpawner(float exptime, u16 attached_id)
+{
+ u32 id = addParticleSpawner(exptime);
+ m_particle_spawner_attachments[id] = attached_id;
+ if (ServerActiveObject *obj = getActiveObject(attached_id)) {
+ obj->attachParticleSpawner(id);
+ }
+ return id;
+}
+
+void ServerEnvironment::deleteParticleSpawner(u32 id, bool remove_from_object)
+{
+ m_particle_spawners.erase(id);
+ UNORDERED_MAP<u32, u16>::iterator it = m_particle_spawner_attachments.find(id);
+ if (it != m_particle_spawner_attachments.end()) {
+ u16 obj_id = (*it).second;
+ ServerActiveObject *sao = getActiveObject(obj_id);
+ if (sao != NULL && remove_from_object) {
+ sao->detachParticleSpawner(id);
+ }
+ m_particle_spawner_attachments.erase(id);
+ }
+}
+
+ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
+{
+ ActiveObjectMap::iterator n = m_active_objects.find(id);
+ return (n != m_active_objects.end() ? n->second : NULL);
+}
+
+bool isFreeServerActiveObjectId(u16 id, ActiveObjectMap &objects)
+{
+ if (id == 0)
+ return false;
+
+ return objects.find(id) == objects.end();
+}
+
+u16 getFreeServerActiveObjectId(ActiveObjectMap &objects)
+{
+ //try to reuse id's as late as possible
+ static u16 last_used_id = 0;
+ u16 startid = last_used_id;
+ for(;;)
+ {
+ last_used_id ++;
+ if(isFreeServerActiveObjectId(last_used_id, objects))
+ return last_used_id;
+
+ if(last_used_id == startid)
+ return 0;
+ }
+}
+
+u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
+{
+ assert(object); // Pre-condition
+ m_added_objects++;
+ u16 id = addActiveObjectRaw(object, true, 0);
+ return id;
+}
+
+/*
+ Finds out what new objects have been added to
+ inside a radius around a position
+*/
+void ServerEnvironment::getAddedActiveObjects(PlayerSAO *playersao, s16 radius,
+ s16 player_radius,
+ std::set<u16> &current_objects,
+ std::queue<u16> &added_objects)
+{
+ f32 radius_f = radius * BS;
+ f32 player_radius_f = player_radius * BS;
+
+ if (player_radius_f < 0)
+ player_radius_f = 0;
+ /*
+ Go through the object list,
+ - discard m_removed objects,
+ - discard objects that are too far away,
+ - discard objects that are found in current_objects.
+ - add remaining objects to added_objects
+ */
+ for (ActiveObjectMap::iterator i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i) {
+ u16 id = i->first;
+
+ // Get object
+ ServerActiveObject *object = i->second;
+ if (object == NULL)
+ continue;
+
+ // Discard if removed or deactivating
+ if(object->m_removed || object->m_pending_deactivation)
+ continue;
+
+ f32 distance_f = object->getBasePosition().
+ getDistanceFrom(playersao->getBasePosition());
+ if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
+ // Discard if too far
+ if (distance_f > player_radius_f && player_radius_f != 0)
+ continue;
+ } else if (distance_f > radius_f)
+ continue;
+
+ // Discard if already on current_objects
+ std::set<u16>::iterator n;
+ n = current_objects.find(id);
+ if(n != current_objects.end())
+ continue;
+ // Add to added_objects
+ added_objects.push(id);
+ }
+}
+
+/*
+ Finds out what objects have been removed from
+ inside a radius around a position
+*/
+void ServerEnvironment::getRemovedActiveObjects(PlayerSAO *playersao, s16 radius,
+ s16 player_radius,
+ std::set<u16> &current_objects,
+ std::queue<u16> &removed_objects)
+{
+ f32 radius_f = radius * BS;
+ f32 player_radius_f = player_radius * BS;
+
+ if (player_radius_f < 0)
+ player_radius_f = 0;
+ /*
+ Go through current_objects; object is removed if:
+ - object is not found in m_active_objects (this is actually an
+ error condition; objects should be set m_removed=true and removed
+ only after all clients have been informed about removal), or
+ - object has m_removed=true, or
+ - object is too far away
+ */
+ for(std::set<u16>::iterator
+ i = current_objects.begin();
+ i != current_objects.end(); ++i)
+ {
+ u16 id = *i;
+ ServerActiveObject *object = getActiveObject(id);
+
+ if (object == NULL) {
+ infostream << "ServerEnvironment::getRemovedActiveObjects():"
+ << " object in current_objects is NULL" << std::endl;
+ removed_objects.push(id);
+ continue;
+ }
+
+ if (object->m_removed || object->m_pending_deactivation) {
+ removed_objects.push(id);
+ continue;
+ }
+
+ f32 distance_f = object->getBasePosition().getDistanceFrom(playersao->getBasePosition());
+ if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
+ if (distance_f <= player_radius_f || player_radius_f == 0)
+ continue;
+ } else if (distance_f <= radius_f)
+ continue;
+
+ // Object is no longer visible
+ removed_objects.push(id);
+ }
+}
+
+void ServerEnvironment::setStaticForActiveObjectsInBlock(
+ v3s16 blockpos, bool static_exists, v3s16 static_block)
+{
+ MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
+ if (!block)
+ return;
+
+ for (std::map<u16, StaticObject>::iterator
+ so_it = block->m_static_objects.m_active.begin();
+ so_it != block->m_static_objects.m_active.end(); ++so_it) {
+ // Get the ServerActiveObject counterpart to this StaticObject
+ ActiveObjectMap::iterator ao_it = m_active_objects.find(so_it->first);
+ if (ao_it == m_active_objects.end()) {
+ // If this ever happens, there must be some kind of nasty bug.
+ errorstream << "ServerEnvironment::setStaticForObjectsInBlock(): "
+ "Object from MapBlock::m_static_objects::m_active not found "
+ "in m_active_objects";
+ continue;
+ }
+
+ ServerActiveObject *sao = ao_it->second;
+ sao->m_static_exists = static_exists;
+ sao->m_static_block = static_block;
+ }
+}
+
+ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
+{
+ if(m_active_object_messages.empty())
+ return ActiveObjectMessage(0);
+
+ ActiveObjectMessage message = m_active_object_messages.front();
+ m_active_object_messages.pop();
+ return message;
+}
+
+/*
+ ************ Private methods *************
+*/
+
+u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
+ bool set_changed, u32 dtime_s)
+{
+ assert(object); // Pre-condition
+ if(object->getId() == 0){
+ u16 new_id = getFreeServerActiveObjectId(m_active_objects);
+ if(new_id == 0)
+ {
+ errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
+ <<"no free ids available"<<std::endl;
+ if(object->environmentDeletes())
+ delete object;
+ return 0;
+ }
+ object->setId(new_id);
+ }
+ else{
+ verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
+ <<"supplied with id "<<object->getId()<<std::endl;
+ }
+
+ if(!isFreeServerActiveObjectId(object->getId(), m_active_objects)) {
+ errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
+ <<"id is not free ("<<object->getId()<<")"<<std::endl;
+ if(object->environmentDeletes())
+ delete object;
+ return 0;
+ }
+
+ if (objectpos_over_limit(object->getBasePosition())) {
+ v3f p = object->getBasePosition();
+ warningstream << "ServerEnvironment::addActiveObjectRaw(): "
+ << "object position (" << p.X << "," << p.Y << "," << p.Z
+ << ") outside maximum range" << std::endl;
+ if (object->environmentDeletes())
+ delete object;
+ return 0;
+ }
+
+ /*infostream<<"ServerEnvironment::addActiveObjectRaw(): "
+ <<"added (id="<<object->getId()<<")"<<std::endl;*/
+
+ m_active_objects[object->getId()] = object;
+
+ verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
+ <<"Added id="<<object->getId()<<"; there are now "
+ <<m_active_objects.size()<<" active objects."
+ <<std::endl;
+
+ // Register reference in scripting api (must be done before post-init)
+ m_script->addObjectReference(object);
+ // Post-initialize object
+ object->addedToEnvironment(dtime_s);
+
+ // Add static data to block
+ if(object->isStaticAllowed())
+ {
+ // Add static object to active static list of the block
+ v3f objectpos = object->getBasePosition();
+ std::string staticdata = "";
+ object->getStaticData(&staticdata);
+ StaticObject s_obj(object->getType(), objectpos, staticdata);
+ // Add to the block where the object is located in
+ v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
+ MapBlock *block = m_map->emergeBlock(blockpos);
+ if(block){
+ block->m_static_objects.m_active[object->getId()] = s_obj;
+ object->m_static_exists = true;
+ object->m_static_block = blockpos;
+
+ if(set_changed)
+ block->raiseModified(MOD_STATE_WRITE_NEEDED,
+ MOD_REASON_ADD_ACTIVE_OBJECT_RAW);
+ } else {
+ v3s16 p = floatToInt(objectpos, BS);
+ errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
+ <<"could not emerge block for storing id="<<object->getId()
+ <<" statically (pos="<<PP(p)<<")"<<std::endl;
+ }
+ }
+
+ return object->getId();
+}
+
+/*
+ Remove objects that satisfy (m_removed && m_known_by_count==0)
+*/
+void ServerEnvironment::removeRemovedObjects()
+{
+ std::vector<u16> objects_to_remove;
+ for(ActiveObjectMap::iterator i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i) {
+ u16 id = i->first;
+ ServerActiveObject* obj = i->second;
+ // This shouldn't happen but check it
+ if(obj == NULL)
+ {
+ infostream<<"NULL object found in ServerEnvironment"
+ <<" while finding removed objects. id="<<id<<std::endl;
+ // Id to be removed from m_active_objects
+ objects_to_remove.push_back(id);
+ continue;
+ }
+
+ /*
+ We will delete objects that are marked as removed or thatare
+ waiting for deletion after deactivation
+ */
+ if (!obj->m_removed && !obj->m_pending_deactivation)
+ continue;
+
+ /*
+ Delete static data from block if is marked as removed
+ */
+ if(obj->m_static_exists && obj->m_removed)
+ {
+ MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
+ if (block) {
+ block->m_static_objects.remove(id);
+ block->raiseModified(MOD_STATE_WRITE_NEEDED,
+ MOD_REASON_REMOVE_OBJECTS_REMOVE);
+ obj->m_static_exists = false;
+ } else {
+ infostream<<"Failed to emerge block from which an object to "
+ <<"be removed was loaded from. id="<<id<<std::endl;
+ }
+ }
+
+ // If m_known_by_count > 0, don't actually remove. On some future
+ // invocation this will be 0, which is when removal will continue.
+ if(obj->m_known_by_count > 0)
+ continue;
+
+ /*
+ Move static data from active to stored if not marked as removed
+ */
+ if(obj->m_static_exists && !obj->m_removed){
+ MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
+ if (block) {
+ std::map<u16, StaticObject>::iterator i =
+ block->m_static_objects.m_active.find(id);
+ if(i != block->m_static_objects.m_active.end()){
+ block->m_static_objects.m_stored.push_back(i->second);
+ block->m_static_objects.m_active.erase(id);
+ block->raiseModified(MOD_STATE_WRITE_NEEDED,
+ MOD_REASON_REMOVE_OBJECTS_DEACTIVATE);
+ }
+ } else {
+ infostream<<"Failed to emerge block from which an object to "
+ <<"be deactivated was loaded from. id="<<id<<std::endl;
+ }
+ }
+
+ // Tell the object about removal
+ obj->removingFromEnvironment();
+ // Deregister in scripting api
+ m_script->removeObjectReference(obj);
+
+ // Delete
+ if(obj->environmentDeletes())
+ delete obj;
+
+ // Id to be removed from m_active_objects
+ objects_to_remove.push_back(id);
+ }
+ // Remove references from m_active_objects
+ for(std::vector<u16>::iterator i = objects_to_remove.begin();
+ i != objects_to_remove.end(); ++i) {
+ m_active_objects.erase(*i);
+ }
+}
+
+static void print_hexdump(std::ostream &o, const std::string &data)
+{
+ const int linelength = 16;
+ for(int l=0; ; l++){
+ int i0 = linelength * l;
+ bool at_end = false;
+ int thislinelength = linelength;
+ if(i0 + thislinelength > (int)data.size()){
+ thislinelength = data.size() - i0;
+ at_end = true;
+ }
+ for(int di=0; di<linelength; di++){
+ int i = i0 + di;
+ char buf[4];
+ if(di<thislinelength)
+ snprintf(buf, 4, "%.2x ", data[i]);
+ else
+ snprintf(buf, 4, " ");
+ o<<buf;
+ }
+ o<<" ";
+ for(int di=0; di<thislinelength; di++){
+ int i = i0 + di;
+ if(data[i] >= 32)
+ o<<data[i];
+ else
+ o<<".";
+ }
+ o<<std::endl;
+ if(at_end)
+ break;
+ }
+}
+
+/*
+ Convert stored objects from blocks near the players to active.
+*/
+void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
+{
+ if(block == NULL)
+ return;
+
+ // Ignore if no stored objects (to not set changed flag)
+ if(block->m_static_objects.m_stored.empty())
+ return;
+
+ verbosestream<<"ServerEnvironment::activateObjects(): "
+ <<"activating objects of block "<<PP(block->getPos())
+ <<" ("<<block->m_static_objects.m_stored.size()
+ <<" objects)"<<std::endl;
+ bool large_amount = (block->m_static_objects.m_stored.size() > g_settings->getU16("max_objects_per_block"));
+ if (large_amount) {
+ errorstream<<"suspiciously large amount of objects detected: "
+ <<block->m_static_objects.m_stored.size()<<" in "
+ <<PP(block->getPos())
+ <<"; removing all of them."<<std::endl;
+ // Clear stored list
+ block->m_static_objects.m_stored.clear();
+ block->raiseModified(MOD_STATE_WRITE_NEEDED,
+ MOD_REASON_TOO_MANY_OBJECTS);
+ return;
+ }
+
+ // Activate stored objects
+ std::vector<StaticObject> new_stored;
+ for (std::vector<StaticObject>::iterator
+ i = block->m_static_objects.m_stored.begin();
+ i != block->m_static_objects.m_stored.end(); ++i) {
+ StaticObject &s_obj = *i;
+
+ // Create an active object from the data
+ ServerActiveObject *obj = ServerActiveObject::create
+ ((ActiveObjectType) s_obj.type, this, 0, s_obj.pos, s_obj.data);
+ // If couldn't create object, store static data back.
+ if(obj == NULL) {
+ errorstream<<"ServerEnvironment::activateObjects(): "
+ <<"failed to create active object from static object "
+ <<"in block "<<PP(s_obj.pos/BS)
+ <<" type="<<(int)s_obj.type<<" data:"<<std::endl;
+ print_hexdump(verbosestream, s_obj.data);
+
+ new_stored.push_back(s_obj);
+ continue;
+ }
+ verbosestream<<"ServerEnvironment::activateObjects(): "
+ <<"activated static object pos="<<PP(s_obj.pos/BS)
+ <<" type="<<(int)s_obj.type<<std::endl;
+ // This will also add the object to the active static list
+ addActiveObjectRaw(obj, false, dtime_s);
+ }
+ // Clear stored list
+ block->m_static_objects.m_stored.clear();
+ // Add leftover failed stuff to stored list
+ for(std::vector<StaticObject>::iterator
+ i = new_stored.begin();
+ i != new_stored.end(); ++i) {
+ StaticObject &s_obj = *i;
+ block->m_static_objects.m_stored.push_back(s_obj);
+ }
+
+ // Turn the active counterparts of activated objects not pending for
+ // deactivation
+ for(std::map<u16, StaticObject>::iterator
+ i = block->m_static_objects.m_active.begin();
+ i != block->m_static_objects.m_active.end(); ++i)
+ {
+ u16 id = i->first;
+ ServerActiveObject *object = getActiveObject(id);
+ assert(object);
+ object->m_pending_deactivation = false;
+ }
+
+ /*
+ Note: Block hasn't really been modified here.
+ The objects have just been activated and moved from the stored
+ static list to the active static list.
+ As such, the block is essentially the same.
+ Thus, do not call block->raiseModified(MOD_STATE_WRITE_NEEDED).
+ Otherwise there would be a huge amount of unnecessary I/O.
+ */
+}
+
+/*
+ Convert objects that are not standing inside active blocks to static.
+
+ If m_known_by_count != 0, active object is not deleted, but static
+ data is still updated.
+
+ If force_delete is set, active object is deleted nevertheless. It
+ shall only be set so in the destructor of the environment.
+
+ If block wasn't generated (not in memory or on disk),
+*/
+void ServerEnvironment::deactivateFarObjects(bool _force_delete)
+{
+ std::vector<u16> objects_to_remove;
+ for(ActiveObjectMap::iterator i = m_active_objects.begin();
+ i != m_active_objects.end(); ++i) {
+ // force_delete might be overriden per object
+ bool force_delete = _force_delete;
+
+ ServerActiveObject* obj = i->second;
+ assert(obj);
+
+ // Do not deactivate if static data creation not allowed
+ if(!force_delete && !obj->isStaticAllowed())
+ continue;
+
+ // If pending deactivation, let removeRemovedObjects() do it
+ if(!force_delete && obj->m_pending_deactivation)
+ continue;
+
+ u16 id = i->first;
+ v3f objectpos = obj->getBasePosition();
+
+ // The block in which the object resides in
+ v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
+
+ // If object's static data is stored in a deactivated block and object
+ // is actually located in an active block, re-save to the block in
+ // which the object is actually located in.
+ if(!force_delete &&
+ obj->m_static_exists &&
+ !m_active_blocks.contains(obj->m_static_block) &&
+ m_active_blocks.contains(blockpos_o))
+ {
+ v3s16 old_static_block = obj->m_static_block;
+
+ // Save to block where object is located
+ MapBlock *block = m_map->emergeBlock(blockpos_o, false);
+ if(!block){
+ errorstream<<"ServerEnvironment::deactivateFarObjects(): "
+ <<"Could not save object id="<<id
+ <<" to it's current block "<<PP(blockpos_o)
+ <<std::endl;
+ continue;
+ }
+ std::string staticdata_new = "";
+ obj->getStaticData(&staticdata_new);
+ StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
+ block->m_static_objects.insert(id, s_obj);
+ obj->m_static_block = blockpos_o;
+ block->raiseModified(MOD_STATE_WRITE_NEEDED,
+ MOD_REASON_STATIC_DATA_ADDED);
+
+ // Delete from block where object was located
+ block = m_map->emergeBlock(old_static_block, false);
+ if(!block){
+ errorstream<<"ServerEnvironment::deactivateFarObjects(): "
+ <<"Could not delete object id="<<id
+ <<" from it's previous block "<<PP(old_static_block)
+ <<std::endl;
+ continue;
+ }
+ block->m_static_objects.remove(id);
+ block->raiseModified(MOD_STATE_WRITE_NEEDED,
+ MOD_REASON_STATIC_DATA_REMOVED);
+ continue;
+ }
+
+ // If block is active, don't remove
+ if(!force_delete && m_active_blocks.contains(blockpos_o))
+ continue;
+
+ verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
+ <<"deactivating object id="<<id<<" on inactive block "
+ <<PP(blockpos_o)<<std::endl;
+
+ // If known by some client, don't immediately delete.
+ bool pending_delete = (obj->m_known_by_count > 0 && !force_delete);
+
+ /*
+ Update the static data
+ */
+
+ if(obj->isStaticAllowed())
+ {
+ // Create new static object
+ std::string staticdata_new = "";
+ obj->getStaticData(&staticdata_new);
+ StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
+
+ bool stays_in_same_block = false;
+ bool data_changed = true;
+
+ if (obj->m_static_exists) {
+ if (obj->m_static_block == blockpos_o)
+ stays_in_same_block = true;
+
+ MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
+
+ if (block) {
+ std::map<u16, StaticObject>::iterator n =
+ block->m_static_objects.m_active.find(id);
+ if (n != block->m_static_objects.m_active.end()) {
+ StaticObject static_old = n->second;
+
+ float save_movem = obj->getMinimumSavedMovement();
+
+ if (static_old.data == staticdata_new &&
+ (static_old.pos - objectpos).getLength() < save_movem)
+ data_changed = false;
+ } else {
+ errorstream<<"ServerEnvironment::deactivateFarObjects(): "
+ <<"id="<<id<<" m_static_exists=true but "
+ <<"static data doesn't actually exist in "
+ <<PP(obj->m_static_block)<<std::endl;
+ }
+ }
+ }
+
+ bool shall_be_written = (!stays_in_same_block || data_changed);
+
+ // Delete old static object
+ if(obj->m_static_exists)
+ {
+ MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
+ if(block)
+ {
+ block->m_static_objects.remove(id);
+ obj->m_static_exists = false;
+ // Only mark block as modified if data changed considerably
+ if(shall_be_written)
+ block->raiseModified(MOD_STATE_WRITE_NEEDED,
+ MOD_REASON_STATIC_DATA_CHANGED);
+ }
+ }
+
+ // Add to the block where the object is located in
+ v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
+ // Get or generate the block
+ MapBlock *block = NULL;
+ try{
+ block = m_map->emergeBlock(blockpos);
+ } catch(InvalidPositionException &e){
+ // Handled via NULL pointer
+ // NOTE: emergeBlock's failure is usually determined by it
+ // actually returning NULL
+ }
+
+ if(block)
+ {
+ if (block->m_static_objects.m_stored.size() >= g_settings->getU16("max_objects_per_block")) {
+ warningstream << "ServerEnv: Trying to store id = " << obj->getId()
+ << " statically but block " << PP(blockpos)
+ << " already contains "
+ << block->m_static_objects.m_stored.size()
+ << " objects."
+ << " Forcing delete." << std::endl;
+ force_delete = true;
+ } else {
+ // If static counterpart already exists in target block,
+ // remove it first.
+ // This shouldn't happen because the object is removed from
+ // the previous block before this according to
+ // obj->m_static_block, but happens rarely for some unknown
+ // reason. Unsuccessful attempts have been made to find
+ // said reason.
+ if(id && block->m_static_objects.m_active.find(id) != block->m_static_objects.m_active.end()){
+ warningstream<<"ServerEnv: Performing hack #83274"
+ <<std::endl;
+ block->m_static_objects.remove(id);
+ }
+ // Store static data
+ u16 store_id = pending_delete ? id : 0;
+ block->m_static_objects.insert(store_id, s_obj);
+
+ // Only mark block as modified if data changed considerably
+ if(shall_be_written)
+ block->raiseModified(MOD_STATE_WRITE_NEEDED,
+ MOD_REASON_STATIC_DATA_CHANGED);
+
+ obj->m_static_exists = true;
+ obj->m_static_block = block->getPos();
+ }
+ }
+ else{
+ if(!force_delete){
+ v3s16 p = floatToInt(objectpos, BS);
+ errorstream<<"ServerEnv: Could not find or generate "
+ <<"a block for storing id="<<obj->getId()
+ <<" statically (pos="<<PP(p)<<")"<<std::endl;
+ continue;
+ }
+ }
+ }
+
+ /*
+ If known by some client, set pending deactivation.
+ Otherwise delete it immediately.
+ */
+
+ if(pending_delete && !force_delete)
+ {
+ verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
+ <<"object id="<<id<<" is known by clients"
+ <<"; not deleting yet"<<std::endl;
+
+ obj->m_pending_deactivation = true;
+ continue;
+ }
+
+ verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
+ <<"object id="<<id<<" is not known by clients"
+ <<"; deleting"<<std::endl;
+
+ // Tell the object about removal
+ obj->removingFromEnvironment();
+ // Deregister in scripting api
+ m_script->removeObjectReference(obj);
+
+ // Delete active object
+ if(obj->environmentDeletes())
+ delete obj;
+ // Id to be removed from m_active_objects
+ objects_to_remove.push_back(id);
+ }
+
+ // Remove references from m_active_objects
+ for(std::vector<u16>::iterator i = objects_to_remove.begin();
+ i != objects_to_remove.end(); ++i) {
+ m_active_objects.erase(*i);
+ }
+}
+
+PlayerDatabase *ServerEnvironment::openPlayerDatabase(const std::string &name,
+ const std::string &savedir, const Settings &conf)
+{
+
+ if (name == "sqlite3")
+ return new PlayerDatabaseSQLite3(savedir);
+ else if (name == "dummy")
+ return new Database_Dummy();
+#if USE_POSTGRESQL
+ else if (name == "postgresql") {
+ std::string connect_string = "";
+ conf.getNoEx("pgsql_player_connection", connect_string);
+ return new PlayerDatabasePostgreSQL(connect_string);
+ }
+#endif
+ else if (name == "files")
+ return new PlayerDatabaseFiles(savedir + DIR_DELIM + "players");
+ else
+ throw BaseException(std::string("Database backend ") + name + " not supported.");
+}
+
+bool ServerEnvironment::migratePlayersDatabase(const GameParams &game_params,
+ const Settings &cmd_args)
+{
+ std::string migrate_to = cmd_args.get("migrate-players");
+ Settings world_mt;
+ std::string world_mt_path = game_params.world_path + DIR_DELIM + "world.mt";
+ if (!world_mt.readConfigFile(world_mt_path.c_str())) {
+ errorstream << "Cannot read world.mt!" << std::endl;
+ return false;
+ }
+
+ if (!world_mt.exists("player_backend")) {
+ errorstream << "Please specify your current backend in world.mt:"
+ << std::endl
+ << " player_backend = {files|sqlite3|postgresql}"
+ << std::endl;
+ return false;
+ }
+
+ std::string backend = world_mt.get("player_backend");
+ if (backend == migrate_to) {
+ errorstream << "Cannot migrate: new backend is same"
+ << " as the old one" << std::endl;
+ return false;
+ }
+
+ const std::string players_backup_path = game_params.world_path + DIR_DELIM
+ + "players.bak";
+
+ if (backend == "files") {
+ // Create backup directory
+ fs::CreateDir(players_backup_path);
+ }
+
+ try {
+ PlayerDatabase *srcdb = ServerEnvironment::openPlayerDatabase(backend,
+ game_params.world_path, world_mt);
+ PlayerDatabase *dstdb = ServerEnvironment::openPlayerDatabase(migrate_to,
+ game_params.world_path, world_mt);
+
+ std::vector<std::string> player_list;
+ srcdb->listPlayers(player_list);
+ for (std::vector<std::string>::const_iterator it = player_list.begin();
+ it != player_list.end(); ++it) {
+ actionstream << "Migrating player " << it->c_str() << std::endl;
+ RemotePlayer player(it->c_str(), NULL);
+ PlayerSAO playerSAO(NULL, &player, 15000, false);
+
+ srcdb->loadPlayer(&player, &playerSAO);
+
+ playerSAO.finalize(&player, std::set<std::string>());
+ player.setPlayerSAO(&playerSAO);
+
+ dstdb->savePlayer(&player);
+
+ // For files source, move player files to backup dir
+ if (backend == "files") {
+ fs::Rename(
+ game_params.world_path + DIR_DELIM + "players" + DIR_DELIM + (*it),
+ players_backup_path + DIR_DELIM + (*it));
+ }
+ }
+
+ actionstream << "Successfully migrated " << player_list.size() << " players"
+ << std::endl;
+ world_mt.set("player_backend", migrate_to);
+ if (!world_mt.updateConfigFile(world_mt_path.c_str()))
+ errorstream << "Failed to update world.mt!" << std::endl;
+ else
+ actionstream << "world.mt updated" << std::endl;
+
+ // When migration is finished from file backend, remove players directory if empty
+ if (backend == "files") {
+ fs::DeleteSingleFileOrEmptyDirectory(game_params.world_path + DIR_DELIM
+ + "players");
+ }
+
+ delete srcdb;
+ delete dstdb;
+
+ } catch (BaseException &e) {
+ errorstream << "An error occured during migration: " << e.what() << std::endl;
+ return false;
+ }
+ return true;
+}
diff --git a/src/serverenvironment.h b/src/serverenvironment.h
new file mode 100644
index 000000000..7c370fd54
--- /dev/null
+++ b/src/serverenvironment.h
@@ -0,0 +1,438 @@
+/*
+Minetest
+Copyright (C) 2010-2017 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 Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 SERVER_ENVIRONMENT_HEADER
+#define SERVER_ENVIRONMENT_HEADER
+
+#include "environment.h"
+#include "mapnode.h"
+#include "mapblock.h"
+#include <set>
+
+class IGameDef;
+class ServerMap;
+struct GameParams;
+class RemotePlayer;
+class PlayerDatabase;
+class PlayerSAO;
+class ServerEnvironment;
+class ActiveBlockModifier;
+class ServerActiveObject;
+class Server;
+class ServerScripting;
+
+/*
+ {Active, Loading} block modifier interface.
+
+ These are fed into ServerEnvironment at initialization time;
+ ServerEnvironment handles deleting them.
+*/
+
+class ActiveBlockModifier
+{
+public:
+ ActiveBlockModifier(){};
+ virtual ~ActiveBlockModifier(){};
+
+ // Set of contents to trigger on
+ virtual const std::set<std::string> &getTriggerContents() const = 0;
+ // Set of required neighbors (trigger doesn't happen if none are found)
+ // Empty = do not check neighbors
+ virtual const std::set<std::string> &getRequiredNeighbors() const = 0;
+ // Trigger interval in seconds
+ virtual float getTriggerInterval() = 0;
+ // Random chance of (1 / return value), 0 is disallowed
+ virtual u32 getTriggerChance() = 0;
+ // Whether to modify chance to simulate time lost by an unnattended block
+ virtual bool getSimpleCatchUp() = 0;
+ // This is called usually at interval for 1/chance of the nodes
+ virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n){};
+ virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n,
+ u32 active_object_count, u32 active_object_count_wider){};
+};
+
+struct ABMWithState
+{
+ ActiveBlockModifier *abm;
+ float timer;
+
+ ABMWithState(ActiveBlockModifier *abm_);
+};
+
+struct LoadingBlockModifierDef
+{
+ // Set of contents to trigger on
+ std::set<std::string> trigger_contents;
+ std::string name;
+ bool run_at_every_load;
+
+ virtual ~LoadingBlockModifierDef() {}
+ virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n){};
+};
+
+struct LBMContentMapping
+{
+ typedef std::map<content_t, std::vector<LoadingBlockModifierDef *> > container_map;
+ container_map map;
+
+ std::vector<LoadingBlockModifierDef *> lbm_list;
+
+ // Needs to be separate method (not inside destructor),
+ // because the LBMContentMapping may be copied and destructed
+ // many times during operation in the lbm_lookup_map.
+ void deleteContents();
+ void addLBM(LoadingBlockModifierDef *lbm_def, IGameDef *gamedef);
+ const std::vector<LoadingBlockModifierDef *> *lookup(content_t c) const;
+};
+
+class LBMManager
+{
+public:
+ LBMManager():
+ m_query_mode(false)
+ {}
+
+ ~LBMManager();
+
+ // Don't call this after loadIntroductionTimes() ran.
+ void addLBMDef(LoadingBlockModifierDef *lbm_def);
+
+ void loadIntroductionTimes(const std::string &times,
+ IGameDef *gamedef, u32 now);
+
+ // Don't call this before loadIntroductionTimes() ran.
+ std::string createIntroductionTimesString();
+
+ // Don't call this before loadIntroductionTimes() ran.
+ void applyLBMs(ServerEnvironment *env, MapBlock *block, u32 stamp);
+
+ // Warning: do not make this std::unordered_map, order is relevant here
+ typedef std::map<u32, LBMContentMapping> lbm_lookup_map;
+
+private:
+ // Once we set this to true, we can only query,
+ // not modify
+ bool m_query_mode;
+
+ // For m_query_mode == false:
+ // The key of the map is the LBM def's name.
+ // TODO make this std::unordered_map
+ std::map<std::string, LoadingBlockModifierDef *> m_lbm_defs;
+
+ // For m_query_mode == true:
+ // The key of the map is the LBM def's first introduction time.
+ lbm_lookup_map m_lbm_lookup;
+
+ // Returns an iterator to the LBMs that were introduced
+ // after the given time. This is guaranteed to return
+ // valid values for everything
+ lbm_lookup_map::const_iterator getLBMsIntroducedAfter(u32 time)
+ { return m_lbm_lookup.lower_bound(time); }
+};
+
+/*
+ List of active blocks, used by ServerEnvironment
+*/
+
+class ActiveBlockList
+{
+public:
+ void update(std::vector<v3s16> &active_positions,
+ s16 radius,
+ std::set<v3s16> &blocks_removed,
+ std::set<v3s16> &blocks_added);
+
+ bool contains(v3s16 p){
+ return (m_list.find(p) != m_list.end());
+ }
+
+ void clear(){
+ m_list.clear();
+ }
+
+ std::set<v3s16> m_list;
+ std::set<v3s16> m_forceloaded_list;
+
+private:
+};
+
+/*
+ Operation mode for ServerEnvironment::clearObjects()
+*/
+enum ClearObjectsMode {
+ // Load and go through every mapblock, clearing objects
+ CLEAR_OBJECTS_MODE_FULL,
+
+ // Clear objects immediately in loaded mapblocks;
+ // clear objects in unloaded mapblocks only when the mapblocks are next activated.
+ CLEAR_OBJECTS_MODE_QUICK,
+};
+
+/*
+ The server-side environment.
+
+ This is not thread-safe. Server uses an environment mutex.
+*/
+
+typedef UNORDERED_MAP<u16, ServerActiveObject *> ActiveObjectMap;
+
+class ServerEnvironment : public Environment
+{
+public:
+ ServerEnvironment(ServerMap *map, ServerScripting *scriptIface,
+ Server *server, const std::string &path_world);
+ ~ServerEnvironment();
+
+ Map & getMap();
+
+ ServerMap & getServerMap();
+
+ //TODO find way to remove this fct!
+ ServerScripting* getScriptIface()
+ { return m_script; }
+
+ Server *getGameDef()
+ { return m_server; }
+
+ float getSendRecommendedInterval()
+ { return m_recommended_send_interval; }
+
+ void kickAllPlayers(AccessDeniedCode reason,
+ const std::string &str_reason, bool reconnect);
+ // Save players
+ void saveLoadedPlayers();
+ void savePlayer(RemotePlayer *player);
+ PlayerSAO *loadPlayer(RemotePlayer *player, bool *new_player, u16 peer_id,
+ bool is_singleplayer);
+ void addPlayer(RemotePlayer *player);
+ void removePlayer(RemotePlayer *player);
+ bool removePlayerFromDatabase(const std::string &name);
+
+ /*
+ Save and load time of day and game timer
+ */
+ void saveMeta();
+ void loadMeta();
+ // to be called instead of loadMeta if
+ // env_meta.txt doesn't exist (e.g. new world)
+ void loadDefaultMeta();
+
+ u32 addParticleSpawner(float exptime);
+ u32 addParticleSpawner(float exptime, u16 attached_id);
+ void deleteParticleSpawner(u32 id, bool remove_from_object = true);
+
+ /*
+ External ActiveObject interface
+ -------------------------------------------
+ */
+
+ ServerActiveObject* getActiveObject(u16 id);
+
+ /*
+ Add an active object to the environment.
+ Environment handles deletion of object.
+ Object may be deleted by environment immediately.
+ If id of object is 0, assigns a free id to it.
+ Returns the id of the object.
+ Returns 0 if not added and thus deleted.
+ */
+ 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.
+ (note: not used, pending removal from engine)
+ */
+ //bool addActiveObjectAsStatic(ServerActiveObject *object);
+
+ /*
+ Find out what new objects have been added to
+ inside a radius around a position
+ */
+ void getAddedActiveObjects(PlayerSAO *playersao, s16 radius,
+ s16 player_radius,
+ std::set<u16> &current_objects,
+ std::queue<u16> &added_objects);
+
+ /*
+ Find out what new objects have been removed from
+ inside a radius around a position
+ */
+ void getRemovedActiveObjects(PlayerSAO *playersao, s16 radius,
+ s16 player_radius,
+ std::set<u16> &current_objects,
+ std::queue<u16> &removed_objects);
+
+ /*
+ Get the next message emitted by some active object.
+ Returns a message with id=0 if no messages are available.
+ */
+ ActiveObjectMessage getActiveObjectMessage();
+
+ /*
+ Activate objects and dynamically modify for the dtime determined
+ from timestamp and additional_dtime
+ */
+ void activateBlock(MapBlock *block, u32 additional_dtime=0);
+
+ /*
+ {Active,Loading}BlockModifiers
+ -------------------------------------------
+ */
+
+ void addActiveBlockModifier(ActiveBlockModifier *abm);
+ void addLoadingBlockModifierDef(LoadingBlockModifierDef *lbm);
+
+ /*
+ Other stuff
+ -------------------------------------------
+ */
+
+ // Script-aware node setters
+ bool setNode(v3s16 p, const MapNode &n);
+ bool removeNode(v3s16 p);
+ bool swapNode(v3s16 p, const MapNode &n);
+
+ // Find all active objects inside a radius around a point
+ void getObjectsInsideRadius(std::vector<u16> &objects, v3f pos, float radius);
+
+ // Clear objects, loading and going through every MapBlock
+ void clearObjects(ClearObjectsMode mode);
+
+ // This makes stuff happen
+ void step(f32 dtime);
+
+ //check if there's a line of sight between two positions
+ bool line_of_sight(v3f pos1, v3f pos2, float stepsize=1.0, v3s16 *p=NULL);
+
+ u32 getGameTime() const { return m_game_time; }
+
+ void reportMaxLagEstimate(float f) { m_max_lag_estimate = f; }
+ float getMaxLagEstimate() { return m_max_lag_estimate; }
+
+ std::set<v3s16>* getForceloadedBlocks() { return &m_active_blocks.m_forceloaded_list; };
+
+ // Sets the static object status all the active objects in the specified block
+ // This is only really needed for deleting blocks from the map
+ void setStaticForActiveObjectsInBlock(v3s16 blockpos,
+ bool static_exists, v3s16 static_block=v3s16(0,0,0));
+
+ RemotePlayer *getPlayer(const u16 peer_id);
+ RemotePlayer *getPlayer(const char* name);
+
+ static bool migratePlayersDatabase(const GameParams &game_params,
+ const Settings &cmd_args);
+private:
+
+ static PlayerDatabase *openPlayerDatabase(const std::string &name,
+ const std::string &savedir, const Settings &conf);
+ /*
+ Internal ActiveObject interface
+ -------------------------------------------
+ */
+
+ /*
+ Add an active object to the environment.
+
+ Called by addActiveObject.
+
+ Object may be deleted by environment immediately.
+ If id of object is 0, assigns a free id to it.
+ Returns the id of the object.
+ Returns 0 if not added and thus deleted.
+ */
+ u16 addActiveObjectRaw(ServerActiveObject *object, bool set_changed, u32 dtime_s);
+
+ /*
+ Remove all objects that satisfy (m_removed && m_known_by_count==0)
+ */
+ void removeRemovedObjects();
+
+ /*
+ Convert stored objects from block to active
+ */
+ void activateObjects(MapBlock *block, u32 dtime_s);
+
+ /*
+ Convert objects that are not in active blocks to static.
+
+ If m_known_by_count != 0, active object is not deleted, but static
+ data is still updated.
+
+ If force_delete is set, active object is deleted nevertheless. It
+ shall only be set so in the destructor of the environment.
+ */
+ void deactivateFarObjects(bool force_delete);
+
+ /*
+ Member variables
+ */
+
+ // The map
+ ServerMap *m_map;
+ // Lua state
+ ServerScripting* m_script;
+ // Server definition
+ Server *m_server;
+ // World path
+ const std::string m_path_world;
+ // Active object list
+ ActiveObjectMap m_active_objects;
+ // Outgoing network message buffer for active objects
+ std::queue<ActiveObjectMessage> m_active_object_messages;
+ // Some timers
+ float m_send_recommended_timer;
+ IntervalLimiter m_object_management_interval;
+ // List of active blocks
+ ActiveBlockList m_active_blocks;
+ IntervalLimiter m_active_blocks_management_interval;
+ IntervalLimiter m_active_block_modifier_interval;
+ IntervalLimiter m_active_blocks_nodemetadata_interval;
+ int m_active_block_interval_overload_skip;
+ // Time from the beginning of the game in seconds.
+ // Incremented in step().
+ u32 m_game_time;
+ // A helper variable for incrementing the latter
+ float m_game_time_fraction_counter;
+ // Time of last clearObjects call (game time).
+ // When a mapblock older than this is loaded, its objects are cleared.
+ u32 m_last_clear_objects_time;
+ // Active block modifiers
+ std::vector<ABMWithState> m_abms;
+ LBMManager m_lbm_mgr;
+ // An interval for generally sending object positions and stuff
+ float m_recommended_send_interval;
+ // Estimate for general maximum lag as determined by server.
+ // Can raise to high values like 15s with eg. map generation mods.
+ float m_max_lag_estimate;
+
+ // peer_ids in here should be unique, except that there may be many 0s
+ std::vector<RemotePlayer*> m_players;
+
+ PlayerDatabase *m_player_database;
+
+ // Particles
+ IntervalLimiter m_particle_management_interval;
+ UNORDERED_MAP<u32, float> m_particle_spawners;
+ UNORDERED_MAP<u32, u16> m_particle_spawner_attachments;
+};
+
+#endif
diff --git a/src/serverlist.cpp b/src/serverlist.cpp
index 87ca5dc04..cc38ec8ce 100644
--- a/src/serverlist.cpp
+++ b/src/serverlist.cpp
@@ -196,7 +196,7 @@ const std::string serializeJson(const std::vector<ServerListSpec> &serverlist)
#if USE_CURL
-void sendAnnounce(const std::string &action,
+void sendAnnounce(AnnounceAction action,
const u16 port,
const std::vector<std::string> &clients_names,
const double uptime,
@@ -204,15 +204,17 @@ void sendAnnounce(const std::string &action,
const float lag,
const std::string &gameid,
const std::string &mg_name,
- const std::vector<ModSpec> &mods)
+ const std::vector<ModSpec> &mods,
+ bool dedicated)
{
+ static const char *aa_names[] = {"start", "update", "delete"};
Json::Value server;
- server["action"] = action;
+ server["action"] = aa_names[action];
server["port"] = port;
if (g_settings->exists("server_address")) {
server["address"] = g_settings->get("server_address");
}
- if (action != "delete") {
+ if (action != AA_DELETE) {
bool strict_checking = g_settings->getBool("strict_protocol_version_checking");
server["name"] = g_settings->get("server_name");
server["description"] = g_settings->get("server_description");
@@ -237,20 +239,19 @@ void sendAnnounce(const std::string &action,
if (gameid != "") server["gameid"] = gameid;
}
- if (action == "start") {
- server["dedicated"] = g_settings->getBool("server_dedicated");
+ if (action == AA_START) {
+ server["dedicated"] = dedicated;
server["rollback"] = g_settings->getBool("enable_rollback_recording");
server["mapgen"] = mg_name;
server["privs"] = g_settings->get("default_privs");
server["can_see_far_names"] = g_settings->getS16("player_transfer_distance") <= 0;
server["mods"] = Json::Value(Json::arrayValue);
for (std::vector<ModSpec>::const_iterator it = mods.begin();
- it != mods.end();
- ++it) {
+ it != mods.end(); ++it) {
server["mods"].append(it->name);
}
actionstream << "Announcing to " << g_settings->get("serverlist_url") << std::endl;
- } else {
+ } else if (action == AA_UPDATE) {
if (lag)
server["lag"] = lag;
}
@@ -264,4 +265,5 @@ void sendAnnounce(const std::string &action,
}
#endif
-} //namespace ServerList
+} // namespace ServerList
+
diff --git a/src/serverlist.h b/src/serverlist.h
index 0747c3920..079026199 100644
--- a/src/serverlist.h
+++ b/src/serverlist.h
@@ -29,22 +29,27 @@ typedef Json::Value ServerListSpec;
namespace ServerList
{
- std::vector<ServerListSpec> getLocal();
- std::vector<ServerListSpec> getOnline();
- bool deleteEntry(const ServerListSpec &server);
- bool insert(const ServerListSpec &server);
- std::vector<ServerListSpec> deSerialize(const std::string &liststring);
- const std::string serialize(const std::vector<ServerListSpec> &serverlist);
- std::vector<ServerListSpec> deSerializeJson(const std::string &liststring);
- const std::string serializeJson(const std::vector<ServerListSpec> &serverlist);
- #if USE_CURL
- void sendAnnounce(const std::string &action, const u16 port,
- const std::vector<std::string> &clients_names = std::vector<std::string>(),
- const double uptime = 0, const u32 game_time = 0,
- const float lag = 0, const std::string &gameid = "",
- const std::string &mg_name = "",
- const std::vector<ModSpec> &mods = std::vector<ModSpec>());
- #endif
-} // ServerList namespace
+std::vector<ServerListSpec> getLocal();
+std::vector<ServerListSpec> getOnline();
+
+bool deleteEntry(const ServerListSpec &server);
+bool insert(const ServerListSpec &server);
+
+std::vector<ServerListSpec> deSerialize(const std::string &liststring);
+const std::string serialize(const std::vector<ServerListSpec> &serverlist);
+std::vector<ServerListSpec> deSerializeJson(const std::string &liststring);
+const std::string serializeJson(const std::vector<ServerListSpec> &serverlist);
+
+#if USE_CURL
+enum AnnounceAction {AA_START, AA_UPDATE, AA_DELETE};
+void sendAnnounce(AnnounceAction, u16 port,
+ const std::vector<std::string> &clients_names = std::vector<std::string>(),
+ double uptime = 0, u32 game_time = 0, float lag = 0,
+ const std::string &gameid = "", const std::string &mg_name = "",
+ const std::vector<ModSpec> &mods = std::vector<ModSpec>(),
+ bool dedicated = false);
+#endif
+
+} // namespace ServerList
#endif
diff --git a/src/serverobject.h b/src/serverobject.h
index 9884eb0a1..38204980e 100644
--- a/src/serverobject.h
+++ b/src/serverobject.h
@@ -119,10 +119,10 @@ public:
when it is created (converted from static to active - actually
the data is the static form)
*/
- virtual std::string getStaticData()
+ virtual void getStaticData(std::string *result) const
{
assert(isStaticAllowed());
- return "";
+ *result = "";
}
/*
Return false in here to never save and instead remove object
@@ -146,8 +146,8 @@ public:
virtual void setArmorGroups(const ItemGroupList &armor_groups)
{}
- virtual ItemGroupList getArmorGroups()
- { return ItemGroupList(); }
+ virtual const ItemGroupList &getArmorGroups()
+ { static const ItemGroupList rv; return rv; }
virtual void setPhysicsOverride(float physics_override_speed, float physics_override_jump, float physics_override_gravity)
{}
virtual void setAnimation(v2f frames, float frame_speed, float frame_blend, bool frame_loop)
@@ -166,8 +166,8 @@ public:
{}
virtual void removeAttachmentChild(int child_id)
{}
- virtual UNORDERED_SET<int> getAttachmentChildIds()
- { return UNORDERED_SET<int>(); }
+ virtual const UNORDERED_SET<int> &getAttachmentChildIds()
+ { static const UNORDERED_SET<int> rv; return rv; }
virtual ObjectProperties* accessObjectProperties()
{ return NULL; }
virtual void notifyObjectPropertiesModified()
diff --git a/src/settings.cpp b/src/settings.cpp
index c4c3c9073..b4083264e 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -90,33 +90,6 @@ bool Settings::checkValueValid(const std::string &value)
return true;
}
-
-std::string Settings::sanitizeName(const std::string &name)
-{
- std::string n = trim(name);
-
- for (const char *s = "=\"{}#"; *s; s++)
- n.erase(std::remove(n.begin(), n.end(), *s), n.end());
-
- return n;
-}
-
-
-std::string Settings::sanitizeValue(const std::string &value)
-{
- std::string v(value);
- size_t p = 0;
-
- if (v.substr(0, 3) == "\"\"\"")
- v.erase(0, 3);
-
- while ((p = v.find("\n\"\"\"")) != std::string::npos)
- v.erase(p, 4);
-
- return v;
-}
-
-
std::string Settings::getMultiline(std::istream &is, size_t *num_lines)
{
size_t lines = 1;
@@ -398,7 +371,7 @@ Settings *Settings::getGroup(const std::string &name) const
}
-std::string Settings::get(const std::string &name) const
+const std::string &Settings::get(const std::string &name) const
{
const SettingsEntry &entry = getEntry(name);
if (entry.is_group)
diff --git a/src/settings.h b/src/settings.h
index b19733514..8c4f6e559 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -74,24 +74,21 @@ struct ValueSpec {
};
struct SettingsEntry {
- SettingsEntry()
- {
- group = NULL;
- is_group = false;
- }
-
- SettingsEntry(const std::string &value_)
- {
- value = value_;
- group = NULL;
- is_group = false;
- }
-
- SettingsEntry(Settings *group_)
- {
- group = group_;
- is_group = true;
- }
+ SettingsEntry() :
+ group(NULL),
+ is_group(false)
+ {}
+
+ SettingsEntry(const std::string &value_) :
+ value(value_),
+ group(NULL),
+ is_group(false)
+ {}
+
+ SettingsEntry(Settings *group_) :
+ group(group_),
+ is_group(true)
+ {}
std::string value;
Settings *group;
@@ -129,8 +126,6 @@ public:
static bool checkNameValid(const std::string &name);
static bool checkValueValid(const std::string &value);
- static std::string sanitizeName(const std::string &name);
- static std::string sanitizeValue(const std::string &value);
static std::string getMultiline(std::istream &is, size_t *num_lines=NULL);
static void printEntry(std::ostream &os, const std::string &name,
const SettingsEntry &entry, u32 tab_depth=0);
@@ -141,7 +136,7 @@ public:
const SettingsEntry &getEntry(const std::string &name) const;
Settings *getGroup(const std::string &name) const;
- std::string get(const std::string &name) const;
+ const std::string &get(const std::string &name) const;
bool getBool(const std::string &name) const;
u16 getU16(const std::string &name) const;
s16 getS16(const std::string &name) const;
diff --git a/src/settings_translation_file.cpp b/src/settings_translation_file.cpp
index 39223d9ce..383da33a7 100644
--- a/src/settings_translation_file.cpp
+++ b/src/settings_translation_file.cpp
@@ -37,6 +37,10 @@ fake_function() {
gettext("Continuous forward movement (only used for testing).");
gettext("Enable Joysticks");
gettext("Enable Joysticks");
+ gettext("Joystick ID");
+ gettext("The identifier of the joystick to use");
+ gettext("Joystick Type");
+ gettext("The type of joystick");
gettext("Joystick button repetition interval");
gettext("The time in seconds it takes between repeated events\nwhen holding down a joystick button combination.");
gettext("Joystick frustum sensitivity");
@@ -61,6 +65,8 @@ fake_function() {
gettext("Key for opening the chat window.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
gettext("Command key");
gettext("Key for opening the chat window to type commands.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
+ gettext("Command key");
+ gettext("Key for opening the chat window to type local commands.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
gettext("Console key");
gettext("Key for opening the chat console.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
gettext("Range select key");
@@ -71,6 +77,16 @@ fake_function() {
gettext("Key for toggling fast mode.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
gettext("Noclip key");
gettext("Key for toggling noclip mode.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
+ gettext("Hotbar next key");
+ gettext("Key for selecting the next item in the hotbar.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
+ gettext("Hotbar previous key");
+ gettext("Key for selecting the previous item in the hotbar.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
+ gettext("Mute key");
+ gettext("Key for muting the game.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
+ gettext("Inc. volume key");
+ gettext("Key for increasing the volume.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
+ gettext("Dec. volume key");
+ gettext("Key for decreasing the volume.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
gettext("Autorun key");
gettext("Key for toggling autorun.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
gettext("Cinematic mode key");
@@ -81,10 +97,14 @@ fake_function() {
gettext("Key for taking screenshots.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
gettext("Drop item key");
gettext("Key for dropping the currently selected item.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
+ gettext("View zoom key");
+ gettext("Key to use view zoom when possible.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
gettext("HUD toggle key");
gettext("Key for toggling the display of the HUD.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
gettext("Chat toggle key");
gettext("Key for toggling the display of the chat.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
+ gettext("Large chat console key");
+ gettext("Key for toggling the display of the large chat console.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
gettext("Fog toggle key");
gettext("Key for toggling the display of the fog.\nSee http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3");
gettext("Camera update toggle key");
@@ -114,6 +134,8 @@ fake_function() {
gettext("Show entity selection boxes");
gettext("Connect to external media server");
gettext("Enable usage of remote media server (if provided by server).\nRemote servers offer a significantly faster way to download media (e.g. textures)\nwhen connecting to the server.");
+ gettext("Client modding");
+ gettext("Enable Lua modding support on client.\nThis support is experimental and API can change.");
gettext("Serverlist URL");
gettext("URL to the server list displayed in the Multiplayer Tab.");
gettext("Serverlist file");
@@ -137,6 +159,8 @@ fake_function() {
gettext("Use 3D cloud look instead of flat.");
gettext("Node highlighting");
gettext("Method used to highlight selected object.");
+ gettext("Digging particles");
+ gettext("Adds particles when digging a node.");
gettext("Filtering");
gettext("Mipmapping");
gettext("Use mip mapping to scale textures. May slightly increase performance.");
@@ -152,9 +176,13 @@ fake_function() {
gettext("When using bilinear/trilinear/anisotropic filters, low-resolution textures\ncan be blurred, so automatically upscale them with nearest-neighbor\ninterpolation to preserve crisp pixels. This sets the minimum texture size\nfor the upscaled textures; higher values look sharper, but require more\nmemory. Powers of 2 are recommended. Setting this higher than 1 may not\nhave a visible effect unless bilinear/trilinear/anisotropic filtering is\nenabled.");
gettext("FSAA");
gettext("Experimental option, might cause visible spaces between blocks\nwhen set to higher number than 0.");
+ gettext("Undersampling");
+ gettext("Undersampling is similar to using lower screen resolution, but it applies\nto the game world only, keeping the GUI intact.\nIt should give significant performance boost at the cost of less detailed image.");
gettext("Shaders");
gettext("Shaders");
- gettext("Shaders allow advanced visual effects and may increase performance on some video cards.\nThy only work with the OpenGL video backend.");
+ gettext("Shaders allow advanced visual effects and may increase performance on some video cards.\nThis only works with the OpenGL video backend.");
+ gettext("Shader path");
+ gettext("Path to shader directory. If no path is defined, default location will be used.");
gettext("Tone Mapping");
gettext("Filmic tone mapping");
gettext("Enables filmic tone mapping");
@@ -212,7 +240,7 @@ fake_function() {
gettext("Field of view for zoom");
gettext("Field of view while zooming in degrees.\nThis requires the \"zoom\" privilege on the server.");
gettext("Gamma");
- gettext("Adjust the gamma encoding for the light tables. Lower numbers are brighter.\nThis setting is for the client only and is ignored by the server.");
+ gettext("Adjust the gamma encoding for the light tables. Higher numbers are brighter.\nThis setting is for the client only and is ignored by the server.");
gettext("Texture path");
gettext("Path to texture directory. All textures are first searched from here.");
gettext("Video driver");
@@ -221,12 +249,16 @@ fake_function() {
gettext("Height on which clouds are appearing.");
gettext("Cloud radius");
gettext("Radius of cloud area stated in number of 64 node cloud squares.\nValues larger than 26 will start to produce sharp cutoffs at cloud area corners.");
- gettext("View bobbing");
- gettext("Multiplier for view bobbing.\nFor example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.");
- gettext("Fall bobbing");
+ gettext("Enable view bobbing");
+ gettext("Enables view bobbing when walking.");
+ gettext("View bobbing factor");
+ gettext("Enable view bobbing and amount of view bobbing.\nFor example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.");
+ gettext("Fall bobbing factor");
gettext("Multiplier for fall bobbing.\nFor example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.");
gettext("3D mode");
gettext("3D support.\nCurrently supported:\n- none: no 3d output.\n- anaglyph: cyan/magenta color 3d.\n- interlaced: odd/even line based polarisation screen support.\n- topbottom: split screen top/bottom.\n- sidebyside: split screen side by side.\n- pageflip: quadbuffer based 3d.");
+ gettext("Console height");
+ gettext("In-game chat console height, between 0.1 (10%) and 1.0 (100%).");
gettext("Console color");
gettext("In-game chat console background color (R,G,B).");
gettext("Console alpha");
@@ -243,8 +275,14 @@ fake_function() {
gettext("Whether node texture animations should be desynchronized per mapblock.");
gettext("Maximum hotbar width");
gettext("Maximum proportion of current window to be used for hotbar.\nUseful if there's something to be displayed right or left of hotbar.");
+ gettext("HUD scale factor");
+ gettext("Modifies the size of the hudbar elements.");
gettext("Mesh cache");
gettext("Enables caching of facedir rotated meshes.");
+ gettext("Mapblock mesh generation delay");
+ gettext("Delay between mesh updates on the client in ms. Increasing this will slow\ndown the rate of mesh updates, thus reducing jitter on slower clients.");
+ gettext("Mapblock mesh generator's MapBlock cache size MB");
+ gettext("Size of the MapBlock cache of the mesh generator. Increasing this will\nincrease the cache hit %, reducing the data being copied from the main\nthread, thus reducing jitter.");
gettext("Minimap");
gettext("Enables minimap.");
gettext("Round minimap");
@@ -257,8 +295,12 @@ fake_function() {
gettext("The strength (darkness) of node ambient-occlusion shading.\nLower is darker, Higher is lighter. The valid range of values for this\nsetting is 0.25 to 4.0 inclusive. If the value is out of range it will be\nset to the nearest valid value.");
gettext("Inventory items animations");
gettext("Enables animation of inventory items.");
+ gettext("Inventory image hack");
+ gettext("Android systems only: Tries to create inventory textures from meshes\nwhen no supported render was found.");
gettext("Fog Start");
gettext("Fraction of the visible distance at which fog starts to be rendered");
+ gettext("Opaque liquids");
+ gettext("Makes all liquids opaque");
gettext("Menus");
gettext("Clouds in menu");
gettext("Use a cloud animation for the main menu background.");
@@ -295,6 +337,8 @@ fake_function() {
gettext("Advanced");
gettext("DPI");
gettext("Adjust dpi configuration to your screen (non X11/Android only) e.g. for 4k screens.");
+ gettext("Enable console window");
+ gettext("Windows systems only: Start Minetest with the command line window in the background.\nContains the same information as the file debug.txt (default name).");
gettext("Sound");
gettext("Sound");
gettext("Volume");
@@ -351,8 +395,12 @@ fake_function() {
gettext("World directory (everything in the world is stored here).\nNot needed if starting from the main menu.");
gettext("Item entity TTL");
gettext("Time in seconds for item entity (dropped items) to live.\nSetting it to -1 disables the feature.");
+ gettext("Status message on connection");
+ gettext("If enabled, show the server status message on player connection.");
gettext("Damage");
gettext("Enable players getting damage and dying.");
+ gettext("Creative");
+ gettext("Enable creative mode for new created maps.");
gettext("Fixed map seed");
gettext("A chosen map seed for a new map, leave empty for random.\nWill be overridden when creating a new world in the main menu.");
gettext("Default password");
@@ -438,6 +486,8 @@ fake_function() {
gettext("Liquid update interval in seconds.");
gettext("block send optimize distance");
gettext("At this distance the server will aggressively optimize which blocks are sent to clients.\nSmall values potentially improve performance a lot, at the expense of visible rendering glitches.\n(some blocks will not be rendered under water and in caves, as well as sometimes on land)\nSetting this to a value greater than max_block_send_distance disables this optimization.\nStated in mapblocks (16 nodes)");
+ gettext("Server side occlusion culling");
+ gettext("If enabled the server will perform map block occlusion culling based on\non the eye position of the player. This can reduce the number of blocks\nsent to the client 50-80%. The client will not longer receive most invisible\nso that the utility of noclip mode is reduced.");
gettext("Mapgen");
gettext("Mapgen name");
gettext("Name of map generator to be used when creating a new world.\nCreating a world in the main menu will override this.");
@@ -446,7 +496,7 @@ fake_function() {
gettext("Max block generate distance");
gettext("From how far blocks are generated for clients, stated in mapblocks (16 nodes).");
gettext("Map generation limit");
- gettext("Where the map generator stops.\nPlease note:\n- Limited to 31000 (setting above has no effect)\n- The map generator works in groups of 80x80x80 nodes (5x5x5 MapBlocks).\n- Those groups have an offset of -32, -32 nodes from the origin.\n- Only groups which are within the map_generation_limit are generated");
+ gettext("Limit of map generation, in nodes, in all 6 directions from (0, 0, 0).\nOnly mapchunks completely within the mapgen limit are generated.\nValue is stored per-world.");
gettext("Mapgen flags");
gettext("Global map generation attributes.\nIn Mapgen v6 the 'decorations' flag controls all decorations except trees\nand junglegrass, in all other mapgens this flag controls all decorations.\nFlags that are not specified in the flag string are not modified from the default.\nFlags starting with 'no' are used to explicitly disable them.");
gettext("Advanced");
@@ -462,109 +512,168 @@ fake_function() {
gettext("Maximum number of blocks to be queued that are to be generated.\nSet to blank for an appropriate amount to be chosen automatically.");
gettext("Number of emerge threads");
gettext("Number of emerge threads to use. Make this field blank, or increase this number\nto use multiple threads. On multiprocessor systems, this will improve mapgen speed greatly\nat the cost of slightly buggy caves.");
- gettext("Mapgen biome heat noise parameters");
- gettext("Noise parameters for biome API temperature, humidity and biome blend.");
- gettext("Mapgen heat blend noise parameters");
- gettext("Mapgen biome humidity noise parameters");
- gettext("Mapgen biome humidity blend noise parameters");
+ gettext("Biome API temperature and humidity noise parameters");
+ gettext("Heat noise");
+ gettext("Temperature variation for biomes.");
+ gettext("Heat blend noise");
+ gettext("Small-scale temperature variation for blending biomes on borders.");
+ gettext("Humidity noise");
+ gettext("Humidity variation for biomes.");
+ gettext("Humidity blend noise");
+ gettext("Small-scale humidity variation for blending biomes on borders.");
gettext("Mapgen v5");
- gettext("Mapgen v5 cave width");
+ gettext("Mapgen v5 specific flags");
+ gettext("Map generation attributes specific to Mapgen v5.\nFlags that are not specified in the flag string are not modified from the default.\nFlags starting with 'no' are used to explicitly disable them.");
+ gettext("Cave width");
gettext("Controls width of tunnels, a smaller value creates wider tunnels.");
- gettext("Mapgen v5 filler depth noise parameters");
- gettext("Mapgen v5 factor noise parameters");
- gettext("Mapgen v5 height noise parameters");
- gettext("Mapgen v5 cave1 noise parameters");
- gettext("Mapgen v5 cave2 noise parameters");
+ gettext("Cavern limit");
+ gettext("Y-level of cavern upper limit.");
+ gettext("Cavern taper");
+ gettext("Y-distance over which caverns expand to full size.");
+ gettext("Cavern threshold");
+ gettext("Defines full size of caverns, smaller values create larger caverns.");
+ gettext("Filler depth noise");
+ gettext("Variation of biome filler depth.");
+ gettext("Factor noise");
+ gettext("Variation of terrain vertical scale.\nWhen noise is < -0.55 terrain is near-flat.");
+ gettext("Height noise");
+ gettext("Y-level of average terrain surface.");
+ gettext("Cave1 noise");
+ gettext("First of 2 3D noises that together define tunnels.");
+ gettext("Cave2 noise");
+ gettext("Second of 2 3D noises that together define tunnels.");
+ gettext("Cavern noise");
+ gettext("3D noise defining giant caverns.");
gettext("Mapgen v6");
- gettext("Mapgen v6 flags");
- gettext("Map generation attributes specific to Mapgen v6.\nWhen snowbiomes are enabled jungles are automatically enabled, the 'jungles' flag is ignored.\nFlags that are not specified in the flag string are not modified from the default.\nFlags starting with 'no' are used to explicitly disable them.");
- gettext("Mapgen v6 desert frequency");
- gettext("Controls size of deserts and beaches in Mapgen v6.\nWhen snowbiomes are enabled 'mgv6_freq_desert' is ignored.");
- gettext("Mapgen v6 beach frequency");
- gettext("Mapgen v6 terrain base noise parameters");
- gettext("Mapgen v6 terrain altitude noise parameters");
- gettext("Mapgen v6 steepness noise parameters");
- gettext("Mapgen v6 height select noise parameters");
- gettext("Mapgen v6 mud noise parameters");
- gettext("Mapgen v6 beach noise parameters");
- gettext("Mapgen v6 biome noise parameters");
- gettext("Mapgen v6 cave noise parameters");
- gettext("Mapgen v6 humidity noise parameters");
- gettext("Mapgen v6 trees noise parameters");
- gettext("Mapgen v6 apple trees noise parameters");
+ gettext("Mapgen v6 specific flags");
+ gettext("Map generation attributes specific to Mapgen v6.\nThe 'snowbiomes' flag enables the new 5 biome system.\nWhen the new biome system is enabled jungles are automatically enabled and\nthe 'jungles' flag is ignored.\nFlags that are not specified in the flag string are not modified from the default.\nFlags starting with 'no' are used to explicitly disable them.");
+ gettext("Desert noise threshold");
+ gettext("Deserts occur when np_biome exceeds this value.\nWhen the new biome system is enabled, this is ignored.");
+ gettext("Beach noise threshold");
+ gettext("Sandy beaches occur when np_beach exceeds this value.");
+ gettext("Terrain base noise");
+ gettext("Y-level of lower terrain and lakebeds.");
+ gettext("Terrain higher noise");
+ gettext("Y-level of higher (cliff-top) terrain.");
+ gettext("Steepness noise");
+ gettext("Varies steepness of cliffs.");
+ gettext("Height select noise");
+ gettext("Defines areas of 'terrain_higher' (cliff-top terrain).");
+ gettext("Mud noise");
+ gettext("Varies depth of biome surface nodes.");
+ gettext("Beach noise");
+ gettext("Defines areas with sandy beaches.");
+ gettext("Biome noise");
+ gettext("Temperature variation for biomes.");
+ gettext("Cave noise");
+ gettext("Variation of number of caves.");
+ gettext("Humidity noise");
+ gettext("Humidity variation for biomes.");
+ gettext("Trees noise");
+ gettext("Defines tree areas and tree density.");
+ gettext("Apple trees noise");
+ gettext("Defines areas where trees have apples.");
gettext("Mapgen v7");
- gettext("Mapgen v7 flags");
+ gettext("Mapgen v7 specific flags");
gettext("Map generation attributes specific to Mapgen v7.\nThe 'ridges' flag enables the rivers.\nFloatlands are currently experimental and subject to change.\nFlags that are not specified in the flag string are not modified from the default.\nFlags starting with 'no' are used to explicitly disable them.");
- gettext("Mapgen v7 cave width");
+ gettext("Cave width");
gettext("Controls width of tunnels, a smaller value creates wider tunnels.");
- gettext("Mapgen v7 floatland mountain density");
+ gettext("Floatland mountain density");
gettext("Controls the density of floatland mountain terrain.\nIs an offset added to the 'np_mountain' noise value.");
- gettext("Mapgen v7 floatland mountain height");
+ gettext("Floatland mountain height");
gettext("Typical maximum height, above and below midpoint, of floatland mountain terrain.");
- gettext("Mapgen v7 floatland level");
+ gettext("Floatland level");
gettext("Y-level of floatland midpoint and lake surface.");
- gettext("Mapgen v7 shadow limit");
+ gettext("Shadow limit");
gettext("Y-level to which floatland shadows extend.");
- gettext("Mapgen v7 terrain base noise parameters");
- gettext("Mapgen v7 terrain altitude noise parameters");
- gettext("Mapgen v7 terrain persistation noise parameters");
- gettext("Mapgen v7 height select noise parameters");
- gettext("Mapgen v7 filler depth noise parameters");
- gettext("Mapgen v7 mount height noise parameters");
- gettext("Mapgen v7 river course noise parameters");
- gettext("Mapgen v7 floatland base terrain noise parameters");
- gettext("Mapgen v7 floatland base terrain height noise parameters");
- gettext("Mapgen v7 mountain noise parameters");
- gettext("Mapgen v7 river channel wall noise parameters");
- gettext("Mapgen v7 cave1 noise parameters");
- gettext("Mapgen v7 cave2 noise parameters");
+ gettext("Cavern limit");
+ gettext("Y-level of cavern upper limit.");
+ gettext("Cavern taper");
+ gettext("Y-distance over which caverns expand to full size.");
+ gettext("Cavern threshold");
+ gettext("Defines full size of caverns, smaller values create larger caverns.");
+ gettext("Terrain base noise");
+ gettext("Y-level of higher (cliff-top) terrain.");
+ gettext("Terrain alt noise");
+ gettext("Y-level of lower terrain and lakebeds.");
+ gettext("Terrain persistence noise");
+ gettext("Varies roughness of terrain.\nDefines the 'persistence' value for terrain_base and terrain_alt noises.");
+ gettext("Height select noise");
+ gettext("Defines areas of higher (cliff-top) terrain and affects steepness of cliffs.");
+ gettext("Filler depth noise");
+ gettext("Variation of biome filler depth.");
+ gettext("Mountain height noise");
+ gettext("Variation of maximum mountain height (in nodes).");
+ gettext("Ridge underwater noise");
+ gettext("Defines large-scale river channel structure.");
+ gettext("Floatland base noise");
+ gettext("Defines areas of floatland smooth terrain.\nSmooth floatlands occur when noise > 0.");
+ gettext("Floatland base height noise");
+ gettext("Variation of hill height and lake depth on floatland smooth terrain.");
+ gettext("Mountain noise");
+ gettext("3D noise defining mountain structure and height.\nAlso defines structure of floatland mountain terrain.");
+ gettext("Ridge noise");
+ gettext("3D noise defining structure of river canyon walls.");
+ gettext("Cavern noise");
+ gettext("3D noise defining giant caverns.");
+ gettext("Cave1 noise");
+ gettext("First of 2 3D noises that together define tunnels.");
+ gettext("Cave2 noise");
+ gettext("Second of 2 3D noises that together define tunnels.");
gettext("Mapgen flat");
- gettext("Mapgen flat flags");
+ gettext("Mapgen flat specific flags");
gettext("Map generation attributes specific to Mapgen flat.\nOccasional lakes and hills can be added to the flat world.\nFlags that are not specified in the flag string are not modified from the default.\nFlags starting with 'no' are used to explicitly disable them.");
- gettext("Mapgen flat ground level");
+ gettext("Ground level");
gettext("Y of flat ground.");
- gettext("Mapgen flat large cave depth");
+ gettext("Large cave depth");
gettext("Y of upper limit of large pseudorandom caves.");
- gettext("Mapgen flat cave width");
+ gettext("Cave width");
gettext("Controls width of tunnels, a smaller value creates wider tunnels.");
- gettext("Mapgen flat lake threshold");
+ gettext("Lake threshold");
gettext("Terrain noise threshold for lakes.\nControls proportion of world area covered by lakes.\nAdjust towards 0.0 for a larger proportion.");
- gettext("Mapgen flat lake steepness");
+ gettext("Lake steepness");
gettext("Controls steepness/depth of lake depressions.");
- gettext("Mapgen flat hill threshold");
+ gettext("Hill threshold");
gettext("Terrain noise threshold for hills.\nControls proportion of world area covered by hills.\nAdjust towards 0.0 for a larger proportion.");
- gettext("Mapgen flat hill steepness");
+ gettext("Hill steepness");
gettext("Controls steepness/height of hills.");
- gettext("Mapgen flat terrain noise parameters");
- gettext("Determines terrain shape.\nThe 3 numbers in brackets control the scale of the\nterrain, the 3 numbers should be identical.");
- gettext("Mapgen flat filler depth noise parameters");
- gettext("Mapgen flat cave1 noise parameters");
- gettext("Mapgen flat cave2 noise parameters");
+ gettext("Terrain noise");
+ gettext("Defines location and terrain of optional hills and lakes.");
+ gettext("Filler depth noise");
+ gettext("Variation of biome filler depth.");
+ gettext("Cave1 noise");
+ gettext("First of 2 3D noises that together define tunnels.");
+ gettext("Cave2 noise");
+ gettext("Second of 2 3D noises that together define tunnels.");
gettext("Mapgen fractal");
- gettext("Mapgen fractal cave width");
+ gettext("Cave width");
gettext("Controls width of tunnels, a smaller value creates wider tunnels.");
- gettext("Mapgen fractal fractal");
+ gettext("Fractal type");
gettext("Choice of 18 fractals from 9 formulas.\n1 = 4D \"Roundy\" mandelbrot set.\n2 = 4D \"Roundy\" julia set.\n3 = 4D \"Squarry\" mandelbrot set.\n4 = 4D \"Squarry\" julia set.\n5 = 4D \"Mandy Cousin\" mandelbrot set.\n6 = 4D \"Mandy Cousin\" julia set.\n7 = 4D \"Variation\" mandelbrot set.\n8 = 4D \"Variation\" julia set.\n9 = 3D \"Mandelbrot/Mandelbar\" mandelbrot set.\n10 = 3D \"Mandelbrot/Mandelbar\" julia set.\n11 = 3D \"Christmas Tree\" mandelbrot set.\n12 = 3D \"Christmas Tree\" julia set.\n13 = 3D \"Mandelbulb\" mandelbrot set.\n14 = 3D \"Mandelbulb\" julia set.\n15 = 3D \"Cosine Mandelbulb\" mandelbrot set.\n16 = 3D \"Cosine Mandelbulb\" julia set.\n17 = 4D \"Mandelbulb\" mandelbrot set.\n18 = 4D \"Mandelbulb\" julia set.");
- gettext("Mapgen fractal iterations");
+ gettext("Iterations");
gettext("Iterations of the recursive function.\nControls the amount of fine detail.");
- gettext("Mapgen fractal scale");
+ gettext("Scale");
gettext("Approximate (X,Y,Z) scale of fractal in nodes.");
- gettext("Mapgen fractal offset");
+ gettext("Offset");
gettext("(X,Y,Z) offset of fractal from world centre in units of 'scale'.\nUsed to move a suitable spawn area of low land close to (0, 0).\nThe default is suitable for mandelbrot sets, it needs to be edited for julia sets.\nRange roughly -2 to 2. Multiply by 'scale' for offset in nodes.");
- gettext("Mapgen fractal slice w");
+ gettext("Slice w");
gettext("W co-ordinate of the generated 3D slice of a 4D fractal.\nDetermines which 3D slice of the 4D shape is generated.\nHas no effect on 3D fractals.\nRange roughly -2 to 2.");
- gettext("Mapgen fractal julia x");
+ gettext("Julia x");
gettext("Julia set only: X component of hypercomplex constant determining julia shape.\nRange roughly -2 to 2.");
- gettext("Mapgen fractal julia y");
+ gettext("Julia y");
gettext("Julia set only: Y component of hypercomplex constant determining julia shape.\nRange roughly -2 to 2.");
- gettext("Mapgen fractal julia z");
+ gettext("Julia z");
gettext("Julia set only: Z component of hypercomplex constant determining julia shape.\nRange roughly -2 to 2.");
- gettext("Mapgen fractal julia w");
+ gettext("Julia w");
gettext("Julia set only: W component of hypercomplex constant determining julia shape.\nHas no effect on 3D fractals.\nRange roughly -2 to 2.");
- gettext("Mapgen fractal seabed noise parameters");
- gettext("Mapgen fractal filler depth noise parameters");
- gettext("Mapgen fractal cave1 noise parameters");
- gettext("Mapgen fractal cave2 noise parameters");
+ gettext("Seabed noise");
+ gettext("Y-level of seabed.");
+ gettext("Filler depth noise");
+ gettext("Variation of biome filler depth.");
+ gettext("Cave1 noise");
+ gettext("First of 2 3D noises that together define tunnels.");
+ gettext("Cave2 noise");
+ gettext("Second of 2 3D noises that together define tunnels.");
gettext("Mapgen Valleys");
gettext("General");
gettext("Valleys C Flags");
@@ -620,7 +729,7 @@ fake_function() {
gettext("Default report format");
gettext("The default format in which profiles are being saved,\nwhen calling `/profiler save [format]` without format.");
gettext("Report path");
- gettext("The file path relative to your worldpath in which profiles will be saved to.\n");
+ gettext("The file path relative to your worldpath in which profiles will be saved to.");
gettext("Instrumentation");
gettext("Entity methods");
gettext("Instrument the methods of entities on registration.");
diff --git a/src/shader.cpp b/src/shader.cpp
index c0ecf738d..66f32c9a1 100644
--- a/src/shader.cpp
+++ b/src/shader.cpp
@@ -340,7 +340,7 @@ IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
/*
Generate shader given the shader name.
*/
-ShaderInfo generate_shader(std::string name,
+ShaderInfo generate_shader(const std::string &name,
u8 material_type, u8 drawtype,
IrrlichtDevice *device, std::vector<ShaderCallback *> &callbacks,
const std::vector<IShaderConstantSetterFactory*> &setter_factories,
@@ -525,7 +525,7 @@ void ShaderSource::rebuildShaders()
}
-ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
+ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
IrrlichtDevice *device, std::vector<ShaderCallback *> &callbacks,
const std::vector<IShaderConstantSetterFactory*> &setter_factories,
SourceShaderCache *sourcecache)
@@ -543,7 +543,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
break;
case TILE_MATERIAL_LIQUID_TRANSPARENT:
- shaderinfo.base_material = video::EMT_TRANSPARENT_VERTEX_ALPHA;
+ shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
break;
case TILE_MATERIAL_LIQUID_OPAQUE:
shaderinfo.base_material = video::EMT_SOLID;
diff --git a/src/sky.cpp b/src/sky.cpp
index 211a2dcdc..b739fe1ad 100644
--- a/src/sky.cpp
+++ b/src/sky.cpp
@@ -85,6 +85,8 @@ Sky::Sky(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id,
}
m_directional_colored_fog = g_settings->getBool("directional_colored_fog");
+
+ m_clouds_enabled = true;
}
@@ -534,8 +536,10 @@ void Sky::update(float time_of_day, float time_brightness,
video::SColorf skycolor_bright_dawn_f = video::SColor(255, 180, 186, 250);
video::SColorf skycolor_bright_night_f = video::SColor(255, 0, 107, 255);
- video::SColorf cloudcolor_bright_normal_f = video::SColor(255, 240, 240, 255);
- video::SColorf cloudcolor_bright_dawn_f = video::SColor(255, 255, 223, 191);
+ // pure white: becomes "diffuse light component" for clouds
+ video::SColorf cloudcolor_bright_normal_f = video::SColor(255, 255, 255, 255);
+ // dawn-factoring version of pure white (note: R is above 1.0)
+ video::SColorf cloudcolor_bright_dawn_f(255.0f/240.0f, 223.0f/240.0f, 191.0f/255.0f);
float cloud_color_change_fraction = 0.95;
if (sunlight_seen) {
@@ -605,7 +609,7 @@ void Sky::update(float time_of_day, float time_brightness,
);
// Horizon coloring based on sun and moon direction during sunset and sunrise
- video::SColor pointcolor = video::SColor(255, 255, 255, m_bgcolor.getAlpha());
+ video::SColor pointcolor = video::SColor(m_bgcolor.getAlpha(), 255, 255, 255);
if (m_directional_colored_fog) {
if (m_horizon_blend() != 0) {
// Calculate hemisphere value from yaw, (inverted in third person front view)
diff --git a/src/sky.h b/src/sky.h
index f19891773..a014a920b 100644
--- a/src/sky.h
+++ b/src/sky.h
@@ -17,9 +17,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include "irrlichttypes_extrabloated.h"
#include <ISceneNode.h>
#include "camera.h"
+#include "irrlichttypes_extrabloated.h"
#ifndef SKY_HEADER
#define SKY_HEADER
@@ -34,7 +34,7 @@ class Sky : public scene::ISceneNode
{
public:
//! constructor
- Sky(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id,
+ Sky(scene::ISceneNode *parent, scene::ISceneManager *mgr, s32 id,
ITextureSource *tsrc);
virtual void OnRegisterSceneNode();
@@ -42,35 +42,37 @@ public:
//! renders the node.
virtual void render();
- virtual const aabb3f &getBoundingBox() const
- { return m_box; }
+ virtual const aabb3f &getBoundingBox() const { return m_box; }
// Used by Irrlicht for optimizing rendering
- virtual video::SMaterial& getMaterial(u32 i)
- { return m_materials[i]; }
+ virtual video::SMaterial &getMaterial(u32 i) { return m_materials[i]; }
// Used by Irrlicht for optimizing rendering
- virtual u32 getMaterialCount() const
- { return SKY_MATERIAL_COUNT; }
+ virtual u32 getMaterialCount() const { return SKY_MATERIAL_COUNT; }
+
+ void update(float m_time_of_day, float time_brightness, float direct_brightness,
+ bool sunlight_seen, CameraMode cam_mode, float yaw, float pitch);
- void update(float m_time_of_day, float time_brightness,
- float direct_brightness, bool sunlight_seen, CameraMode cam_mode,
- float yaw, float pitch);
-
- float getBrightness(){ return m_brightness; }
+ float getBrightness() { return m_brightness; }
- video::SColor getBgColor(){
+ const video::SColor &getBgColor() const
+ {
return m_visible ? m_bgcolor : m_fallback_bg_color;
}
- video::SColor getSkyColor(){
+
+ const video::SColor &getSkyColor() const
+ {
return m_visible ? m_skycolor : m_fallback_bg_color;
}
-
- bool getCloudsVisible(){ return m_clouds_visible && m_visible; }
- video::SColorf getCloudColor(){ return m_cloudcolor_f; }
- void setVisible(bool visible){ m_visible = visible; }
- void setFallbackBgColor(const video::SColor &fallback_bg_color){
+ bool getCloudsVisible() { return m_clouds_visible && m_clouds_enabled; }
+ const video::SColorf &getCloudColor() { return m_cloudcolor_f; }
+
+ void setVisible(bool visible) { m_visible = visible; }
+ // Set only from set_sky API
+ void setCloudsEnabled(bool clouds_enabled) { m_clouds_enabled = clouds_enabled; }
+ void setFallbackBgColor(const video::SColor &fallback_bg_color)
+ {
m_fallback_bg_color = fallback_bg_color;
}
@@ -83,7 +85,8 @@ private:
{
if (!m_sunlight_seen)
return 0;
- float x = m_time_of_day >= 0.5 ? (1 - m_time_of_day) * 2 : m_time_of_day * 2;
+ float x = m_time_of_day >= 0.5 ? (1 - m_time_of_day) * 2
+ : m_time_of_day * 2;
if (x <= 0.3)
return 0;
@@ -98,19 +101,19 @@ private:
video::SColor m_mix_scolor(video::SColor col1, video::SColor col2, f32 factor)
{
video::SColor result = video::SColor(
- col1.getAlpha() * (1 - factor) + col2.getAlpha() * factor,
- col1.getRed() * (1 - factor) + col2.getRed() * factor,
- col1.getGreen() * (1 - factor) + col2.getGreen() * factor,
- col1.getBlue() * (1 - factor) + col2.getBlue() * factor);
+ col1.getAlpha() * (1 - factor) + col2.getAlpha() * factor,
+ col1.getRed() * (1 - factor) + col2.getRed() * factor,
+ col1.getGreen() * (1 - factor) + col2.getGreen() * factor,
+ col1.getBlue() * (1 - factor) + col2.getBlue() * factor);
return result;
}
video::SColorf m_mix_scolorf(video::SColorf col1, video::SColorf col2, f32 factor)
{
- video::SColorf result = video::SColorf(
- col1.r * (1 - factor) + col2.r * factor,
- col1.g * (1 - factor) + col2.g * factor,
- col1.b * (1 - factor) + col2.b * factor,
- col1.a * (1 - factor) + col2.a * factor);
+ video::SColorf result =
+ video::SColorf(col1.r * (1 - factor) + col2.r * factor,
+ col1.g * (1 - factor) + col2.g * factor,
+ col1.b * (1 - factor) + col2.b * factor,
+ col1.a * (1 - factor) + col2.a * factor);
return result;
}
@@ -122,7 +125,8 @@ private:
bool m_sunlight_seen;
float m_brightness;
float m_cloud_brightness;
- bool m_clouds_visible;
+ bool m_clouds_visible; // Whether clouds are disabled due to player underground
+ bool m_clouds_enabled; // Initialised to true, reset only by set_sky API
bool m_directional_colored_fog;
video::SColorf m_bgcolor_bright_f;
video::SColorf m_skycolor_bright_f;
@@ -131,12 +135,11 @@ private:
video::SColor m_skycolor;
video::SColorf m_cloudcolor_f;
v3f m_stars[SKY_STAR_COUNT];
- video::S3DVertex m_star_vertices[SKY_STAR_COUNT*4];
- video::ITexture* m_sun_texture;
- video::ITexture* m_moon_texture;
- video::ITexture* m_sun_tonemap;
- video::ITexture* m_moon_tonemap;
+ video::S3DVertex m_star_vertices[SKY_STAR_COUNT * 4];
+ video::ITexture *m_sun_texture;
+ video::ITexture *m_moon_texture;
+ video::ITexture *m_sun_tonemap;
+ video::ITexture *m_moon_tonemap;
};
#endif
-
diff --git a/src/sound.h b/src/sound.h
index c21401e8b..76c0d1be4 100644
--- a/src/sound.h
+++ b/src/sound.h
@@ -20,9 +20,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef SOUND_HEADER
#define SOUND_HEADER
-#include "irrlichttypes_bloated.h"
-#include <string>
#include <set>
+#include <string>
+#include "irrlichttypes_bloated.h"
class OnDemandSoundFetcher
{
@@ -34,68 +34,88 @@ public:
struct SimpleSoundSpec
{
+ SimpleSoundSpec(const std::string &name = "", float gain = 1.0, float fade = 0.0)
+ : name(name), gain(gain), fade(fade)
+ {
+ }
+
+ bool exists() const { return name != ""; }
+
std::string name;
float gain;
- SimpleSoundSpec(std::string name="", float gain=1.0):
- name(name),
- gain(gain)
- {}
- bool exists() {return name != "";}
- // Serialization intentionally left out
+ float fade;
};
class ISoundManager
{
public:
- virtual ~ISoundManager(){}
-
+ virtual ~ISoundManager() {}
// Multiple sounds can be loaded per name; when played, the sound
// should be chosen randomly from alternatives
// Return value determines success/failure
- virtual bool loadSoundFile(const std::string &name,
- const std::string &filepath) = 0;
- virtual bool loadSoundData(const std::string &name,
- const std::string &filedata) = 0;
+ virtual bool loadSoundFile(
+ const std::string &name, const std::string &filepath) = 0;
+ virtual bool loadSoundData(
+ const std::string &name, const std::string &filedata) = 0;
virtual void updateListener(v3f pos, v3f vel, v3f at, v3f up) = 0;
virtual void setListenerGain(float gain) = 0;
// playSound functions return -1 on failure, otherwise a handle to the
// sound. If name=="", call should be ignored without error.
- virtual int playSound(const std::string &name, bool loop,
- float volume) = 0;
- virtual int playSoundAt(const std::string &name, bool loop,
- float volume, v3f pos) = 0;
+ virtual int playSound(const std::string &name, bool loop, float volume,
+ float fade = 0) = 0;
+ virtual int playSoundAt(
+ const std::string &name, bool loop, float volume, v3f pos) = 0;
virtual void stopSound(int sound) = 0;
virtual bool soundExists(int sound) = 0;
virtual void updateSoundPosition(int sound, v3f pos) = 0;
+ virtual bool updateSoundGain(int id, float gain) = 0;
+ virtual float getSoundGain(int id) = 0;
+ virtual void step(float dtime) = 0;
+ virtual void fadeSound(int sound, float step, float gain) = 0;
int playSound(const SimpleSoundSpec &spec, bool loop)
- { return playSound(spec.name, loop, spec.gain); }
+ {
+ return playSound(spec.name, loop, spec.gain, spec.fade);
+ }
int playSoundAt(const SimpleSoundSpec &spec, bool loop, v3f pos)
- { return playSoundAt(spec.name, loop, spec.gain, pos); }
+ {
+ return playSoundAt(spec.name, loop, spec.gain, pos);
+ }
};
-class DummySoundManager: public ISoundManager
+class DummySoundManager : public ISoundManager
{
public:
- virtual bool loadSoundFile(const std::string &name,
- const std::string &filepath) {return true;}
- virtual bool loadSoundData(const std::string &name,
- const std::string &filedata) {return true;}
+ virtual bool loadSoundFile(const std::string &name, const std::string &filepath)
+ {
+ return true;
+ }
+ virtual bool loadSoundData(const std::string &name, const std::string &filedata)
+ {
+ return true;
+ }
void updateListener(v3f pos, v3f vel, v3f at, v3f up) {}
void setListenerGain(float gain) {}
- int playSound(const std::string &name, bool loop,
- float volume) {return 0;}
- int playSoundAt(const std::string &name, bool loop,
- float volume, v3f pos) {return 0;}
+ int playSound(const std::string &name, bool loop, float volume, float fade)
+ {
+ return 0;
+ }
+ int playSoundAt(const std::string &name, bool loop, float volume, v3f pos)
+ {
+ return 0;
+ }
void stopSound(int sound) {}
- bool soundExists(int sound) {return false;}
+ bool soundExists(int sound) { return false; }
void updateSoundPosition(int sound, v3f pos) {}
+ bool updateSoundGain(int id, float gain) { return false; }
+ float getSoundGain(int id) { return 0; }
+ void step(float dtime) {}
+ void fadeSound(int sound, float step, float gain) {}
};
// Global DummySoundManager singleton
extern DummySoundManager dummySoundManager;
#endif
-
diff --git a/src/sound_openal.cpp b/src/sound_openal.cpp
index 317667f52..a425af827 100644
--- a/src/sound_openal.cpp
+++ b/src/sound_openal.cpp
@@ -274,6 +274,19 @@ private:
UNORDERED_MAP<std::string, std::vector<SoundBuffer*> > m_buffers;
UNORDERED_MAP<int, PlayingSound*> m_sounds_playing;
v3f m_listener_pos;
+ struct FadeState {
+ FadeState() {}
+ FadeState(float step, float current_gain, float target_gain):
+ step(step),
+ current_gain(current_gain),
+ target_gain(target_gain) {}
+ float step;
+ float current_gain;
+ float target_gain;
+ };
+
+ UNORDERED_MAP<int, FadeState> m_sounds_fading;
+ float m_fade_delay;
public:
bool m_is_initialized;
OpenALSoundManager(OnDemandSoundFetcher *fetcher):
@@ -281,6 +294,7 @@ public:
m_device(NULL),
m_context(NULL),
m_next_id(1),
+ m_fade_delay(0),
m_is_initialized(false)
{
ALCenum error = ALC_NO_ERROR;
@@ -317,7 +331,7 @@ public:
return;
}
- alDistanceModel(AL_EXPONENT_DISTANCE);
+ alDistanceModel(AL_INVERSE_DISTANCE);
infostream<<"Audio: Initialized: OpenAL "<<alGetString(AL_VERSION)
<<", using "<<alcGetString(m_device, ALC_DEVICE_SPECIFIER)
@@ -349,6 +363,11 @@ public:
infostream<<"Audio: Deinitialized."<<std::endl;
}
+ void step(float dtime)
+ {
+ doFades(dtime);
+ }
+
void addBuffer(const std::string &name, SoundBuffer *buf)
{
UNORDERED_MAP<std::string, std::vector<SoundBuffer*> >::iterator i =
@@ -409,7 +428,6 @@ public:
alSourcei(sound->source_id, AL_SOURCE_RELATIVE, false);
alSource3f(sound->source_id, AL_POSITION, pos.X, pos.Y, pos.Z);
alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
- //alSourcef(sound->source_id, AL_ROLLOFF_FACTOR, 0.7);
alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
alSourcei(sound->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
volume = MYMAX(0.0, volume);
@@ -516,6 +534,7 @@ public:
addBuffer(name, buf);
return false;
}
+
bool loadSoundData(const std::string &name,
const std::string &filedata)
{
@@ -542,7 +561,7 @@ public:
alListenerf(AL_GAIN, gain);
}
- int playSound(const std::string &name, bool loop, float volume)
+ int playSound(const std::string &name, bool loop, float volume, float fade)
{
maintain();
if(name == "")
@@ -553,8 +572,16 @@ public:
<<std::endl;
return -1;
}
- return playSoundRaw(buf, loop, volume);
+ int handle = -1;
+ if (fade > 0) {
+ handle = playSoundRaw(buf, loop, 0);
+ fadeSound(handle, fade, volume);
+ } else {
+ handle = playSoundRaw(buf, loop, volume);
+ }
+ return handle;
}
+
int playSoundAt(const std::string &name, bool loop, float volume, v3f pos)
{
maintain();
@@ -568,16 +595,55 @@ public:
}
return playSoundRawAt(buf, loop, volume, pos);
}
+
void stopSound(int sound)
{
maintain();
deleteSound(sound);
}
+
+ void fadeSound(int soundid, float step, float gain)
+ {
+ m_sounds_fading[soundid] = FadeState(step, getSoundGain(soundid), gain);
+ }
+
+ void doFades(float dtime)
+ {
+ m_fade_delay += dtime;
+
+ if (m_fade_delay < 0.1f)
+ return;
+
+ float chkGain = 0;
+ for (UNORDERED_MAP<int, FadeState>::iterator i = m_sounds_fading.begin();
+ i != m_sounds_fading.end();) {
+ if (i->second.step < 0.f)
+ chkGain = -(i->second.current_gain);
+ else
+ chkGain = i->second.current_gain;
+
+ if (chkGain < i->second.target_gain) {
+ i->second.current_gain += (i->second.step * m_fade_delay);
+ i->second.current_gain = rangelim(i->second.current_gain, 0, 1);
+
+ updateSoundGain(i->first, i->second.current_gain);
+ ++i;
+ } else {
+ if (i->second.target_gain <= 0.f)
+ stopSound(i->first);
+
+ m_sounds_fading.erase(i++);
+ }
+ }
+ m_fade_delay = 0;
+ }
+
bool soundExists(int sound)
{
maintain();
return (m_sounds_playing.count(sound) != 0);
}
+
void updateSoundPosition(int id, v3f pos)
{
UNORDERED_MAP<int, PlayingSound*>::iterator i = m_sounds_playing.find(id);
@@ -590,6 +656,29 @@ public:
alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
}
+
+ bool updateSoundGain(int id, float gain)
+ {
+ UNORDERED_MAP<int, PlayingSound*>::iterator i = m_sounds_playing.find(id);
+ if (i == m_sounds_playing.end())
+ return false;
+
+ PlayingSound *sound = i->second;
+ alSourcef(sound->source_id, AL_GAIN, gain);
+ return true;
+ }
+
+ float getSoundGain(int id)
+ {
+ UNORDERED_MAP<int, PlayingSound*>::iterator i = m_sounds_playing.find(id);
+ if (i == m_sounds_playing.end())
+ return 0;
+
+ PlayingSound *sound = i->second;
+ ALfloat gain;
+ alGetSourcef(sound->source_id, AL_GAIN, &gain);
+ return gain;
+ }
};
ISoundManager *createOpenALSoundManager(OnDemandSoundFetcher *fetcher)
diff --git a/src/threading/event.cpp b/src/threading/event.cpp
index 0d5928f10..a22c6628b 100644
--- a/src/threading/event.cpp
+++ b/src/threading/event.cpp
@@ -35,6 +35,8 @@ Event::Event()
pthread_mutex_init(&mutex, NULL);
notified = false;
# endif
+#elif USE_CPP11_MUTEX
+ notified = false;
#endif
}
diff --git a/src/threading/event.h b/src/threading/event.h
index 26cb8997a..79a99ce1f 100644
--- a/src/threading/event.h
+++ b/src/threading/event.h
@@ -29,19 +29,19 @@ DEALINGS IN THE SOFTWARE.
#include "threads.h"
#if USE_CPP11_MUTEX
- #include <condition_variable>
- #include "threading/mutex.h"
- #include "threading/mutex_auto_lock.h"
+#include <condition_variable>
+#include "threading/mutex.h"
+#include "threading/mutex_auto_lock.h"
#endif
-
/** A syncronization primitive that will wake up one waiting thread when signaled.
* Calling @c signal() multiple times before a waiting thread has had a chance
* to notice the signal will wake only one thread. Additionally, if no threads
* are waiting on the event when it is signaled, the next call to @c wait()
* will return (almost) immediately.
*/
-class Event {
+class Event
+{
public:
Event();
#ifndef USE_CPP11_MUTEX
diff --git a/src/threading/mutex.cpp b/src/threading/mutex.cpp
index 0908b5d37..d864f12c5 100644
--- a/src/threading/mutex.cpp
+++ b/src/threading/mutex.cpp
@@ -88,6 +88,15 @@ void Mutex::lock()
#endif
}
+bool Mutex::try_lock()
+{
+#if USE_WIN_MUTEX
+ return TryEnterCriticalSection(&mutex) != 0;
+#else
+ return pthread_mutex_trylock(&mutex) == 0;
+#endif
+}
+
void Mutex::unlock()
{
#if USE_WIN_MUTEX
diff --git a/src/threading/mutex.h b/src/threading/mutex.h
index fb5c029fc..6feb23c25 100644
--- a/src/threading/mutex.h
+++ b/src/threading/mutex.h
@@ -56,6 +56,8 @@ public:
void lock();
void unlock();
+ bool try_lock();
+
protected:
Mutex(bool recursive);
void init_mutex(bool recursive);
diff --git a/src/threading/semaphore.h b/src/threading/semaphore.h
index 822856396..8ff376666 100644
--- a/src/threading/semaphore.h
+++ b/src/threading/semaphore.h
@@ -21,21 +21,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define THREADING_SEMAPHORE_H
#if defined(_WIN32)
- #include <windows.h>
+#include <windows.h>
#elif defined(__MACH__) && defined(__APPLE__)
- #include <mach/semaphore.h>
+#include <mach/semaphore.h>
#else
- #include <semaphore.h>
+#include <semaphore.h>
#endif
#include "util/basic_macros.h"
-class Semaphore {
+class Semaphore
+{
public:
- Semaphore(int val=0);
+ Semaphore(int val = 0);
~Semaphore();
- void post(unsigned int num=1);
+ void post(unsigned int num = 1);
void wait();
bool wait(unsigned int time_ms);
@@ -52,4 +53,3 @@ private:
};
#endif
-
diff --git a/src/threading/thread.cpp b/src/threading/thread.cpp
index fbe4ba1f3..1909da61d 100644
--- a/src/threading/thread.cpp
+++ b/src/threading/thread.cpp
@@ -101,6 +101,11 @@ Thread::Thread(const std::string &name) :
Thread::~Thread()
{
kill();
+
+ // Make sure start finished mutex is unlocked before it's destroyed
+ m_start_finished_mutex.try_lock();
+ m_start_finished_mutex.unlock();
+
}
@@ -113,6 +118,9 @@ bool Thread::start()
m_request_stop = false;
+ // The mutex may already be locked if the thread is being restarted
+ m_start_finished_mutex.try_lock();
+
#if USE_CPP11_THREADS
try {
@@ -135,6 +143,9 @@ bool Thread::start()
#endif
+ // Allow spawned thread to continue
+ m_start_finished_mutex.unlock();
+
while (!m_running)
sleep_ms(1);
@@ -241,7 +252,7 @@ DWORD WINAPI Thread::threadProc(LPVOID param)
Thread *thr = (Thread *)param;
#ifdef _AIX
- m_kernel_thread_id = thread_self();
+ thr->m_kernel_thread_id = thread_self();
#endif
thr->setName(thr->m_name);
@@ -249,6 +260,10 @@ DWORD WINAPI Thread::threadProc(LPVOID param)
g_logger.registerThread(thr->m_name);
thr->m_running = true;
+ // Wait for the thread that started this one to finish initializing the
+ // thread handle so that getThreadId/getThreadHandle will work.
+ thr->m_start_finished_mutex.lock();
+
thr->m_retval = thr->run();
thr->m_running = false;
diff --git a/src/threading/thread.h b/src/threading/thread.h
index 14a0e13ab..4785d3e03 100644
--- a/src/threading/thread.h
+++ b/src/threading/thread.h
@@ -153,6 +153,7 @@ private:
Atomic<bool> m_request_stop;
Atomic<bool> m_running;
Mutex m_mutex;
+ Mutex m_start_finished_mutex;
#if USE_CPP11_THREADS
std::thread *m_thread_obj;
diff --git a/src/tileanimation.cpp b/src/tileanimation.cpp
new file mode 100644
index 000000000..67d27d396
--- /dev/null
+++ b/src/tileanimation.cpp
@@ -0,0 +1,131 @@
+/*
+Minetest
+Copyright (C) 2016 sfan5 <sfan5@live.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 "tileanimation.h"
+#include "util/serialize.h"
+
+void TileAnimationParams::serialize(std::ostream &os, u16 protocol_version) const
+{
+ if (protocol_version < 29) {
+ if (type == TAT_VERTICAL_FRAMES) {
+ writeU8(os, type);
+ writeU16(os, vertical_frames.aspect_w);
+ writeU16(os, vertical_frames.aspect_h);
+ writeF1000(os, vertical_frames.length);
+ } else {
+ writeU8(os, TAT_NONE);
+ writeU16(os, 1);
+ writeU16(os, 1);
+ writeF1000(os, 1.0);
+ }
+ return;
+ }
+
+ writeU8(os, type);
+ if (type == TAT_VERTICAL_FRAMES) {
+ writeU16(os, vertical_frames.aspect_w);
+ writeU16(os, vertical_frames.aspect_h);
+ writeF1000(os, vertical_frames.length);
+ } else if (type == TAT_SHEET_2D) {
+ writeU8(os, sheet_2d.frames_w);
+ writeU8(os, sheet_2d.frames_h);
+ writeF1000(os, sheet_2d.frame_length);
+ }
+}
+
+void TileAnimationParams::deSerialize(std::istream &is, u16 protocol_version)
+{
+ type = (TileAnimationType) readU8(is);
+ if (protocol_version < 29) {
+ vertical_frames.aspect_w = readU16(is);
+ vertical_frames.aspect_h = readU16(is);
+ vertical_frames.length = readF1000(is);
+ return;
+ }
+
+ if (type == TAT_VERTICAL_FRAMES) {
+ vertical_frames.aspect_w = readU16(is);
+ vertical_frames.aspect_h = readU16(is);
+ vertical_frames.length = readF1000(is);
+ } else if (type == TAT_SHEET_2D) {
+ sheet_2d.frames_w = readU8(is);
+ sheet_2d.frames_h = readU8(is);
+ sheet_2d.frame_length = readF1000(is);
+ }
+}
+
+void TileAnimationParams::determineParams(v2u32 texture_size, int *frame_count,
+ int *frame_length_ms, v2u32 *frame_size) const
+{
+ if (type == TAT_VERTICAL_FRAMES) {
+ int frame_height = (float)texture_size.X /
+ (float)vertical_frames.aspect_w *
+ (float)vertical_frames.aspect_h;
+ int _frame_count = texture_size.Y / frame_height;
+ if (frame_count)
+ *frame_count = _frame_count;
+ if (frame_length_ms)
+ *frame_length_ms = 1000.0 * vertical_frames.length / _frame_count;
+ if (frame_size)
+ *frame_size = v2u32(texture_size.X, frame_height);
+ } else if (type == TAT_SHEET_2D) {
+ if (frame_count)
+ *frame_count = sheet_2d.frames_w * sheet_2d.frames_h;
+ if (frame_length_ms)
+ *frame_length_ms = 1000 * sheet_2d.frame_length;
+ if (frame_size)
+ *frame_size = v2u32(texture_size.X / sheet_2d.frames_w, texture_size.Y / sheet_2d.frames_h);
+ }
+ // caller should check for TAT_NONE
+}
+
+void TileAnimationParams::getTextureModifer(std::ostream &os, v2u32 texture_size, int frame) const
+{
+ if (type == TAT_NONE)
+ return;
+ if (type == TAT_VERTICAL_FRAMES) {
+ int frame_count;
+ determineParams(texture_size, &frame_count, NULL, NULL);
+ os << "^[verticalframe:" << frame_count << ":" << frame;
+ } else if (type == TAT_SHEET_2D) {
+ int q, r;
+ q = frame / sheet_2d.frames_w;
+ r = frame % sheet_2d.frames_w;
+ os << "^[sheet:" << sheet_2d.frames_w << "x" << sheet_2d.frames_h
+ << ":" << r << "," << q;
+ }
+}
+
+v2f TileAnimationParams::getTextureCoords(v2u32 texture_size, int frame) const
+{
+ v2u32 ret(0, 0);
+ if (type == TAT_VERTICAL_FRAMES) {
+ int frame_height = (float)texture_size.X /
+ (float)vertical_frames.aspect_w *
+ (float)vertical_frames.aspect_h;
+ ret = v2u32(0, frame_height * frame);
+ } else if (type == TAT_SHEET_2D) {
+ v2u32 frame_size;
+ determineParams(texture_size, NULL, NULL, &frame_size);
+ int q, r;
+ q = frame / sheet_2d.frames_w;
+ r = frame % sheet_2d.frames_w;
+ ret = v2u32(r * frame_size.X, q * frame_size.Y);
+ }
+ return v2f(ret.X / (float) texture_size.X, ret.Y / (float) texture_size.Y);
+}
diff --git a/src/tileanimation.h b/src/tileanimation.h
new file mode 100644
index 000000000..9872e7917
--- /dev/null
+++ b/src/tileanimation.h
@@ -0,0 +1,62 @@
+/*
+Minetest
+Copyright (C) 2016 sfan5 <sfan5@live.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 TILEANIMATION_HEADER
+#define TILEANIMATION_HEADER
+
+#include <iostream>
+#include "irrlichttypes_bloated.h"
+
+enum TileAnimationType
+{
+ TAT_NONE = 0,
+ TAT_VERTICAL_FRAMES = 1,
+ TAT_SHEET_2D = 2,
+};
+
+struct TileAnimationParams
+{
+ enum TileAnimationType type;
+ union
+ {
+ // struct {
+ // } none;
+ struct
+ {
+ int aspect_w; // width for aspect ratio
+ int aspect_h; // height for aspect ratio
+ float length; // seconds
+ } vertical_frames;
+ struct
+ {
+ int frames_w; // number of frames left-to-right
+ int frames_h; // number of frames top-to-bottom
+ float frame_length; // seconds
+ } sheet_2d;
+ };
+
+ void serialize(std::ostream &os, u16 protocol_version) const;
+ void deSerialize(std::istream &is, u16 protocol_version);
+ void determineParams(v2u32 texture_size, int *frame_count, int *frame_length_ms,
+ v2u32 *frame_size) const;
+ void getTextureModifer(std::ostream &os, v2u32 texture_size, int frame) const;
+ v2f getTextureCoords(v2u32 texture_size, int frame) const;
+};
+
+#endif
diff --git a/src/tool.cpp b/src/tool.cpp
index 20b71fb31..bb884938c 100644
--- a/src/tool.cpp
+++ b/src/tool.cpp
@@ -27,33 +27,30 @@ with this program; if not, write to the Free Software Foundation, Inc.,
void ToolCapabilities::serialize(std::ostream &os, u16 protocol_version) const
{
- if(protocol_version <= 17)
- writeU8(os, 1); // version
- else
- writeU8(os, 2); // version
+ writeU8(os, 2); // version (protocol >= 18)
writeF1000(os, full_punch_interval);
writeS16(os, max_drop_level);
writeU32(os, groupcaps.size());
for (ToolGCMap::const_iterator i = groupcaps.begin(); i != groupcaps.end(); ++i) {
const std::string *name = &i->first;
const ToolGroupCap *cap = &i->second;
- os<<serializeString(*name);
+ os << serializeString(*name);
writeS16(os, cap->uses);
writeS16(os, cap->maxlevel);
writeU32(os, cap->times.size());
for (UNORDERED_MAP<int, float>::const_iterator
- i = cap->times.begin(); i != cap->times.end(); ++i) {
- writeS16(os, i->first);
- writeF1000(os, i->second);
+ j = cap->times.begin(); j != cap->times.end(); ++j) {
+ writeS16(os, j->first);
+ writeF1000(os, j->second);
}
}
- if(protocol_version > 17){
- writeU32(os, damageGroups.size());
- for (DamageGroup::const_iterator i = damageGroups.begin();
- i != damageGroups.end(); ++i) {
- os<<serializeString(i->first);
- writeS16(os, i->second);
- }
+
+ writeU32(os, damageGroups.size());
+
+ for (DamageGroup::const_iterator i = damageGroups.begin();
+ i != damageGroups.end(); ++i) {
+ os << serializeString(i->first);
+ writeS16(os, i->second);
}
}
@@ -101,7 +98,7 @@ DigParams getDigParams(const ItemGroupList &groups,
return DigParams(true, 0.5, 0, "dig_immediate");
case 3:
//infostream<<"dig_immediate=3"<<std::endl;
- return DigParams(true, 0.0, 0, "dig_immediate");
+ return DigParams(true, 0, 0, "dig_immediate");
default:
break;
}
diff --git a/src/tool.h b/src/tool.h
index ebba5b749..f33152355 100644
--- a/src/tool.h
+++ b/src/tool.h
@@ -63,8 +63,8 @@ struct ToolCapabilities
ToolCapabilities(
float full_punch_interval_=1.4,
int max_drop_level_=1,
- ToolGCMap groupcaps_=ToolGCMap(),
- DamageGroup damageGroups_=DamageGroup()
+ const ToolGCMap &groupcaps_ = ToolGCMap(),
+ const DamageGroup &damageGroups_ = DamageGroup()
):
full_punch_interval(full_punch_interval_),
max_drop_level(max_drop_level_),
@@ -85,8 +85,8 @@ struct DigParams
u16 wear;
std::string main_group;
- DigParams(bool a_diggable=false, float a_time=0, u16 a_wear=0,
- std::string a_main_group=""):
+ DigParams(bool a_diggable = false, float a_time = 0.0f, u16 a_wear = 0,
+ const std::string &a_main_group = ""):
diggable(a_diggable),
time(a_time),
wear(a_wear),
diff --git a/src/touchscreengui.cpp b/src/touchscreengui.cpp
index 8d210c63a..0139b8c4f 100644
--- a/src/touchscreengui.cpp
+++ b/src/touchscreengui.cpp
@@ -794,7 +794,7 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
if (m_move_id == -1) {
m_move_id = event.TouchInput.ID;
m_move_has_really_moved = false;
- m_move_downtime = getTimeMs();
+ m_move_downtime = porting::getTimeMs();
m_move_downlocation = v2s32(event.TouchInput.X, event.TouchInput.Y);
m_move_sent_as_mouse_event = false;
}
@@ -922,7 +922,7 @@ bool TouchScreenGUI::doubleTapDetection()
m_key_events[1].x = m_move_downlocation.X;
m_key_events[1].y = m_move_downlocation.Y;
- u32 delta = porting::getDeltaMs(m_key_events[0].down_time, getTimeMs());
+ u64 delta = porting::getDeltaMs(m_key_events[0].down_time, porting::getTimeMs());
if (delta > 400)
return false;
@@ -1006,7 +1006,7 @@ void TouchScreenGUI::step(float dtime)
(!m_move_has_really_moved) &&
(!m_move_sent_as_mouse_event)) {
- u32 delta = porting::getDeltaMs(m_move_downtime,getTimeMs());
+ u64 delta = porting::getDeltaMs(m_move_downtime, porting::getTimeMs());
if (delta > MIN_DIG_TIME_MS) {
m_shootline = m_device
diff --git a/src/touchscreengui.h b/src/touchscreengui.h
index 53fc6d683..f4f1766c9 100644
--- a/src/touchscreengui.h
+++ b/src/touchscreengui.h
@@ -19,15 +19,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef TOUCHSCREENGUI_HEADER
#define TOUCHSCREENGUI_HEADER
-#include <IGUIEnvironment.h>
-#include <IGUIButton.h>
#include <IEventReceiver.h>
+#include <IGUIButton.h>
+#include <IGUIEnvironment.h>
-#include <vector>
#include <map>
+#include <vector>
-#include "game.h"
#include "client/tile.h"
+#include "game.h"
using namespace irr;
using namespace irr::core;
@@ -68,32 +68,32 @@ typedef enum {
#define SETTINGS_BAR_Y_OFFSET 6.5
#define RARE_CONTROLS_BAR_Y_OFFSET 4
-extern const char** touchgui_button_imagenames;
+extern const char **touchgui_button_imagenames;
-struct button_info {
- float repeatcounter;
- float repeatdelay;
- irr::EKEY_CODE keycode;
+struct button_info
+{
+ float repeatcounter;
+ float repeatdelay;
+ irr::EKEY_CODE keycode;
std::vector<int> ids;
- IGUIButton* guibutton = NULL;
- bool immediate_release;
+ IGUIButton *guibutton = NULL;
+ bool immediate_release;
};
class AutoHideButtonBar
{
public:
+ AutoHideButtonBar(IrrlichtDevice *device, IEventReceiver *receiver);
- AutoHideButtonBar( IrrlichtDevice *device, IEventReceiver* receiver );
-
- void init(ISimpleTextureSource* tsrc, const char* starter_img,
- int button_id, v2s32 UpperLeft, v2s32 LowerRight,
- autohide_button_bar_dir dir, float timeout);
+ void init(ISimpleTextureSource *tsrc, const char *starter_img, int button_id,
+ v2s32 UpperLeft, v2s32 LowerRight, autohide_button_bar_dir dir,
+ float timeout);
~AutoHideButtonBar();
/* add button to be shown */
- void addButton(touch_gui_button_id id, const wchar_t* caption,
- const char* btn_image);
+ void addButton(touch_gui_button_id id, const wchar_t *caption,
+ const char *btn_image);
/* detect settings bar button events */
bool isButton(const SEvent &event);
@@ -114,40 +114,41 @@ public:
void show();
private:
- ISimpleTextureSource* m_texturesource;
- irr::video::IVideoDriver* m_driver;
- IGUIEnvironment* m_guienv;
- IEventReceiver* m_receiver;
- v2u32 m_screensize;
- button_info m_starter;
- std::vector<button_info*> m_buttons;
+ ISimpleTextureSource *m_texturesource;
+ irr::video::IVideoDriver *m_driver;
+ IGUIEnvironment *m_guienv;
+ IEventReceiver *m_receiver;
+ v2u32 m_screensize;
+ button_info m_starter;
+ std::vector<button_info *> m_buttons;
- v2s32 m_upper_left;
- v2s32 m_lower_right;
+ v2s32 m_upper_left;
+ v2s32 m_lower_right;
/* show settings bar */
- bool m_active;
+ bool m_active;
- bool m_visible;
+ bool m_visible;
/* settings bar timeout */
- float m_timeout;
- float m_timeout_value;
- bool m_initialized;
- autohide_button_bar_dir m_dir;
+ float m_timeout;
+ float m_timeout_value;
+ bool m_initialized;
+ autohide_button_bar_dir m_dir;
};
class TouchScreenGUI
{
public:
- TouchScreenGUI(IrrlichtDevice *device, IEventReceiver* receiver);
+ TouchScreenGUI(IrrlichtDevice *device, IEventReceiver *receiver);
~TouchScreenGUI();
void translateEvent(const SEvent &event);
- void init(ISimpleTextureSource* tsrc);
+ void init(ISimpleTextureSource *tsrc);
- double getYawChange() {
+ double getYawChange()
+ {
double res = m_camera_yaw_change;
m_camera_yaw_change = 0;
return res;
@@ -166,28 +167,28 @@ public:
void show();
private:
- IrrlichtDevice* m_device;
- IGUIEnvironment* m_guienv;
- IEventReceiver* m_receiver;
- ISimpleTextureSource* m_texturesource;
- v2u32 m_screensize;
- std::map<int,rect<s32> > m_hud_rects;
- std::map<int,irr::EKEY_CODE> m_hud_ids;
- bool m_visible; // is the gui visible
+ IrrlichtDevice *m_device;
+ IGUIEnvironment *m_guienv;
+ IEventReceiver *m_receiver;
+ ISimpleTextureSource *m_texturesource;
+ v2u32 m_screensize;
+ std::map<int, rect<s32> > m_hud_rects;
+ std::map<int, irr::EKEY_CODE> m_hud_ids;
+ bool m_visible; // is the gui visible
/* value in degree */
- double m_camera_yaw_change;
- double m_camera_pitch;
+ double m_camera_yaw_change;
+ double m_camera_pitch;
- line3d<f32> m_shootline;
+ line3d<f32> m_shootline;
- rect<s32> m_control_pad_rect;
+ rect<s32> m_control_pad_rect;
- int m_move_id;
- bool m_move_has_really_moved;
- s32 m_move_downtime;
- bool m_move_sent_as_mouse_event;
- v2s32 m_move_downlocation;
+ int m_move_id;
+ bool m_move_has_really_moved;
+ s64 m_move_downtime;
+ bool m_move_sent_as_mouse_event;
+ v2s32 m_move_downlocation;
button_info m_buttons[after_last_element_id];
@@ -206,9 +207,10 @@ private:
float repeat_delay = BUTTON_REPEAT_DELAY);
/* load texture */
- void loadButtonTexture(button_info* btn, const char* path, rect<s32> button_rect);
+ void loadButtonTexture(button_info *btn, const char *path, rect<s32> button_rect);
- struct id_status{
+ struct id_status
+ {
int id;
int X;
int Y;
@@ -236,7 +238,8 @@ private:
int getGuiButtonSize();
/* doubleclick detection variables */
- struct key_event {
+ struct key_event
+ {
unsigned int down_time;
s32 x;
s32 y;
diff --git a/src/treegen.cpp b/src/treegen.cpp
index f37bf0e86..8bf9619a0 100644
--- a/src/treegen.cpp
+++ b/src/treegen.cpp
@@ -21,11 +21,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <stack>
#include "util/pointer.h"
#include "util/numeric.h"
-#include "util/mathconstants.h"
#include "map.h"
-#include "environment.h"
+#include "serverenvironment.h"
#include "nodedef.h"
#include "treegen.h"
+#include "voxelalgorithms.h"
namespace treegen
{
@@ -113,7 +113,7 @@ void make_tree(MMVManip &vmanip, v3s16 p0,
// L-System tree LUA spawner
treegen::error spawn_ltree(ServerEnvironment *env, v3s16 p0,
- INodeDefManager *ndef, TreeDef tree_definition)
+ INodeDefManager *ndef, const TreeDef &tree_definition)
{
ServerMap *map = &env->getServerMap();
std::map<v3s16, MapBlock*> modified_blocks;
@@ -126,12 +126,8 @@ treegen::error spawn_ltree(ServerEnvironment *env, v3s16 p0,
if (e != SUCCESS)
return e;
- vmanip.blitBackAll(&modified_blocks);
+ voxalgo::blit_back_with_light(map, &vmanip, &modified_blocks);
- // update lighting
- std::map<v3s16, MapBlock*> lighting_modified_blocks;
- lighting_modified_blocks.insert(modified_blocks.begin(), modified_blocks.end());
- map->updateLighting(lighting_modified_blocks, modified_blocks);
// Send a MEET_OTHER event
MapEditEvent event;
event.type = MEET_OTHER;
diff --git a/src/treegen.h b/src/treegen.h
index 4e6f95e67..8777c369c 100644
--- a/src/treegen.h
+++ b/src/treegen.h
@@ -73,7 +73,7 @@ namespace treegen {
TreeDef tree_definition);
// Spawn L-systems tree from LUA
treegen::error spawn_ltree (ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef,
- TreeDef tree_definition);
+ const TreeDef &tree_definition);
// L-System tree gen helper functions
void tree_node_placement(MMVManip &vmanip, v3f p0,
diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp
index 41ccf0d2d..570807ba7 100644
--- a/src/unittest/test.cpp
+++ b/src/unittest/test.cpp
@@ -19,10 +19,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "test.h"
-#include "log.h"
#include "nodedef.h"
#include "itemdef.h"
#include "gamedef.h"
+#include "mods.h"
content_t t_CONTENT_STONE;
content_t t_CONTENT_GRASS;
@@ -59,6 +59,16 @@ public:
void defineSomeNodes();
+ virtual const std::vector<ModSpec> &getMods() const
+ {
+ static std::vector<ModSpec> testmodspec;
+ return testmodspec;
+ }
+ virtual const ModSpec* getModSpec(const std::string &modname) const { return NULL; }
+ virtual std::string getModStoragePath() const { return "."; }
+ virtual bool registerModStorage(ModMetadata *meta) { return true; }
+ virtual void unregisterModStorage(const std::string &name) {}
+
private:
IItemDefManager *m_itemdef;
INodeDefManager *m_nodedef;
@@ -219,7 +229,7 @@ bool run_tests()
{
DSTACK(FUNCTION_NAME);
- u32 t1 = porting::getTime(PRECISION_MILLI);
+ u64 t1 = porting::getTimeMs();
TestGameDef gamedef;
g_logger.setLevelSilenced(LL_ERROR, true);
@@ -236,7 +246,7 @@ bool run_tests()
num_total_tests_run += testmods[i]->num_tests_run;
}
- u32 tdiff = porting::getTime(PRECISION_MILLI) - t1;
+ u64 tdiff = porting::getTimeMs() - t1;
g_logger.setLevelSilenced(LL_ERROR, false);
@@ -263,12 +273,12 @@ bool run_tests()
bool TestBase::testModule(IGameDef *gamedef)
{
rawstream << "======== Testing module " << getName() << std::endl;
- u32 t1 = porting::getTime(PRECISION_MILLI);
+ u64 t1 = porting::getTimeMs();
runTests(gamedef);
- u32 tdiff = porting::getTime(PRECISION_MILLI) - t1;
+ u64 tdiff = porting::getTimeMs() - t1;
rawstream << "======== Module " << getName() << " "
<< (num_tests_failed ? "failed" : "passed") << " (" << num_tests_failed
<< " failures / " << num_tests_run << " tests) - " << tdiff
diff --git a/src/unittest/test.h b/src/unittest/test.h
index e60e657cc..bf76e8bb2 100644
--- a/src/unittest/test.h
+++ b/src/unittest/test.h
@@ -33,7 +33,7 @@ class TestFailedException : public std::exception {
// Runs a unit test and reports results
#define TEST(fxn, ...) do { \
- u32 t1 = porting::getTime(PRECISION_MILLI); \
+ u64 t1 = porting::getTimeMs(); \
try { \
fxn(__VA_ARGS__); \
rawstream << "[PASS] "; \
@@ -46,7 +46,7 @@ class TestFailedException : public std::exception {
num_tests_failed++; \
} \
num_tests_run++; \
- u32 tdiff = porting::getTime(PRECISION_MILLI) - t1; \
+ u64 tdiff = porting::getTimeMs() - t1; \
rawstream << #fxn << " - " << tdiff << "ms" << std::endl; \
} while (0)
diff --git a/src/unittest/test_connection.cpp b/src/unittest/test_connection.cpp
index 49e412fc8..d63322d69 100644
--- a/src/unittest/test_connection.cpp
+++ b/src/unittest/test_connection.cpp
@@ -305,7 +305,7 @@ void TestConnection::testConnectSendReceive()
u16 peer_id = 132;
u16 size = 0;
bool received = false;
- u32 timems0 = porting::getTimeMs();
+ u64 timems0 = porting::getTimeMs();
for (;;) {
if (porting::getTimeMs() - timems0 > 5000 || received)
break;
diff --git a/src/unittest/test_mapnode.cpp b/src/unittest/test_mapnode.cpp
index 9ecc2f82d..70e7d42cf 100644
--- a/src/unittest/test_mapnode.cpp
+++ b/src/unittest/test_mapnode.cpp
@@ -23,7 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodedef.h"
#include "content_mapnode.h"
-class TestMapNode : public TestBase {
+class TestMapNode : public TestBase
+{
public:
TestMapNode() { TestManager::registerTestModule(this); }
const char *getName() { return "TestMapNode"; }
diff --git a/src/unittest/test_nodedef.cpp b/src/unittest/test_nodedef.cpp
index 85093f52f..cb99ae854 100644
--- a/src/unittest/test_nodedef.cpp
+++ b/src/unittest/test_nodedef.cpp
@@ -25,7 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodedef.h"
#include "network/networkprotocol.h"
-class TestNodeDef : public TestBase {
+class TestNodeDef : public TestBase
+{
public:
TestNodeDef() { TestManager::registerTestModule(this); }
const char *getName() { return "TestNodeDef"; }
@@ -55,7 +56,7 @@ void TestNodeDef::testContentFeaturesSerialization()
std::ostringstream os(std::ios::binary);
f.serialize(os, LATEST_PROTOCOL_VERSION);
- //verbosestream<<"Test ContentFeatures size: "<<os.str().size()<<std::endl;
+ // verbosestream<<"Test ContentFeatures size: "<<os.str().size()<<std::endl;
std::istringstream is(os.str(), std::ios::binary);
ContentFeatures f2;
diff --git a/src/unittest/test_noderesolver.cpp b/src/unittest/test_noderesolver.cpp
index 55acece6a..b009f5d2e 100644
--- a/src/unittest/test_noderesolver.cpp
+++ b/src/unittest/test_noderesolver.cpp
@@ -24,6 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gamedef.h"
#include "nodedef.h"
+#include <algorithm>
+
class TestNodeResolver : public TestBase {
public:
diff --git a/src/unittest/test_objdef.cpp b/src/unittest/test_objdef.cpp
index df2633b38..c2acdcfe7 100644
--- a/src/unittest/test_objdef.cpp
+++ b/src/unittest/test_objdef.cpp
@@ -22,7 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "exceptions.h"
#include "objdef.h"
-class TestObjDef : public TestBase {
+class TestObjDef : public TestBase
+{
public:
TestObjDef() { TestManager::registerTestModule(this); }
const char *getName() { return "TestObjDef"; }
@@ -60,7 +61,6 @@ void TestObjDef::testHandles()
UASSERTEQ(ObjDefHandle, OBJDEF_ORE, type);
}
-
void TestObjDef::testAddGetSetClear()
{
ObjDefManager testmgr(NULL, OBJDEF_GENERIC);
diff --git a/src/unittest/test_player.cpp b/src/unittest/test_player.cpp
index 85fbc8b2d..e2b1cd855 100644
--- a/src/unittest/test_player.cpp
+++ b/src/unittest/test_player.cpp
@@ -24,65 +24,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_sao.h"
#include "server.h"
-class TestPlayer : public TestBase {
+class TestPlayer : public TestBase
+{
public:
TestPlayer() { TestManager::registerTestModule(this); }
const char *getName() { return "TestPlayer"; }
void runTests(IGameDef *gamedef);
-
- void testSave(IGameDef *gamedef);
- void testLoad(IGameDef *gamedef);
};
static TestPlayer g_test_instance;
void TestPlayer::runTests(IGameDef *gamedef)
{
- TEST(testSave, gamedef);
- TEST(testLoad, gamedef);
-}
-
-void TestPlayer::testSave(IGameDef *gamedef)
-{
- RemotePlayer rplayer("testplayer_save", gamedef->idef());
- PlayerSAO sao(NULL, 1, false);
- sao.initialize(&rplayer, std::set<std::string>());
- rplayer.setPlayerSAO(&sao);
- sao.setBreath(10);
- sao.setHPRaw(8);
- sao.setYaw(0.1f);
- sao.setPitch(0.6f);
- sao.setBasePosition(v3f(450.2f, -15.7f, 68.1f));
- rplayer.save(".", gamedef);
- UASSERT(fs::PathExists("testplayer_save"));
-}
-
-void TestPlayer::testLoad(IGameDef *gamedef)
-{
- RemotePlayer rplayer("testplayer_load", gamedef->idef());
- PlayerSAO sao(NULL, 1, false);
- sao.initialize(&rplayer, std::set<std::string>());
- rplayer.setPlayerSAO(&sao);
- sao.setBreath(10);
- sao.setHPRaw(8);
- sao.setYaw(0.1f);
- sao.setPitch(0.6f);
- sao.setBasePosition(v3f(450.2f, -15.7f, 68.1f));
- rplayer.save(".", gamedef);
- UASSERT(fs::PathExists("testplayer_load"));
-
- RemotePlayer rplayer_load("testplayer_load", gamedef->idef());
- PlayerSAO sao_load(NULL, 2, false);
- std::ifstream is("testplayer_load", std::ios_base::binary);
- UASSERT(is.good());
- rplayer_load.deSerialize(is, "testplayer_load", &sao_load);
- is.close();
-
- UASSERT(strcmp(rplayer_load.getName(), "testplayer_load") == 0);
- UASSERT(sao_load.getBreath() == 10);
- UASSERT(sao_load.getHP() == 8);
- UASSERT(sao_load.getYaw() == 0.1f);
- UASSERT(sao_load.getPitch() == 0.6f);
- UASSERT(sao_load.getBasePosition() == v3f(450.2f, -15.7f, 68.1f));
}
diff --git a/src/unittest/test_profiler.cpp b/src/unittest/test_profiler.cpp
index fbc03f232..92d336a72 100644
--- a/src/unittest/test_profiler.cpp
+++ b/src/unittest/test_profiler.cpp
@@ -21,7 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "profiler.h"
-class TestProfiler : public TestBase {
+class TestProfiler : public TestBase
+{
public:
TestProfiler() { TestManager::registerTestModule(this); }
const char *getName() { return "TestProfiler"; }
diff --git a/src/unittest/test_threading.cpp b/src/unittest/test_threading.cpp
index cdbf9674e..e1e1d3660 100644
--- a/src/unittest/test_threading.cpp
+++ b/src/unittest/test_threading.cpp
@@ -39,9 +39,7 @@ static TestThreading g_test_instance;
void TestThreading::runTests(IGameDef *gamedef)
{
-#if !(defined(__MACH__) && defined(__APPLE__))
TEST(testStartStopWait);
-#endif
TEST(testThreadKill);
TEST(testAtomicSemaphoreThread);
}
diff --git a/src/unittest/test_voxelalgorithms.cpp b/src/unittest/test_voxelalgorithms.cpp
index 31b9cadd5..fd83844af 100644
--- a/src/unittest/test_voxelalgorithms.cpp
+++ b/src/unittest/test_voxelalgorithms.cpp
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gamedef.h"
#include "voxelalgorithms.h"
+#include "util/numeric.h"
class TestVoxelAlgorithms : public TestBase {
public:
@@ -31,6 +32,7 @@ public:
void testPropogateSunlight(INodeDefManager *ndef);
void testClearLightAndCollectSources(INodeDefManager *ndef);
+ void testVoxelLineIterator(INodeDefManager *ndef);
};
static TestVoxelAlgorithms g_test_instance;
@@ -41,6 +43,7 @@ void TestVoxelAlgorithms::runTests(IGameDef *gamedef)
TEST(testPropogateSunlight, ndef);
TEST(testClearLightAndCollectSources, ndef);
+ TEST(testVoxelLineIterator, ndef);
}
////////////////////////////////////////////////////////////////////////////////
@@ -202,3 +205,59 @@ void TestVoxelAlgorithms::testClearLightAndCollectSources(INodeDefManager *ndef)
UASSERT(unlight_from.size() == 1);
}
}
+
+void TestVoxelAlgorithms::testVoxelLineIterator(INodeDefManager *ndef)
+{
+ // Test some lines
+ // Do not test lines that start or end on the border of
+ // two voxels as rounding errors can make the test fail!
+ std::vector<core::line3d<f32> > lines;
+ for (f32 x = -9.1; x < 9; x += 3.124) {
+ for (f32 y = -9.2; y < 9; y += 3.123) {
+ for (f32 z = -9.3; z < 9; z += 3.122) {
+ lines.push_back(core::line3d<f32>(-x, -y, -z, x, y, z));
+ }
+ }
+ }
+ lines.push_back(core::line3d<f32>(0, 0, 0, 0, 0, 0));
+ // Test every line
+ std::vector<core::line3d<f32> >::iterator it = lines.begin();
+ for (; it < lines.end(); it++) {
+ core::line3d<f32> l = *it;
+
+ // Initialize test
+ voxalgo::VoxelLineIterator iterator(l.start, l.getVector());
+
+ //Test the first voxel
+ v3s16 start_voxel = floatToInt(l.start, 1);
+ UASSERT(iterator.m_current_node_pos == start_voxel);
+
+ // Values for testing
+ v3s16 end_voxel = floatToInt(l.end, 1);
+ v3s16 voxel_vector = end_voxel - start_voxel;
+ int nodecount = abs(voxel_vector.X) + abs(voxel_vector.Y)
+ + abs(voxel_vector.Z);
+ int actual_nodecount = 0;
+ v3s16 old_voxel = iterator.m_current_node_pos;
+
+ while (iterator.hasNext()) {
+ iterator.next();
+ actual_nodecount++;
+ v3s16 new_voxel = iterator.m_current_node_pos;
+ // This must be a neighbor of the old voxel
+ UASSERTEQ(f32, (new_voxel - old_voxel).getLengthSQ(), 1);
+ // The line must intersect with the voxel
+ v3f voxel_center = intToFloat(iterator.m_current_node_pos, 1);
+ aabb3f box(voxel_center - v3f(0.5, 0.5, 0.5),
+ voxel_center + v3f(0.5, 0.5, 0.5));
+ UASSERT(box.intersectsWithLine(l));
+ // Update old voxel
+ old_voxel = new_voxel;
+ }
+
+ // Test last node
+ UASSERT(iterator.m_current_node_pos == end_voxel);
+ // Test node count
+ UASSERTEQ(int, actual_nodecount, nodecount);
+ }
+}
diff --git a/src/util/basic_macros.h b/src/util/basic_macros.h
index c100b4f25..687d7cf85 100644
--- a/src/util/basic_macros.h
+++ b/src/util/basic_macros.h
@@ -20,14 +20,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef BASICMACROS_HEADER
#define BASICMACROS_HEADER
-#include <algorithm>
-
#define ARRLEN(x) (sizeof(x) / sizeof((x)[0]))
#define MYMIN(a, b) ((a) < (b) ? (a) : (b))
#define MYMAX(a, b) ((a) > (b) ? (a) : (b))
+// Requires <algorithm>
#define CONTAINS(c, v) (std::find((c).begin(), (c).end(), (v)) != (c).end())
// To disable copy constructors and assignment operations for some class
@@ -50,4 +49,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define STATIC_ASSERT(expr, msg) \
UNUSED_ATTRIBUTE typedef char msg[!!(expr) * 2 - 1]
+// Macros to facilitate writing position vectors to a stream
+// Usage:
+// v3s16 pos(1,2,3);
+// mystream << "message " << PP(pos) << std::endl;
+
+#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
+
+#define PP2(x) "("<<(x).X<<","<<(x).Y<<")"
+
#endif
diff --git a/src/util/cpp11.h b/src/util/cpp11.h
new file mode 100644
index 000000000..14913cb86
--- /dev/null
+++ b/src/util/cpp11.h
@@ -0,0 +1,32 @@
+/*
+Minetest
+Copyright (C) 2016 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser 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 MT_CPP11_HEADER
+#define MT_CPP11_HEADER
+
+#if __cplusplus < 201103L || _MSC_VER < 1600
+#define USE_CPP11_FAKE_KEYWORD
+#endif
+
+#ifdef USE_CPP11_FAKE_KEYWORD
+#define constexpr const
+#define nullptr NULL
+#endif
+
+#endif
diff --git a/src/util/cpp11_container.h b/src/util/cpp11_container.h
index 88317c9c4..0194385fc 100644
--- a/src/util/cpp11_container.h
+++ b/src/util/cpp11_container.h
@@ -29,15 +29,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#endif
#ifdef USE_UNORDERED_CONTAINERS
- #include <unordered_map>
- #include <unordered_set>
- #define UNORDERED_MAP std::unordered_map
- #define UNORDERED_SET std::unordered_set
+#include <unordered_map>
+#include <unordered_set>
+#define UNORDERED_MAP std::unordered_map
+#define UNORDERED_SET std::unordered_set
#else
- #include <map>
- #include <set>
- #define UNORDERED_MAP std::map
- #define UNORDERED_SET std::set
+#include <map>
+#include <set>
+#define UNORDERED_MAP std::map
+#define UNORDERED_SET std::set
#endif
#endif
diff --git a/src/util/directiontables.h b/src/util/directiontables.h
index 0dd3aab09..3cfe0fb3e 100644
--- a/src/util/directiontables.h
+++ b/src/util/directiontables.h
@@ -30,5 +30,59 @@ extern const v3s16 g_26dirs[26];
// 26th is (0,0,0)
extern const v3s16 g_27dirs[27];
-#endif
+/// Direction in the 6D format. g_27dirs contains corresponding vectors.
+/// Here P means Positive, N stands for Negative.
+enum Direction6D {
+// 0
+ D6D_ZP,
+ D6D_YP,
+ D6D_XP,
+ D6D_ZN,
+ D6D_YN,
+ D6D_XN,
+// 6
+ D6D_XN_YP,
+ D6D_XP_YP,
+ D6D_YP_ZP,
+ D6D_YP_ZN,
+ D6D_XN_ZP,
+ D6D_XP_ZP,
+ D6D_XN_ZN,
+ D6D_XP_ZN,
+ D6D_XN_YN,
+ D6D_XP_YN,
+ D6D_YN_ZP,
+ D6D_YN_ZN,
+// 18
+ D6D_XN_YP_ZP,
+ D6D_XP_YP_ZP,
+ D6D_XN_YP_ZN,
+ D6D_XP_YP_ZN,
+ D6D_XN_YN_ZP,
+ D6D_XP_YN_ZP,
+ D6D_XN_YN_ZN,
+ D6D_XP_YN_ZN,
+// 26
+ D6D,
+
+// aliases
+ D6D_BACK = D6D_ZP,
+ D6D_TOP = D6D_YP,
+ D6D_RIGHT = D6D_XP,
+ D6D_FRONT = D6D_ZN,
+ D6D_BOTTOM = D6D_YN,
+ D6D_LEFT = D6D_XN,
+};
+/// Direction in the wallmounted format.
+/// P is Positive, N is Negative.
+enum DirectionWallmounted {
+ DWM_YP,
+ DWM_YN,
+ DWM_XP,
+ DWM_XN,
+ DWM_ZP,
+ DWM_ZN,
+};
+
+#endif
diff --git a/src/util/hex.h b/src/util/hex.h
index 6f00a79bf..c205d01da 100644
--- a/src/util/hex.h
+++ b/src/util/hex.h
@@ -30,9 +30,8 @@ static inline std::string hex_encode(const char *data, unsigned int data_size)
char buf2[3];
buf2[2] = '\0';
- for(unsigned int i = 0; i < data_size; i++)
- {
- unsigned char c = (unsigned char) data[i];
+ for (unsigned int i = 0; i < data_size; i++) {
+ unsigned char c = (unsigned char)data[i];
buf2[0] = hex_chars[(c & 0xf0) >> 4];
buf2[1] = hex_chars[c & 0x0f];
ret.append(buf2);
@@ -43,16 +42,16 @@ static inline std::string hex_encode(const char *data, unsigned int data_size)
static inline std::string hex_encode(const std::string &data)
{
- return hex_encode(data.c_str(), data.size());
+ return hex_encode(data.c_str(), data.size());
}
static inline bool hex_digit_decode(char hexdigit, unsigned char &value)
{
- if(hexdigit >= '0' && hexdigit <= '9')
+ if (hexdigit >= '0' && hexdigit <= '9')
value = hexdigit - '0';
- else if(hexdigit >= 'A' && hexdigit <= 'F')
+ else if (hexdigit >= 'A' && hexdigit <= 'F')
value = hexdigit - 'A' + 10;
- else if(hexdigit >= 'a' && hexdigit <= 'f')
+ else if (hexdigit >= 'a' && hexdigit <= 'f')
value = hexdigit - 'a' + 10;
else
return false;
diff --git a/src/util/mathconstants.h b/src/util/mathconstants.h
deleted file mode 100644
index 1b478aa95..000000000
--- a/src/util/mathconstants.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#include <math.h>
-
-// MSVC doesn't seem to define this
-#ifndef M_PI
- #define M_PI 3.1415926535
-#endif
-
diff --git a/src/util/numeric.cpp b/src/util/numeric.cpp
index a9e7ae584..e6a9cb75e 100644
--- a/src/util/numeric.cpp
+++ b/src/util/numeric.cpp
@@ -18,107 +18,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "numeric.h"
-#include "mathconstants.h"
#include "log.h"
#include "../constants.h" // BS, MAP_BLOCKSIZE
#include "../noise.h" // PseudoRandom, PcgRandom
#include "../threading/mutex_auto_lock.h"
#include <string.h>
-#include <iostream>
-UNORDERED_MAP<u16, std::vector<v3s16> > FacePositionCache::m_cache;
-Mutex FacePositionCache::m_cache_mutex;
-// Calculate the borders of a "d-radius" cube
-// TODO: Make it work without mutex and data races, probably thread-local
-std::vector<v3s16> FacePositionCache::getFacePositions(u16 d)
-{
- MutexAutoLock cachelock(m_cache_mutex);
- if (m_cache.find(d) != m_cache.end())
- return m_cache[d];
-
- generateFacePosition(d);
- return m_cache[d];
-
-}
-
-void FacePositionCache::generateFacePosition(u16 d)
-{
- m_cache[d] = std::vector<v3s16>();
- if(d == 0) {
- m_cache[d].push_back(v3s16(0,0,0));
- return;
- }
- if(d == 1) {
- /*
- This is an optimized sequence of coordinates.
- */
- m_cache[d].push_back(v3s16( 0, 1, 0)); // top
- m_cache[d].push_back(v3s16( 0, 0, 1)); // back
- m_cache[d].push_back(v3s16(-1, 0, 0)); // left
- m_cache[d].push_back(v3s16( 1, 0, 0)); // right
- m_cache[d].push_back(v3s16( 0, 0,-1)); // front
- m_cache[d].push_back(v3s16( 0,-1, 0)); // bottom
- // 6
- m_cache[d].push_back(v3s16(-1, 0, 1)); // back left
- m_cache[d].push_back(v3s16( 1, 0, 1)); // back right
- m_cache[d].push_back(v3s16(-1, 0,-1)); // front left
- m_cache[d].push_back(v3s16( 1, 0,-1)); // front right
- m_cache[d].push_back(v3s16(-1,-1, 0)); // bottom left
- m_cache[d].push_back(v3s16( 1,-1, 0)); // bottom right
- m_cache[d].push_back(v3s16( 0,-1, 1)); // bottom back
- m_cache[d].push_back(v3s16( 0,-1,-1)); // bottom front
- m_cache[d].push_back(v3s16(-1, 1, 0)); // top left
- m_cache[d].push_back(v3s16( 1, 1, 0)); // top right
- m_cache[d].push_back(v3s16( 0, 1, 1)); // top back
- m_cache[d].push_back(v3s16( 0, 1,-1)); // top front
- // 18
- m_cache[d].push_back(v3s16(-1, 1, 1)); // top back-left
- m_cache[d].push_back(v3s16( 1, 1, 1)); // top back-right
- m_cache[d].push_back(v3s16(-1, 1,-1)); // top front-left
- m_cache[d].push_back(v3s16( 1, 1,-1)); // top front-right
- m_cache[d].push_back(v3s16(-1,-1, 1)); // bottom back-left
- m_cache[d].push_back(v3s16( 1,-1, 1)); // bottom back-right
- m_cache[d].push_back(v3s16(-1,-1,-1)); // bottom front-left
- m_cache[d].push_back(v3s16( 1,-1,-1)); // bottom front-right
- // 26
- return;
- }
- // Take blocks in all sides, starting from y=0 and going +-y
- for(s16 y=0; y<=d-1; y++) {
- // Left and right side, including borders
- for(s16 z=-d; z<=d; z++) {
- m_cache[d].push_back(v3s16(d,y,z));
- m_cache[d].push_back(v3s16(-d,y,z));
- if(y != 0) {
- m_cache[d].push_back(v3s16(d,-y,z));
- m_cache[d].push_back(v3s16(-d,-y,z));
- }
- }
- // Back and front side, excluding borders
- for(s16 x=-d+1; x<=d-1; x++) {
- m_cache[d].push_back(v3s16(x,y,d));
- m_cache[d].push_back(v3s16(x,y,-d));
- if(y != 0) {
- m_cache[d].push_back(v3s16(x,-y,d));
- m_cache[d].push_back(v3s16(x,-y,-d));
- }
- }
- }
-
- // Take the bottom and top face with borders
- // -d<x<d, y=+-d, -d<z<d
- for(s16 x=-d; x<=d; x++)
- for(s16 z=-d; z<=d; z++) {
- m_cache[d].push_back(v3s16(x,-d,z));
- m_cache[d].push_back(v3s16(x,d,z));
- }
-}
-
-/*
- myrand
-*/
+// myrand
PcgRandom g_pcgrand;
diff --git a/src/util/numeric.h b/src/util/numeric.h
index 4cdc254c3..4a27f657d 100644
--- a/src/util/numeric.h
+++ b/src/util/numeric.h
@@ -26,28 +26,20 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "../irr_v3d.h"
#include "../irr_aabb3d.h"
#include "../threading/mutex.h"
-#include "cpp11_container.h"
-#include <list>
-#include <vector>
+#define rangelim(d, min, max) ((d) < (min) ? (min) : ((d) > (max) ? (max) : (d)))
+#define myfloor(x) ((x) < 0.0 ? (int)(x) - 1 : (int)(x))
+// The naive swap performs better than the xor version
+#define SWAP(t, x, y) do { \
+ t temp = x; \
+ x = y; \
+ y = temp; \
+} while (0)
-/*
- * This class permits to cache getFacePosition call results
- * This reduces CPU usage and vector calls
- */
-class FacePositionCache
-{
-public:
- static std::vector<v3s16> getFacePositions(u16 d);
-private:
- static void generateFacePosition(u16 d);
- static UNORDERED_MAP<u16, std::vector<v3s16> > m_cache;
- static Mutex m_cache_mutex;
-};
inline s16 getContainerPos(s16 p, s16 d)
{
- return (p>=0 ? p : p-d+1) / d;
+ return (p >= 0 ? p : p - d + 1) / d;
}
inline v2s16 getContainerPos(v2s16 p, s16 d)
@@ -130,16 +122,6 @@ inline bool isInArea(v3s16 p, v3s16 d)
);
}
-#define rangelim(d, min, max) ((d) < (min) ? (min) : ((d)>(max)?(max):(d)))
-#define myfloor(x) ((x) > 0.0 ? (int)(x) : (int)(x) - 1)
-
-// The naive swap performs better than the xor version
-#define SWAP(t, x, y) do { \
- t temp = x; \
- x = y; \
- y = temp; \
-} while (0)
-
inline void sortBoxVerticies(v3s16 &p1, v3s16 &p2) {
if (p1.X > p2.X)
SWAP(s16, p1.X, p2.X);
@@ -149,6 +131,16 @@ inline void sortBoxVerticies(v3s16 &p1, v3s16 &p2) {
SWAP(s16, p1.Z, p2.Z);
}
+inline v3s16 componentwise_min(const v3s16 &a, const v3s16 &b)
+{
+ return v3s16(MYMIN(a.X, b.X), MYMIN(a.Y, b.Y), MYMIN(a.Z, b.Z));
+}
+
+inline v3s16 componentwise_max(const v3s16 &a, const v3s16 &b)
+{
+ return v3s16(MYMAX(a.X, b.X), MYMAX(a.Y, b.Y), MYMAX(a.Z, b.Z));
+}
+
/** Returns \p f wrapped to the range [-360, 360]
*
@@ -256,11 +248,10 @@ inline s32 myround(f32 f)
*/
inline v3s16 floatToInt(v3f p, f32 d)
{
- v3s16 p2(
- (p.X + (p.X>0 ? d/2 : -d/2))/d,
- (p.Y + (p.Y>0 ? d/2 : -d/2))/d,
- (p.Z + (p.Z>0 ? d/2 : -d/2))/d);
- return p2;
+ return v3s16(
+ (p.X + (p.X > 0 ? d / 2 : -d / 2)) / d,
+ (p.Y + (p.Y > 0 ? d / 2 : -d / 2)) / d,
+ (p.Z + (p.Z > 0 ? d / 2 : -d / 2)) / d);
}
/*
@@ -268,34 +259,31 @@ inline v3s16 floatToInt(v3f p, f32 d)
*/
inline v3f intToFloat(v3s16 p, f32 d)
{
- v3f p2(
+ return v3f(
(f32)p.X * d,
(f32)p.Y * d,
(f32)p.Z * d
);
- return p2;
}
// Random helper. Usually d=BS
inline aabb3f getNodeBox(v3s16 p, float d)
{
return aabb3f(
- (float)p.X * d - 0.5*d,
- (float)p.Y * d - 0.5*d,
- (float)p.Z * d - 0.5*d,
- (float)p.X * d + 0.5*d,
- (float)p.Y * d + 0.5*d,
- (float)p.Z * d + 0.5*d
+ (float)p.X * d - 0.5 * d,
+ (float)p.Y * d - 0.5 * d,
+ (float)p.Z * d - 0.5 * d,
+ (float)p.X * d + 0.5 * d,
+ (float)p.Y * d + 0.5 * d,
+ (float)p.Z * d + 0.5 * d
);
}
+
class IntervalLimiter
{
public:
- IntervalLimiter():
- m_accumulator(0)
- {
- }
+ IntervalLimiter() : m_accumulator(0) {}
/*
dtime: time from last call to this method
wanted_interval: interval wanted
@@ -306,15 +294,17 @@ public:
bool step(float dtime, float wanted_interval)
{
m_accumulator += dtime;
- if(m_accumulator < wanted_interval)
+ if (m_accumulator < wanted_interval)
return false;
m_accumulator -= wanted_interval;
return true;
}
-protected:
+
+private:
float m_accumulator;
};
+
/*
Splits a list into "pages". For example, the list [1,2,3,4,5] split
into two pages would be [1,2,3],[4,5]. This function computes the
@@ -330,29 +320,21 @@ protected:
*/
inline void paging(u32 length, u32 page, u32 pagecount, u32 &minindex, u32 &maxindex)
{
- if(length < 1 || pagecount < 1 || page < 1 || page > pagecount)
- {
+ if (length < 1 || pagecount < 1 || page < 1 || page > pagecount) {
// Special cases or invalid parameters
minindex = maxindex = 0;
- }
- else if(pagecount <= length)
- {
+ } else if(pagecount <= length) {
// Less pages than entries in the list:
// Each page contains at least one entry
minindex = (length * (page-1) + (pagecount-1)) / pagecount;
maxindex = (length * page + (pagecount-1)) / pagecount;
- }
- else
- {
+ } else {
// More pages than entries in the list:
// Make sure the empty pages are at the end
- if(page < length)
- {
+ if (page < length) {
minindex = page-1;
maxindex = page;
- }
- else
- {
+ } else {
minindex = 0;
maxindex = 0;
}
@@ -361,14 +343,14 @@ inline void paging(u32 length, u32 page, u32 pagecount, u32 &minindex, u32 &maxi
inline float cycle_shift(float value, float by = 0, float max = 1)
{
- if (value + by < 0) return max + by + value;
+ if (value + by < 0) return value + by + max;
if (value + by > max) return value + by - max;
return value + by;
}
inline bool is_power_of_two(u32 n)
{
- return n != 0 && (n & (n-1)) == 0;
+ return n != 0 && (n & (n - 1)) == 0;
}
// Compute next-higher power of 2 efficiently, e.g. for power-of-2 texture sizes.
diff --git a/src/util/pointedthing.cpp b/src/util/pointedthing.cpp
index cd13000b5..ed3d4bb67 100644
--- a/src/util/pointedthing.cpp
+++ b/src/util/pointedthing.cpp
@@ -27,29 +27,25 @@ PointedThing::PointedThing():
type(POINTEDTHING_NOTHING),
node_undersurface(0,0,0),
node_abovesurface(0,0,0),
+ node_real_undersurface(0,0,0),
+ intersection_point(0,0,0),
+ intersection_normal(0,0,0),
object_id(-1)
{}
std::string PointedThing::dump() const
{
std::ostringstream os(std::ios::binary);
- if(type == POINTEDTHING_NOTHING)
- {
+ if (type == POINTEDTHING_NOTHING) {
os<<"[nothing]";
- }
- else if(type == POINTEDTHING_NODE)
- {
+ } else if (type == POINTEDTHING_NODE) {
const v3s16 &u = node_undersurface;
const v3s16 &a = node_abovesurface;
os<<"[node under="<<u.X<<","<<u.Y<<","<<u.Z
<< " above="<<a.X<<","<<a.Y<<","<<a.Z<<"]";
- }
- else if(type == POINTEDTHING_OBJECT)
- {
+ } else if (type == POINTEDTHING_OBJECT) {
os<<"[object "<<object_id<<"]";
- }
- else
- {
+ } else {
os<<"[unknown PointedThing]";
}
return os.str();
@@ -59,61 +55,56 @@ void PointedThing::serialize(std::ostream &os) const
{
writeU8(os, 0); // version
writeU8(os, (u8)type);
- if(type == POINTEDTHING_NOTHING)
- {
- // nothing
- }
- else if(type == POINTEDTHING_NODE)
- {
+ switch (type) {
+ case POINTEDTHING_NOTHING:
+ break;
+ case POINTEDTHING_NODE:
writeV3S16(os, node_undersurface);
writeV3S16(os, node_abovesurface);
- }
- else if(type == POINTEDTHING_OBJECT)
- {
+ break;
+ case POINTEDTHING_OBJECT:
writeS16(os, object_id);
+ break;
}
}
void PointedThing::deSerialize(std::istream &is)
{
int version = readU8(is);
- if(version != 0) throw SerializationError(
+ if (version != 0) throw SerializationError(
"unsupported PointedThing version");
type = (PointedThingType) readU8(is);
- if(type == POINTEDTHING_NOTHING)
- {
- // nothing
- }
- else if(type == POINTEDTHING_NODE)
- {
+ switch (type) {
+ case POINTEDTHING_NOTHING:
+ break;
+ case POINTEDTHING_NODE:
node_undersurface = readV3S16(is);
node_abovesurface = readV3S16(is);
- }
- else if(type == POINTEDTHING_OBJECT)
- {
+ break;
+ case POINTEDTHING_OBJECT:
object_id = readS16(is);
- }
- else
- {
- throw SerializationError(
- "unsupported PointedThingType");
+ break;
+ default:
+ throw SerializationError("unsupported PointedThingType");
}
}
bool PointedThing::operator==(const PointedThing &pt2) const
{
- if(type != pt2.type)
+ if (type != pt2.type)
+ {
return false;
- if(type == POINTEDTHING_NODE)
+ }
+ if (type == POINTEDTHING_NODE)
{
- if(node_undersurface != pt2.node_undersurface)
- return false;
- if(node_abovesurface != pt2.node_abovesurface)
+ if ((node_undersurface != pt2.node_undersurface)
+ || (node_abovesurface != pt2.node_abovesurface)
+ || (node_real_undersurface != pt2.node_real_undersurface))
return false;
}
- else if(type == POINTEDTHING_OBJECT)
+ else if (type == POINTEDTHING_OBJECT)
{
- if(object_id != pt2.object_id)
+ if (object_id != pt2.object_id)
return false;
}
return true;
diff --git a/src/util/pointedthing.h b/src/util/pointedthing.h
index 2b2703e98..f695a4ebd 100644
--- a/src/util/pointedthing.h
+++ b/src/util/pointedthing.h
@@ -32,17 +32,57 @@ enum PointedThingType
POINTEDTHING_OBJECT
};
+//! An active object or node which is selected by a ray on the map.
struct PointedThing
{
+ //! The type of the pointed object.
PointedThingType type;
+ /*!
+ * Only valid if type is POINTEDTHING_NODE.
+ * The coordinates of the node which owns the
+ * nodebox that the ray hits first.
+ * This may differ from node_real_undersurface if
+ * a nodebox exceeds the limits of its node.
+ */
v3s16 node_undersurface;
+ /*!
+ * Only valid if type is POINTEDTHING_NODE.
+ * The coordinates of the last node the ray intersects
+ * before node_undersurface. Same as node_undersurface
+ * if the ray starts in a nodebox.
+ */
v3s16 node_abovesurface;
+ /*!
+ * Only valid if type is POINTEDTHING_NODE.
+ * The coordinates of the node which contains the
+ * point of the collision and the nodebox of the node.
+ */
+ v3s16 node_real_undersurface;
+ /*!
+ * Only valid if type isn't POINTEDTHING_NONE.
+ * First intersection point of the ray and the nodebox.
+ */
+ v3f intersection_point;
+ /*!
+ * Only valid if type isn't POINTEDTHING_NONE.
+ * Normal vector of the intersection.
+ * This is perpendicular to the face the ray hits,
+ * points outside of the box and it's length is 1.
+ */
+ v3s16 intersection_normal;
+ /*!
+ * Only valid if type is POINTEDTHING_OBJECT.
+ * The ID of the object the ray hit.
+ */
s16 object_id;
PointedThing();
std::string dump() const;
void serialize(std::ostream &os) const;
void deSerialize(std::istream &is);
+ /*!
+ * This function ignores the intersection point and normal.
+ */
bool operator==(const PointedThing &pt2) const;
bool operator!=(const PointedThing &pt2) const;
};
diff --git a/src/util/serialize.cpp b/src/util/serialize.cpp
index 99cb990f1..61d369bc4 100644
--- a/src/util/serialize.cpp
+++ b/src/util/serialize.cpp
@@ -354,6 +354,55 @@ std::string deSerializeJsonString(std::istream &is)
return os.str();
}
+std::string serializeJsonStringIfNeeded(const std::string &s)
+{
+ for (size_t i = 0; i < s.size(); ++i) {
+ if (s[i] <= 0x1f || s[i] >= 0x7f || s[i] == ' ' || s[i] == '\"')
+ return serializeJsonString(s);
+ }
+ return s;
+}
+
+std::string deSerializeJsonStringIfNeeded(std::istream &is)
+{
+ std::ostringstream tmp_os;
+ bool expect_initial_quote = true;
+ bool is_json = false;
+ bool was_backslash = false;
+ for (;;) {
+ char c = is.get();
+ if (is.eof())
+ break;
+
+ if (expect_initial_quote && c == '"') {
+ tmp_os << c;
+ is_json = true;
+ } else if(is_json) {
+ tmp_os << c;
+ if (was_backslash)
+ was_backslash = false;
+ else if (c == '\\')
+ was_backslash = true;
+ else if (c == '"')
+ break; // Found end of string
+ } else {
+ if (c == ' ') {
+ // Found end of word
+ is.unget();
+ break;
+ } else {
+ tmp_os << c;
+ }
+ }
+ expect_initial_quote = false;
+ }
+ if (is_json) {
+ std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
+ return deSerializeJsonString(tmp_is);
+ } else
+ return tmp_os.str();
+}
+
////
//// String/Struct conversions
////
diff --git a/src/util/serialize.h b/src/util/serialize.h
index 36324a675..e22434191 100644
--- a/src/util/serialize.h
+++ b/src/util/serialize.h
@@ -405,6 +405,13 @@ std::string serializeJsonString(const std::string &plain);
// Reads a string encoded in JSON format
std::string deSerializeJsonString(std::istream &is);
+// If the string contains spaces, quotes or control characters, encodes as JSON.
+// Else returns the string unmodified.
+std::string serializeJsonStringIfNeeded(const std::string &s);
+
+// Parses a string serialized by serializeJsonStringIfNeeded.
+std::string deSerializeJsonStringIfNeeded(std::istream &is);
+
// Creates a string consisting of the hexadecimal representation of `data`
std::string serializeHexString(const std::string &data, bool insert_spaces=false);
diff --git a/src/util/sha1.h b/src/util/sha1.h
index c04947373..0ac08c67b 100644
--- a/src/util/sha1.h
+++ b/src/util/sha1.h
@@ -29,22 +29,23 @@ typedef unsigned int Uint32;
class SHA1
{
- private:
- // fields
- Uint32 H0, H1, H2, H3, H4;
- unsigned char bytes[64];
- int unprocessedBytes;
- Uint32 size;
- void process();
- public:
- SHA1();
- ~SHA1();
- void addBytes( const char* data, int num );
- unsigned char* getDigest();
- // utility methods
- static Uint32 lrot( Uint32 x, int bits );
- static void storeBigEndianUint32( unsigned char* byte, Uint32 num );
- static void hexPrinter( unsigned char* c, int l );
+private:
+ // fields
+ Uint32 H0, H1, H2, H3, H4;
+ unsigned char bytes[64];
+ int unprocessedBytes;
+ Uint32 size;
+ void process();
+
+public:
+ SHA1();
+ ~SHA1();
+ void addBytes(const char *data, int num);
+ unsigned char *getDigest();
+ // utility methods
+ static Uint32 lrot(Uint32 x, int bits);
+ static void storeBigEndianUint32(unsigned char *byte, Uint32 num);
+ static void hexPrinter(unsigned char *c, int l);
};
#define SHA1_HEADER
diff --git a/src/util/sha2.h b/src/util/sha2.h
index 6ac045feb..233c85a81 100644
--- a/src/util/sha2.h
+++ b/src/util/sha2.h
@@ -57,21 +57,21 @@
*/
#ifndef HEADER_SHA_H
-# define HEADER_SHA_H
+#define HEADER_SHA_H
-# include <stddef.h>
+#include <stddef.h>
-#ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
#endif
-# if defined(OPENSSL_NO_SHA) || (defined(OPENSSL_NO_SHA0) && defined(OPENSSL_NO_SHA1))
-# error SHA is disabled.
-# endif
+#if defined(OPENSSL_NO_SHA) || (defined(OPENSSL_NO_SHA0) && defined(OPENSSL_NO_SHA1))
+#error SHA is disabled.
+#endif
-# if defined(OPENSSL_FIPS)
-# define FIPS_SHA_SIZE_T size_t
-# endif
+#if defined(OPENSSL_FIPS)
+#define FIPS_SHA_SIZE_T size_t
+#endif
/*
Compat stuff from OpenSSL land
@@ -79,11 +79,10 @@ extern "C" {
/* crypto.h */
-# define fips_md_init(alg) fips_md_init_ctx(alg, alg)
+#define fips_md_init(alg) fips_md_init_ctx(alg, alg)
-# define fips_md_init_ctx(alg, cx) \
- int alg##_Init(cx##_CTX *c)
-# define fips_cipher_abort(alg) while(0)
+#define fips_md_init_ctx(alg, cx) int alg##_Init(cx##_CTX *c)
+#define fips_cipher_abort(alg) while (0)
/*-
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@@ -92,47 +91,51 @@ extern "C" {
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
-# if defined(__LP32__)
-# define SHA_LONG unsigned long
-# elif defined(__ILP64__)
-# define SHA_LONG unsigned long
-# define SHA_LONG_LOG2 3
-# else
-# define SHA_LONG unsigned int
-# endif
-
-# define SHA_LBLOCK 16
-# define SHA_CBLOCK (SHA_LBLOCK*4)/* SHA treats input data as a
- * contiguous array of 32 bit wide
- * big-endian values. */
-# define SHA_LAST_BLOCK (SHA_CBLOCK-8)
-# define SHA_DIGEST_LENGTH 20
-
-typedef struct SHAstate_st {
- SHA_LONG h0, h1, h2, h3, h4;
- SHA_LONG Nl, Nh;
- SHA_LONG data[SHA_LBLOCK];
- unsigned int num;
+#if defined(__LP32__)
+#define SHA_LONG unsigned long
+#elif defined(__ILP64__)
+#define SHA_LONG unsigned long
+#define SHA_LONG_LOG2 3
+#else
+#define SHA_LONG unsigned int
+#endif
+
+#define SHA_LBLOCK 16
+#define SHA_CBLOCK \
+ (SHA_LBLOCK * 4) /* SHA treats input data as a \
+ * contiguous array of 32 bit wide \
+ * big-endian values. */
+#define SHA_LAST_BLOCK (SHA_CBLOCK - 8)
+#define SHA_DIGEST_LENGTH 20
+
+typedef struct SHAstate_st
+{
+ SHA_LONG h0, h1, h2, h3, h4;
+ SHA_LONG Nl, Nh;
+ SHA_LONG data[SHA_LBLOCK];
+ unsigned int num;
} SHA_CTX;
-# define SHA256_CBLOCK (SHA_LBLOCK*4)/* SHA-256 treats input data as a
- * contiguous array of 32 bit wide
- * big-endian values. */
-# define SHA224_DIGEST_LENGTH 28
-# define SHA256_DIGEST_LENGTH 32
-
-typedef struct SHA256state_st {
- SHA_LONG h[8];
- SHA_LONG Nl, Nh;
- SHA_LONG data[SHA_LBLOCK];
- unsigned int num, md_len;
+#define SHA256_CBLOCK \
+ (SHA_LBLOCK * 4) /* SHA-256 treats input data as a \
+ * contiguous array of 32 bit wide \
+ * big-endian values. */
+#define SHA224_DIGEST_LENGTH 28
+#define SHA256_DIGEST_LENGTH 32
+
+typedef struct SHA256state_st
+{
+ SHA_LONG h[8];
+ SHA_LONG Nl, Nh;
+ SHA_LONG data[SHA_LBLOCK];
+ unsigned int num, md_len;
} SHA256_CTX;
-# ifndef OPENSSL_NO_SHA256
-# ifdef OPENSSL_FIPS
+#ifndef OPENSSL_NO_SHA256
+#ifdef OPENSSL_FIPS
int private_SHA224_Init(SHA256_CTX *c);
int private_SHA256_Init(SHA256_CTX *c);
-# endif
+#endif
int SHA224_Init(SHA256_CTX *c);
int SHA224_Update(SHA256_CTX *c, const void *data, size_t len);
int SHA224_Final(unsigned char *md, SHA256_CTX *c);
@@ -142,12 +145,12 @@ int SHA256_Update(SHA256_CTX *c, const void *data, size_t len);
int SHA256_Final(unsigned char *md, SHA256_CTX *c);
unsigned char *SHA256(const unsigned char *d, size_t n, unsigned char *md);
void SHA256_Transform(SHA256_CTX *c, const unsigned char *data);
-# endif
+#endif
-# define SHA384_DIGEST_LENGTH 48
-# define SHA512_DIGEST_LENGTH 64
+#define SHA384_DIGEST_LENGTH 48
+#define SHA512_DIGEST_LENGTH 64
-#ifdef __cplusplus
+#ifdef __cplusplus
}
#endif
diff --git a/src/util/sha256.c b/src/util/sha256.c
index 4c2bb71a8..4241f31f3 100644
--- a/src/util/sha256.c
+++ b/src/util/sha256.c
@@ -30,11 +30,6 @@ static void OPENSSL_cleanse(void *ptr, size_t len)
cleanse_ctr = (unsigned char)ctr;
}
-# define fips_md_init(alg) fips_md_init_ctx(alg, alg)
-# define fips_md_init_ctx(alg, cx) \
- int alg##_Init(cx##_CTX *c)
-# define fips_cipher_abort(alg) while(0)
-
fips_md_init_ctx(SHA224, SHA256)
{
memset(c, 0, sizeof(*c));
diff --git a/src/util/srp.cpp b/src/util/srp.cpp
index 77c1816e8..430ba1137 100644
--- a/src/util/srp.cpp
+++ b/src/util/srp.cpp
@@ -44,7 +44,7 @@
#if USE_SYSTEM_GMP || defined (__ANDROID__) || defined (ANDROID)
#include <gmp.h>
#else
- #include <gmp/mini-gmp.h>
+ #include <mini-gmp.h>
#endif
#include <util/sha2.h>
diff --git a/src/util/string.cpp b/src/util/string.cpp
index 94064ef93..d41b91f24 100644
--- a/src/util/string.cpp
+++ b/src/util/string.cpp
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "hex.h"
#include "../porting.h"
+#include <algorithm>
#include <sstream>
#include <iomanip>
#include <map>
@@ -561,6 +562,7 @@ ColorContainer::ColorContainer()
colors["darkgoldenrod"] = 0xb8860b;
colors["darkgray"] = 0xa9a9a9;
colors["darkgreen"] = 0x006400;
+ colors["darkgrey"] = 0xa9a9a9;
colors["darkkhaki"] = 0xbdb76b;
colors["darkmagenta"] = 0x8b008b;
colors["darkolivegreen"] = 0x556b2f;
@@ -571,11 +573,13 @@ ColorContainer::ColorContainer()
colors["darkseagreen"] = 0x8fbc8f;
colors["darkslateblue"] = 0x483d8b;
colors["darkslategray"] = 0x2f4f4f;
+ colors["darkslategrey"] = 0x2f4f4f;
colors["darkturquoise"] = 0x00ced1;
colors["darkviolet"] = 0x9400d3;
colors["deeppink"] = 0xff1493;
colors["deepskyblue"] = 0x00bfff;
colors["dimgray"] = 0x696969;
+ colors["dimgrey"] = 0x696969;
colors["dodgerblue"] = 0x1e90ff;
colors["firebrick"] = 0xb22222;
colors["floralwhite"] = 0xfffaf0;
@@ -588,6 +592,7 @@ ColorContainer::ColorContainer()
colors["gray"] = 0x808080;
colors["green"] = 0x008000;
colors["greenyellow"] = 0xadff2f;
+ colors["grey"] = 0x808080;
colors["honeydew"] = 0xf0fff0;
colors["hotpink"] = 0xff69b4;
colors["indianred"] = 0xcd5c5c;
@@ -604,11 +609,13 @@ ColorContainer::ColorContainer()
colors["lightgoldenrodyellow"] = 0xfafad2;
colors["lightgray"] = 0xd3d3d3;
colors["lightgreen"] = 0x90ee90;
+ colors["lightgrey"] = 0xd3d3d3;
colors["lightpink"] = 0xffb6c1;
colors["lightsalmon"] = 0xffa07a;
colors["lightseagreen"] = 0x20b2aa;
colors["lightskyblue"] = 0x87cefa;
colors["lightslategray"] = 0x778899;
+ colors["lightslategrey"] = 0x778899;
colors["lightsteelblue"] = 0xb0c4de;
colors["lightyellow"] = 0xffffe0;
colors["lime"] = 0x00ff00;
@@ -661,6 +668,7 @@ ColorContainer::ColorContainer()
colors["skyblue"] = 0x87ceeb;
colors["slateblue"] = 0x6a5acd;
colors["slategray"] = 0x708090;
+ colors["slategrey"] = 0x708090;
colors["snow"] = 0xfffafa;
colors["springgreen"] = 0x00ff7f;
colors["steelblue"] = 0x4682b4;
diff --git a/src/util/string.h b/src/util/string.h
index 572c37150..cc278da13 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -232,7 +232,7 @@ inline std::vector<std::basic_string<T> > str_split(
*/
inline std::string lowercase(const std::string &str)
{
- std::string s2;
+ std::string s2 = "";
s2.reserve(str.size());
@@ -423,6 +423,18 @@ inline void str_replace(std::string &str, const std::string &pattern,
}
/**
+ * Escapes characters [ ] \ , ; that can not be used in formspecs
+ */
+inline void str_formspec_escape(std::string &str)
+{
+ str_replace(str, "\\", "\\\\");
+ str_replace(str, "]", "\\]");
+ str_replace(str, "[", "\\[");
+ str_replace(str, ";", "\\;");
+ str_replace(str, ",", "\\,");
+}
+
+/**
* Replace all occurrences of the character \p from in \p str with \p to.
*
* @param str The string to (potentially) modify.
@@ -614,4 +626,28 @@ inline const char *bool_to_cstr(bool val)
return val ? "true" : "false";
}
+inline const std::string duration_to_string(int sec)
+{
+ int min = sec / 60;
+ sec %= 60;
+ int hour = min / 60;
+ min %= 60;
+
+ std::stringstream ss;
+ if (hour > 0) {
+ ss << hour << "h ";
+ }
+
+ if (min > 0) {
+ ss << min << "m ";
+ }
+
+ if (sec > 0) {
+ ss << sec << "s ";
+ }
+
+ return ss.str();
+}
+
+
#endif
diff --git a/src/util/thread.h b/src/util/thread.h
index 5ed63544c..b96f302f6 100644
--- a/src/util/thread.h
+++ b/src/util/thread.h
@@ -26,11 +26,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "../threading/mutex_auto_lock.h"
#include "porting.h"
#include "log.h"
+#include "container.h"
template<typename T>
-class MutexedVariable {
+class MutexedVariable
+{
public:
- MutexedVariable(T value):
+ MutexedVariable(const T &value):
m_value(value)
{}
@@ -40,21 +42,14 @@ public:
return m_value;
}
- void set(T value)
+ void set(const T &value)
{
MutexAutoLock lock(m_mutex);
m_value = value;
}
- // You'll want to grab this in a SharedPtr
- MutexAutoLock *getLock()
- {
- return new MutexAutoLock(m_mutex);
- }
-
// You pretty surely want to grab the lock when accessing this
T m_value;
-
private:
Mutex m_mutex;
};
@@ -88,8 +83,8 @@ public:
GetRequest() {}
~GetRequest() {}
- GetRequest(Key a_key) {
- key = a_key;
+ GetRequest(const Key &a_key): key(a_key)
+ {
}
Key key;
@@ -111,7 +106,7 @@ public:
return m_queue.empty();
}
- void add(Key key, Caller caller, CallerData callerdata,
+ void add(const Key &key, Caller caller, CallerData callerdata,
ResultQueue<Key, T, Caller, CallerData> *dest)
{
typename std::deque<GetRequest<Key, T, Caller, CallerData> >::iterator i;
diff --git a/src/util/timetaker.cpp b/src/util/timetaker.cpp
index dcf07dc0d..ac686c3a3 100644
--- a/src/util/timetaker.cpp
+++ b/src/util/timetaker.cpp
@@ -19,31 +19,26 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "timetaker.h"
-#include "../gettime.h"
+#include "../porting.h"
#include "../log.h"
#include <ostream>
-TimeTaker::TimeTaker(const char *name, u32 *result, TimePrecision prec)
+TimeTaker::TimeTaker(const std::string &name, u64 *result, TimePrecision prec)
{
m_name = name;
m_result = result;
m_running = true;
m_precision = prec;
- m_time1 = getTime(prec);
+ m_time1 = porting::getTime(prec);
}
-u32 TimeTaker::stop(bool quiet)
+u64 TimeTaker::stop(bool quiet)
{
- if(m_running)
- {
- u32 time2 = getTime(m_precision);
- u32 dtime = time2 - m_time1;
- if(m_result != NULL)
- {
+ if (m_running) {
+ u64 dtime = porting::getTime(m_precision) - m_time1;
+ if (m_result != NULL) {
(*m_result) += dtime;
- }
- else
- {
+ } else {
if (!quiet) {
static const char* const units[] = {
"s" /* PRECISION_SECONDS */,
@@ -62,10 +57,8 @@ u32 TimeTaker::stop(bool quiet)
return 0;
}
-u32 TimeTaker::getTimerTime()
+u64 TimeTaker::getTimerTime()
{
- u32 time2 = getTime(m_precision);
- u32 dtime = time2 - m_time1;
- return dtime;
+ return porting::getTime(m_precision) - m_time1;
}
diff --git a/src/util/timetaker.h b/src/util/timetaker.h
index 5512c205f..c10f4f535 100644
--- a/src/util/timetaker.h
+++ b/src/util/timetaker.h
@@ -30,24 +30,24 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class TimeTaker
{
public:
- TimeTaker(const char *name, u32 *result=NULL,
- TimePrecision=PRECISION_MILLI);
+ TimeTaker(const std::string &name, u64 *result=NULL,
+ TimePrecision prec=PRECISION_MILLI);
~TimeTaker()
{
stop();
}
- u32 stop(bool quiet=false);
+ u64 stop(bool quiet=false);
- u32 getTimerTime();
+ u64 getTimerTime();
private:
- const char *m_name;
- u32 m_time1;
+ std::string m_name;
+ u64 m_time1;
bool m_running;
TimePrecision m_precision;
- u32 *m_result;
+ u64 *m_result;
};
#endif
diff --git a/src/voxel.cpp b/src/voxel.cpp
index 87773b240..78efde5bb 100644
--- a/src/voxel.cpp
+++ b/src/voxel.cpp
@@ -27,14 +27,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
/*
Debug stuff
*/
-u32 addarea_time = 0;
-u32 emerge_time = 0;
-u32 emerge_load_time = 0;
-u32 clearflag_time = 0;
-//u32 getwaterpressure_time = 0;
-//u32 spreadwaterpressure_time = 0;
-u32 updateareawaterpressure_time = 0;
-u32 flowwater_pre_time = 0;
+u64 addarea_time = 0;
+u64 emerge_time = 0;
+u64 emerge_load_time = 0;
+u64 clearflag_time = 0;
VoxelManipulator::VoxelManipulator():
diff --git a/src/voxel.h b/src/voxel.h
index 58ad39be4..3a64ccc79 100644
--- a/src/voxel.h
+++ b/src/voxel.h
@@ -49,8 +49,8 @@ class INodeDefManager;
/*
Debug stuff
*/
-extern u32 emerge_time;
-extern u32 emerge_load_time;
+extern u64 emerge_time;
+extern u64 emerge_load_time;
/*
This class resembles aabbox3d<s16> a lot, but has inclusive
diff --git a/src/voxelalgorithms.cpp b/src/voxelalgorithms.cpp
index 93cc33acc..40f8595a7 100644
--- a/src/voxelalgorithms.cpp
+++ b/src/voxelalgorithms.cpp
@@ -423,6 +423,7 @@ void unspread_light(Map *map, INodeDefManager *nodemgr, LightBank bank,
if (step_rel_block_pos(i, neighbor_rel_pos, neighbor_block_pos)) {
neighbor_block = map->getBlockNoCreateNoEx(neighbor_block_pos);
if (neighbor_block == NULL) {
+ current.block->setLightingComplete(bank, i, false);
continue;
}
} else {
@@ -486,7 +487,8 @@ void unspread_light(Map *map, INodeDefManager *nodemgr, LightBank bank,
* \param modified_blocks output, all modified map blocks are added to this
*/
void spread_light(Map *map, INodeDefManager *nodemgr, LightBank bank,
- LightQueue &light_sources, std::map<v3s16, MapBlock*> &modified_blocks)
+ LightQueue &light_sources,
+ std::map<v3s16, MapBlock*> &modified_blocks)
{
// The light the current node can provide to its neighbors.
u8 spreading_light;
@@ -511,6 +513,7 @@ void spread_light(Map *map, INodeDefManager *nodemgr, LightBank bank,
if (step_rel_block_pos(i, neighbor_rel_pos, neighbor_block_pos)) {
neighbor_block = map->getBlockNoCreateNoEx(neighbor_block_pos);
if (neighbor_block == NULL) {
+ current.block->setLightingComplete(bank, i, false);
continue;
}
} else {
@@ -539,6 +542,21 @@ void spread_light(Map *map, INodeDefManager *nodemgr, LightBank bank,
}
}
+struct SunlightPropagationUnit{
+ v2s16 relative_pos;
+ bool is_sunlit;
+
+ SunlightPropagationUnit(v2s16 relpos, bool sunlit):
+ relative_pos(relpos),
+ is_sunlit(sunlit)
+ {}
+};
+
+struct SunlightPropagationData{
+ std::vector<SunlightPropagationUnit> data;
+ v3s16 target_block;
+};
+
/*!
* Returns true if the node gets sunlight from the
* node above it.
@@ -584,10 +602,11 @@ bool is_sunlight_above(Map *map, v3s16 pos, INodeDefManager *ndef)
static const LightBank banks[] = { LIGHTBANK_DAY, LIGHTBANK_NIGHT };
-void update_lighting_nodes(Map *map, INodeDefManager *ndef,
+void update_lighting_nodes(Map *map,
std::vector<std::pair<v3s16, MapNode> > &oldnodes,
std::map<v3s16, MapBlock*> &modified_blocks)
{
+ INodeDefManager *ndef = map->getNodeDefManager();
// For node getter functions
bool is_valid_position;
@@ -596,6 +615,22 @@ void update_lighting_nodes(Map *map, INodeDefManager *ndef,
LightBank bank = banks[i];
UnlightQueue disappearing_lights(256);
ReLightQueue light_sources(256);
+ // Nodes that are brighter than the brightest modified node was
+ // won't change, since they didn't get their light from a
+ // modified node.
+ u8 min_safe_light = 0;
+ for (std::vector<std::pair<v3s16, MapNode> >::iterator it =
+ oldnodes.begin(); it < oldnodes.end(); ++it) {
+ u8 old_light = it->second.getLight(bank, ndef);
+ if (old_light > min_safe_light) {
+ min_safe_light = old_light;
+ }
+ }
+ // If only one node changed, even nodes with the same brightness
+ // didn't get their light from the changed node.
+ if (oldnodes.size() > 1) {
+ min_safe_light++;
+ }
// For each changed node process sunlight and initialize
for (std::vector<std::pair<v3s16, MapNode> >::iterator it =
oldnodes.begin(); it < oldnodes.end(); ++it) {
@@ -634,11 +669,9 @@ void update_lighting_nodes(Map *map, INodeDefManager *ndef,
MapNode n2 = map->getNodeNoEx(p2, &is_valid);
if (is_valid) {
u8 spread = n2.getLight(bank, ndef);
- // If the neighbor is at least as bright as
- // this node then its light is not from
- // this node.
- // Its light can spread to this node.
- if (spread > new_light && spread >= old_light) {
+ // If it is sure that the neighbor won't be
+ // unlighted, its light can spread to this node.
+ if (spread > new_light && spread >= min_safe_light) {
new_light = spread - 1;
}
}
@@ -735,7 +768,129 @@ void update_lighting_nodes(Map *map, INodeDefManager *ndef,
for (u8 i = 0; i <= LIGHT_SUN; i++) {
const std::vector<ChangingLight> &lights = light_sources.lights[i];
for (std::vector<ChangingLight>::const_iterator it = lights.begin();
- it < lights.end(); it++) {
+ it < lights.end(); ++it) {
+ MapNode n = it->block->getNodeNoCheck(it->rel_position,
+ &is_valid_position);
+ n.setLight(bank, i, ndef);
+ it->block->setNodeNoCheck(it->rel_position, n);
+ }
+ }
+ // Spread lights.
+ spread_light(map, ndef, bank, light_sources, modified_blocks);
+ }
+}
+
+/*!
+ * Borders of a map block in relative node coordinates.
+ * Compatible with type 'direction'.
+ */
+const VoxelArea block_borders[] = {
+ VoxelArea(v3s16(15, 0, 0), v3s16(15, 15, 15)), //X+
+ VoxelArea(v3s16(0, 15, 0), v3s16(15, 15, 15)), //Y+
+ VoxelArea(v3s16(0, 0, 15), v3s16(15, 15, 15)), //Z+
+ VoxelArea(v3s16(0, 0, 0), v3s16(15, 15, 0)), //Z-
+ VoxelArea(v3s16(0, 0, 0), v3s16(15, 0, 15)), //Y-
+ VoxelArea(v3s16(0, 0, 0), v3s16(0, 15, 15)) //X-
+};
+
+/*!
+ * Returns true if:
+ * -the node has unloaded neighbors
+ * -the node doesn't have light
+ * -the node's light is the same as the maximum of
+ * its light source and its brightest neighbor minus one.
+ * .
+ */
+bool is_light_locally_correct(Map *map, INodeDefManager *ndef, LightBank bank,
+ v3s16 pos)
+{
+ bool is_valid_position;
+ MapNode n = map->getNodeNoEx(pos, &is_valid_position);
+ const ContentFeatures &f = ndef->get(n);
+ if (f.param_type != CPT_LIGHT) {
+ return true;
+ }
+ u8 light = n.getLightNoChecks(bank, &f);
+ assert(f.light_source <= LIGHT_MAX);
+ u8 brightest_neighbor = f.light_source + 1;
+ for (direction d = 0; d < 6; ++d) {
+ MapNode n2 = map->getNodeNoEx(pos + neighbor_dirs[d],
+ &is_valid_position);
+ u8 light2 = n2.getLight(bank, ndef);
+ if (brightest_neighbor < light2) {
+ brightest_neighbor = light2;
+ }
+ }
+ assert(light <= LIGHT_SUN);
+ return brightest_neighbor == light + 1;
+}
+
+void update_block_border_lighting(Map *map, MapBlock *block,
+ std::map<v3s16, MapBlock*> &modified_blocks)
+{
+ INodeDefManager *ndef = map->getNodeDefManager();
+ bool is_valid_position;
+ for (s32 i = 0; i < 2; i++) {
+ LightBank bank = banks[i];
+ // Since invalid light is not common, do not allocate
+ // memory if not needed.
+ UnlightQueue disappearing_lights(0);
+ ReLightQueue light_sources(0);
+ // Get incorrect lights
+ for (direction d = 0; d < 6; d++) {
+ // For each direction
+ // Get neighbor block
+ v3s16 otherpos = block->getPos() + neighbor_dirs[d];
+ MapBlock *other = map->getBlockNoCreateNoEx(otherpos);
+ if (other == NULL) {
+ continue;
+ }
+ // Only update if lighting was not completed.
+ if (block->isLightingComplete(bank, d) &&
+ other->isLightingComplete(bank, 5 - d))
+ continue;
+ // Reset flags
+ block->setLightingComplete(bank, d, true);
+ other->setLightingComplete(bank, 5 - d, true);
+ // The two blocks and their connecting surfaces
+ MapBlock *blocks[] = {block, other};
+ VoxelArea areas[] = {block_borders[d], block_borders[5 - d]};
+ // For both blocks
+ for (u8 blocknum = 0; blocknum < 2; blocknum++) {
+ MapBlock *b = blocks[blocknum];
+ VoxelArea a = areas[blocknum];
+ // For all nodes
+ for (s32 x = a.MinEdge.X; x <= a.MaxEdge.X; x++)
+ for (s32 z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++)
+ for (s32 y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
+ MapNode n = b->getNodeNoCheck(x, y, z,
+ &is_valid_position);
+ u8 light = n.getLight(bank, ndef);
+ // Sunlight is fixed
+ if (light < LIGHT_SUN) {
+ // Unlight if not correct
+ if (!is_light_locally_correct(map, ndef, bank,
+ v3s16(x, y, z) + b->getPosRelative())) {
+ // Initialize for unlighting
+ n.setLight(bank, 0, ndef);
+ b->setNodeNoCheck(x, y, z, n);
+ modified_blocks[b->getPos()]=b;
+ disappearing_lights.push(light,
+ relative_v3(x, y, z), b->getPos(), b,
+ 6);
+ }
+ }
+ }
+ }
+ }
+ // Remove lights
+ unspread_light(map, ndef, bank, disappearing_lights, light_sources,
+ modified_blocks);
+ // Initialize light values for light spreading.
+ for (u8 i = 0; i <= LIGHT_SUN; i++) {
+ const std::vector<ChangingLight> &lights = light_sources.lights[i];
+ for (std::vector<ChangingLight>::const_iterator it = lights.begin();
+ it < lights.end(); ++it) {
MapNode n = it->block->getNodeNoCheck(it->rel_position,
&is_valid_position);
n.setLight(bank, i, ndef);
@@ -747,5 +902,573 @@ void update_lighting_nodes(Map *map, INodeDefManager *ndef,
}
}
+/*!
+ * Resets the lighting of the given VoxelManipulator to
+ * complete darkness and full sunlight.
+ * Operates in one map sector.
+ *
+ * \param offset contains the least x and z node coordinates
+ * of the map sector.
+ * \param light incoming sunlight, light[x][z] is true if there
+ * is sunlight above the voxel manipulator at the given x-z coordinates.
+ * The array's indices are relative node coordinates in the sector.
+ * After the procedure returns, this contains outgoing light at
+ * the bottom of the voxel manipulator.
+ */
+void fill_with_sunlight(MMVManip *vm, INodeDefManager *ndef, v2s16 offset,
+ bool light[MAP_BLOCKSIZE][MAP_BLOCKSIZE])
+{
+ // Distance in array between two nodes on top of each other.
+ s16 ystride = vm->m_area.getExtent().X;
+ // Cache the ignore node.
+ MapNode ignore = MapNode(CONTENT_IGNORE);
+ // For each column of nodes:
+ for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
+ for (s16 x = 0; x < MAP_BLOCKSIZE; x++) {
+ // Position of the column on the map.
+ v2s16 realpos = offset + v2s16(x, z);
+ // Array indices in the voxel manipulator
+ s32 maxindex = vm->m_area.index(realpos.X, vm->m_area.MaxEdge.Y,
+ realpos.Y);
+ s32 minindex = vm->m_area.index(realpos.X, vm->m_area.MinEdge.Y,
+ realpos.Y);
+ // True if the current node has sunlight.
+ bool lig = light[z][x];
+ // For each node, downwards:
+ for (s32 i = maxindex; i >= minindex; i -= ystride) {
+ MapNode *n;
+ if (vm->m_flags[i] & VOXELFLAG_NO_DATA)
+ n = &ignore;
+ else
+ n = &vm->m_data[i];
+ // Ignore IGNORE nodes, these are not generated yet.
+ if(n->getContent() == CONTENT_IGNORE)
+ continue;
+ const ContentFeatures &f = ndef->get(n->getContent());
+ if (lig && !f.sunlight_propagates)
+ // Sunlight is stopped.
+ lig = false;
+ // Reset light
+ n->setLight(LIGHTBANK_DAY, lig ? 15 : 0, f);
+ n->setLight(LIGHTBANK_NIGHT, 0, f);
+ }
+ // Output outgoing light.
+ light[z][x] = lig;
+ }
+}
+
+/*!
+ * Returns incoming sunlight for one map block.
+ * If block above is not found, it is loaded.
+ *
+ * \param pos position of the map block that gets the sunlight.
+ * \param light incoming sunlight, light[z][x] is true if there
+ * is sunlight above the block at the given z-x relative
+ * node coordinates.
+ */
+void is_sunlight_above_block(ServerMap *map, mapblock_v3 pos,
+ INodeDefManager *ndef, bool light[MAP_BLOCKSIZE][MAP_BLOCKSIZE])
+{
+ mapblock_v3 source_block_pos = pos + v3s16(0, 1, 0);
+ // Get or load source block.
+ // It might take a while to load, but correcting incorrect
+ // sunlight may be even slower.
+ MapBlock *source_block = map->emergeBlock(source_block_pos, false);
+ // Trust only generated blocks.
+ if (source_block == NULL || source_block->isDummy()
+ || !source_block->isGenerated()) {
+ // But if there is no block above, then use heuristics
+ bool sunlight = true;
+ MapBlock *node_block = map->getBlockNoCreateNoEx(pos);
+ if (node_block == NULL)
+ // This should not happen.
+ sunlight = false;
+ else
+ sunlight = !node_block->getIsUnderground();
+ for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
+ for (s16 x = 0; x < MAP_BLOCKSIZE; x++)
+ light[z][x] = sunlight;
+ } else {
+ // Dummy boolean, the position is valid.
+ bool is_valid_position;
+ // For each column:
+ for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
+ for (s16 x = 0; x < MAP_BLOCKSIZE; x++) {
+ // Get the bottom block.
+ MapNode above = source_block->getNodeNoCheck(x, 0, z,
+ &is_valid_position);
+ light[z][x] = above.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN;
+ }
+ }
+}
+
+/*!
+ * Propagates sunlight down in a given map block.
+ *
+ * \param data contains incoming sunlight and shadow and
+ * the coordinates of the target block.
+ * \param unlight propagated shadow is inserted here
+ * \param relight propagated sunlight is inserted here
+ *
+ * \returns true if the block was modified, false otherwise.
+ */
+bool propagate_block_sunlight(Map *map, INodeDefManager *ndef,
+ SunlightPropagationData *data, UnlightQueue *unlight, ReLightQueue *relight)
+{
+ bool modified = false;
+ // Get the block.
+ MapBlock *block = map->getBlockNoCreateNoEx(data->target_block);
+ if (block == NULL || block->isDummy()) {
+ // The work is done if the block does not contain data.
+ data->data.clear();
+ return false;
+ }
+ // Dummy boolean
+ bool is_valid;
+ // For each changing column of nodes:
+ size_t index;
+ for (index = 0; index < data->data.size(); index++) {
+ SunlightPropagationUnit it = data->data[index];
+ // Relative position of the currently inspected node.
+ relative_v3 current_pos(it.relative_pos.X, MAP_BLOCKSIZE - 1,
+ it.relative_pos.Y);
+ if (it.is_sunlit) {
+ // Propagate sunlight.
+ // For each node downwards:
+ for (; current_pos.Y >= 0; current_pos.Y--) {
+ MapNode n = block->getNodeNoCheck(current_pos, &is_valid);
+ const ContentFeatures &f = ndef->get(n);
+ if (n.getLightRaw(LIGHTBANK_DAY, f) < LIGHT_SUN
+ && f.sunlight_propagates) {
+ // This node gets sunlight.
+ n.setLight(LIGHTBANK_DAY, LIGHT_SUN, f);
+ block->setNodeNoCheck(current_pos, n);
+ modified = true;
+ relight->push(LIGHT_SUN, current_pos, data->target_block,
+ block, 4);
+ } else {
+ // Light already valid, propagation stopped.
+ break;
+ }
+ }
+ } else {
+ // Propagate shadow.
+ // For each node downwards:
+ for (; current_pos.Y >= 0; current_pos.Y--) {
+ MapNode n = block->getNodeNoCheck(current_pos, &is_valid);
+ const ContentFeatures &f = ndef->get(n);
+ if (n.getLightRaw(LIGHTBANK_DAY, f) == LIGHT_SUN) {
+ // The sunlight is no longer valid.
+ n.setLight(LIGHTBANK_DAY, 0, f);
+ block->setNodeNoCheck(current_pos, n);
+ modified = true;
+ unlight->push(LIGHT_SUN, current_pos, data->target_block,
+ block, 4);
+ } else {
+ // Reached shadow, propagation stopped.
+ break;
+ }
+ }
+ }
+ if (current_pos.Y >= 0) {
+ // Propagation stopped, remove from data.
+ data->data[index] = data->data.back();
+ data->data.pop_back();
+ index--;
+ }
+ }
+ return modified;
+}
+
+/*!
+ * Borders of a map block in relative node coordinates.
+ * The areas do not overlap.
+ * Compatible with type 'direction'.
+ */
+const VoxelArea block_pad[] = {
+ VoxelArea(v3s16(15, 0, 0), v3s16(15, 15, 15)), //X+
+ VoxelArea(v3s16(1, 15, 0), v3s16(14, 15, 15)), //Y+
+ VoxelArea(v3s16(1, 1, 15), v3s16(14, 14, 15)), //Z+
+ VoxelArea(v3s16(1, 1, 0), v3s16(14, 14, 0)), //Z-
+ VoxelArea(v3s16(1, 0, 0), v3s16(14, 0, 15)), //Y-
+ VoxelArea(v3s16(0, 0, 0), v3s16(0, 15, 15)) //X-
+};
+
+/*!
+ * The common part of bulk light updates - it is always executed.
+ * The procedure takes the nodes that should be unlit, and the
+ * full modified area.
+ *
+ * The procedure handles the correction of all lighting except
+ * direct sunlight spreading.
+ *
+ * \param minblock least coordinates of the changed area in block
+ * coordinates
+ * \param maxblock greatest coordinates of the changed area in block
+ * coordinates
+ * \param unlight the first queue is for day light, the second is for
+ * night light. Contains all nodes on the borders that need to be unlit.
+ * \param relight the first queue is for day light, the second is for
+ * night light. Contains nodes that were not modified, but got sunlight
+ * because the changes.
+ * \param modified_blocks the procedure adds all modified blocks to
+ * this map
+ */
+void finish_bulk_light_update(Map *map, mapblock_v3 minblock,
+ mapblock_v3 maxblock, UnlightQueue unlight[2], ReLightQueue relight[2],
+ std::map<v3s16, MapBlock*> *modified_blocks)
+{
+ INodeDefManager *ndef = map->getNodeDefManager();
+ // dummy boolean
+ bool is_valid;
+
+ // --- STEP 1: Do unlighting
+
+ for (size_t bank = 0; bank < 2; bank++) {
+ LightBank b = banks[bank];
+ unspread_light(map, ndef, b, unlight[bank], relight[bank],
+ *modified_blocks);
+ }
+
+ // --- STEP 2: Get all newly inserted light sources
+
+ // For each block:
+ for (s16 b_x = minblock.X; b_x <= maxblock.X; b_x++)
+ for (s16 b_y = minblock.Y; b_y <= maxblock.Y; b_y++)
+ for (s16 b_z = minblock.Z; b_z <= maxblock.Z; b_z++) {
+ const v3s16 blockpos(b_x, b_y, b_z);
+ MapBlock *block = map->getBlockNoCreateNoEx(blockpos);
+ if (!block || block->isDummy())
+ // Skip not existing blocks
+ continue;
+ // For each node in the block:
+ for (s32 x = 0; x < MAP_BLOCKSIZE; x++)
+ for (s32 z = 0; z < MAP_BLOCKSIZE; z++)
+ for (s32 y = 0; y < MAP_BLOCKSIZE; y++) {
+ v3s16 relpos(x, y, z);
+ MapNode node = block->getNodeNoCheck(x, y, z, &is_valid);
+ const ContentFeatures &f = ndef->get(node);
+ // For each light bank
+ for (size_t b = 0; b < 2; b++) {
+ LightBank bank = banks[b];
+ u8 light = f.param_type == CPT_LIGHT ?
+ node.getLightNoChecks(bank, &f):
+ f.light_source;
+ if (light > 1)
+ relight[b].push(light, relpos, blockpos, block, 6);
+ } // end of banks
+ } // end of nodes
+ } // end of blocks
+
+ // --- STEP 3: do light spreading
+
+ // For each light bank:
+ for (size_t b = 0; b < 2; b++) {
+ LightBank bank = banks[b];
+ // Sunlight is already initialized.
+ u8 maxlight = (b == 0) ? LIGHT_MAX : LIGHT_SUN;
+ // Initialize light values for light spreading.
+ for (u8 i = 0; i <= maxlight; i++) {
+ const std::vector<ChangingLight> &lights = relight[b].lights[i];
+ for (std::vector<ChangingLight>::const_iterator it = lights.begin();
+ it < lights.end(); ++it) {
+ MapNode n = it->block->getNodeNoCheck(it->rel_position,
+ &is_valid);
+ n.setLight(bank, i, ndef);
+ it->block->setNodeNoCheck(it->rel_position, n);
+ }
+ }
+ // Spread lights.
+ spread_light(map, ndef, bank, relight[b], *modified_blocks);
+ }
+}
+
+void blit_back_with_light(ServerMap *map, MMVManip *vm,
+ std::map<v3s16, MapBlock*> *modified_blocks)
+{
+ INodeDefManager *ndef = map->getNodeDefManager();
+ mapblock_v3 minblock = getNodeBlockPos(vm->m_area.MinEdge);
+ mapblock_v3 maxblock = getNodeBlockPos(vm->m_area.MaxEdge);
+ // First queue is for day light, second is for night light.
+ UnlightQueue unlight[] = { UnlightQueue(256), UnlightQueue(256) };
+ ReLightQueue relight[] = { ReLightQueue(256), ReLightQueue(256) };
+ // Will hold sunlight data.
+ bool lights[MAP_BLOCKSIZE][MAP_BLOCKSIZE];
+ SunlightPropagationData data;
+ // Dummy boolean.
+ bool is_valid;
+
+ // --- STEP 1: reset everything to sunlight
+
+ // For each map block:
+ for (s16 x = minblock.X; x <= maxblock.X; x++)
+ for (s16 z = minblock.Z; z <= maxblock.Z; z++) {
+ // Extract sunlight above.
+ is_sunlight_above_block(map, v3s16(x, maxblock.Y, z), ndef, lights);
+ v2s16 offset(x, z);
+ offset *= MAP_BLOCKSIZE;
+ // Reset the voxel manipulator.
+ fill_with_sunlight(vm, ndef, offset, lights);
+ // Copy sunlight data
+ data.target_block = v3s16(x, minblock.Y - 1, z);
+ for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
+ for (s16 x = 0; x < MAP_BLOCKSIZE; x++)
+ data.data.push_back(
+ SunlightPropagationUnit(v2s16(x, z), lights[z][x]));
+ // Propagate sunlight and shadow below the voxel manipulator.
+ while (!data.data.empty()) {
+ if (propagate_block_sunlight(map, ndef, &data, &unlight[0],
+ &relight[0]))
+ (*modified_blocks)[data.target_block] =
+ map->getBlockNoCreateNoEx(data.target_block);
+ // Step downwards.
+ data.target_block.Y--;
+ }
+ }
+
+ // --- STEP 2: Get nodes from borders to unlight
+
+ // In case there are unloaded holes in the voxel manipulator
+ // unlight each block.
+ // For each block:
+ for (s16 b_x = minblock.X; b_x <= maxblock.X; b_x++)
+ for (s16 b_y = minblock.Y; b_y <= maxblock.Y; b_y++)
+ for (s16 b_z = minblock.Z; b_z <= maxblock.Z; b_z++) {
+ v3s16 blockpos(b_x, b_y, b_z);
+ MapBlock *block = map->getBlockNoCreateNoEx(blockpos);
+ if (!block || block->isDummy())
+ // Skip not existing blocks.
+ continue;
+ v3s16 offset = block->getPosRelative();
+ // For each border of the block:
+ for (direction d = 0; d < 6; d++) {
+ VoxelArea a = block_pad[d];
+ // For each node of the border:
+ for (s32 x = a.MinEdge.X; x <= a.MaxEdge.X; x++)
+ for (s32 z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++)
+ for (s32 y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
+ v3s16 relpos(x, y, z);
+ // Get old and new node
+ MapNode oldnode = block->getNodeNoCheck(x, y, z, &is_valid);
+ const ContentFeatures &oldf = ndef->get(oldnode);
+ MapNode newnode = vm->getNodeNoExNoEmerge(relpos + offset);
+ const ContentFeatures &newf = ndef->get(newnode);
+ // For each light bank
+ for (size_t b = 0; b < 2; b++) {
+ LightBank bank = banks[b];
+ u8 oldlight = oldf.param_type == CPT_LIGHT ?
+ oldnode.getLightNoChecks(bank, &oldf):
+ LIGHT_SUN; // no light information, force unlighting
+ u8 newlight = newf.param_type == CPT_LIGHT ?
+ newnode.getLightNoChecks(bank, &newf):
+ newf.light_source;
+ // If the new node is dimmer, unlight.
+ if (oldlight > newlight) {
+ unlight[b].push(
+ oldlight, relpos, blockpos, block, 6);
+ }
+ } // end of banks
+ } // end of nodes
+ } // end of borders
+ } // end of blocks
+
+ // --- STEP 3: All information extracted, overwrite
+
+ vm->blitBackAll(modified_blocks, true);
+
+ // --- STEP 4: Finish light update
+
+ finish_bulk_light_update(map, minblock, maxblock, unlight, relight,
+ modified_blocks);
+}
+
+/*!
+ * Resets the lighting of the given map block to
+ * complete darkness and full sunlight.
+ *
+ * \param light incoming sunlight, light[x][z] is true if there
+ * is sunlight above the map block at the given x-z coordinates.
+ * The array's indices are relative node coordinates in the block.
+ * After the procedure returns, this contains outgoing light at
+ * the bottom of the map block.
+ */
+void fill_with_sunlight(MapBlock *block, INodeDefManager *ndef,
+ bool light[MAP_BLOCKSIZE][MAP_BLOCKSIZE])
+{
+ if (block->isDummy())
+ return;
+ // dummy boolean
+ bool is_valid;
+ // For each column of nodes:
+ for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
+ for (s16 x = 0; x < MAP_BLOCKSIZE; x++) {
+ // True if the current node has sunlight.
+ bool lig = light[z][x];
+ // For each node, downwards:
+ for (s16 y = MAP_BLOCKSIZE - 1; y >= 0; y--) {
+ MapNode n = block->getNodeNoCheck(x, y, z, &is_valid);
+ // Ignore IGNORE nodes, these are not generated yet.
+ if (n.getContent() == CONTENT_IGNORE)
+ continue;
+ const ContentFeatures &f = ndef->get(n.getContent());
+ if (lig && !f.sunlight_propagates) {
+ // Sunlight is stopped.
+ lig = false;
+ }
+ // Reset light
+ n.setLight(LIGHTBANK_DAY, lig ? 15 : 0, f);
+ n.setLight(LIGHTBANK_NIGHT, 0, f);
+ block->setNodeNoCheck(x, y, z, n);
+ }
+ // Output outgoing light.
+ light[z][x] = lig;
+ }
+}
+
+void repair_block_light(ServerMap *map, MapBlock *block,
+ std::map<v3s16, MapBlock*> *modified_blocks)
+{
+ if (!block || block->isDummy())
+ return;
+ INodeDefManager *ndef = map->getNodeDefManager();
+ // First queue is for day light, second is for night light.
+ UnlightQueue unlight[] = { UnlightQueue(256), UnlightQueue(256) };
+ ReLightQueue relight[] = { ReLightQueue(256), ReLightQueue(256) };
+ // Will hold sunlight data.
+ bool lights[MAP_BLOCKSIZE][MAP_BLOCKSIZE];
+ SunlightPropagationData data;
+ // Dummy boolean.
+ bool is_valid;
+
+ // --- STEP 1: reset everything to sunlight
+
+ mapblock_v3 blockpos = block->getPos();
+ (*modified_blocks)[blockpos] = block;
+ // For each map block:
+ // Extract sunlight above.
+ is_sunlight_above_block(map, blockpos, ndef, lights);
+ // Reset the voxel manipulator.
+ fill_with_sunlight(block, ndef, lights);
+ // Copy sunlight data
+ data.target_block = v3s16(blockpos.X, blockpos.Y - 1, blockpos.Z);
+ for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
+ for (s16 x = 0; x < MAP_BLOCKSIZE; x++) {
+ data.data.push_back(
+ SunlightPropagationUnit(v2s16(x, z), lights[z][x]));
+ }
+ // Propagate sunlight and shadow below the voxel manipulator.
+ while (!data.data.empty()) {
+ if (propagate_block_sunlight(map, ndef, &data, &unlight[0],
+ &relight[0]))
+ (*modified_blocks)[data.target_block] =
+ map->getBlockNoCreateNoEx(data.target_block);
+ // Step downwards.
+ data.target_block.Y--;
+ }
+
+ // --- STEP 2: Get nodes from borders to unlight
+
+ // For each border of the block:
+ for (direction d = 0; d < 6; d++) {
+ VoxelArea a = block_pad[d];
+ // For each node of the border:
+ for (s32 x = a.MinEdge.X; x <= a.MaxEdge.X; x++)
+ for (s32 z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++)
+ for (s32 y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
+ v3s16 relpos(x, y, z);
+ // Get node
+ MapNode node = block->getNodeNoCheck(x, y, z, &is_valid);
+ const ContentFeatures &f = ndef->get(node);
+ // For each light bank
+ for (size_t b = 0; b < 2; b++) {
+ LightBank bank = banks[b];
+ u8 light = f.param_type == CPT_LIGHT ?
+ node.getLightNoChecks(bank, &f):
+ f.light_source;
+ // If the new node is dimmer than sunlight, unlight.
+ // (if it has maximal light, it is pointless to remove
+ // surrounding light, as it can only become brighter)
+ if (LIGHT_SUN > light) {
+ unlight[b].push(
+ LIGHT_SUN, relpos, blockpos, block, 6);
+ }
+ } // end of banks
+ } // end of nodes
+ } // end of borders
+
+ // STEP 3: Remove and spread light
+
+ finish_bulk_light_update(map, blockpos, blockpos, unlight, relight,
+ modified_blocks);
+}
+
+VoxelLineIterator::VoxelLineIterator(
+ const v3f &start_position,
+ const v3f &line_vector) :
+ m_start_position(start_position),
+ m_line_vector(line_vector),
+ m_next_intersection_multi(10000.0f, 10000.0f, 10000.0f),
+ m_intersection_multi_inc(10000.0f, 10000.0f, 10000.0f),
+ m_step_directions(1.0f, 1.0f, 1.0f)
+{
+ m_current_node_pos = floatToInt(m_start_position, 1);
+
+ if (m_line_vector.X > 0) {
+ m_next_intersection_multi.X = (floorf(m_start_position.X - 0.5) + 1.5
+ - m_start_position.X) / m_line_vector.X;
+ m_intersection_multi_inc.X = 1 / m_line_vector.X;
+ } else if (m_line_vector.X < 0) {
+ m_next_intersection_multi.X = (floorf(m_start_position.X - 0.5)
+ - m_start_position.X + 0.5) / m_line_vector.X;
+ m_intersection_multi_inc.X = -1 / m_line_vector.X;
+ m_step_directions.X = -1;
+ }
+
+ if (m_line_vector.Y > 0) {
+ m_next_intersection_multi.Y = (floorf(m_start_position.Y - 0.5) + 1.5
+ - m_start_position.Y) / m_line_vector.Y;
+ m_intersection_multi_inc.Y = 1 / m_line_vector.Y;
+ } else if (m_line_vector.Y < 0) {
+ m_next_intersection_multi.Y = (floorf(m_start_position.Y - 0.5)
+ - m_start_position.Y + 0.5) / m_line_vector.Y;
+ m_intersection_multi_inc.Y = -1 / m_line_vector.Y;
+ m_step_directions.Y = -1;
+ }
+
+ if (m_line_vector.Z > 0) {
+ m_next_intersection_multi.Z = (floorf(m_start_position.Z - 0.5) + 1.5
+ - m_start_position.Z) / m_line_vector.Z;
+ m_intersection_multi_inc.Z = 1 / m_line_vector.Z;
+ } else if (m_line_vector.Z < 0) {
+ m_next_intersection_multi.Z = (floorf(m_start_position.Z - 0.5)
+ - m_start_position.Z + 0.5) / m_line_vector.Z;
+ m_intersection_multi_inc.Z = -1 / m_line_vector.Z;
+ m_step_directions.Z = -1;
+ }
+
+ m_has_next = (m_next_intersection_multi.X <= 1)
+ || (m_next_intersection_multi.Y <= 1)
+ || (m_next_intersection_multi.Z <= 1);
+}
+
+void VoxelLineIterator::next()
+{
+ if ((m_next_intersection_multi.X < m_next_intersection_multi.Y)
+ && (m_next_intersection_multi.X < m_next_intersection_multi.Z)) {
+ m_next_intersection_multi.X += m_intersection_multi_inc.X;
+ m_current_node_pos.X += m_step_directions.X;
+ } else if ((m_next_intersection_multi.Y < m_next_intersection_multi.Z)) {
+ m_next_intersection_multi.Y += m_intersection_multi_inc.Y;
+ m_current_node_pos.Y += m_step_directions.Y;
+ } else {
+ m_next_intersection_multi.Z += m_intersection_multi_inc.Z;
+ m_current_node_pos.Z += m_step_directions.Z;
+ }
+
+ m_has_next = (m_next_intersection_multi.X <= 1)
+ || (m_next_intersection_multi.Y <= 1)
+ || (m_next_intersection_multi.Z <= 1);
+}
+
} // namespace voxalgo
diff --git a/src/voxelalgorithms.h b/src/voxelalgorithms.h
index 3632546dd..b518979d7 100644
--- a/src/voxelalgorithms.h
+++ b/src/voxelalgorithms.h
@@ -22,11 +22,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "voxel.h"
#include "mapnode.h"
-#include <set>
-#include <map>
+#include "util/container.h"
+#include "util/cpp11_container.h"
class Map;
+class ServerMap;
class MapBlock;
+class MMVManip;
namespace voxalgo
{
@@ -69,11 +71,103 @@ SunlightPropagateResult propagateSunlight(VoxelManipulator &v, VoxelArea a,
*/
void update_lighting_nodes(
Map *map,
- INodeDefManager *ndef,
std::vector<std::pair<v3s16, MapNode> > &oldnodes,
std::map<v3s16, MapBlock*> &modified_blocks);
+/*!
+ * Updates borders of the given mapblock.
+ * Only updates if the block was marked with incomplete
+ * lighting and the neighbor is also loaded.
+ *
+ * \param block the block to update
+ * \param modified_blocks output, contains all map blocks that
+ * the function modified
+ */
+void update_block_border_lighting(Map *map, MapBlock *block,
+ std::map<v3s16, MapBlock*> &modified_blocks);
+
+/*!
+ * Copies back nodes from a voxel manipulator
+ * to the map and updates lighting.
+ * For server use only.
+ *
+ * \param modified_blocks output, contains all map blocks that
+ * the function modified
+ */
+void blit_back_with_light(ServerMap *map, MMVManip *vm,
+ std::map<v3s16, MapBlock*> *modified_blocks);
+
+/*!
+ * Corrects the light in a map block.
+ * For server use only.
+ *
+ * \param block the block to update
+ */
+void repair_block_light(ServerMap *map, MapBlock *block,
+ std::map<v3s16, MapBlock*> *modified_blocks);
+
+/*!
+ * This class iterates trough voxels that intersect with
+ * a line. The collision detection does not see nodeboxes,
+ * every voxel is a cube and is returned.
+ * This iterator steps to all nodes exactly once.
+ */
+struct VoxelLineIterator
+{
+public:
+ //! Starting position of the line in world coordinates.
+ v3f m_start_position;
+ //! Direction and length of the line in world coordinates.
+ v3f m_line_vector;
+ /*!
+ * Each component stores the next smallest positive number, by
+ * which multiplying the line's vector gives a vector that ends
+ * on the intersection of two nodes.
+ */
+ v3f m_next_intersection_multi;
+ /*!
+ * Each component stores the smallest positive number, by which
+ * m_next_intersection_multi's components can be increased.
+ */
+ v3f m_intersection_multi_inc;
+ /*!
+ * Direction of the line. Each component can be -1 or 1 (if a
+ * component of the line's vector is 0, then there will be 1).
+ */
+ v3s16 m_step_directions;
+ //! Position of the current node.
+ v3s16 m_current_node_pos;
+ //! If true, the next node will intersect the line, too.
+ bool m_has_next;
+
+ /*!
+ * Creates a voxel line iterator with the given line.
+ * @param start_position starting point of the line
+ * in voxel coordinates
+ * @param line_vector length and direction of the
+ * line in voxel coordinates. start_position+line_vector
+ * is the end of the line
+ */
+ VoxelLineIterator(const v3f &start_position,const v3f &line_vector);
+
+ /*!
+ * Steps to the next voxel.
+ * Updates m_current_node_pos and
+ * m_previous_node_pos.
+ * Note that it works even if hasNext() is false,
+ * continuing the line as a ray.
+ */
+ void next();
+
+ /*!
+ * Returns true if the next voxel intersects the given line.
+ */
+ inline bool hasNext() const { return m_has_next; }
+};
+
} // namespace voxalgo
+
+
#endif
diff --git a/src/wieldmesh.cpp b/src/wieldmesh.cpp
index 9c4d5b642..7736ec2a2 100644
--- a/src/wieldmesh.cpp
+++ b/src/wieldmesh.cpp
@@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "wieldmesh.h"
#include "inventory.h"
-#include "gamedef.h"
+#include "client.h"
#include "itemdef.h"
#include "nodedef.h"
#include "mesh.h"
@@ -235,27 +235,16 @@ WieldMeshSceneNode::~WieldMeshSceneNode()
g_extrusion_mesh_cache = NULL;
}
-void WieldMeshSceneNode::setCube(const TileSpec tiles[6],
+void WieldMeshSceneNode::setCube(const ContentFeatures &f,
v3f wield_scale, ITextureSource *tsrc)
{
scene::IMesh *cubemesh = g_extrusion_mesh_cache->createCube();
- changeToMesh(cubemesh);
+ scene::SMesh *copy = cloneMesh(cubemesh);
cubemesh->drop();
-
+ postProcessNodeMesh(copy, f, false, true, &m_material_type, &m_colors);
+ changeToMesh(copy);
+ copy->drop();
m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR);
-
- // Customize materials
- for (u32 i = 0; i < m_meshnode->getMaterialCount(); ++i) {
- assert(i < 6);
- video::SMaterial &material = m_meshnode->getMaterial(i);
- if (tiles[i].animation_frame_count == 1) {
- material.setTexture(0, tiles[i].texture);
- } else {
- FrameSpec animation_frame = tiles[i].frames[0];
- material.setTexture(0, animation_frame.texture);
- }
- tiles[i].applyMaterialOptions(material);
- }
}
void WieldMeshSceneNode::setExtruded(const std::string &imagename,
@@ -274,8 +263,10 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
dim = core::dimension2d<u32>(dim.Width, frame_height);
}
scene::IMesh *mesh = g_extrusion_mesh_cache->create(dim);
- changeToMesh(mesh);
+ scene::SMesh *copy = cloneMesh(mesh);
mesh->drop();
+ changeToMesh(copy);
+ copy->drop();
m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR_EXTRUDED);
@@ -283,7 +274,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
video::SMaterial &material = m_meshnode->getMaterial(0);
material.setTexture(0, tsrc->getTextureForMesh(imagename));
material.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
- material.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
+ material.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
material.MaterialType = m_material_type;
material.setFlag(video::EMF_BACK_FACE_CULLING, true);
// Enable bi/trilinear filtering only for high resolution textures
@@ -304,12 +295,12 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
}
}
-void WieldMeshSceneNode::setItem(const ItemStack &item, IGameDef *gamedef)
+void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client)
{
- ITextureSource *tsrc = gamedef->getTextureSource();
- IItemDefManager *idef = gamedef->getItemDefManager();
- IShaderSource *shdrsrc = gamedef->getShaderSource();
- INodeDefManager *ndef = gamedef->getNodeDefManager();
+ ITextureSource *tsrc = client->getTextureSource();
+ IItemDefManager *idef = client->getItemDefManager();
+ IShaderSource *shdrsrc = client->getShaderSource();
+ INodeDefManager *ndef = client->getNodeDefManager();
const ItemDefinition &def = item.getDefinition(idef);
const ContentFeatures &f = ndef->get(def.name);
content_t id = ndef->getId(def.name);
@@ -319,9 +310,14 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, IGameDef *gamedef)
m_material_type = shdrsrc->getShaderInfo(shader_id).material;
}
+ // Color-related
+ m_colors.clear();
+ m_base_color = idef->getItemstackColor(item, client);
+
// If wield_image is defined, it overrides everything else
if (def.wield_image != "") {
setExtruded(def.wield_image, def.wield_scale, tsrc, 1);
+ m_colors.push_back(ItemPartColor());
return;
}
// Handle nodes
@@ -329,63 +325,50 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, IGameDef *gamedef)
else if (def.type == ITEM_NODE) {
if (f.mesh_ptr[0]) {
// e.g. mesh nodes and nodeboxes
- changeToMesh(f.mesh_ptr[0]);
- // mesh_ptr[0] is pre-scaled by BS * f->visual_scale
+ scene::SMesh *mesh = cloneMesh(f.mesh_ptr[0]);
+ postProcessNodeMesh(mesh, f, m_enable_shaders, true,
+ &m_material_type, &m_colors);
+ changeToMesh(mesh);
+ mesh->drop();
+ // mesh is pre-scaled by BS * f->visual_scale
m_meshnode->setScale(
def.wield_scale * WIELD_SCALE_FACTOR
/ (BS * f.visual_scale));
} else if (f.drawtype == NDT_AIRLIKE) {
changeToMesh(NULL);
} else if (f.drawtype == NDT_PLANTLIKE) {
- setExtruded(tsrc->getTextureName(f.tiles[0].texture_id), def.wield_scale, tsrc, f.tiles[0].animation_frame_count);
+ setExtruded(tsrc->getTextureName(f.tiles[0].layers[0].texture_id),
+ def.wield_scale, tsrc,
+ f.tiles[0].layers[0].animation_frame_count);
} else if (f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES) {
- setCube(f.tiles, def.wield_scale, tsrc);
+ setCube(f, def.wield_scale, tsrc);
} else {
- MeshMakeData mesh_make_data(gamedef, false);
+ MeshMakeData mesh_make_data(client, false);
MapNode mesh_make_node(id, 255, 0);
mesh_make_data.fillSingleNode(&mesh_make_node);
MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0));
- changeToMesh(mapblock_mesh.getMesh());
- translateMesh(m_meshnode->getMesh(), v3f(-BS, -BS, -BS));
+ scene::SMesh *mesh = cloneMesh(mapblock_mesh.getMesh());
+ translateMesh(mesh, v3f(-BS, -BS, -BS));
+ postProcessNodeMesh(mesh, f, m_enable_shaders, true,
+ &m_material_type, &m_colors);
+ changeToMesh(mesh);
+ mesh->drop();
m_meshnode->setScale(
def.wield_scale * WIELD_SCALE_FACTOR
/ (BS * f.visual_scale));
}
u32 material_count = m_meshnode->getMaterialCount();
- if (material_count > 6) {
- errorstream << "WieldMeshSceneNode::setItem: Invalid material "
- "count " << material_count << ", truncating to 6" << std::endl;
- material_count = 6;
- }
for (u32 i = 0; i < material_count; ++i) {
video::SMaterial &material = m_meshnode->getMaterial(i);
material.setFlag(video::EMF_BACK_FACE_CULLING, true);
material.setFlag(video::EMF_BILINEAR_FILTER, m_bilinear_filter);
material.setFlag(video::EMF_TRILINEAR_FILTER, m_trilinear_filter);
- bool animated = (f.tiles[i].animation_frame_count > 1);
- if (animated) {
- FrameSpec animation_frame = f.tiles[i].frames[0];
- material.setTexture(0, animation_frame.texture);
- } else {
- material.setTexture(0, f.tiles[i].texture);
- }
- material.MaterialType = m_material_type;
- if (m_enable_shaders) {
- if (f.tiles[i].normal_texture) {
- if (animated) {
- FrameSpec animation_frame = f.tiles[i].frames[0];
- material.setTexture(1, animation_frame.normal_texture);
- } else {
- material.setTexture(1, f.tiles[i].normal_texture);
- }
- }
- material.setTexture(2, f.tiles[i].flags_texture);
- }
}
return;
}
else if (def.inventory_image != "") {
setExtruded(def.inventory_image, def.wield_scale, tsrc, 1);
+ m_colors.push_back(ItemPartColor());
return;
}
@@ -393,11 +376,28 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, IGameDef *gamedef)
changeToMesh(NULL);
}
-void WieldMeshSceneNode::setColor(video::SColor color)
+void WieldMeshSceneNode::setColor(video::SColor c)
{
assert(!m_lighting);
- setMeshColor(m_meshnode->getMesh(), color);
- shadeMeshFaces(m_meshnode->getMesh());
+ scene::IMesh *mesh=m_meshnode->getMesh();
+ if (mesh == NULL)
+ return;
+
+ u8 red = c.getRed();
+ u8 green = c.getGreen();
+ u8 blue = c.getBlue();
+ u32 mc = mesh->getMeshBufferCount();
+ for (u32 j = 0; j < mc; j++) {
+ video::SColor bc(m_base_color);
+ if ((m_colors.size() > j) && (m_colors[j].override_base))
+ bc = m_colors[j].color;
+ video::SColor buffercolor(255,
+ bc.getRed() * red / 255,
+ bc.getGreen() * green / 255,
+ bc.getBlue() * blue / 255);
+ scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+ colorizeMeshBuffer(buf, &buffercolor);
+ }
}
void WieldMeshSceneNode::render()
@@ -414,19 +414,7 @@ void WieldMeshSceneNode::changeToMesh(scene::IMesh *mesh)
m_meshnode->setMesh(dummymesh);
dummymesh->drop(); // m_meshnode grabbed it
} else {
- if (m_lighting) {
- m_meshnode->setMesh(mesh);
- } else {
- /*
- Lighting is disabled, this means the caller can (and probably will)
- call setColor later. We therefore need to clone the mesh so that
- setColor will only modify this scene node's mesh, not others'.
- */
- scene::IMeshManipulator *meshmanip = SceneManager->getMeshManipulator();
- scene::IMesh *new_mesh = meshmanip->createMeshCopy(mesh);
- m_meshnode->setMesh(new_mesh);
- new_mesh->drop(); // m_meshnode grabbed it
- }
+ m_meshnode->setMesh(mesh);
}
m_meshnode->setMaterialFlag(video::EMF_LIGHTING, m_lighting);
@@ -435,11 +423,11 @@ void WieldMeshSceneNode::changeToMesh(scene::IMesh *mesh)
m_meshnode->setVisible(true);
}
-scene::IMesh *getItemMesh(IGameDef *gamedef, const ItemStack &item)
+void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
{
- ITextureSource *tsrc = gamedef->getTextureSource();
- IItemDefManager *idef = gamedef->getItemDefManager();
- INodeDefManager *ndef = gamedef->getNodeDefManager();
+ ITextureSource *tsrc = client->getTextureSource();
+ IItemDefManager *idef = client->getItemDefManager();
+ INodeDefManager *ndef = client->getNodeDefManager();
const ItemDefinition &def = item.getDefinition(idef);
const ContentFeatures &f = ndef->get(def.name);
content_t id = ndef->getId(def.name);
@@ -450,35 +438,38 @@ scene::IMesh *getItemMesh(IGameDef *gamedef, const ItemStack &item)
g_extrusion_mesh_cache->grab();
}
- scene::IMesh *mesh;
+ scene::SMesh *mesh = NULL;
+
+ // Shading is on by default
+ result->needs_shading = true;
// If inventory_image is defined, it overrides everything else
if (def.inventory_image != "") {
mesh = getExtrudedMesh(tsrc, def.inventory_image);
- return mesh;
+ result->buffer_colors.push_back(ItemPartColor());
+ // Items with inventory images do not need shading
+ result->needs_shading = false;
} else if (def.type == ITEM_NODE) {
if (f.mesh_ptr[0]) {
mesh = cloneMesh(f.mesh_ptr[0]);
scaleMesh(mesh, v3f(0.12, 0.12, 0.12));
- setMeshColor(mesh, video::SColor (255, 255, 255, 255));
} else if (f.drawtype == NDT_PLANTLIKE) {
mesh = getExtrudedMesh(tsrc,
- tsrc->getTextureName(f.tiles[0].texture_id));
- return mesh;
+ tsrc->getTextureName(f.tiles[0].layers[0].texture_id));
} else if (f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES
|| f.drawtype == NDT_LIQUID || f.drawtype == NDT_FLOWINGLIQUID) {
- mesh = cloneMesh(g_extrusion_mesh_cache->createCube());
+ scene::IMesh *cube = g_extrusion_mesh_cache->createCube();
+ mesh = cloneMesh(cube);
+ cube->drop();
scaleMesh(mesh, v3f(1.2, 1.2, 1.2));
} else {
- MeshMakeData mesh_make_data(gamedef, false);
+ MeshMakeData mesh_make_data(client, false);
MapNode mesh_make_node(id, 255, 0);
mesh_make_data.fillSingleNode(&mesh_make_node);
MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0));
mesh = cloneMesh(mapblock_mesh.getMesh());
translateMesh(mesh, v3f(-BS, -BS, -BS));
scaleMesh(mesh, v3f(0.12, 0.12, 0.12));
- rotateMeshXZby(mesh, -45);
- rotateMeshYZby(mesh, -30);
u32 mc = mesh->getMeshBufferCount();
for (u32 i = 0; i < mc; ++i) {
@@ -492,34 +483,31 @@ scene::IMesh *getItemMesh(IGameDef *gamedef, const ItemStack &item)
material1.setTexture(3, material2.getTexture(3));
material1.MaterialType = material2.MaterialType;
}
- return mesh;
}
- shadeMeshFaces(mesh);
- rotateMeshXZby(mesh, -45);
- rotateMeshYZby(mesh, -30);
-
u32 mc = mesh->getMeshBufferCount();
for (u32 i = 0; i < mc; ++i) {
- video::SMaterial &material = mesh->getMeshBuffer(i)->getMaterial();
+ scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
+ video::SMaterial &material = buf->getMaterial();
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
material.setFlag(video::EMF_BILINEAR_FILTER, false);
material.setFlag(video::EMF_TRILINEAR_FILTER, false);
material.setFlag(video::EMF_BACK_FACE_CULLING, true);
material.setFlag(video::EMF_LIGHTING, false);
- if (f.tiles[i].animation_frame_count > 1) {
- FrameSpec animation_frame = f.tiles[i].frames[0];
- material.setTexture(0, animation_frame.texture);
- } else {
- material.setTexture(0, f.tiles[i].texture);
- }
}
- return mesh;
+
+ rotateMeshXZby(mesh, -45);
+ rotateMeshYZby(mesh, -30);
+
+ postProcessNodeMesh(mesh, f, false, false, NULL,
+ &result->buffer_colors);
}
- return NULL;
+ result->mesh = mesh;
}
-scene::IMesh * getExtrudedMesh(ITextureSource *tsrc,
+
+
+scene::SMesh * getExtrudedMesh(ITextureSource *tsrc,
const std::string &imagename)
{
video::ITexture *texture = tsrc->getTextureForMesh(imagename);
@@ -528,7 +516,9 @@ scene::IMesh * getExtrudedMesh(ITextureSource *tsrc,
}
core::dimension2d<u32> dim = texture->getSize();
- scene::IMesh *mesh = cloneMesh(g_extrusion_mesh_cache->create(dim));
+ scene::IMesh *original = g_extrusion_mesh_cache->create(dim);
+ scene::SMesh *mesh = cloneMesh(original);
+ original->drop();
// Customize material
video::SMaterial &material = mesh->getMeshBuffer(0)->getMaterial();
@@ -544,3 +534,57 @@ scene::IMesh * getExtrudedMesh(ITextureSource *tsrc,
return mesh;
}
+
+void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f,
+ bool use_shaders, bool set_material, video::E_MATERIAL_TYPE *mattype,
+ std::vector<ItemPartColor> *colors)
+{
+ u32 mc = mesh->getMeshBufferCount();
+ // Allocate colors for existing buffers
+ colors->clear();
+ for (u32 i = 0; i < mc; ++i)
+ colors->push_back(ItemPartColor());
+
+ for (u32 i = 0; i < mc; ++i) {
+ const TileSpec *tile = &(f.tiles[i]);
+ scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
+ for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
+ const TileLayer *layer = &tile->layers[layernum];
+ if (layer->texture_id == 0)
+ continue;
+ if (layernum != 0) {
+ scene::IMeshBuffer *copy = cloneMeshBuffer(buf);
+ copy->getMaterial() = buf->getMaterial();
+ mesh->addMeshBuffer(copy);
+ copy->drop();
+ buf = copy;
+ colors->push_back(
+ ItemPartColor(layer->has_color, layer->color));
+ } else {
+ (*colors)[i] = ItemPartColor(layer->has_color, layer->color);
+ }
+ video::SMaterial &material = buf->getMaterial();
+ if (set_material)
+ layer->applyMaterialOptions(material);
+ if (mattype) {
+ material.MaterialType = *mattype;
+ }
+ if (layer->animation_frame_count > 1) {
+ FrameSpec animation_frame = layer->frames[0];
+ material.setTexture(0, animation_frame.texture);
+ } else {
+ material.setTexture(0, layer->texture);
+ }
+ if (use_shaders) {
+ if (layer->normal_texture) {
+ if (layer->animation_frame_count > 1) {
+ FrameSpec animation_frame = layer->frames[0];
+ material.setTexture(1, animation_frame.normal_texture);
+ } else
+ material.setTexture(1, layer->normal_texture);
+ }
+ material.setTexture(2, layer->flags_texture);
+ }
+ }
+ }
+}
diff --git a/src/wieldmesh.h b/src/wieldmesh.h
index 0b3136bc1..faedce484 100644
--- a/src/wieldmesh.h
+++ b/src/wieldmesh.h
@@ -20,41 +20,78 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef WIELDMESH_HEADER
#define WIELDMESH_HEADER
-#include "irrlichttypes_extrabloated.h"
#include <string>
+#include "irrlichttypes_extrabloated.h"
struct ItemStack;
-class IGameDef;
+class Client;
class ITextureSource;
-struct TileSpec;
+struct ContentFeatures;
+
+/*!
+ * Holds color information of an item mesh's buffer.
+ */
+struct ItemPartColor
+{
+ /*!
+ * If this is false, the global base color of the item
+ * will be used instead of the specific color of the
+ * buffer.
+ */
+ bool override_base;
+ /*!
+ * The color of the buffer.
+ */
+ video::SColor color;
+
+ ItemPartColor() : override_base(false), color(0) {}
+
+ ItemPartColor(bool override, video::SColor color)
+ : override_base(override), color(color)
+ {
+ }
+};
+
+struct ItemMesh
+{
+ scene::IMesh *mesh;
+ /*!
+ * Stores the color of each mesh buffer.
+ */
+ std::vector<ItemPartColor> buffer_colors;
+ /*!
+ * If false, all faces of the item should have the same brightness.
+ * Disables shading based on normal vectors.
+ */
+ bool needs_shading;
+
+ ItemMesh() : mesh(NULL), buffer_colors(), needs_shading(true) {}
+};
/*
Wield item scene node, renders the wield mesh of some item
*/
-class WieldMeshSceneNode: public scene::ISceneNode
+class WieldMeshSceneNode : public scene::ISceneNode
{
public:
WieldMeshSceneNode(scene::ISceneNode *parent, scene::ISceneManager *mgr,
s32 id = -1, bool lighting = false);
virtual ~WieldMeshSceneNode();
- void setCube(const TileSpec tiles[6],
- v3f wield_scale, ITextureSource *tsrc);
- void setExtruded(const std::string &imagename,
- v3f wield_scale, ITextureSource *tsrc, u8 num_frames);
- void setItem(const ItemStack &item, IGameDef *gamedef);
+ void setCube(const ContentFeatures &f, v3f wield_scale, ITextureSource *tsrc);
+ void setExtruded(const std::string &imagename, v3f wield_scale,
+ ITextureSource *tsrc, u8 num_frames);
+ void setItem(const ItemStack &item, Client *client);
// Sets the vertex color of the wield mesh.
// Must only be used if the constructor was called with lighting = false
void setColor(video::SColor color);
- scene::IMesh *getMesh()
- { return m_meshnode->getMesh(); }
+ scene::IMesh *getMesh() { return m_meshnode->getMesh(); }
virtual void render();
- virtual const aabb3f &getBoundingBox() const
- { return m_bounding_box; }
+ virtual const aabb3f &getBoundingBox() const { return m_bounding_box; }
private:
void changeToMesh(scene::IMesh *mesh);
@@ -70,6 +107,16 @@ private:
bool m_anisotropic_filter;
bool m_bilinear_filter;
bool m_trilinear_filter;
+ /*!
+ * Stores the colors of the mesh's mesh buffers.
+ * This does not include lighting.
+ */
+ std::vector<ItemPartColor> m_colors;
+ /*!
+ * The base color of this mesh. This is the default
+ * for all mesh buffers.
+ */
+ video::SColor m_base_color;
// Bounding box culling is disabled for this type of scene node,
// so this variable is just required so we can implement
@@ -77,8 +124,18 @@ private:
aabb3f m_bounding_box;
};
-scene::IMesh *getItemMesh(IGameDef *gamedef, const ItemStack &item);
+void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result);
+
+scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename);
-scene::IMesh *getExtrudedMesh(ITextureSource *tsrc,
- const std::string &imagename);
+/*!
+ * Applies overlays, textures and optionally materials to the given mesh and
+ * extracts tile colors for colorization.
+ * \param mattype overrides the buffer's material type, but can also
+ * be NULL to leave the original material.
+ * \param colors returns the colors of the mesh buffers in the mesh.
+ */
+void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f, bool use_shaders,
+ bool set_material, video::E_MATERIAL_TYPE *mattype,
+ std::vector<ItemPartColor> *colors);
#endif