Merge remote-tracking branch 'minetest/master'

Conflicts:
	src/environment.cpp
	src/game.cpp
	src/guiFormSpecMenu.h
	src/mapgen.h
master
Brandon 2016-07-08 19:14:22 -05:00
commit 55925444eb
98 changed files with 3180 additions and 1896 deletions

View File

@ -113,7 +113,7 @@ $ sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl* openal*
You can install git for easily keeping your copy up to date.
If you dont want git, read below on how to get the source without git.
This is an example for installing git on Debian/Ubuntu:
$ sudo apt-get install git-core
$ sudo apt-get install git
For Fedora users:
$ sudo dnf install git-core

View File

@ -169,6 +169,7 @@ LOCAL_SRC_FILES := \
jni/src/log.cpp \
jni/src/main.cpp \
jni/src/map.cpp \
jni/src/map_settings_manager.cpp \
jni/src/mapblock.cpp \
jni/src/mapblock_mesh.cpp \
jni/src/mapgen.cpp \
@ -224,6 +225,7 @@ LOCAL_SRC_FILES := \
jni/src/util/auth.cpp \
jni/src/util/base64.cpp \
jni/src/util/directiontables.cpp \
jni/src/util/enriched_string.cpp \
jni/src/util/numeric.cpp \
jni/src/util/pointedthing.cpp \
jni/src/util/serialize.cpp \
@ -237,6 +239,7 @@ LOCAL_SRC_FILES := \
jni/src/unittest/test_connection.cpp \
jni/src/unittest/test_filepath.cpp \
jni/src/unittest/test_inventory.cpp \
jni/src/unittest/test_map_settings_manager.cpp \
jni/src/unittest/test_mapnode.cpp \
jni/src/unittest/test_nodedef.cpp \
jni/src/unittest/test_noderesolver.cpp \
@ -256,7 +259,9 @@ LOCAL_SRC_FILES := \
jni/src/settings.cpp \
jni/src/wieldmesh.cpp \
jni/src/client/clientlauncher.cpp \
jni/src/client/tile.cpp
jni/src/client/tile.cpp \
jni/src/client/joystick_controller.cpp \
jni/src/irrlicht_changes/static_text.cpp
# intentionally kept out (we already build openssl itself): jni/src/util/sha256.c

View File

@ -5,6 +5,9 @@ local WARN_INIT = false
function core.global_exists(name)
if type(name) ~= "string" then
error("core.global_exists: " .. tostring(name) .. " is not a string")
end
return rawget(_G, name) ~= nil
end

View File

@ -250,7 +250,9 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
local newnode = {name = def.name, param1 = 0, param2 = param2}
-- Calculate direction for wall mounted stuff like torches and signs
if def.paramtype2 == 'wallmounted' and not param2 then
if def.place_param2 ~= nil then
newnode.param2 = def.place_param2
elseif def.paramtype2 == 'wallmounted' and not param2 then
local dir = {
x = under.x - above.x,
y = under.y - above.y,

View File

@ -70,7 +70,7 @@ fast_move (Fast movement) bool false
# This requires the "noclip" privilege on the server.
noclip (Noclip) bool false
# Smooths camera when moving and looking around.
# Smooths camera when looking around. Also called look or mouse smoothing.
# Useful for recording videos.
cinematic (Cinematic mode) bool false
@ -104,6 +104,17 @@ random_input (Random input) bool false
# Continuous forward movement (only used for testing).
continuous_forward (Continuous forward) bool false
# Enable Joysticks
enable_joysticks (Enable Joysticks) bool false
# The time in seconds it takes between repeated events
# when holding down a joystick button combination.
repeat_joystick_button_time (Joystick button repetition invterval) float 0.17
# The sensitivity of the joystick axes for moving the
# ingame view frustum around.
joystick_frustum_sensitivity (Joystick frustum sensitivity) float 170
# Key for moving the player forward.
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
keymap_forward (Forward key) key KEY_KEY_W
@ -167,7 +178,7 @@ keymap_noclip (Noclip key) key KEY_KEY_H
# Key for toggling cinematic mode.
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
keymap_cinematic (Cinematic mode key) key KEY_F8
keymap_cinematic (Cinematic mode key) key
# Key for toggling display of minimap.
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
@ -943,7 +954,7 @@ mgv6_np_apple_trees (Mapgen v6 apple trees noise parameters) noise_params 0, 1,
mgv7_spflags (Mapgen v7 flags) flags mountains,ridges mountains,ridges,nomountains,noridges
# Controls width of tunnels, a smaller value creates wider tunnels.
mgv7_cave_width (Mapgen v7 cave width) float 0.3
mgv7_cave_width (Mapgen v7 cave width) float 0.2
mgv7_np_terrain_base (Mapgen v7 terrain base noise parameters) noise_params 4, 70, (600, 600, 600), 82341, 5, 0.6, 2.0
mgv7_np_terrain_alt (Mapgen v7 terrain altitude noise parameters) noise_params 4, 25, (600, 600, 600), 5934, 5, 0.6, 2.0
@ -954,8 +965,8 @@ mgv7_np_mount_height (Mapgen v7 mount height noise parameters) noise_params 256,
mgv7_np_ridge_uwater (Mapgen v7 ridge water noise parameters) noise_params 0, 1, (1000, 1000, 1000), 85039, 5, 0.6, 2.0
mgv7_np_mountain (Mapgen v7 mountain noise parameters) noise_params -0.6, 1, (250, 350, 250), 5333, 5, 0.63, 2.0
mgv7_np_ridge (Mapgen v7 ridge noise parameters) noise_params 0, 1, (100, 100, 100), 6467, 4, 0.75, 2.0
mgv7_np_cave1 (Mapgen v7 cave1 noise parameters) noise_params 0, 12, (100, 100, 100), 52534, 4, 0.5, 2.0
mgv7_np_cave2 (Mapgen v7 cave2 noise parameters) noise_params 0, 12, (100, 100, 100), 10325, 4, 0.5, 2.0
mgv7_np_cave1 (Mapgen v7 cave1 noise parameters) noise_params 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0
mgv7_np_cave2 (Mapgen v7 cave2 noise parameters) noise_params 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0
[***Mapgen flat]
@ -972,7 +983,7 @@ mgflat_ground_level (Mapgen flat ground level) int 8
mgflat_large_cave_depth (Mapgen flat large cave depth) int -33
# Controls width of tunnels, a smaller value creates wider tunnels.
mgflat_cave_width (Mapgen flat cave width) float 0.3
mgflat_cave_width (Mapgen flat cave width) float 0.2
# Terrain noise threshold for lakes.
# Controls proportion of world area covered by lakes.
@ -996,13 +1007,13 @@ mgflat_hill_steepness (Mapgen flat hill steepness) float 64.0
mgflat_np_terrain (Mapgen flat terrain noise parameters) noise_params 0, 1, (600, 600, 600), 7244, 5, 0.6, 2.0
mgflat_np_filler_depth (Mapgen flat filler depth noise parameters) noise_params 0, 1.2, (150, 150, 150), 261, 3, 0.7, 2.0
mgflat_np_cave1 (Mapgen flat cave1 noise parameters) noise_params 0, 12, (128, 128, 128), 52534, 4, 0.5, 2.0
mgflat_np_cave2 (Mapgen flat cave2 noise parameters) noise_params 0, 12, (128, 128, 128), 10325, 4, 0.5, 2.0
mgflat_np_cave1 (Mapgen flat cave1 noise parameters) noise_params 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0
mgflat_np_cave2 (Mapgen flat cave2 noise parameters) noise_params 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0
[***Mapgen fractal]
# Controls width of tunnels, a smaller value creates wider tunnels.
mgfractal_cave_width (Mapgen fractal cave width) float 0.3
mgfractal_cave_width (Mapgen fractal cave width) float 0.2
# Choice of 18 fractals from 9 formulas.
# 1 = 4D "Roundy" mandelbrot set.
@ -1063,8 +1074,8 @@ mgfractal_julia_w (Mapgen fractal julia w) float 0.33
mgfractal_np_seabed (Mapgen fractal seabed noise parameters) noise_params -14, 9, (600, 600, 600), 41900, 5, 0.6, 2.0
mgfractal_np_filler_depth (Mapgen fractal filler depth noise parameters) noise_params 0, 1.2, (150, 150, 150), 261, 3, 0.7, 2.0
mgfractal_np_cave1 (Mapgen fractal cave1 noise parameters) noise_params 0, 12, (128, 128, 128), 52534, 4, 0.5, 2.0
mgfractal_np_cave2 (Mapgen fractal cave2 noise parameters) noise_params 0, 12, (128, 128, 128), 10325, 4, 0.5, 2.0
mgfractal_np_cave1 (Mapgen fractal cave1 noise parameters) noise_params 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0
mgfractal_np_cave2 (Mapgen fractal cave2 noise parameters) noise_params 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0
# Mapgen Valleys parameters
[***Mapgen Valleys]
@ -1104,16 +1115,16 @@ mgvalleys_river_size (River Size) int 5
mgvalleys_water_features (Water Features) int 0
# Controls width of tunnels, a smaller value creates wider tunnels.
mgvalleys_cave_width (Cave width) float 0.3
mgvalleys_cave_width (Cave width) float 0.2
# Noise parameters
[****Noises]
# Caves and tunnels form at the intersection of the two noises
mgvalleys_np_cave1 (Cave noise #1) noise_params 0, 12, (100, 100, 100), 52534, 4, 0.5, 2.0
mgvalleys_np_cave1 (Cave noise #1) noise_params 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0
# Caves and tunnels form at the intersection of the two noises
mgvalleys_np_cave2 (Cave noise #2) noise_params 0, 12, (100, 100, 100), 10325, 4, 0.5, 2.0
mgvalleys_np_cave2 (Cave noise #2) noise_params 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0
# The depth of dirt or other filler
mgvalleys_np_filler_depth (Filler Depth) noise_params 0, 1.2, (256, 256, 256), 1605, 3, 0.5, 2.0

View File

@ -65,15 +65,19 @@ e.g.
The game directory can contain the file minetest.conf, which will be used
to set default settings when running the particular game.
It can also contain a settingtypes.txt in the same format as the one in builtin.
This settingtypes.txt will be parsed by the menu and the settings will be displayed in the "Games" category in the settings tab.
This settingtypes.txt will be parsed by the menu and the settings will be displayed
in the "Games" category in the settings tab.
### Menu images
Games can provide custom main menu images. They are put inside a `menu` directory inside the game directory.
Games can provide custom main menu images. They are put inside a `menu` directory
inside the game directory.
The images are named `$identifier.png`, where `$identifier` is one of `overlay,background,footer,header`.
If you want to specify multiple images for one identifier, add additional images named like `$identifier.$n.png`, with an ascending number $n starting with 1,
and a random image will be chosen from the provided ones.
The images are named `$identifier.png`, where `$identifier` is
one of `overlay,background,footer,header`.
If you want to specify multiple images for one identifier, add additional images named
like `$identifier.$n.png`, with an ascending number $n starting with 1, and a random
image will be chosen from the provided ones.
Mod load path
@ -243,7 +247,8 @@ Example:
default_dirt.png^default_grass_side.png
`default_grass_side.png` is overlayed over `default_dirt.png`.
The texture with the lower resolution will be automatically upscaled to the higher resolution texture.
The texture with the lower resolution will be automatically upscaled to
the higher resolution texture.
### Texture grouping
Textures can be grouped together by enclosing them in `(` and `)`.
@ -468,8 +473,8 @@ the global `minetest.registered_*` tables.
* added to `minetest.registered_schematic` with the key of `schematic.name`
* if `schematic.name` is nil, the key is the returned ID
* if the schematic is loaded from a file, schematic.name is set to the filename
* if the function is called when loading the mod, and schematic.name is a relative path,
* then the current mod path will be prepended to the schematic filename
* if the function is called when loading the mod, and schematic.name is a relative
path, then the current mod path will be prepended to the schematic filename
* `minetest.clear_registered_biomes()`
* clears all biomes currently registered
@ -1416,13 +1421,13 @@ examples.
#### `listring[<inventory location>;<list name>]`
* Allows to create a ring of inventory lists
* Shift-clicking on items in one element of the ring
* will send them to the next inventory list inside the ring
will send them to the next inventory list inside the ring
* The first occurrence of an element inside the ring will
* determine the inventory where items will be sent to
determine the inventory where items will be sent to
#### `listring[]`
* Shorthand for doing `listring[<inventory location>;<list name>]`
* for the last two inventory lists added by list[...]
for the last two inventory lists added by list[...]
#### `listcolors[<slot_bg_normal>;<slot_bg_hover>]`
* Sets background color of slots as `ColorString`
@ -1475,7 +1480,7 @@ examples.
* Textual password style field; will be sent to server when a button is clicked
* `x` and `y` position the field relative to the top left of the menu
* `w` and `h` are the size of the field
* fields are a set height, but will be vertically centred on `h`
* Fields are a set height, but will be vertically centred on `h`
* Position and size units are inventory slots
* `name` is the name of the field as returned in fields to `on_receive_fields`
* `label`, if not blank, will be text printed on the top left above the field
@ -1484,7 +1489,7 @@ examples.
* Textual field; will be sent to server when a button is clicked
* `x` and `y` position the field relative to the top left of the menu
* `w` and `h` are the size of the field
* fields are a set height, but will be vertically centred on `h`
* Fields are a set height, but will be vertically centred on `h`
* Position and size units are inventory slots
* `name` is the name of the field as returned in fields to `on_receive_fields`
* `label`, if not blank, will be text printed on the top left above the field
@ -1494,13 +1499,13 @@ examples.
* **Note**: no extra text or more than a single variable is supported ATM.
#### `field[<name>;<label>;<default>]`
* as above, but without position/size units
* special field for creating simple forms, such as sign text input
* must be used without a `size[]` element
* a "Proceed" button will be added automatically
* As above, but without position/size units
* Special field for creating simple forms, such as sign text input
* Must be used without a `size[]` element
* A "Proceed" button will be added automatically
#### `textarea[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]`
* same as fields above, but with multi-line input
* Same as fields above, but with multi-line input
#### `label[<X>,<Y>;<label>]`
* `x` and `y` work as per field
@ -1561,12 +1566,12 @@ examples.
* `name` fieldname sent to server on doubleclick value is current selected element
* `listelements` can be prepended by #RRGGBB (only) in hexadecimal format
* if you want a listelement to start with "#" write "##"
* index to be selected within textlist
* Index to be selected within textlist
* `true`/`false`: draw transparent background
* see also `minetest.explode_textlist_event` (main menu: `engine.explode_textlist_event`)
* See also `minetest.explode_textlist_event` (main menu: `engine.explode_textlist_event`)
#### `tabheader[<X>,<Y>;<name>;<caption 1>,<caption 2>,...,<caption n>;<current_tab>;<transparent>;<draw_border>]`
* show a tab**header** at specific position (ignores formsize)
* Show a tab**header** at specific position (ignores formsize)
* `x` and `y` position the itemlist relative to the top left of the menu
* `name` fieldname data is transferred to Lua
* `caption 1`...: name shown on top of tab
@ -1575,24 +1580,24 @@ examples.
* `draw_border` (optional): draw border
#### `box[<X>,<Y>;<W>,<H>;<color>]`
* simple colored semitransparent box
* Simple colored semitransparent box
* `x` and `y` position the box relative to the top left of the menu
* `w` and `h` are the size of box
* `color` is color specified as a `ColorString`
#### `dropdown[<X>,<Y>;<W>;<name>;<item 1>,<item 2>, ...,<item n>;<selected idx>]`
* show a dropdown field
* Show a dropdown field
* **Important note**: There are two different operation modes:
1. handle directly on change (only changed dropdown is submitted)
2. read the value on pressing a button (all dropdown values are available)
* `x` and `y` position of dropdown
* width of dropdown
* fieldname data is transferred to Lua
* items to be shown in dropdown
* index of currently selected dropdown item
* Width of dropdown
* Fieldname data is transferred to Lua
* Items to be shown in dropdown
* Index of currently selected dropdown item
#### `checkbox[<X>,<Y>;<name>;<label>;<selected>;<tooltip>]`
* show a checkbox
* Show a checkbox
* `x` and `y`: position of checkbox
* `name` fieldname data is transferred to Lua
* `label` to be shown left of checkbox
@ -1600,29 +1605,29 @@ examples.
* `tooltip` (optional)
#### `scrollbar[<X>,<Y>;<W>,<H>;<orientation>;<name>;<value>]`
* show a scrollbar
* there are two ways to use it:
* Show a scrollbar
* There are two ways to use it:
1. handle the changed event (only changed scrollbar is available)
2. read the value on pressing a button (all scrollbars are available)
* `x` and `y`: position of trackbar
* `w` and `h`: width and height
* `orientation`: `vertical`/`horizontal`
* fieldname data is transferred to Lua
* value this trackbar is set to (`0`-`1000`)
* see also `minetest.explode_scrollbar_event` (main menu: `engine.explode_scrollbar_event`)
* Fieldname data is transferred to Lua
* Value this trackbar is set to (`0`-`1000`)
* See also `minetest.explode_scrollbar_event` (main menu: `engine.explode_scrollbar_event`)
#### `table[<X>,<Y>;<W>,<H>;<name>;<cell 1>,<cell 2>,...,<cell n>;<selected idx>]`
* show scrollable table using options defined by the previous `tableoptions[]`
* displays cells as defined by the previous `tablecolumns[]`
* Show scrollable table using options defined by the previous `tableoptions[]`
* Displays cells as defined by the previous `tablecolumns[]`
* `x` and `y`: position the itemlist relative to the top left of the menu
* `w` and `h` are the size of the itemlist
* `name`: fieldname sent to server on row select or doubleclick
* `cell 1`...`cell n`: cell contents given in row-major order
* `selected idx`: index of row to be selected within table (first row = `1`)
* see also `minetest.explode_table_event` (main menu: `engine.explode_table_event`)
* See also `minetest.explode_table_event` (main menu: `engine.explode_table_event`)
#### `tableoptions[<opt 1>;<opt 2>;...]`
* sets options for `table[]`
* Sets options for `table[]`
* `color=#RRGGBB`
* default text color (`ColorString`), defaults to `#FFFFFF`
* `background=#RRGGBB`
@ -1638,14 +1643,14 @@ examples.
* only useful when there is a column of type "tree"
#### `tablecolumns[<type 1>,<opt 1a>,<opt 1b>,...;<type 2>,<opt 2a>,<opt 2b>;...]`
* sets columns for `table[]`
* types: `text`, `image`, `color`, `indent`, `tree`
* Sets columns for `table[]`
* Types: `text`, `image`, `color`, `indent`, `tree`
* `text`: show cell contents as text
* `image`: cell contents are an image index, use column options to define images
* `color`: cell contents are a ColorString and define color of following cell
* `indent`: cell contents are a number and define indentation of following cell
* `tree`: same as indent, but user can open and close subtrees (treeview-like)
* column options:
* Column options:
* `align=<value>`
* for `text` and `image`: content alignment within cells.
Available values: `left` (default), `center`, `right`, `inline`
@ -1842,6 +1847,14 @@ Call these functions only at load time!
* `minetest.register_craftitem(name, item definition)`
* `minetest.register_alias(name, convert_to)`
* `minetest.register_craft(recipe)`
* Check recipe table syntax for different types below.
* `minetest.clear_craft(recipe)`
* Will erase existing craft based either on output item or on input recipe.
* Specify either output or input only. If you specify both, input will be ignored. For input use the same recipe table
syntax as for `minetest.register_craft(recipe)`. For output specify only the item, without a quantity.
* If no erase candidate could be found, Lua exception will be thrown.
* Warning! The type field ("shaped","cooking" or any other) will be ignored if the recipe
contains output. Erasing is then done independently from the crafting method.
* `minetest.register_ore(ore definition)`
* `minetest.register_decoration(decoration definition)`
* `minetest.override_item(name, redefinition)`
@ -1907,8 +1920,9 @@ Call these functions only at load time!
* If it returns a string, the player is disconnected with that string as reason
* `minetest.register_on_joinplayer(func(ObjectRef))`
* Called when a player joins the game
* `minetest.register_on_leaveplayer(func(ObjectRef))`
* `minetest.register_on_leaveplayer(func(ObjectRef, timed_out))`
* Called when a player leaves the game
* `timed_out`: True for timeout, false for other reasons.
* `minetest.register_on_cheat(func(ObjectRef, cheat))`
* Called when a player cheats
* `cheat`: `{type=<cheat_type>}`, where `<cheat_type>` is one of:
@ -1948,7 +1962,8 @@ Call these functions only at load time!
* `minetest.register_chatcommand(cmd, chatcommand definition)`
* `minetest.register_privilege(name, definition)`
* `definition`: `"description text"`
* `definition`: `{ description = "description text", give_to_singleplayer = boolean, -- default: true }`
* `definition`: `{ description = "description text", give_to_singleplayer = boolean}`
the default of `give_to_singleplayer` is true
* To allow players with basic_privs to grant, see basic_privs minetest.conf setting.
* `minetest.register_authentication_handler(handler)`
* See `minetest.builtin_auth_handler` in `builtin.lua` for reference
@ -2082,7 +2097,9 @@ and `minetest.auth_reload` call the authetification handler.
given biome_name string.
* `minetest.get_mapgen_params()` Returns mapgen parameters, a table containing
`mgname`, `seed`, `chunksize`, `water_level`, and `flags`.
* Deprecated: use minetest.get_mapgen_setting(name) instead
* `minetest.set_mapgen_params(MapgenParams)`
* Deprecated: use minetest.set_mapgen_setting(name, value, override) instead
* Set map generation parameters
* Function cannot be called after the registration period; only initialization
and `on_mapgen_init`
@ -2092,6 +2109,23 @@ and `minetest.auth_reload` call the authetification handler.
* `flags` contains a comma-delimited string of flags to set,
or if the prefix `"no"` is attached, clears instead.
* `flags` is in the same format and has the same options as `mg_flags` in `minetest.conf`
* `minetest.get_mapgen_setting(name)`
* Gets the *active* mapgen setting (or nil if none exists) in string format with the following
order of precedence:
1) Settings loaded from map_meta.txt or overrides set during mod execution
2) Settings set by mods without a metafile override
3) Settings explicitly set in the user config file, minetest.conf
4) Settings set as the user config default
* `minetest.get_mapgen_setting_noiseparams(name)`
* Same as above, but returns the value as a NoiseParams table if the setting `name` exists
and is a valid NoiseParams
* `minetest.set_mapgen_setting(name, value, [override_meta=false])`
* Sets a mapgen param to `value`, and will take effect if the corresponding mapgen setting
is not already present in map_meta.txt. If the optional boolean override_meta is set to true,
this setting will become the active setting regardless of the map metafile contents.
* Note: to set the seed, use "seed", not "fixed_map_seed"
* `minetest.set_mapgen_setting_noiseparams(name, value, [override_meta=false])`
* Same as above, except value is a NoiseParams table
* `minetest.set_noiseparams(name, noiseparams, set_default)`
* Sets the noiseparams setting of `name` to the noiseparams table specified in `noiseparams`.
* `set_default` is an optional boolean (default: `true`) that specifies whether the setting
@ -2669,12 +2703,23 @@ This is basically a reference to a C++ `ServerActiveObject`
##### Player-only (no-op for other objects)
* `get_player_name()`: returns `""` if is not a player
* `get_player_velocity()`: returns `nil` if is not a player otherwise a table {x, y, z} representing the player's instantaneous velocity in nodes/s
* `get_player_velocity()`: returns `nil` if is not a player, otherwise a
table {x, y, z} representing the player's instantaneous velocity in nodes/s
* `get_look_dir()`: get camera direction as a unit vector
* `get_look_pitch()`: pitch in radians
* `get_look_yaw()`: yaw in radians (wraps around pretty randomly as of now)
* `set_look_pitch(radians)`: sets look pitch
* `set_look_yaw(radians)`: sets look yaw
* `get_look_vertical()`: pitch in radians
* Angle ranges between -pi/2 and pi/2, which are straight up and down respectively.
* `get_look_horizontal()`: yaw in radians
* Angle is counter-clockwise from the +z direction.
* `set_look_vertical(radians)`: sets look pitch
* radians - Angle from looking forward, where positive is downwards.
* `set_look_horizontal(radians)`: sets look yaw
* radians - Angle from the +z direction, where positive is counter-clockwise.
* `get_look_pitch()`: pitch in radians - Deprecated as broken. Use get_look_vertical.
* Angle ranges between -pi/2 and pi/2, which are straight down and up respectively.
* `get_look_yaw()`: yaw in radians - Deprecated as broken. Use get_look_horizontal.
* Angle is counter-clockwise from the +x direction.
* `set_look_pitch(radians)`: sets look pitch - Deprecated. Use set_look_vertical.
* `set_look_yaw(radians)`: sets look yaw - Deprecated. Use set_look_horizontal.
* `get_breath()`: returns players breath
* `set_breath(value)`: sets players breath
* values:
@ -2783,25 +2828,40 @@ An `InvRef` is a reference to an inventory.
A fast access data structure to store areas, and find areas near a given position or area.
Every area has a `data` string attribute to store additional information.
You can create an empty `AreaStore` by calling `AreaStore()`, or `AreaStore(type_name)`.
If you chose the parameter-less constructor, a fast implementation will be automatically chosen for you.
If you chose the parameter-less constructor, a fast implementation will be automatically
chosen for you.
#### Methods
* `get_area(id, include_borders, include_data)`: returns the area with the id `id`. (optional) Boolean values `include_borders` and `include_data` control what's copied.
* `get_areas_for_pos(pos, include_borders, include_data)`: returns all areas that contain the position `pos`. (optional) Boolean values `include_borders` and `include_data` control what's copied.
* `get_areas_in_area(edge1, edge2, accept_overlap, include_borders, include_data)`: returns all areas that contain all nodes inside the area specified by `edge1` and `edge2` (inclusive). If `accept_overlap` is true, also areas are returned that have nodes in common with the specified area. (optional) Boolean values `include_borders` and `include_data` control what's copied.
* `insert_area(edge1, edge2, data, [id])`: inserts an area into the store. Returns the new area's ID, or nil if the insertion failed. The (inclusive) positions `edge1` and `edge2` describe the area. `data` is a string stored with the area. If passed, `id` will be used as the internal area ID, it must be a unique number between 0 and 2^32-2. If you use the `id` parameter you must always use it, or insertions are likely to fail due to conflicts.
* `reserve(count)`: reserves resources for at most `count` many contained areas. Only needed for efficiency, and only some implementations profit.
* `get_area(id, include_borders, include_data)`: returns the area with the id `id`.
(optional) Boolean values `include_borders` and `include_data` control what's copied.
* `get_areas_for_pos(pos, include_borders, include_data)`: returns all areas that contain
the position `pos`. (optional) Boolean values `include_borders` and `include_data` control
what's copied.
* `get_areas_in_area(edge1, edge2, accept_overlap, include_borders, include_data)`:
returns all areas that contain all nodes inside the area specified by `edge1` and `edge2` (inclusive).
If `accept_overlap` is true, also areas are returned that have nodes in common with the specified area.
(optional) Boolean values `include_borders` and `include_data` control what's copied.
* `insert_area(edge1, edge2, data, [id])`: inserts an area into the store. Returns the new area's ID,
or nil if the insertion failed. The (inclusive) positions `edge1` and `edge2` describe the area.
`data` is a string stored with the area. If passed, `id` will be used as the internal area ID,
it must be a unique number between 0 and 2^32-2. If you use the `id` parameter you must always use it,
or insertions are likely to fail due to conflicts.
* `reserve(count)`: reserves resources for at most `count` many contained areas.
Only needed for efficiency, and only some implementations profit.
* `remove_area(id)`: removes the area with the given id from the store, returns success.
* `set_cache_params(params)`: sets params for the included prefiltering cache. Calling invalidates the cache, so that its elements have to be newly generated.
* `set_cache_params(params)`: sets params for the included prefiltering cache.
Calling invalidates the cache, so that its elements have to be newly generated.
* `params`:
{
enabled = boolean, -- whether to enable, default true
block_radius = number, -- the radius (in nodes) of the areas the cache generates prefiltered lists for, minimum 16, default 64
block_radius = number, -- the radius (in nodes) of the areas the cache generates
prefiltered lists for, minimum 16, default 64
limit = number, -- the cache's size, minimum 20, default 1000
}
* `to_string()`: Experimental. Returns area store serialized as a (binary) string.
* `to_file(filename)`: Experimental. Like `to_string()`, but writes the data to a file.
* `from_string(str)`: Experimental. Deserializes string and loads it into the AreaStore. Returns success and, optionally, an error message.
* `from_string(str)`: Experimental. Deserializes string and loads it into the AreaStore.
Returns success and, optionally, an error message.
* `from_file(filename)`: Experimental. Like `from_string()`, but reads the data from a file.
### `ItemStack`
@ -2865,7 +2925,9 @@ It can be created via `PcgRandom(seed)` or `PcgRandom(seed, sequence)`.
* `next()`: return next integer random number [`-2147483648`...`2147483647`]
* `next(min, max)`: return next integer random number [`min`...`max`]
* `rand_normal_dist(min, max, num_trials=6)`: return normally distributed random number [`min`...`max`]
* This is only a rough approximation of a normal distribution with mean=(max-min)/2 and variance=1
* This is only a rough approximation of a normal distribution with:
* mean = (max - min) / 2, and
* variance = (((max - min + 1) ^ 2) - 1) / (12 * num_trials)
* Increasing num_trials improves accuracy of the approximation
### `SecureRandom`
@ -3503,6 +3565,7 @@ Definition tables
^ paramtype = "light" allows light to propagate from or through the node with light value
^ falling by 1 per node. This line is essential for a light source node to spread its light. ]]
paramtype2 = "none", -- See "Nodes"
place_param2 = nil, -- Force value for param2 when player places node
is_ground_content = true, -- If false, the cave generator will not carve through this
sunlight_propagates = false, -- If true, sunlight will go infinitely through this
walkable = true, -- If true, objects collide with node
@ -3515,7 +3578,8 @@ Definition tables
liquid_alternative_flowing = "", -- Flowing version of source liquid
liquid_alternative_source = "", -- Source version of flowing liquid
liquid_viscosity = 0, -- Higher viscosity = slower flow (max. 7)
liquid_renewable = true, -- Can new liquid source be created by placing two or more sources nearby?
liquid_renewable = true, --[[
^ If true, a new liquid source can be created by placing two or more sources nearby ]]
leveled = 0, --[[
^ Block contains level in param2. Value is default level, used for snow.
^ Don't forget to use "leveled" type nodebox. ]]
@ -3721,6 +3785,9 @@ Definition tables
### Biome definition (`register_biome`)
**Note**
The Biome API is still in an experimental phase and subject to change.
{
name = "tundra",
node_dust = "default:snow",
@ -3740,6 +3807,9 @@ Definition tables
-- ^ Node that replaces all seawater nodes not in the defined surface layer.
node_river_water = "default:ice",
-- ^ Node that replaces river water in mapgens that use default:river_water.
node_riverbed = "default:gravel",
depth_riverbed = 2,
-- ^ Node placed under river water and thickness of this layer.
y_min = 1,
y_max = 31000,
-- ^ Lower and upper limits for biome.

View File

@ -1,345 +0,0 @@
------------------------------------------------------------------
The ancient comment from the beginning of main.cpp is stored here.
------------------------------------------------------------------
/*
=============================== NOTES ==============================
NOTE: Things starting with TODO are sometimes only suggestions.
NOTE: iostream.imbue(std::locale("C")) is very slow
NOTE: Global locale is now set at initialization
NOTE: If VBO (EHM_STATIC) is used, remember to explicitly free the
hardware buffer (it is not freed automatically)
NOTE: A random to-do list saved here as documentation:
A list of "active blocks" in which stuff happens. (+=done)
+ Add a never-resetted game timer to the server
+ Add a timestamp value to blocks
+ The simple rule: All blocks near some player are "active"
- Do stuff in real time in active blocks
+ Handle objects
- Grow grass, delete leaves without a tree
- Spawn some mobs based on some rules
- Transform cobble to mossy cobble near water
- Run a custom script
- ...And all kinds of other dynamic stuff
+ Keep track of when a block becomes active and becomes inactive
+ When a block goes inactive:
+ Store objects statically to block
+ Store timer value as the timestamp
+ When a block goes active:
+ Create active objects out of static objects
- Simulate the results of what would have happened if it would have
been active for all the time
- Grow a lot of grass and so on
+ Initially it is fine to send information about every active object
to every player. Eventually it should be modified to only send info
about the nearest ones.
+ This was left to be done by the old system and it sends only the
nearest ones.
NOTE: Seeds in 1260:6c77e7dbfd29:
5721858502589302589:
Spawns you on a small sand island with a surface dungeon
2983455799928051958:
Enormous jungle + a surface dungeon at ~(250,0,0)
Old, wild and random suggestions that probably won't be done:
-------------------------------------------------------------
SUGG: If player is on ground, mainly fetch ground-level blocks
SUGG: Expose Connection's seqnums and ACKs to server and client.
- This enables saving many packets and making a faster connection
- This also enables server to check if client has received the
most recent block sent, for example.
SUGG: Add a sane bandwidth throttling system to Connection
SUGG: More fine-grained control of client's dumping of blocks from
memory
- ...What does this mean in the first place?
SUGG: A map editing mode (similar to dedicated server mode)
SUGG: Transfer more blocks in a single packet
SUGG: A blockdata combiner class, to which blocks are added and at
destruction it sends all the stuff in as few packets as possible.
SUGG: Make a PACKET_COMBINED which contains many subpackets. Utilize
it by sending more stuff in a single packet.
- Add a packet queue to RemoteClient, from which packets will be
combined with object data packets
- This is not exactly trivial: the object data packets are
sometimes very big by themselves
- This might not give much network performance gain though.
SUGG: Precalculate lighting translation table at runtime (at startup)
- This is not doable because it is currently hand-made and not
based on some mathematical function.
- Note: This has been changing lately
SUGG: A version number to blocks, which increments when the block is
modified (node add/remove, water update, lighting update)
- This can then be used to make sure the most recent version of
a block has been sent to client, for example
SUGG: Make the amount of blocks sending to client and the total
amount of blocks dynamically limited. Transferring blocks is the
main network eater of this system, so it is the one that has
to be throttled so that RTTs stay low.
SUGG: Meshes of blocks could be split into 6 meshes facing into
different directions and then only those drawn that need to be
SUGG: Background music based on cellular automata?
http://www.earslap.com/projectslab/otomata
SUGG: Simple light color information to air
SUGG: Server-side objects could be moved based on nodes to enable very
lightweight operation and simple AI
- Not practical; client would still need to show smooth movement.
SUGG: Make a system for pregenerating quick information for mapblocks, so
that the client can show them as cubes before they are actually sent
or even generated.
SUGG: Erosion simulation at map generation time
- This might be plausible if larger areas of map were pregenerated
without lighting (which is slow)
- Simulate water flows, which would carve out dirt fast and
then turn stone into gravel and sand and relocate it.
- How about relocating minerals, too? Coal and gold in
downstream sand and gravel would be kind of cool
- This would need a better way of handling minerals, mainly
to have mineral content as a separate field. the first
parameter field is free for this.
- Simulate rock falling from cliffs when water has removed
enough solid rock from the bottom
SUGG: For non-mapgen FarMesh: Add a per-sector database to store surface
stuff as simple flags/values
- Light?
- A building?
And at some point make the server send this data to the client too,
instead of referring to the noise functions
- Ground height
- Surface ground type
- Trees?
Gaming ideas:
-------------
- Aim for something like controlling a single dwarf in Dwarf Fortress
- The player could go faster by a crafting a boat, or riding an animal
- Random NPC traders. what else?
Game content:
-------------
- When furnace is destroyed, move items to player's inventory
- Add lots of stuff
- Glass blocks
- Growing grass, decaying leaves
- This can be done in the active blocks I guess.
- Lots of stuff can be done in the active blocks.
- Uh, is there an active block list somewhere? I think not. Add it.
- Breaking weak structures
- This can probably be accomplished in the same way as grass
- Player health points
- When player dies, throw items on map (needs better item-on-map
implementation)
- Cobble to get mossy if near water
- More slots in furnace source list, so that multiple ingredients
are possible.
- Keys to chests?
- The Treasure Guard; a big monster with a hammer
- The hammer does great damage, shakes the ground and removes a block
- You can drop on top of it, and have some time to attack there
before he shakes you off
- Maybe the difficulty could come from monsters getting tougher in
far-away places, and the player starting to need something from
there when time goes by.
- The player would have some of that stuff at the beginning, and
would need new supplies of it when it runs out
- A bomb
- A spread-items-on-map routine for the bomb, and for dying players
- Fighting:
- Proper sword swing simulation
- Player should get damage from colliding to a wall at high speed
Documentation:
--------------
Build system / running:
-----------------------
Networking and serialization:
-----------------------------
SUGG: Fix address to be ipv6 compatible
User Interface:
---------------
Graphics:
---------
SUGG: Combine MapBlock's face caches to so big pieces that VBO
can be used
- That is >500 vertices
- This is not easy; all the MapBlocks close to the player would
still need to be drawn separately and combining the blocks
would have to happen in a background thread
SUGG: Make fetching sector's blocks more efficient when rendering
sectors that have very large amounts of blocks (on client)
- Is this necessary at all?
SUGG: Draw cubes in inventory directly with 3D drawing commands, so that
animating them is easier.
SUGG: Option for enabling proper alpha channel for textures
TODO: Flowing water animation
TODO: A setting for enabling bilinear filtering for textures
TODO: Better control of draw_control.wanted_max_blocks
TODO: Further investigate the use of GPU lighting in addition to the
current one
TODO: Artificial (night) light could be more yellow colored than sunlight.
- This is technically doable.
- Also the actual colors of the textures could be made less colorful
in the dark but it's a bit more difficult.
SUGG: Somehow make the night less colorful
TODO: Occlusion culling
- At the same time, move some of the renderMap() block choosing code
to the same place as where the new culling happens.
- Shoot some rays per frame and when ready, make a new list of
blocks for usage of renderMap and give it a new pointer to it.
Configuration:
--------------
Client:
-------
TODO: Untie client network operations from framerate
- Needs some input queues or something
- This won't give much performance boost because calculating block
meshes takes so long
SUGG: Make morning and evening transition more smooth and maybe shorter
TODO: Don't update all meshes always on single node changes, but
check which ones should be updated
- implement Map::updateNodeMeshes() and the usage of it
- It will give almost always a 4x boost in mesh update performance.
- A weapon engine
- Tool/weapon visualization
FIXME: When disconnected to the menu, memory is not freed properly
TODO: Investigate how much the mesh generator thread gets used when
transferring map data
Server:
-------
SUGG: Make an option to the server to disable building and digging near
the starting position
FIXME: Server sometimes goes into some infinite PeerNotFoundException loop
* Fix the problem with the server constantly saving one or a few
blocks? List the first saved block, maybe it explains.
- It is probably caused by oscillating water
- TODO: Investigate if this still happens (this is a very old one)
* Make a small history check to transformLiquids to detect and log
continuous oscillations, in such detail that they can be fixed.
FIXME: The new optimized map sending doesn't sometimes send enough blocks
from big caves and such
FIXME: Block send distance configuration does not take effect for some reason
Environment:
------------
TODO: Add proper hooks to when adding and removing active blocks
TODO: Finish the ActiveBlockModifier stuff and use it for something
Objects:
--------
TODO: Get rid of MapBlockObjects and use only ActiveObjects
- Skipping the MapBlockObject data is nasty - there is no "total
length" stored; have to make a SkipMBOs function which contains
enough of the current code to skip them properly.
SUGG: MovingObject::move and Player::move are basically the same.
combine them.
- NOTE: This is a bit tricky because player has the sneaking ability
- NOTE: Player::move is more up-to-date.
- NOTE: There is a simple move implementation now in collision.{h,cpp}
- NOTE: MovingObject will be deleted (MapBlockObject)
TODO: Add a long step function to objects that is called with the time
difference when block activates
Map:
----
TODO: Flowing water to actually contain flow direction information
- There is a space for this - it just has to be implemented.
TODO: Consider smoothening cave floors after generating them
TODO: Fix make_tree, make_* to use seed-position-consistent pseudorandom
- delta also
Misc. stuff:
------------
TODO: Make sure server handles removing grass when a block is placed (etc)
- The client should not do it by itself
- NOTE: I think nobody does it currently...
TODO: Block cube placement around player's head
TODO: Protocol version field
TODO: Think about using same bits for material for fences and doors, for
example
SUGG: Restart irrlicht completely when coming back to main menu from game.
- This gets rid of everything that is stored in irrlicht's caches.
- This might be needed for texture pack selection in menu
TODO: Merge bahamada's audio stuff (clean patch available)
Making it more portable:
------------------------
Stuff to do before release:
---------------------------
Fixes to the current release:
-----------------------------
Stuff to do after release:
---------------------------
Doing currently:
----------------
======================================================================
*/

View File

@ -1,147 +0,0 @@
Minetest changelog
----------------------
This should contain all the major changes.
For minor stuff, refer to the commit log of the repository.
0.3.1: (released on 2011-11-09)
- Fix frustum culling (previous versions have rendered too much stuff that is not actually visible (about 180 degrees, while should have been more like 100.))
- Add occlusion culling (improves performance a lot)
- Add “3d clouds” on/off checkbox in main menu
- Add “opaque water” on/off checkbox
- Fix some random minor stuff
- Turn mipmapping off (This makes far-away textures a bit noisier but better looking)
- Add Command-line signal handler for Windows (contributed by SpeedProg)
- Fix network layer segmentation fault introduced in 0.3.dev-20111021
- Fix water-glass and water-lava and lava-glass surfaces
0.3.0: (released on 2011-11-01)
- Some small fixes
0.3.dev-20111021:
- Modify dungeon masters to only try to shoot players
- Fix object duplication bug at block load/unload bug
- Improve network layer
0.3.dev-20111016:
- Locked chest (contributed)
- Server user limit setting (max_users)
- Wielded tool is shown in HUD (contributed)
- View bobbing (contributed)
- Saplings that drop from leaf blocks and when placed on ground will grow to trees (contributed)
- Optimized map saving (does not re-save everything all the time)
- New mob system and new mob: dungeon master
- Death/respawn screen
0.2.20110922_3:
- Fix the build for MSVC2010; also released for windows using MSVC2010.
0.2.20110922_1:
- Make client report a newer version number to the server than 2011-07-31 does and make server disallow old clients
0.2.20110922:
- Map is saved in an SQLite database file (by Queatz)
- Ladders (MarkTraceur)
- Lava
- Apple trees (sfan5)
- Slightly better looking inventory with transparency
- /me chat command (Oblomov)
- Using chosen map seed possible through fixed_map_seed configuration option (kahrl)
- Fix the long-existed PeerNotFound loop bug
- Some translations and localization-related fixes
- Lots of small fixes
2011-07-31_3:
- Fixes a bug that made the server to deny non-empty passwords from players connecting the first time
2011-07-31_2:
- Fixes a bug that caused the server to always read an empty password from the client when a client connected.
2011-07-31:
- A number of small fixes, build system stuff and such (refer to version control log)
- Map generator no longer crashes at generation limit
- Fixed mapgen producing lots of cut-down trees
- Some minor tweaks in map generator (some contributed)
- Volumetric clouds (contributed)
- Icon added (graphic contributed)
- Key configuration menu (contributed)
- Decorative blocks and items: bookshelf, sandstone, cactus, clay, brick, papyrus, rail, paper, book (contributed)
- Jungles!
- Hotbar is a bit smaller
- Health is now enabled by default; You can now eat cooked rats to heal yourself.
- Finally added sword textures, altough sword is still of no use
- Creative mode now preserves normal mode inventory
2011-07-04:
- Many small fixes
- Code reorganizing to aid further development
- Renewed map generator
2011-06-02:
- Password crash on windows fixed
- Optimized server CPU usage a lot
- Furnaces now work also while players are not near to them
2011-05-29:
- Optimized smooth lighting
- A number of small fixes
- Added clouds and simple skyboxes
- The glass block added
- Added key configuration to config file
- Player privileges on server
- Slightly updated map format
- Player passwords
- All textures first searched from texture_path
- Map directory ("map") has been renamed to "world" (just rename it to load an old world)
- Mouse inversion (invert_mouse)
- Grass doesn't grow immediately anymore
- Fence added
2011-04-24:
- Smooth lighting with simple ambient occlusion
- Updated main menu
2011-04-23_0_test:
- Small bug fixes
- Item drop multiplication fixed
- HP added
- Added A simple monster which spawns to dark places at map generation time
- Some code refactoring and cleaning (possibly new bugs)
2011-04-11:
- Fixed crafting a bit
2011-04-10_0:
- Asynchronous map generation
- New object system
2011-04-06:
- Mesh update of node addition/removal is now done asynchronously on client, removing frametime spike
- Node addition/removal is sent directly only to clients that are closer than 100 nodes to the modification. For the others, the modified blocks are set unsent. (and are re-sent when applicable)
2011-04-05:
- Made furnace usable
- Added cobblestone
- Added wood, stone and steel tools: pickaxes, shovels and axes
- Incremented to version 0.0.2
2011-04-04:
- Cleaned client to be completely synchronous, except for the mesh calculation, which is now done with queues in a separate thread.
- Added node metadata support
- Added chests
2011-02-17:
- Added better handling of textures. Now many file extensions are searched. Also too large textures are not put on the texture atlas, and the construction of the texture atlas is stopped when it is full.
2011-02-16:
- Better handling of Ctrl-C on POSIX systems
2011-02-15:
- Fixed a problem of not saving and loading the "lighting expired" value of MapBlocks properly. This caused high server CPU usage.
- Ctrl-C handling on POSIX systems
- Added simple command support to server
- Added settings enable_texture_atlas and texture_path
2011-02-14:
- Created changelog.txt
- Added sneaking/crouching
- Modified the looks of the hotbar and cleaned code
- Added code to allow generating 3D cube images for inventory

View File

@ -38,7 +38,7 @@
# type: bool
# noclip = false
# Smooths camera when moving and looking around.
# Smooths camera when looking around. Also called look or mouse smoothing.
# Useful for recording videos.
# type: bool
# cinematic = false
@ -162,7 +162,7 @@
# Key for toggling cinematic mode.
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
# type: key
# keymap_cinematic = KEY_F8
# keymap_cinematic =
# Key for toggling display of minimap.
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
@ -1176,7 +1176,7 @@
# Controls width of tunnels, a smaller value creates wider tunnels.
# type: float
# mgv7_cave_width = 0.3
# mgv7_cave_width = 0.2
# type: noise_params
# mgv7_np_terrain_base = 4, 70, (600, 600, 600), 82341, 5, 0.6, 2.0
@ -1206,10 +1206,10 @@
# mgv7_np_ridge = 0, 1, (100, 100, 100), 6467, 4, 0.75, 2.0
# type: noise_params
# mgv7_np_cave1 = 0, 12, (100, 100, 100), 52534, 4, 0.5, 2.0
# mgv7_np_cave1 = 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0
# type: noise_params
# mgv7_np_cave2 = 0, 12, (100, 100, 100), 10325, 4, 0.5, 2.0
# mgv7_np_cave2 = 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0
#### Mapgen flat
@ -1230,7 +1230,7 @@
# Controls width of tunnels, a smaller value creates wider tunnels.
# type: float
# mgflat_cave_width = 0.3
# mgflat_cave_width = 0.2
# Terrain noise threshold for lakes.
# Controls proportion of world area covered by lakes.
@ -1262,16 +1262,16 @@
# mgflat_np_filler_depth = 0, 1.2, (150, 150, 150), 261, 3, 0.7, 2.0
# type: noise_params
# mgflat_np_cave1 = 0, 12, (128, 128, 128), 52534, 4, 0.5, 2.0
# mgflat_np_cave1 = 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0
# type: noise_params
# mgflat_np_cave2 = 0, 12, (128, 128, 128), 10325, 4, 0.5, 2.0
# mgflat_np_cave2 = 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0
#### Mapgen fractal
# Controls width of tunnels, a smaller value creates wider tunnels.
# type: float
# mgfractal_cave_width = 0.3
# mgfractal_cave_width = 0.2
# Choice of 18 fractals from 9 formulas.
# 1 = 4D "Roundy" mandelbrot set.
@ -1346,10 +1346,10 @@
# mgfractal_np_filler_depth = 0, 1.2, (150, 150, 150), 261, 3, 0.7, 2.0
# type: noise_params
# mgfractal_np_cave1 = 0, 12, (128, 128, 128), 52534, 4, 0.5, 2.0
# mgfractal_np_cave1 = 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0
# type: noise_params
# mgfractal_np_cave2 = 0, 12, (128, 128, 128), 10325, 4, 0.5, 2.0
# mgfractal_np_cave2 = 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0
#### Mapgen Valleys
@ -1396,17 +1396,17 @@
# Controls width of tunnels, a smaller value creates wider tunnels.
# type: float
# mgvalleys_cave_width = 0.3
# mgvalleys_cave_width = 0.2
##### Noises
# Caves and tunnels form at the intersection of the two noises
# type: noise_params
# mgvalleys_np_cave1 = 0, 12, (100, 100, 100), 52534, 4, 0.5, 2.0
# mgvalleys_np_cave1 = 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0
# Caves and tunnels form at the intersection of the two noises
# type: noise_params
# mgvalleys_np_cave2 = 0, 12, (100, 100, 100), 10325, 4, 0.5, 2.0
# mgvalleys_np_cave2 = 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0
# The depth of dirt or other filler
# type: noise_params
@ -1527,4 +1527,3 @@
# type: string
# modstore_details_url = https://forum.minetest.net/mmdb/mod/*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -336,7 +336,10 @@ else()
if(APPLE)
set(PLATFORM_LIBS "-framework CoreFoundation" ${PLATFORM_LIBS})
else()
set(PLATFORM_LIBS -lrt ${PLATFORM_LIBS})
check_library_exists(rt clock_gettime "" HAVE_LIBRT)
if (HAVE_LIBRT)
set(PLATFORM_LIBS -lrt ${PLATFORM_LIBS})
endif(HAVE_LIBRT)
endif(APPLE)
# This way Xxf86vm is found on OpenBSD too
@ -411,6 +414,7 @@ set(common_SRCS
light.cpp
log.cpp
map.cpp
map_settings_manager.cpp
mapblock.cpp
mapgen.cpp
mapgen_flat.cpp
@ -556,6 +560,7 @@ include_directories(
${LUA_INCLUDE_DIR}
${GMP_INCLUDE_DIR}
${JSON_INCLUDE_DIR}
${X11_INCLUDE_DIR}
${PROJECT_SOURCE_DIR}/script
)

View File

@ -35,7 +35,7 @@ static NoiseParams nparams_caveliquids(0, 1, v3f(150.0, 150.0, 150.0), 776, 3, 0
CavesNoiseIntersection::CavesNoiseIntersection(
INodeDefManager *nodedef, BiomeManager *biomemgr, v3s16 chunksize,
NoiseParams *np_cave1, NoiseParams *np_cave2, int seed, float cave_width)
NoiseParams *np_cave1, NoiseParams *np_cave2, s32 seed, float cave_width)
{
assert(nodedef);
assert(biomemgr);
@ -130,7 +130,7 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm,
CavesRandomWalk::CavesRandomWalk(
INodeDefManager *ndef,
GenerateNotifier *gennotify,
int seed,
s32 seed,
int water_level,
content_t water_source,
content_t lava_source)

View File

@ -41,7 +41,7 @@ class CavesNoiseIntersection {
public:
CavesNoiseIntersection(INodeDefManager *nodedef, BiomeManager *biomemgr,
v3s16 chunksize, NoiseParams *np_cave1, NoiseParams *np_cave2,
int seed, float cave_width);
s32 seed, float cave_width);
~CavesNoiseIntersection();
void generateCaves(MMVManip *vm, v3s16 nmin, v3s16 nmax, u8 *biomemap);
@ -83,7 +83,7 @@ public:
s16 *heightmap;
// configurable parameters
int seed;
s32 seed;
int water_level;
int lava_depth;
NoiseParams *np_caveliquids;
@ -122,7 +122,7 @@ public:
// If gennotify is NULL, generation events are not logged.
CavesRandomWalk(INodeDefManager *ndef,
GenerateNotifier *gennotify = NULL,
int seed = 0,
s32 seed = 0,
int water_level = 1,
content_t water_source = CONTENT_IGNORE,
content_t lava_source = CONTENT_IGNORE);

View File

@ -1,6 +1,7 @@
set(client_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/clientlauncher.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/joystick_controller.cpp
PARENT_SCOPE
)

View File

@ -32,7 +32,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiEngine.h"
#include "player.h"
#include "fontengine.h"
#include "joystick_controller.h"
#include "clientlauncher.h"
#include "version.h"
/* mainmenumanager.h
*/
@ -112,6 +114,9 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
porting::setXorgClassHint(video_driver->getExposedVideoData(), PROJECT_NAME_C);
porting::setXorgWindowIcon(device,
porting::path_share + "/misc/minetest-xorg-icon-128.png");
/*
This changes the minimum allowed number of vertices in a VBO.
Default is 500.
@ -184,7 +189,9 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
{
// Set the window caption
const wchar_t *text = wgettext("Main Menu");
device->setWindowCaption((utf8_to_wide(PROJECT_NAME_C) + L" [" + text + L"]").c_str());
device->setWindowCaption((utf8_to_wide(PROJECT_NAME_C) +
L" " + utf8_to_wide(g_version_hash) +
L" [" + text + L"]").c_str());
delete[] text;
try { // This is used for catching disconnects
@ -499,7 +506,8 @@ void ClientLauncher::main_menu(MainMenuData *menudata)
#endif
/* show main menu */
GUIEngine mymenu(device, guiroot, &g_menumgr, smgr, menudata, *kill);
GUIEngine mymenu(device, &input->joystick, guiroot,
&g_menumgr, smgr, menudata, *kill);
smgr->clear(); /* leave scene manager in a clean state */
}
@ -558,6 +566,22 @@ 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;
}
}
porting::initIrrlicht(device);
}

View File

@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define INPUT_HANDLER_H
#include "irrlichttypes_extrabloated.h"
#include "joystick_controller.h"
class MyEventReceiver : public IEventReceiver
{
@ -62,6 +63,14 @@ public:
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 (noMenuActive() == false) {
@ -172,6 +181,8 @@ public:
s32 mouse_wheel;
JoystickController *joystick;
#ifdef HAVE_TOUCHSCREENGUI
TouchScreenGUI* m_touchscreengui;
#endif
@ -202,6 +213,7 @@ public:
m_receiver(receiver),
m_mousepos(0,0)
{
m_receiver->joystick = &joystick;
}
virtual bool isKeyDown(const KeyPress &keyCode)
{
@ -288,6 +300,7 @@ public:
void clear()
{
joystick.clear();
m_receiver->clearInput();
}
private:

View File

@ -0,0 +1,179 @@
/*
Minetest
Copyright (C) 2016 est31, <MTest31@outlook.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 "joystick_controller.h"
#include "irrlichttypes_extrabloated.h"
#include "keys.h"
#include "settings.h"
#include "gettime.h"
bool JoystickButtonCmb::isTriggered(const irr::SEvent::SJoystickEvent &ev) const
{
u32 buttons = ev.ButtonStates;
buttons &= filter_mask;
return buttons == compare_mask;
}
bool JoystickAxisCmb::isTriggered(const irr::SEvent::SJoystickEvent &ev) const
{
s16 ax_val = ev.Axis[axis_to_compare];
return (ax_val * direction < 0) && (thresh * direction > ax_val * direction);
}
// spares many characters
#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 jlo;
jlo.axes_dead_border = 1024;
const JoystickAxisLayout axes[JA_COUNT] = {
{0, 1}, // JA_SIDEWARD_MOVE
{1, 1}, // JA_FORWARD_MOVE
{3, 1}, // JA_FRUSTUM_HORIZONTAL
{4, 1}, // JA_FRUSTUM_VERTICAL
};
memcpy(jlo.axes, axes, sizeof(jlo.axes));
u32 sb = 1 << 7; // START button mask
u32 fb = 1 << 3; // FOUR button mask
u32 bm = sb | fb; // Mask for Both Modifiers
// The back button means "ESC".
JLO_B_PB(KeyType::ESC, 1 << 6, 1 << 6);
// The start button counts as modifier as well as use key.
// JLO_B_PB(KeyType::USE, sb, sb));
// Accessible without start modifier button pressed
// regardless whether four is pressed or not
JLO_B_PB(KeyType::SNEAK, sb | 1 << 2, 1 << 2);
// Accessible without four modifier button pressed
// regardless whether start is pressed or not
JLO_B_PB(KeyType::MOUSE_L, fb | 1 << 4, 1 << 4);
JLO_B_PB(KeyType::MOUSE_R, fb | 1 << 5, 1 << 5);
// Accessible without any modifier pressed
JLO_B_PB(KeyType::JUMP, bm | 1 << 0, 1 << 0);
JLO_B_PB(KeyType::SPECIAL1, bm | 1 << 1, 1 << 1);
// Accessible with start button not pressed, but four pressed
// TODO find usage for button 0
JLO_B_PB(KeyType::DROP, bm | 1 << 1, fb | 1 << 1);
JLO_B_PB(KeyType::SCROLL_UP, bm | 1 << 4, fb | 1 << 4);
JLO_B_PB(KeyType::SCROLL_DOWN,bm | 1 << 5, fb | 1 << 5);
// Accessible with start button and four pressed
// TODO find usage for buttons 0, 1 and 4, 5
// Now about the buttons simulated by the axes
// 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);
// Scroll buttons
JLO_A_PB(KeyType::SCROLL_UP, 2, -1, 1024);
JLO_A_PB(KeyType::SCROLL_DOWN, 5, -1, 1024);
return jlo;
}
static const JoystickLayout default_layout = create_default_layout();
JoystickController::JoystickController()
{
m_layout = &default_layout;
doubling_dtime = g_settings->getFloat("repeat_joystick_button_time");
for (size_t i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) {
m_past_pressed_time[i] = 0;
}
clear();
}
bool JoystickController::handleEvent(const irr::SEvent::SJoystickEvent &ev)
{
m_internal_time = 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->axis_keys.size(); i++) {
if (m_layout->axis_keys[i].isTriggered(ev)) {
keys_pressed.set(m_layout->axis_keys[i].key);
}
}
// Then update the values
for (size_t i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) {
if (keys_pressed[i]) {
if (!m_past_pressed_keys[i] &&
m_past_pressed_time[i] < m_internal_time - doubling_dtime) {
m_past_pressed_keys[i] = true;
m_past_pressed_time[i] = m_internal_time;
}
} else if (m_pressed_keys[i]) {
m_past_released_keys[i] = true;
}
m_pressed_keys[i] = keys_pressed[i];
}
for (size_t i = 0; i < JA_COUNT; i++) {
const JoystickAxisLayout &ax_la = m_layout->axes[i];
m_axes_vals[i] = ax_la.invert * ev.Axis[ax_la.axis_id];
}
return true;
}
void JoystickController::clear()
{
m_pressed_keys.reset();
m_past_pressed_keys.reset();
m_past_released_keys.reset();
memset(m_axes_vals, 0, sizeof(m_axes_vals));
}
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)))
return 0;
return v;
}

View File

@ -0,0 +1,163 @@
/*
Minetest
Copyright (C) 2016 est31, <MTest31@outlook.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 JOYSTICK_HEADER
#define JOYSTICK_HEADER
#include "irrlichttypes_extrabloated.h"
#include "keys.h"
#include <bitset>
#include <vector>
enum JoystickAxis {
JA_SIDEWARD_MOVE,
JA_FORWARD_MOVE,
JA_FRUSTUM_HORIZONTAL,
JA_FRUSTUM_VERTICAL,
// To know the count of enum values
JA_COUNT,
};
struct JoystickAxisLayout {
u16 axis_id;
// -1 if to invert, 1 if to keep it.
int invert;
};
struct JoystickCombination {
virtual bool isTriggered(const irr::SEvent::SJoystickEvent &ev) const=0;
GameKeyType key;
};
struct JoystickButtonCmb : public JoystickCombination {
JoystickButtonCmb() {}
JoystickButtonCmb(GameKeyType key, u32 filter_mask, u32 compare_mask) :
filter_mask(filter_mask),
compare_mask(compare_mask)
{
this->key = key;
}
virtual bool isTriggered(const irr::SEvent::SJoystickEvent &ev) const;
u32 filter_mask;
u32 compare_mask;
};
struct JoystickAxisCmb : public JoystickCombination {
JoystickAxisCmb() {}
JoystickAxisCmb(GameKeyType key, u16 axis_to_compare, int direction, s16 thresh) :
axis_to_compare(axis_to_compare),
direction(direction),
thresh(thresh)
{
this->key = key;
}
virtual bool isTriggered(const irr::SEvent::SJoystickEvent &ev) const;
u16 axis_to_compare;
// if -1, thresh must be smaller than the axis value in order to trigger
// if 1, thresh must be bigger than the axis value in order to trigger
int direction;
s16 thresh;
};
struct JoystickLayout {
std::vector<JoystickButtonCmb> button_keys;
std::vector<JoystickAxisCmb> axis_keys;
JoystickAxisLayout axes[JA_COUNT];
s16 axes_dead_border;
};
class JoystickController {
public:
JoystickController();
bool handleEvent(const irr::SEvent::SJoystickEvent &ev);
void clear();
bool wasKeyDown(GameKeyType b)
{
bool r = m_past_pressed_keys[b];
m_past_pressed_keys[b] = false;
return r;
}
bool getWasKeyDown(GameKeyType b)
{
return m_past_pressed_keys[b];
}
void clearWasKeyDown(GameKeyType b)
{
m_past_pressed_keys[b] = false;
}
bool wasKeyReleased(GameKeyType b)
{
bool r = m_past_released_keys[b];
m_past_released_keys[b] = false;
return r;
}
bool getWasKeyReleased(GameKeyType b)
{
return m_past_pressed_keys[b];
}
void clearWasKeyReleased(GameKeyType b)
{
m_past_pressed_keys[b] = false;
}
bool isKeyDown(GameKeyType b)
{
return m_pressed_keys[b];
}
s16 getAxis(JoystickAxis axis)
{
return m_axes_vals[axis];
}
s16 getAxisWithoutDead(JoystickAxis axis);
f32 doubling_dtime;
private:
const JoystickLayout *m_layout;
s16 m_axes_vals[JA_COUNT];
std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_pressed_keys;
f32 m_internal_time;
f32 m_past_pressed_time[KeyType::INTERNAL_ENUM_COUNT];
std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_past_pressed_keys;
std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_past_released_keys;
};
#endif

85
src/client/keys.h Normal file
View File

@ -0,0 +1,85 @@
/*
Minetest
Copyright (C) 2016 est31, <MTest31@outlook.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 KEYS_HEADER
#define KEYS_HEADER
#include<list>
class KeyType {
public:
enum T {
// Player movement
FORWARD,
BACKWARD,
LEFT,
RIGHT,
JUMP,
SPECIAL1,
SNEAK,
AUTORUN,
ESC,
// Other
DROP,
INVENTORY,
CHAT,
CMD,
CONSOLE,
MINIMAP,
FREEMOVE,
FASTMOVE,
NOCLIP,
CINEMATIC,
SCREENSHOT,
TOGGLE_HUD,
TOGGLE_CHAT,
TOGGLE_FORCE_FOG_OFF,
TOGGLE_UPDATE_CAMERA,
TOGGLE_DEBUG,
TOGGLE_PROFILER,
CAMERA_MODE,
INCREASE_VIEWING_RANGE,
DECREASE_VIEWING_RANGE,
RANGESELECT,
QUICKTUNE_NEXT,
QUICKTUNE_PREV,
QUICKTUNE_INC,
QUICKTUNE_DEC,
DEBUG_STACKS,
// joystick specific keys
MOUSE_L,
MOUSE_R,
SCROLL_UP,
SCROLL_DOWN,
// Fake keycode for array size and internal checks
INTERNAL_ENUM_COUNT
};
};
typedef KeyType::T GameKeyType;
#endif

View File

@ -1060,7 +1060,9 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
PlayerControl controls = player->getPlayerControl();
bool walking = false;
if(controls.up || controls.down || controls.left || controls.right)
if (controls.up || controls.down || controls.left || controls.right ||
controls.forw_move_joystick_axis != 0.f ||
controls.sidew_move_joystick_axis != 0.f)
walking = true;
f32 new_speed = player->local_animation_speed;

View File

@ -186,7 +186,7 @@ void content_nodemeta_deserialize_legacy(std::istream &is,
meta->set(p, data);
if(need_timer)
timers->set(p, NodeTimer(1., 0.));
timers->set(NodeTimer(1., 0., p));
}
}

View File

@ -960,6 +960,96 @@ public:
return recipes;
}
virtual bool clearCraftRecipesByOutput(const CraftOutput &output, IGameDef *gamedef)
{
std::map<std::string, std::vector<CraftDefinition*> >::iterator vec_iter =
m_output_craft_definitions.find(output.item);
if (vec_iter == m_output_craft_definitions.end())
return false;
std::vector<CraftDefinition*> &vec = vec_iter->second;
for (std::vector<CraftDefinition*>::iterator i = vec.begin();
i != vec.end(); ++i) {
CraftDefinition *def = *i;
// Recipes are not yet hashed at this point
std::vector<CraftDefinition*> &unhashed_inputs_vec = m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0];
std::vector<CraftDefinition*> new_vec_by_input;
/* We will preallocate necessary memory addresses, so we don't need to reallocate them later.
This would save us some performance. */
new_vec_by_input.reserve(unhashed_inputs_vec.size());
for (std::vector<CraftDefinition*>::iterator i2 = unhashed_inputs_vec.begin();
i2 != unhashed_inputs_vec.end(); ++i2) {
if (def != *i2) {
new_vec_by_input.push_back(*i2);
}
}
m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0].swap(new_vec_by_input);
}
m_output_craft_definitions.erase(output.item);
return true;
}
virtual bool clearCraftRecipesByInput(CraftMethod craft_method, unsigned int craft_grid_width,
const std::vector<std::string> &recipe, IGameDef *gamedef)
{
bool all_empty = true;
for (std::vector<std::string>::size_type i = 0;
i < recipe.size(); i++) {
if (!recipe[i].empty()) {
all_empty = false;
break;
}
}
if (all_empty)
return false;
CraftInput input(craft_method, craft_grid_width, craftGetItems(recipe, gamedef));
// Recipes are not yet hashed at this point
std::vector<CraftDefinition*> &unhashed_inputs_vec = m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0];
std::vector<CraftDefinition*> new_vec_by_input;
bool got_hit = false;
for (std::vector<CraftDefinition*>::size_type
i = unhashed_inputs_vec.size(); i > 0; i--) {
CraftDefinition *def = unhashed_inputs_vec[i - 1];
/* If the input doesn't match the recipe definition, this recipe definition later
will be added back in source map. */
if (!def->check(input, gamedef)) {
new_vec_by_input.push_back(def);
continue;
}
CraftOutput output = def->getOutput(input, gamedef);
got_hit = true;
std::map<std::string, std::vector<CraftDefinition*> >::iterator
vec_iter = m_output_craft_definitions.find(output.item);
if (vec_iter == m_output_craft_definitions.end())
continue;
std::vector<CraftDefinition*> &vec = vec_iter->second;
std::vector<CraftDefinition*> new_vec_by_output;
/* We will preallocate necessary memory addresses, so we don't need
to reallocate them later. This would save us some performance. */
new_vec_by_output.reserve(vec.size());
for (std::vector<CraftDefinition*>::iterator i = vec.begin();
i != vec.end(); ++i) {
/* If pointers from map by input and output are not same,
we will add 'CraftDefinition*' to a new vector. */
if (def != *i) {
/* Adding dereferenced iterator value (which are
'CraftDefinition' reference) to a new vector. */
new_vec_by_output.push_back(*i);
}
}
// Swaps assigned to current key value with new vector for output map.
m_output_craft_definitions[output.item].swap(new_vec_by_output);
}
if (got_hit)
// Swaps value with new vector for input map.
m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0].swap(new_vec_by_input);
return got_hit;
}
virtual std::string dump() const
{
std::ostringstream os(std::ios::binary);

View File

@ -426,6 +426,10 @@ public:
virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output,
IGameDef *gamedef, unsigned limit=0) const=0;
virtual bool clearCraftRecipesByOutput(const CraftOutput &output, IGameDef *gamedef) = 0;
virtual bool clearCraftRecipesByInput(CraftMethod craft_method,
unsigned int craft_grid_width, const std::vector<std::string> &recipe, IGameDef *gamedef) = 0;
// Print crafting recipes for debugging
virtual std::string dump() const=0;

View File

@ -56,8 +56,14 @@ SQLite format specification:
SQLOK(sqlite3_prepare_v2(m_database, query, -1, &m_stmt_##name, NULL),\
"Failed to prepare query '" query "'")
#define FINALIZE_STATEMENT(statement) \
SQLOK(sqlite3_finalize(statement), "Failed to finalize " #statement)
#define SQLOK_ERRSTREAM(s, m) \
if ((s) != SQLITE_OK) { \
errorstream << (m) << ": " \
<< sqlite3_errmsg(m_database) << std::endl; \
}
#define FINALIZE_STATEMENT(statement) SQLOK_ERRSTREAM(sqlite3_finalize(statement), \
"Failed to finalize " #statement)
int Database_SQLite3::busyHandler(void *data, int count)
{
@ -289,6 +295,6 @@ Database_SQLite3::~Database_SQLite3()
FINALIZE_STATEMENT(m_stmt_end)
FINALIZE_STATEMENT(m_stmt_delete)
SQLOK(sqlite3_close(m_database), "Failed to close database");
SQLOK_ERRSTREAM(sqlite3_close(m_database), "Failed to close database");
}

View File

@ -50,7 +50,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("keymap_freemove", "KEY_KEY_K");
settings->setDefault("keymap_fastmove", "KEY_KEY_J");
settings->setDefault("keymap_noclip", "KEY_KEY_H");
settings->setDefault("keymap_cinematic", "KEY_F8");
settings->setDefault("keymap_cinematic", "");
settings->setDefault("keymap_screenshot", "KEY_F12");
settings->setDefault("keymap_toggle_hud", "KEY_F1");
settings->setDefault("keymap_toggle_chat", "KEY_F2");
@ -116,6 +116,9 @@ void set_default_settings(Settings *settings)
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");

View File

@ -30,9 +30,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
//#define DGEN_USE_TORCHES
NoiseParams nparams_dungeon_rarity(0.0, 1.0, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0);
NoiseParams nparams_dungeon_wetness(0.0, 1.0, v3f(40.0, 40.0, 40.0), 32474, 4, 1.1, 2.0);
NoiseParams nparams_dungeon_density(0.0, 1.0, v3f(2.5, 2.5, 2.5), 0, 2, 1.4, 2.0);
NoiseParams nparams_dungeon_density(0.9, 0.5, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0);
NoiseParams nparams_dungeon_alt_wall(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0);
///////////////////////////////////////////////////////////////////////////////
@ -55,26 +54,27 @@ DungeonGen::DungeonGen(INodeDefManager *ndef,
} else {
dp.seed = 0;
dp.c_water = ndef->getId("mapgen_water_source");
dp.c_cobble = ndef->getId("mapgen_cobble");
dp.c_moss = ndef->getId("mapgen_mossycobble");
dp.c_stair = ndef->getId("mapgen_stair_cobble");
dp.c_water = ndef->getId("mapgen_water_source");
dp.c_river_water = ndef->getId("mapgen_river_water_source");
dp.c_wall = ndef->getId("mapgen_cobble");
dp.c_alt_wall = ndef->getId("mapgen_mossycobble");
dp.c_stair = ndef->getId("mapgen_stair_cobble");
if (dp.c_river_water == CONTENT_IGNORE)
dp.c_river_water = ndef->getId("mapgen_water_source");
dp.diagonal_dirs = false;
dp.mossratio = 3.0;
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.np_rarity = nparams_dungeon_rarity;
dp.np_wetness = nparams_dungeon_wetness;
dp.np_density = nparams_dungeon_density;
dp.np_density = nparams_dungeon_density;
dp.np_alt_wall = nparams_dungeon_alt_wall;
}
// For mapgens using river water
dp.c_river_water = ndef->getId("mapgen_river_water_source");
if (dp.c_river_water == CONTENT_IGNORE)
dp.c_river_water = ndef->getId("mapgen_water_source");
}
@ -83,7 +83,11 @@ void DungeonGen::generate(MMVManip *vm, u32 bseed, v3s16 nmin, v3s16 nmax)
assert(vm);
//TimeTaker t("gen dungeons");
if (NoisePerlin3D(&dp.np_rarity, nmin.X, nmin.Y, nmin.Z, dp.seed) < 0.2)
if (nmin.Y < dp.y_min || nmax.Y > dp.y_max)
return;
float nval_density = NoisePerlin3D(&dp.np_density, nmin.X, nmin.Y, nmin.Z, dp.seed);
if (nval_density < 1.0f)
return;
this->vm = vm;
@ -107,23 +111,23 @@ void DungeonGen::generate(MMVManip *vm, u32 bseed, v3s16 nmin, v3s16 nmax)
}
}
// Add it
makeDungeon(v3s16(1, 1, 1) * MAP_BLOCKSIZE);
// Add them
for (u32 i = 0; i < floor(nval_density); i++)
makeDungeon(v3s16(1, 1, 1) * MAP_BLOCKSIZE);
// Convert some cobble to mossy cobble
if (dp.mossratio != 0.0) {
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++) {
if (vm->m_data[i].getContent() == dp.c_cobble) {
float wetness = NoisePerlin3D(&dp.np_wetness, x, y, z, dp.seed);
float density = NoisePerlin3D(&dp.np_density, x, y, z, blockseed);
if (density < wetness / dp.mossratio)
vm->m_data[i].setContent(dp.c_moss);
}
i++;
// Optionally convert some structure to alternative structure
if (dp.c_alt_wall == CONTENT_IGNORE)
return;
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++) {
if (vm->m_data[i].getContent() == dp.c_wall) {
if (NoisePerlin3D(&dp.np_alt_wall, x, y, z, blockseed) > 0.0f)
vm->m_data[i].setContent(dp.c_alt_wall);
}
i++;
}
}
@ -189,7 +193,7 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
*/
v3s16 last_room_center = roomplace + v3s16(roomsize.X / 2, 1, roomsize.Z / 2);
u32 room_count = random.range(2, 16);
u32 room_count = random.range(dp.rooms_min, dp.rooms_max);
for (u32 i = 0; i < room_count; i++) {
// Make a room to the determined place
makeRoom(roomsize, roomplace);
@ -265,7 +269,7 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
void DungeonGen::makeRoom(v3s16 roomsize, v3s16 roomplace)
{
MapNode n_cobble(dp.c_cobble);
MapNode n_wall(dp.c_wall);
MapNode n_air(CONTENT_AIR);
// Make +-X walls
@ -278,7 +282,7 @@ void DungeonGen::makeRoom(v3s16 roomsize, v3s16 roomplace)
u32 vi = vm->m_area.index(p);
if (vm->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
continue;
vm->m_data[vi] = n_cobble;
vm->m_data[vi] = n_wall;
}
{
v3s16 p = roomplace + v3s16(roomsize.X - 1, y, z);
@ -287,7 +291,7 @@ void DungeonGen::makeRoom(v3s16 roomsize, v3s16 roomplace)
u32 vi = vm->m_area.index(p);
if (vm->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
continue;
vm->m_data[vi] = n_cobble;
vm->m_data[vi] = n_wall;
}
}
@ -301,7 +305,7 @@ void DungeonGen::makeRoom(v3s16 roomsize, v3s16 roomplace)
u32 vi = vm->m_area.index(p);
if (vm->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
continue;
vm->m_data[vi] = n_cobble;
vm->m_data[vi] = n_wall;
}
{
v3s16 p = roomplace + v3s16(x, y, roomsize.Z - 1);
@ -310,7 +314,7 @@ void DungeonGen::makeRoom(v3s16 roomsize, v3s16 roomplace)
u32 vi = vm->m_area.index(p);
if (vm->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
continue;
vm->m_data[vi] = n_cobble;
vm->m_data[vi] = n_wall;
}
}
@ -324,7 +328,7 @@ void DungeonGen::makeRoom(v3s16 roomsize, v3s16 roomplace)
u32 vi = vm->m_area.index(p);
if (vm->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
continue;
vm->m_data[vi] = n_cobble;
vm->m_data[vi] = n_wall;
}
{
v3s16 p = roomplace + v3s16(x,roomsize. Y - 1, z);
@ -333,7 +337,7 @@ void DungeonGen::makeRoom(v3s16 roomsize, v3s16 roomplace)
u32 vi = vm->m_area.index(p);
if (vm->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
continue;
vm->m_data[vi] = n_cobble;
vm->m_data[vi] = n_wall;
}
}
@ -417,7 +421,7 @@ void DungeonGen::makeCorridor(v3s16 doorplace, v3s16 doordir,
makeFill(p + v3s16(-1, -1, -1),
dp.holesize + v3s16(2, 3, 2),
VMANIP_FLAG_DUNGEON_UNTOUCHABLE,
MapNode(dp.c_cobble),
MapNode(dp.c_wall),
0);
makeHole(p);
makeHole(p - dir);
@ -435,18 +439,18 @@ void DungeonGen::makeCorridor(v3s16 doorplace, v3s16 doordir,
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_cobble)
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_cobble)
if (vm->m_data[vi].getContent() == dp.c_wall)
vm->m_data[vi] = MapNode(dp.c_stair, 0, facedir);
}
} else {
makeFill(p + v3s16(-1, -1, -1),
dp.holesize + v3s16(2, 2, 2),
VMANIP_FLAG_DUNGEON_UNTOUCHABLE,
MapNode(dp.c_cobble),
MapNode(dp.c_wall),
0);
makeHole(p);
}
@ -488,8 +492,8 @@ bool DungeonGen::findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
randomizeDir();
continue;
}
if (vm->getNodeNoExNoEmerge(p).getContent() == dp.c_cobble &&
vm->getNodeNoExNoEmerge(p1).getContent() == dp.c_cobble) {
if (vm->getNodeNoExNoEmerge(p).getContent() == dp.c_wall &&
vm->getNodeNoExNoEmerge(p1).getContent() == dp.c_wall) {
// Found wall, this is a good place!
result_place = p;
result_dir = m_dir;
@ -502,7 +506,7 @@ bool DungeonGen::findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
*/
// Jump one up if the actual space is there
if (vm->getNodeNoExNoEmerge(p +
v3s16(0, 0, 0)).getContent() == dp.c_cobble &&
v3s16(0, 0, 0)).getContent() == dp.c_wall &&
vm->getNodeNoExNoEmerge(p +
v3s16(0, 1, 0)).getContent() == CONTENT_AIR &&
vm->getNodeNoExNoEmerge(p +
@ -510,7 +514,7 @@ bool DungeonGen::findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
p += v3s16(0,1,0);
// Jump one down if the actual space is there
if (vm->getNodeNoExNoEmerge(p +
v3s16(0, 1, 0)).getContent() == dp.c_cobble &&
v3s16(0, 1, 0)).getContent() == dp.c_wall &&
vm->getNodeNoExNoEmerge(p +
v3s16(0, 0, 0)).getContent() == CONTENT_AIR &&
vm->getNodeNoExNoEmerge(p +

View File

@ -39,23 +39,25 @@ int dir_to_facedir(v3s16 d);
struct DungeonParams {
int seed;
s32 seed;
content_t c_water;
content_t c_river_water;
content_t c_cobble;
content_t c_moss;
content_t c_wall;
content_t c_alt_wall;
content_t c_stair;
GenNotifyType notifytype;
bool diagonal_dirs;
float mossratio;
v3s16 holesize;
v3s16 roomsize;
u16 rooms_min;
u16 rooms_max;
s16 y_min;
s16 y_max;
GenNotifyType notifytype;
NoiseParams np_rarity;
NoiseParams np_wetness;
NoiseParams np_density;
NoiseParams np_alt_wall;
};
class DungeonGen {
@ -99,8 +101,7 @@ public:
}
};
extern NoiseParams nparams_dungeon_rarity;
extern NoiseParams nparams_dungeon_wetness;
extern NoiseParams nparams_dungeon_density;
extern NoiseParams nparams_dungeon_alt_wall;
#endif

View File

@ -34,13 +34,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
#include "map.h"
#include "mapblock.h"
#include "mapgen_flat.h"
#include "mapgen_fractal.h"
#include "mapgen_v5.h"
#include "mapgen_v6.h"
#include "mapgen_v7.h"
#include "mapgen_valleys.h"
#include "mapgen_singlenode.h"
#include "mg_biome.h"
#include "mg_ore.h"
#include "mg_decoration.h"
@ -53,13 +46,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "voxel.h"
struct MapgenDesc {
const char *name;
MapgenFactory *factory;
bool is_user_visible;
};
class EmergeThread : public Thread {
public:
bool enable_mapgen_debug_info;
@ -99,20 +85,6 @@ private:
friend class EmergeManager;
};
////
//// Built-in mapgens
////
MapgenDesc g_reg_mapgens[] = {
{"v5", new MapgenFactoryV5, true},
{"v6", new MapgenFactoryV6, true},
{"v7", new MapgenFactoryV7, true},
{"flat", new MapgenFactoryFlat, true},
{"fractal", new MapgenFactoryFractal, true},
{"valleys", new MapgenFactoryValleys, true},
{"singlenode", new MapgenFactorySinglenode, false},
};
////
//// EmergeManager
////
@ -184,37 +156,19 @@ EmergeManager::~EmergeManager()
}
void EmergeManager::loadMapgenParams()
{
params.load(*g_settings);
}
void EmergeManager::initMapgens()
bool EmergeManager::initMapgens(MapgenParams *params)
{
if (m_mapgens.size())
return;
return false;
MapgenFactory *mgfactory = getMapgenFactory(params.mg_name);
if (!mgfactory) {
errorstream << "EmergeManager: mapgen " << params.mg_name <<
" not registered; falling back to " << DEFAULT_MAPGEN << std::endl;
params.mg_name = DEFAULT_MAPGEN;
mgfactory = getMapgenFactory(params.mg_name);
FATAL_ERROR_IF(mgfactory == NULL, "Couldn't use any mapgen!");
}
if (!params.sparams) {
params.sparams = mgfactory->createMapgenParams();
params.sparams->readParams(g_settings);
}
this->mgparams = params;
for (u32 i = 0; i != m_threads.size(); i++) {
Mapgen *mg = mgfactory->createMapgen(i, &params, this);
Mapgen *mg = Mapgen::createMapgen(params->mgtype, i, params, this);
m_mapgens.push_back(mg);
}
return true;
}
@ -316,12 +270,14 @@ bool EmergeManager::enqueueBlockEmergeEx(
// Mapgen-related helper functions
//
// TODO(hmmmm): Move this to ServerMap
v3s16 EmergeManager::getContainingChunk(v3s16 blockpos)
{
return getContainingChunk(blockpos, params.chunksize);
return getContainingChunk(blockpos, mgparams->chunksize);
}
// TODO(hmmmm): Move this to ServerMap
v3s16 EmergeManager::getContainingChunk(v3s16 blockpos, s16 chunksize)
{
s16 coff = -chunksize / 2;
@ -355,7 +311,7 @@ int EmergeManager::getGroundLevelAtPoint(v2s16 p)
return m_mapgens[0]->getGroundLevelAtPoint(p);
}
// TODO(hmmmm): Move this to ServerMap
bool EmergeManager::isBlockUnderground(v3s16 blockpos)
{
#if 0
@ -366,31 +322,9 @@ bool EmergeManager::isBlockUnderground(v3s16 blockpos)
#endif
// Use a simple heuristic; the above method is wildly inaccurate anyway.
return blockpos.Y * (MAP_BLOCKSIZE + 1) <= params.water_level;
return blockpos.Y * (MAP_BLOCKSIZE + 1) <= mgparams->water_level;
}
void EmergeManager::getMapgenNames(
std::vector<const char *> *mgnames, bool include_hidden)
{
for (u32 i = 0; i != ARRLEN(g_reg_mapgens); i++) {
if (include_hidden || g_reg_mapgens[i].is_user_visible)
mgnames->push_back(g_reg_mapgens[i].name);
}
}
MapgenFactory *EmergeManager::getMapgenFactory(const std::string &mgname)
{
for (u32 i = 0; i != ARRLEN(g_reg_mapgens); i++) {
if (mgname == g_reg_mapgens[i].name)
return g_reg_mapgens[i].factory;
}
return NULL;
}
bool EmergeManager::pushBlockEmergeData(
v3s16 pos,
u16 peer_requested,

View File

@ -97,8 +97,16 @@ public:
u32 gen_notify_on;
std::set<u32> gen_notify_on_deco_ids;
// Map generation parameters
MapgenParams params;
// Parameters passed to mapgens owned by ServerMap
// TODO(hmmmm): Remove this after mapgen helper methods using them
// are moved to ServerMap
MapgenParams *mgparams;
// Hackish workaround:
// For now, EmergeManager must hold onto a ptr to the Map's setting manager
// since the Map can only be accessed through the Environment, and the
// Environment is not created until after script initialization.
MapSettingsManager *map_settings_mgr;
// Managers of various map generation-related components
BiomeManager *biomemgr;
@ -110,8 +118,7 @@ public:
EmergeManager(IGameDef *gamedef);
~EmergeManager();
void loadMapgenParams();
void initMapgens();
bool initMapgens(MapgenParams *mgparams);
void startThreads();
void stopThreads();
@ -140,9 +147,6 @@ public:
int getGroundLevelAtPoint(v2s16 p);
bool isBlockUnderground(v3s16 blockpos);
static MapgenFactory *getMapgenFactory(const std::string &mgname);
static void getMapgenNames(
std::vector<const char *> *mgnames, bool include_hidden);
static v3s16 getContainingChunk(v3s16 blockpos, s16 chunksize);
private:

View File

@ -1030,17 +1030,17 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
m_lbm_mgr.applyLBMs(this, block, stamp);
// Run node timers
std::map<v3s16, NodeTimer> elapsed_timers =
std::vector<NodeTimer> elapsed_timers =
block->m_node_timers.step((float)dtime_s);
if(!elapsed_timers.empty()){
if (!elapsed_timers.empty()) {
MapNode n;
for(std::map<v3s16, NodeTimer>::iterator
for (std::vector<NodeTimer>::iterator
i = elapsed_timers.begin();
i != elapsed_timers.end(); ++i){
n = block->getNodeNoEx(i->first);
v3s16 p = i->first + block->getPosRelative();
if(m_script->node_on_timer(p,n,i->second.elapsed))
block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
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));
}
}
@ -1435,16 +1435,19 @@ void ServerEnvironment::step(float dtime)
MOD_REASON_BLOCK_EXPIRED);
// Run node timers
std::map<v3s16, NodeTimer> elapsed_timers = block->m_node_timers.step(m_cache_nodetimer_interval);
if(!elapsed_timers.empty()){
MapNode n;
for(std::map<v3s16, NodeTimer>::iterator
for (std::vector<NodeTimer>::iterator
i = elapsed_timers.begin();
i != elapsed_timers.end(); ++i){
n = block->getNodeNoEx(i->first);
p = i->first + block->getPosRelative();
if(m_script->node_on_timer(p,n,i->second.elapsed))
block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
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));
}
}
}
}

View File

@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "camera.h"
#include "client.h"
#include "client/tile.h" // For TextureSource
#include "client/keys.h"
#include "client/joystick_controller.h"
#include "clientmap.h"
#include "clouds.h"
#include "config.h"
@ -1107,12 +1109,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)
{
if (*cur_formspec == 0) {
*cur_formspec = new GUIFormSpecMenu(device, guiroot, -1, &g_menumgr,
invmgr, gamedef, tsrc, fs_src, txt_dest, client);
*cur_formspec = new GUIFormSpecMenu(device, joystick,
guiroot, -1, &g_menumgr, invmgr, gamedef, tsrc,
fs_src, txt_dest, client);
(*cur_formspec)->doPause = false;
/*
@ -1137,7 +1141,8 @@ static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec,
static void show_deathscreen(GUIFormSpecMenu **cur_formspec,
InventoryManager *invmgr, IGameDef *gamedef,
IWritableTextureSource *tsrc, IrrlichtDevice *device, Client *client)
IWritableTextureSource *tsrc, IrrlichtDevice *device,
JoystickController *joystick, Client *client)
{
std::string formspec =
std::string(FORMSPEC_VERSION_STRING) +
@ -1153,14 +1158,15 @@ static void show_deathscreen(GUIFormSpecMenu **cur_formspec,
FormspecFormSource *fs_src = new FormspecFormSource(formspec);
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client);
create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device, fs_src, txt_dst, NULL);
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,
bool singleplayermode)
JoystickController *joystick, bool singleplayermode)
{
#ifdef __ANDROID__
std::string control_text = strgettext("Default Controls:\n"
@ -1225,7 +1231,8 @@ static void show_pause_menu(GUIFormSpecMenu **cur_formspec,
FormspecFormSource *fs_src = new FormspecFormSource(os.str());
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU");
create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device, fs_src, txt_dst, NULL);
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;
@ -1266,10 +1273,10 @@ static void updateChat(Client &client, f32 dtime, bool show_debug,
setStaticText(guitext_chat, recent_chat);
// Update gui element size and position
s32 chat_y = 5 + line_height;
s32 chat_y = 5;
if (show_debug)
chat_y += line_height;
chat_y += 2 * line_height;
// first pass to calculate height of text to be set
s32 width = std::min(g_fontengine->getTextWidth(recent_chat.c_str()) + 10,
@ -1306,114 +1313,76 @@ struct KeyCache {
{
handler = NULL;
populate();
populate_nonchanging();
}
enum {
// Player movement
KEYMAP_ID_FORWARD,
KEYMAP_ID_BACKWARD,
KEYMAP_ID_LEFT,
KEYMAP_ID_RIGHT,
KEYMAP_ID_JUMP,
KEYMAP_ID_SPECIAL1,
KEYMAP_ID_SNEAK,
KEYMAP_ID_AUTORUN,
// Other
KEYMAP_ID_DROP,
KEYMAP_ID_INVENTORY,
KEYMAP_ID_CHAT,
KEYMAP_ID_CMD,
KEYMAP_ID_CONSOLE,
KEYMAP_ID_MINIMAP,
KEYMAP_ID_FREEMOVE,
KEYMAP_ID_FASTMOVE,
KEYMAP_ID_NOCLIP,
KEYMAP_ID_CINEMATIC,
KEYMAP_ID_SCREENSHOT,
KEYMAP_ID_TOGGLE_HUD,
KEYMAP_ID_TOGGLE_CHAT,
KEYMAP_ID_TOGGLE_FORCE_FOG_OFF,
KEYMAP_ID_TOGGLE_UPDATE_CAMERA,
KEYMAP_ID_TOGGLE_DEBUG,
KEYMAP_ID_TOGGLE_PROFILER,
KEYMAP_ID_CAMERA_MODE,
KEYMAP_ID_INCREASE_VIEWING_RANGE,
KEYMAP_ID_DECREASE_VIEWING_RANGE,
KEYMAP_ID_RANGESELECT,
KEYMAP_ID_QUICKTUNE_NEXT,
KEYMAP_ID_QUICKTUNE_PREV,
KEYMAP_ID_QUICKTUNE_INC,
KEYMAP_ID_QUICKTUNE_DEC,
KEYMAP_ID_DEBUG_STACKS,
// Fake keycode for array size and internal checks
KEYMAP_INTERNAL_ENUM_COUNT
};
void populate();
KeyPress key[KEYMAP_INTERNAL_ENUM_COUNT];
// Keys that are not settings dependent
void populate_nonchanging();
KeyPress key[KeyType::INTERNAL_ENUM_COUNT];
InputHandler *handler;
};
void KeyCache::populate_nonchanging()
{
key[KeyType::ESC] = EscapeKey;
}
void KeyCache::populate()
{
key[KEYMAP_ID_FORWARD] = getKeySetting("keymap_forward");
key[KEYMAP_ID_BACKWARD] = getKeySetting("keymap_backward");
key[KEYMAP_ID_LEFT] = getKeySetting("keymap_left");
key[KEYMAP_ID_RIGHT] = getKeySetting("keymap_right");
key[KEYMAP_ID_JUMP] = getKeySetting("keymap_jump");
key[KEYMAP_ID_SPECIAL1] = getKeySetting("keymap_special1");
key[KEYMAP_ID_SNEAK] = getKeySetting("keymap_sneak");
key[KeyType::FORWARD] = getKeySetting("keymap_forward");
key[KeyType::BACKWARD] = getKeySetting("keymap_backward");
key[KeyType::LEFT] = getKeySetting("keymap_left");
key[KeyType::RIGHT] = getKeySetting("keymap_right");
key[KeyType::JUMP] = getKeySetting("keymap_jump");
key[KeyType::SPECIAL1] = getKeySetting("keymap_special1");
key[KeyType::SNEAK] = getKeySetting("keymap_sneak");
key[KEYMAP_ID_AUTORUN] = getKeySetting("keymap_autorun");
key[KeyType::AUTORUN] = getKeySetting("keymap_autorun");
key[KEYMAP_ID_DROP] = getKeySetting("keymap_drop");
key[KEYMAP_ID_INVENTORY] = getKeySetting("keymap_inventory");
key[KEYMAP_ID_CHAT] = getKeySetting("keymap_chat");
key[KEYMAP_ID_CMD] = getKeySetting("keymap_cmd");
key[KEYMAP_ID_CONSOLE] = getKeySetting("keymap_console");
key[KEYMAP_ID_MINIMAP] = getKeySetting("keymap_minimap");
key[KEYMAP_ID_FREEMOVE] = getKeySetting("keymap_freemove");
key[KEYMAP_ID_FASTMOVE] = getKeySetting("keymap_fastmove");
key[KEYMAP_ID_NOCLIP] = getKeySetting("keymap_noclip");
key[KEYMAP_ID_CINEMATIC] = getKeySetting("keymap_cinematic");
key[KEYMAP_ID_SCREENSHOT] = getKeySetting("keymap_screenshot");
key[KEYMAP_ID_TOGGLE_HUD] = getKeySetting("keymap_toggle_hud");
key[KEYMAP_ID_TOGGLE_CHAT] = getKeySetting("keymap_toggle_chat");
key[KEYMAP_ID_TOGGLE_FORCE_FOG_OFF]
key[KeyType::DROP] = getKeySetting("keymap_drop");
key[KeyType::INVENTORY] = getKeySetting("keymap_inventory");
key[KeyType::CHAT] = getKeySetting("keymap_chat");
key[KeyType::CMD] = getKeySetting("keymap_cmd");
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::CINEMATIC] = getKeySetting("keymap_cinematic");
key[KeyType::SCREENSHOT] = getKeySetting("keymap_screenshot");
key[KeyType::TOGGLE_HUD] = getKeySetting("keymap_toggle_hud");
key[KeyType::TOGGLE_CHAT] = getKeySetting("keymap_toggle_chat");
key[KeyType::TOGGLE_FORCE_FOG_OFF]
= getKeySetting("keymap_toggle_force_fog_off");
key[KEYMAP_ID_TOGGLE_UPDATE_CAMERA]
key[KeyType::TOGGLE_UPDATE_CAMERA]
= getKeySetting("keymap_toggle_update_camera");
key[KEYMAP_ID_TOGGLE_DEBUG]
key[KeyType::TOGGLE_DEBUG]
= getKeySetting("keymap_toggle_debug");
key[KEYMAP_ID_TOGGLE_PROFILER]
key[KeyType::TOGGLE_PROFILER]
= getKeySetting("keymap_toggle_profiler");
key[KEYMAP_ID_CAMERA_MODE]
key[KeyType::CAMERA_MODE]
= getKeySetting("keymap_camera_mode");
key[KEYMAP_ID_INCREASE_VIEWING_RANGE]
key[KeyType::INCREASE_VIEWING_RANGE]
= getKeySetting("keymap_increase_viewing_range_min");
key[KEYMAP_ID_DECREASE_VIEWING_RANGE]
key[KeyType::DECREASE_VIEWING_RANGE]
= getKeySetting("keymap_decrease_viewing_range_min");
key[KEYMAP_ID_RANGESELECT]
key[KeyType::RANGESELECT]
= getKeySetting("keymap_rangeselect");
key[KEYMAP_ID_QUICKTUNE_NEXT] = getKeySetting("keymap_quicktune_next");
key[KEYMAP_ID_QUICKTUNE_PREV] = getKeySetting("keymap_quicktune_prev");
key[KEYMAP_ID_QUICKTUNE_INC] = getKeySetting("keymap_quicktune_inc");
key[KEYMAP_ID_QUICKTUNE_DEC] = getKeySetting("keymap_quicktune_dec");
key[KeyType::QUICKTUNE_NEXT] = getKeySetting("keymap_quicktune_next");
key[KeyType::QUICKTUNE_PREV] = getKeySetting("keymap_quicktune_prev");
key[KeyType::QUICKTUNE_INC] = getKeySetting("keymap_quicktune_inc");
key[KeyType::QUICKTUNE_DEC] = getKeySetting("keymap_quicktune_dec");
key[KEYMAP_ID_DEBUG_STACKS] = getKeySetting("keymap_print_debug_stacks");
key[KeyType::DEBUG_STACKS] = getKeySetting("keymap_print_debug_stacks");
if (handler) {
// First clear all keys, then re-add the ones we listen for
handler->dontListenForKeys();
for (size_t i = 0; i < KEYMAP_INTERNAL_ENUM_COUNT; i++) {
for (size_t i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) {
handler->listenForKey(key[i]);
}
handler->listenForKey(EscapeKey);
@ -1575,9 +1544,10 @@ protected:
f32 dtime);
void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
// Input related
void processUserInput(VolatileRunFlags *flags, GameRunData *runData,
f32 dtime);
void processKeyboardInput(VolatileRunFlags *flags,
void processKeyInput(VolatileRunFlags *flags,
float *statustext_time,
float *jump_timer,
bool *reset_jump_timer,
@ -1610,9 +1580,10 @@ protected:
void decreaseViewRange(float *statustext_time);
void toggleFullViewRange(float *statustext_time);
void updateCameraDirection(CameraOrientation *cam, VolatileRunFlags *flags);
void updateCameraDirection(CameraOrientation *cam, VolatileRunFlags *flags,
float dtime);
void updateCameraOrientation(CameraOrientation *cam,
const VolatileRunFlags &flags);
const VolatileRunFlags &flags, float dtime);
void updatePlayerControl(const CameraOrientation &cam);
void step(f32 *dtime);
void processClientEvents(CameraOrientation *cam, float *damage_flash);
@ -1647,6 +1618,41 @@ protected:
static void settingChangedCallback(const std::string &setting_name, void *data);
void readSettings();
inline bool getLeftClicked()
{
return input->getLeftClicked() ||
input->joystick.getWasKeyDown(KeyType::MOUSE_L);
}
inline bool getRightClicked()
{
return input->getRightClicked() ||
input->joystick.getWasKeyDown(KeyType::MOUSE_R);
}
inline bool isLeftPressed()
{
return input->getLeftState() ||
input->joystick.isKeyDown(KeyType::MOUSE_L);
}
inline bool isRightPressed()
{
return input->getRightState() ||
input->joystick.isKeyDown(KeyType::MOUSE_R);
}
inline bool getLeftReleased()
{
return input->getLeftReleased() ||
input->joystick.wasKeyReleased(KeyType::MOUSE_L);
}
inline bool isKeyDown(GameKeyType k)
{
return input->isKeyDown(keycache.key[k]) || input->joystick.isKeyDown(k);
}
inline bool wasKeyDown(GameKeyType k)
{
return input->wasKeyDown(keycache.key[k]) || input->joystick.wasKeyDown(k);
}
#ifdef __ANDROID__
void handleAndroidChatInput();
#endif
@ -1730,9 +1736,11 @@ private:
*/
bool m_cache_doubletap_jump;
bool m_cache_enable_clouds;
bool m_cache_enable_joysticks;
bool m_cache_enable_particles;
bool m_cache_enable_fog;
f32 m_cache_mouse_sensitivity;
f32 m_cache_joystick_frustum_sensitivity;
f32 m_repeat_right_click_time;
#ifdef __ANDROID__
@ -1768,12 +1776,16 @@ Game::Game() :
&settingChangedCallback, this);
g_settings->registerChangedCallback("enable_clouds",
&settingChangedCallback, this);
g_settings->registerChangedCallback("doubletap_joysticks",
&settingChangedCallback, this);
g_settings->registerChangedCallback("enable_particles",
&settingChangedCallback, this);
g_settings->registerChangedCallback("enable_fog",
&settingChangedCallback, this);
g_settings->registerChangedCallback("mouse_sensitivity",
&settingChangedCallback, this);
g_settings->registerChangedCallback("joystick_frustum_sensitivity",
&settingChangedCallback, this);
g_settings->registerChangedCallback("repeat_rightclick_time",
&settingChangedCallback, this);
@ -1936,7 +1948,7 @@ void Game::run()
updateProfilers(runData, stats, draw_times, dtime);
processUserInput(&flags, &runData, dtime);
// Update camera before player movement to avoid camera lag of one frame
updateCameraDirection(&cam_view_target, &flags);
updateCameraDirection(&cam_view_target, &flags, dtime);
float cam_smoothing = 0;
if (g_settings->getBool("cinematic"))
cam_smoothing = 1 - g_settings->getFloat("cinematic_camera_smoothing");
@ -2193,6 +2205,8 @@ bool Game::createClient(const std::string &playername,
/* Set window caption
*/
std::wstring str = utf8_to_wide(PROJECT_NAME_C);
str += L" ";
str += utf8_to_wide(g_version_hash);
str += L" [";
str += driver->getName();
str += L"]";
@ -2379,7 +2393,7 @@ bool Game::connectToServer(const std::string &playername,
break;
}
if (input->wasKeyDown(EscapeKey) || input->wasKeyDown(CancelKey)) {
if (wasKeyDown(KeyType::ESC) || input->wasKeyDown(CancelKey)) {
*aborted = true;
infostream << "Connect aborted [Escape]" << std::endl;
break;
@ -2440,7 +2454,7 @@ bool Game::getServerContent(bool *aborted)
return false;
}
if (input->wasKeyDown(EscapeKey) || input->wasKeyDown(CancelKey)) {
if (wasKeyDown(KeyType::ESC) || input->wasKeyDown(CancelKey)) {
*aborted = true;
infostream << "Connect aborted [Escape]" << std::endl;
return false;
@ -2702,7 +2716,7 @@ void Game::processUserInput(VolatileRunFlags *flags,
if (m_cache_doubletap_jump && runData->jump_timer <= 0.2)
runData->jump_timer += dtime;
processKeyboardInput(
processKeyInput(
flags,
&runData->statustext_time,
&runData->jump_timer,
@ -2714,7 +2728,7 @@ void Game::processUserInput(VolatileRunFlags *flags,
}
void Game::processKeyboardInput(VolatileRunFlags *flags,
void Game::processKeyInput(VolatileRunFlags *flags,
float *statustext_time,
float *jump_timer,
bool *reset_jump_timer,
@ -2724,66 +2738,67 @@ void Game::processKeyboardInput(VolatileRunFlags *flags,
//TimeTaker tt("process kybd input", NULL, PRECISION_NANO);
if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_DROP])) {
if (wasKeyDown(KeyType::DROP)) {
dropSelectedItem();
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_AUTORUN])) {
} else if (wasKeyDown(KeyType::AUTORUN)) {
toggleAutorun(statustext_time);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_INVENTORY])) {
} else if (wasKeyDown(KeyType::INVENTORY)) {
openInventory();
} else if (input->wasKeyDown(EscapeKey) || input->wasKeyDown(CancelKey)) {
} else if (wasKeyDown(KeyType::ESC) || input->wasKeyDown(CancelKey)) {
if (!gui_chat_console->isOpenInhibited()) {
show_pause_menu(&current_formspec, client, gamedef,
texture_src, device, simple_singleplayer_mode);
texture_src, device, &input->joystick,
simple_singleplayer_mode);
}
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CHAT])) {
} else if (wasKeyDown(KeyType::CHAT)) {
openConsole(0.2, L"");
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CMD])) {
} else if (wasKeyDown(KeyType::CMD)) {
openConsole(0.2, L"/");
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CONSOLE])) {
} else if (wasKeyDown(KeyType::CONSOLE)) {
openConsole(1);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_FREEMOVE])) {
} else if (wasKeyDown(KeyType::FREEMOVE)) {
toggleFreeMove(statustext_time);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_JUMP])) {
} else if (wasKeyDown(KeyType::JUMP)) {
toggleFreeMoveAlt(statustext_time, jump_timer);
*reset_jump_timer = true;
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_FASTMOVE])) {
} else if (wasKeyDown(KeyType::FASTMOVE)) {
toggleFast(statustext_time);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_NOCLIP])) {
} else if (wasKeyDown(KeyType::NOCLIP)) {
toggleNoClip(statustext_time);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CINEMATIC])) {
} else if (wasKeyDown(KeyType::CINEMATIC)) {
toggleCinematic(statustext_time);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_SCREENSHOT])) {
} else if (wasKeyDown(KeyType::SCREENSHOT)) {
client->makeScreenshot(device);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_HUD])) {
} else if (wasKeyDown(KeyType::TOGGLE_HUD)) {
toggleHud(statustext_time, &flags->show_hud);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_MINIMAP])) {
} else if (wasKeyDown(KeyType::MINIMAP)) {
toggleMinimap(statustext_time, &flags->show_minimap, flags->show_hud,
input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_SNEAK]));
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_CHAT])) {
isKeyDown(KeyType::SNEAK));
} else if (wasKeyDown(KeyType::TOGGLE_CHAT)) {
toggleChat(statustext_time, &flags->show_chat);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_FORCE_FOG_OFF])) {
} else if (wasKeyDown(KeyType::TOGGLE_FORCE_FOG_OFF)) {
toggleFog(statustext_time, &flags->force_fog_off);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_UPDATE_CAMERA])) {
} else if (wasKeyDown(KeyType::TOGGLE_UPDATE_CAMERA)) {
toggleUpdateCamera(statustext_time, &flags->disable_camera_update);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_DEBUG])) {
} else if (wasKeyDown(KeyType::TOGGLE_DEBUG)) {
toggleDebug(statustext_time, &flags->show_debug, &flags->show_profiler_graph);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_PROFILER])) {
} else if (wasKeyDown(KeyType::TOGGLE_PROFILER)) {
toggleProfiler(statustext_time, profiler_current_page, profiler_max_page);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_INCREASE_VIEWING_RANGE])) {
} else if (wasKeyDown(KeyType::INCREASE_VIEWING_RANGE)) {
increaseViewRange(statustext_time);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_DECREASE_VIEWING_RANGE])) {
} else if (wasKeyDown(KeyType::DECREASE_VIEWING_RANGE)) {
decreaseViewRange(statustext_time);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_RANGESELECT])) {
} else if (wasKeyDown(KeyType::RANGESELECT)) {
toggleFullViewRange(statustext_time);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_NEXT])) {
} else if (wasKeyDown(KeyType::QUICKTUNE_NEXT)) {
quicktune->next();
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_PREV])) {
} else if (wasKeyDown(KeyType::QUICKTUNE_PREV)) {
quicktune->prev();
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_INC])) {
} else if (wasKeyDown(KeyType::QUICKTUNE_INC)) {
quicktune->inc();
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_DEC])) {
} else if (wasKeyDown(KeyType::QUICKTUNE_DEC)) {
quicktune->dec();
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_DEBUG_STACKS])) {
} else if (wasKeyDown(KeyType::DEBUG_STACKS)) {
// Print debug stacks
dstream << "-----------------------------------------"
<< std::endl;
@ -2844,7 +2859,7 @@ void Game::processKeyboardInput(VolatileRunFlags *flags,
}
}
if (!input->isKeyDown(getKeySetting("keymap_jump")) && *reset_jump_timer) {
if (!isKeyDown(KeyType::JUMP) && *reset_jump_timer) {
*reset_jump_timer = false;
*jump_timer = 0.0;
}
@ -2858,7 +2873,6 @@ void Game::processKeyboardInput(VolatileRunFlags *flags,
}
}
void Game::processItemSelection(u16 *new_playeritem)
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
@ -2871,12 +2885,21 @@ void Game::processItemSelection(u16 *new_playeritem)
u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE - 1,
player->hud_hotbar_itemcount - 1);
if (wheel < 0)
*new_playeritem = *new_playeritem < max_item ? *new_playeritem + 1 : 0;
else if (wheel > 0)
*new_playeritem = *new_playeritem > 0 ? *new_playeritem - 1 : max_item;
// else wheel == 0
s32 dir = wheel;
if (input->joystick.wasKeyDown(KeyType::SCROLL_DOWN)) {
dir = -1;
}
if (input->joystick.wasKeyDown(KeyType::SCROLL_UP)) {
dir = 1;
}
if (dir < 0)
*new_playeritem = *new_playeritem < max_item ? *new_playeritem + 1 : 0;
else if (dir > 0)
*new_playeritem = *new_playeritem > 0 ? *new_playeritem - 1 : max_item;
// else dir == 0
/* Item selection using keyboard
*/
@ -2926,7 +2949,7 @@ void Game::openInventory()
TextDest *txt_dst = new TextDestPlayerInventory(client);
create_formspec_menu(&current_formspec, client, gamedef, texture_src,
device, fs_src, txt_dst, client);
device, &input->joystick, fs_src, txt_dst, client);
InventoryLocation inventoryloc;
inventoryloc.setCurrentPlayer();
@ -3212,7 +3235,7 @@ void Game::toggleFullViewRange(float *statustext_time)
void Game::updateCameraDirection(CameraOrientation *cam,
VolatileRunFlags *flags)
VolatileRunFlags *flags, float dtime)
{
if ((device->isWindowActive() && noMenuActive()) || random_input) {
@ -3227,7 +3250,7 @@ void Game::updateCameraDirection(CameraOrientation *cam,
if (flags->first_loop_after_window_activation)
flags->first_loop_after_window_activation = false;
else
updateCameraOrientation(cam, *flags);
updateCameraOrientation(cam, *flags, dtime);
input->setMousePos((driver->getScreenSize().Width / 2),
(driver->getScreenSize().Height / 2));
@ -3245,9 +3268,8 @@ void Game::updateCameraDirection(CameraOrientation *cam,
}
}
void Game::updateCameraOrientation(CameraOrientation *cam,
const VolatileRunFlags &flags)
const VolatileRunFlags &flags, float dtime)
{
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui) {
@ -3255,6 +3277,7 @@ void Game::updateCameraOrientation(CameraOrientation *cam,
cam->camera_pitch = g_touchscreengui->getPitch();
} else {
#endif
s32 dx = input->getMousePos().X - (driver->getScreenSize().Width / 2);
s32 dy = input->getMousePos().Y - (driver->getScreenSize().Height / 2);
@ -3270,6 +3293,14 @@ void Game::updateCameraOrientation(CameraOrientation *cam,
}
#endif
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_pitch = rangelim(cam->camera_pitch, -89.5, 89.5);
}
@ -3278,30 +3309,36 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
{
//TimeTaker tt("update player control", NULL, PRECISION_NANO);
// DO NOT use the isKeyDown method for the forward, backward, left, right
// buttons, as the code that uses the controls needs to be able to
// distinguish between the two in order to know when to use joysticks.
PlayerControl control(
input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_FORWARD]),
input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_BACKWARD]),
input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_LEFT]),
input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_RIGHT]),
input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_JUMP]),
input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_SPECIAL1]),
input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_SNEAK]),
input->getLeftState(),
input->getRightState(),
input->isKeyDown(keycache.key[KeyType::FORWARD]),
input->isKeyDown(keycache.key[KeyType::BACKWARD]),
input->isKeyDown(keycache.key[KeyType::LEFT]),
input->isKeyDown(keycache.key[KeyType::RIGHT]),
isKeyDown(KeyType::JUMP),
isKeyDown(KeyType::SPECIAL1),
isKeyDown(KeyType::SNEAK),
isLeftPressed(),
isRightPressed(),
cam.camera_pitch,
cam.camera_yaw
cam.camera_yaw,
input->joystick.getAxisWithoutDead(JA_SIDEWARD_MOVE),
input->joystick.getAxisWithoutDead(JA_FORWARD_MOVE)
);
u32 keypress_bits =
( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_FORWARD]) & 0x1) << 0) |
( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_BACKWARD]) & 0x1) << 1) |
( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_LEFT]) & 0x1) << 2) |
( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_RIGHT]) & 0x1) << 3) |
( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_JUMP]) & 0x1) << 4) |
( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_SPECIAL1]) & 0x1) << 5) |
( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_SNEAK]) & 0x1) << 6) |
( (u32)(input->getLeftState() & 0x1) << 7) |
( (u32)(input->getRightState() & 0x1) << 8
( (u32)(isKeyDown(KeyType::FORWARD) & 0x1) << 0) |
( (u32)(isKeyDown(KeyType::BACKWARD) & 0x1) << 1) |
( (u32)(isKeyDown(KeyType::LEFT) & 0x1) << 2) |
( (u32)(isKeyDown(KeyType::RIGHT) & 0x1) << 3) |
( (u32)(isKeyDown(KeyType::JUMP) & 0x1) << 4) |
( (u32)(isKeyDown(KeyType::SPECIAL1) & 0x1) << 5) |
( (u32)(isKeyDown(KeyType::SNEAK) & 0x1) << 6) |
( (u32)(isLeftPressed() & 0x1) << 7) |
( (u32)(isRightPressed() & 0x1) << 8
);
#ifdef ANDROID
@ -3370,7 +3407,7 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash)
cam->camera_pitch = event.player_force_move.pitch;
} else if (event.type == CE_DEATHSCREEN) {
show_deathscreen(&current_formspec, client, gamedef, texture_src,
device, client);
device, &input->joystick, client);
chat_backend->addMessage(L"", L"You died.");
@ -3386,7 +3423,8 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash)
new TextDestPlayerInventory(client, *(event.show_formspec.formname));
create_formspec_menu(&current_formspec, client, gamedef,
texture_src, device, fs_src, txt_dst, client);
texture_src, device, &input->joystick,
fs_src, txt_dst, client);
delete(event.show_formspec.formspec);
delete(event.show_formspec.formname);
@ -3573,7 +3611,7 @@ void Game::updateCamera(VolatileRunFlags *flags, u32 busy_time,
v3s16 old_camera_offset = camera->getOffset();
if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CAMERA_MODE])) {
if (wasKeyDown(KeyType::CAMERA_MODE)) {
GenericCAO *playercao = player->getCAO();
// If playercao not loaded, don't change camera
@ -3723,7 +3761,7 @@ void Game::processPlayerInteraction(GameRunData *runData,
- pointing away from node
*/
if (runData->digging) {
if (input->getLeftReleased()) {
if (getLeftReleased()) {
infostream << "Left button released"
<< " (stopped digging)" << std::endl;
runData->digging = false;
@ -3749,7 +3787,7 @@ void Game::processPlayerInteraction(GameRunData *runData,
}
}
if (!runData->digging && runData->ldown_for_dig && !input->getLeftState()) {
if (!runData->digging && runData->ldown_for_dig && !isLeftPressed()) {
runData->ldown_for_dig = false;
}
@ -3757,13 +3795,13 @@ void Game::processPlayerInteraction(GameRunData *runData,
soundmaker->m_player_leftpunch_sound.name = "";
if (input->getRightState())
if (isRightPressed())
runData->repeat_rightclick_timer += dtime;
else
runData->repeat_rightclick_timer = 0;
if (playeritem_def.usable && input->getLeftState()) {
if (input->getLeftClicked())
if (playeritem_def.usable && isLeftPressed()) {
if (getLeftClicked())
client->interact(4, pointed);
} else if (pointed.type == POINTEDTHING_NODE) {
ToolCapabilities playeritem_toolcap =
@ -3773,23 +3811,29 @@ void Game::processPlayerInteraction(GameRunData *runData,
} else if (pointed.type == POINTEDTHING_OBJECT) {
handlePointingAtObject(runData, pointed, playeritem,
player_position, show_debug);
} else if (input->getLeftState()) {
} else if (isLeftPressed()) {
// When button is held down in air, show continuous animation
runData->left_punch = true;
} else if (input->getRightClicked()) {
} else if (getRightClicked()) {
handlePointingAtNothing(runData, playeritem);
}
runData->pointed_old = pointed;
if (runData->left_punch || input->getLeftClicked())
if (runData->left_punch || getLeftClicked())
camera->setDigging(0); // left click animation
input->resetLeftClicked();
input->resetRightClicked();
input->joystick.clearWasKeyDown(KeyType::MOUSE_L);
input->joystick.clearWasKeyDown(KeyType::MOUSE_R);
input->resetLeftReleased();
input->resetRightReleased();
input->joystick.clearWasKeyReleased(KeyType::MOUSE_L);
input->joystick.clearWasKeyReleased(KeyType::MOUSE_R);
}
@ -3827,19 +3871,19 @@ void Game::handlePointingAtNode(GameRunData *runData,
}
}
if (runData->nodig_delay_timer <= 0.0 && input->getLeftState()
if (runData->nodig_delay_timer <= 0.0 && isLeftPressed()
&& client->checkPrivilege("interact")) {
handleDigging(runData, pointed, nodepos, playeritem_toolcap, dtime);
}
if ((input->getRightClicked() ||
if ((getRightClicked() ||
runData->repeat_rightclick_timer >= m_repeat_right_click_time) &&
client->checkPrivilege("interact")) {
runData->repeat_rightclick_timer = 0;
infostream << "Ground right-clicked" << std::endl;
if (meta && meta->getString("formspec") != "" && !random_input
&& !input->isKeyDown(getKeySetting("keymap_sneak"))) {
&& !isKeyDown(KeyType::SNEAK)) {
infostream << "Launching custom inventory view" << std::endl;
InventoryLocation inventoryloc;
@ -3850,7 +3894,7 @@ void Game::handlePointingAtNode(GameRunData *runData,
TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client);
create_formspec_menu(&current_formspec, client, gamedef,
texture_src, device, fs_src, txt_dst, client);
texture_src, device, &input->joystick, fs_src, txt_dst, client);
current_formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
} else {
@ -3904,7 +3948,7 @@ void Game::handlePointingAtObject(GameRunData *runData,
runData->selected_object->debugInfoText()));
}
if (input->getLeftState()) {
if (isLeftPressed()) {
bool do_punch = false;
bool do_punch_damage = false;
@ -3914,7 +3958,7 @@ void Game::handlePointingAtObject(GameRunData *runData,
runData->object_hit_delay_timer = object_hit_delay;
}
if (input->getLeftClicked())
if (getLeftClicked())
do_punch = true;
if (do_punch) {
@ -3934,7 +3978,7 @@ void Game::handlePointingAtObject(GameRunData *runData,
if (!disable_send)
client->interact(0, pointed);
}
} else if (input->getRightClicked()) {
} else if (getRightClicked()) {
infostream << "Right-clicked object" << std::endl;
client->interact(3, pointed); // place
}
@ -4312,23 +4356,12 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats,
inline static const char *yawToDirectionString(int yaw)
{
// NOTE: TODO: This can be done mathematically without the else/else-if
// cascade.
const char *player_direction;
static const char *direction[4] = {"North [+Z]", "West [-X]", "South [-Z]", "East [+X]"};
yaw = wrapDegrees_0_360(yaw);
yaw = (yaw + 45) % 360 / 90;
if (yaw >= 45 && yaw < 135)
player_direction = "West [-X]";
else if (yaw >= 135 && yaw < 225)
player_direction = "South [-Z]";
else if (yaw >= 225 && yaw < 315)
player_direction = "East [+X]";
else
player_direction = "North [+Z]";
return player_direction;
return direction[yaw];
}
@ -4364,9 +4397,9 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
<< ", RTT = " << client->getRTT();
setStaticText(guitext, utf8_to_wide(os.str()).c_str());
guitext->setVisible(true);
} else if (flags.show_hud || flags.show_chat) {
std::ostringstream os(std::ios_base::binary);
os << PROJECT_NAME_C " " << g_version_hash
<< " (" << (player_standing.X)
<< ", " << (player_standing.Y)
@ -4539,12 +4572,14 @@ void Game::settingChangedCallback(const std::string &setting_name, void *data)
void Game::readSettings()
{
m_cache_doubletap_jump = g_settings->getBool("doubletap_jump");
m_cache_enable_clouds = g_settings->getBool("enable_clouds");
m_cache_enable_particles = g_settings->getBool("enable_particles");
m_cache_enable_fog = g_settings->getBool("enable_fog");
m_cache_mouse_sensitivity = g_settings->getFloat("mouse_sensitivity");
m_repeat_right_click_time = g_settings->getFloat("repeat_rightclick_time");
m_cache_doubletap_jump = g_settings->getBool("doubletap_jump");
m_cache_enable_clouds = g_settings->getBool("enable_clouds");
m_cache_enable_joysticks = g_settings->getBool("enable_joysticks");
m_cache_enable_particles = g_settings->getBool("enable_particles");
m_cache_enable_fog = g_settings->getBool("enable_fog");
m_cache_mouse_sensitivity = g_settings->getFloat("mouse_sensitivity");
m_cache_joystick_frustum_sensitivity = g_settings->getFloat("joystick_frustum_sensitivity");
m_repeat_right_click_time = g_settings->getFloat("repeat_rightclick_time");
m_cache_mouse_sensitivity = rangelim(m_cache_mouse_sensitivity, 0.001, 100.0);
}

View File

@ -22,6 +22,8 @@ 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>
@ -134,6 +136,8 @@ public:
virtual void step(float dtime) {}
virtual void clear() {}
JoystickController joystick;
};
class ChatBackend; /* to avoid having to include chat.h */

View File

@ -630,7 +630,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
}
else if(event.KeyInput.Char != 0 && !event.KeyInput.Control)
{
#if (defined(linux) || defined(__linux))
#if (defined(__linux__))
wchar_t wc = L'_';
mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) );
prompt.input(wc);

View File

@ -131,6 +131,7 @@ void MenuMusicFetcher::fetchSounds(const std::string &name,
/** GUIEngine */
/******************************************************************************/
GUIEngine::GUIEngine( irr::IrrlichtDevice* dev,
JoystickController *joystick,
gui::IGUIElement* parent,
IMenuManager *menumgr,
scene::ISceneManager* smgr,
@ -173,8 +174,7 @@ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev,
m_sound_manager = &dummySoundManager;
//create topleft header
m_toplefttext = utf8_to_wide(std::string(PROJECT_NAME_C " ") +
g_version_hash);
m_toplefttext = L"";
core::rect<s32> rect(0, 0, g_fontengine->getTextWidth(m_toplefttext.c_str()),
g_fontengine->getTextHeight());
@ -189,6 +189,7 @@ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev,
/* Create menu */
m_menu = new GUIFormSpecMenu(m_device,
joystick,
m_parent,
-1,
m_menumanager,
@ -569,18 +570,9 @@ bool GUIEngine::downloadFile(std::string url, std::string target)
}
/******************************************************************************/
void GUIEngine::setTopleftText(std::string append)
void GUIEngine::setTopleftText(const std::string &text)
{
std::wstring toset = utf8_to_wide(std::string(PROJECT_NAME_C " ") +
g_version_hash);
if (append != "")
{
toset += L" / ";
toset += utf8_to_wide(append);
}
m_toplefttext = toset;
m_toplefttext = utf8_to_wide(text);
updateTopLeftTextSize();
}

View File

@ -149,7 +149,8 @@ public:
* @param smgr scene manager to add scene elements to
* @param data struct to transfer data to main game handling
*/
GUIEngine( irr::IrrlichtDevice* dev,
GUIEngine(irr::IrrlichtDevice* dev,
JoystickController *joystick,
gui::IGUIElement* parent,
IMenuManager *menumgr,
scene::ISceneManager* smgr,
@ -269,10 +270,10 @@ private:
void drawVersion();
/**
* specify text to be appended to version string
* specify text to appear as top left string
* @param text to set
*/
void setTopleftText(std::string append);
void setTopleftText(const std::string &text);
/** pointer to gui element shown at topleft corner */
irr::gui::IGUIStaticText* m_irr_toplefttext;

View File

@ -79,6 +79,7 @@ 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,
ISimpleTextureSource *tsrc, IFormSource* fsrc, TextDest* tdst,
@ -102,6 +103,7 @@ GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev,
m_text_dst(tdst),
m_formspec_version(0),
m_focused_element(""),
m_joystick(joystick),
m_font(NULL),
m_remap_dbl_click(remap_dbl_click)
#ifdef __ANDROID__
@ -3024,6 +3026,25 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event)
}
#endif
if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) {
/* TODO add a check like:
if (event.JoystickEvent != joystick_we_listen_for)
return false;
*/
bool handled = m_joystick->handleEvent(event.JoystickEvent);
if (handled) {
if (m_joystick->wasKeyDown(KeyType::ESC)) {
tryClose();
} else if (m_joystick->wasKeyDown(KeyType::JUMP)) {
if (m_allowclose) {
acceptInput(quit_mode_accept);
quitMenu();
}
}
}
return handled;
}
return false;
}
@ -3085,19 +3106,24 @@ bool GUIFormSpecMenu::DoubleClickDetection(const SEvent event)
return false;
}
void GUIFormSpecMenu::tryClose()
{
if (m_allowclose) {
doPause = false;
acceptInput(quit_mode_cancel);
quitMenu();
} else {
m_text_dst->gotText(L"MenuQuit");
}
}
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 (m_allowclose) {
doPause = false;
acceptInput(quit_mode_cancel);
quitMenu();
} else {
m_text_dst->gotText(L"MenuQuit");
}
tryClose();
return true;
} else if (m_client != NULL && event.KeyInput.PressedDown &&
(kp == getKeySetting("keymap_screenshot"))) {

View File

@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "modalMenu.h"
#include "guiTable.h"
#include "network/networkprotocol.h"
#include "client/joystick_controller.h"
#include "util/string.h"
#include "util/enriched_string.h"
@ -278,6 +279,7 @@ class GUIFormSpecMenu : public GUIModalMenu
public:
GUIFormSpecMenu(irr::IrrlichtDevice* dev,
JoystickController *joystick,
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr,
InventoryManager *invmgr,
@ -438,6 +440,8 @@ private:
unsigned int m_formspec_version;
std::string m_focused_element;
bool m_selection_active;
JoystickController *m_joystick;
typedef struct {
bool explicit_size;
@ -495,6 +499,8 @@ private:
bool parseSizeDirect(parserData* data, std::string element);
void parseScrollBar(parserData* data, std::string element);
void tryClose();
/**
* check if event is part of a double click
* @param event event to evaluate

View File

@ -167,7 +167,7 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
{
key_setting *k = key_settings.at(i);
{
core::rect < s32 > rect(0, 0, 110, 20);
core::rect < s32 > rect(0, 0, 150, 20);
rect += topleft + v2s32(offset.X, offset.Y);
Environment->addStaticText(k->button_name, rect, false, true, this, -1);
}

View File

@ -271,7 +271,7 @@ bool intlGUIEditBox::OnEvent(const SEvent& event)
break;
case EET_KEY_INPUT_EVENT:
{
#if (defined(linux) || defined(__linux) || defined(__FreeBSD__))
#if (defined(__linux__) || defined(__FreeBSD__))
// ################################################################
// ValkaTR:
// This part is the difference from the original intlGUIEditBox

View File

@ -528,18 +528,23 @@ void LocalPlayer::applyControl(float dtime)
speedH += move_direction;
}
}
if(control.down)
{
if (control.down) {
speedH -= move_direction;
}
if(control.left)
{
if (!control.up && !control.down) {
speedH -= move_direction *
(control.forw_move_joystick_axis / 32767.f);
}
if (control.left) {
speedH += move_direction.crossProduct(v3f(0,1,0));
}
if(control.right)
{
if (control.right) {
speedH += move_direction.crossProduct(v3f(0,-1,0));
}
if (!control.left && !control.right) {
speedH -= move_direction.crossProduct(v3f(0,1,0)) *
(control.sidew_move_joystick_axis / 32767.f);
}
if(control.jump)
{
if (free_move) {

View File

@ -2093,11 +2093,13 @@ NodeTimer Map::getNodeTimer(v3s16 p)
return NodeTimer();
}
NodeTimer t = block->m_node_timers.get(p_rel);
return t;
NodeTimer nt(t.timeout, t.elapsed, p);
return nt;
}
void Map::setNodeTimer(v3s16 p, NodeTimer t)
void Map::setNodeTimer(const NodeTimer &t)
{
v3s16 p = t.position;
v3s16 blockpos = getNodeBlockPos(p);
v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
MapBlock *block = getBlockNoCreateNoEx(blockpos);
@ -2111,7 +2113,8 @@ void Map::setNodeTimer(v3s16 p, NodeTimer t)
<<std::endl;
return;
}
block->m_node_timers.set(p_rel, t);
NodeTimer nt(t.timeout, t.elapsed, p_rel);
block->m_node_timers.set(nt);
}
void Map::removeNodeTimer(v3s16 p)
@ -2133,11 +2136,15 @@ void Map::removeNodeTimer(v3s16 p)
*/
ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
Map(dout_server, gamedef),
settings_mgr(g_settings, savedir + DIR_DELIM + "map_meta.txt"),
m_emerge(emerge),
m_map_metadata_changed(true)
{
verbosestream<<FUNCTION_NAME<<std::endl;
// Tell the EmergeManager about our MapSettingsManager
emerge->map_settings_mgr = &settings_mgr;
/*
Try to load map; if not found, create a new one.
*/
@ -2173,26 +2180,15 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emer
}
else
{
try{
// Load map metadata (seed, chunksize)
loadMapMeta();
}
catch(SettingNotFoundException &e){
infostream<<"ServerMap: Some metadata not found."
<<" Using default settings."<<std::endl;
}
catch(FileNotGoodException &e){
warningstream<<"Could not load map metadata"
//<<" Disabling chunk-based generator."
<<std::endl;
//m_chunksize = 0;
}
infostream<<"ServerMap: Successfully loaded map "
<<"metadata from "<<savedir
<<", assuming valid save directory."
<<" seed="<< m_emerge->params.seed <<"."
<<std::endl;
if (settings_mgr.loadMapMeta()) {
infostream << "ServerMap: Metadata loaded from "
<< savedir << std::endl;
} else {
infostream << "ServerMap: Metadata could not be loaded "
"from " << savedir << ", assuming valid save "
"directory." << std::endl;
}
m_map_saving_enabled = true;
// Map loaded, not creating new one
@ -2262,19 +2258,26 @@ ServerMap::~ServerMap()
#endif
}
MapgenParams *ServerMap::getMapgenParams()
{
// getMapgenParams() should only ever be called after Server is initialized
assert(settings_mgr.mapgen_params != NULL);
return settings_mgr.mapgen_params;
}
u64 ServerMap::getSeed()
{
return m_emerge->params.seed;
return getMapgenParams()->seed;
}
s16 ServerMap::getWaterLevel()
{
return m_emerge->params.water_level;
return getMapgenParams()->water_level;
}
bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
{
s16 csize = m_emerge->params.chunksize;
s16 csize = getMapgenParams()->chunksize;
v3s16 bpmin = EmergeManager::getContainingChunk(blockpos, csize);
v3s16 bpmax = bpmin + v3s16(1, 1, 1) * (csize - 1);
@ -2290,7 +2293,7 @@ bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
blockpos_over_limit(full_bpmax))
return false;
data->seed = m_emerge->params.seed;
data->seed = getSeed();
data->blockpos_min = bpmin;
data->blockpos_max = bpmax;
data->blockpos_requested = blockpos;
@ -2908,8 +2911,9 @@ void ServerMap::save(ModifiedState save_level)
infostream<<"ServerMap: Saving whole map, this can take time."
<<std::endl;
if(m_map_metadata_changed || save_level == MOD_STATE_CLEAN) {
saveMapMeta();
if (m_map_metadata_changed || save_level == MOD_STATE_CLEAN) {
if (settings_mgr.saveMapMeta())
m_map_metadata_changed = false;
}
// Profile modified reasons
@ -3008,55 +3012,6 @@ void ServerMap::listAllLoadedBlocks(std::vector<v3s16> &dst)
}
}
void ServerMap::saveMapMeta()
{
DSTACK(FUNCTION_NAME);
createDirs(m_savedir);
std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
std::ostringstream oss(std::ios_base::binary);
Settings conf;
m_emerge->params.save(conf);
conf.writeLines(oss);
oss << "[end_of_params]\n";
if(!fs::safeWriteToFile(fullpath, oss.str())) {
errorstream << "ServerMap::saveMapMeta(): "
<< "could not write " << fullpath << std::endl;
throw FileNotGoodException("Cannot save chunk metadata");
}
m_map_metadata_changed = false;
}
void ServerMap::loadMapMeta()
{
DSTACK(FUNCTION_NAME);
Settings conf;
std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
if (!is.good()) {
errorstream << "ServerMap::loadMapMeta(): "
"could not open " << fullpath << std::endl;
throw FileNotGoodException("Cannot open map metadata");
}
if (!conf.parseConfigLines(is, "[end_of_params]")) {
throw SerializationError("ServerMap::loadMapMeta(): "
"[end_of_params] not found!");
}
m_emerge->params.load(conf);
verbosestream << "ServerMap::loadMapMeta(): seed="
<< m_emerge->params.seed << std::endl;
}
void ServerMap::saveSectorMeta(ServerMapSector *sector)
{
DSTACK(FUNCTION_NAME);

View File

@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "modifiedstate.h"
#include "util/container.h"
#include "nodetimer.h"
#include "map_settings_manager.h"
class Settings;
class Database;
@ -46,8 +47,6 @@ class IRollbackManager;
class EmergeManager;
class ServerEnvironment;
struct BlockMakeData;
struct MapgenParams;
/*
MapEditEvent
@ -327,7 +326,7 @@ public:
*/
NodeTimer getNodeTimer(v3s16 p);
void setNodeTimer(v3s16 p, NodeTimer t);
void setNodeTimer(const NodeTimer &t);
void removeNodeTimer(v3s16 p);
/*
@ -463,9 +462,8 @@ public:
void save(ModifiedState save_level);
void listAllLoadableBlocks(std::vector<v3s16> &dst);
void listAllLoadedBlocks(std::vector<v3s16> &dst);
// Saves map seed and possibly other stuff
void saveMapMeta();
void loadMapMeta();
MapgenParams *getMapgenParams();
/*void saveChunkMeta();
void loadChunkMeta();*/
@ -506,6 +504,8 @@ public:
u64 getSeed();
s16 getWaterLevel();
MapSettingsManager settings_mgr;
private:
// Emerge manager
EmergeManager *m_emerge;

View File

@ -0,0 +1,194 @@
/*
Minetest
Copyright (C) 2010-2013 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
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 "debug.h"
#include "filesys.h"
#include "log.h"
#include "mapgen.h"
#include "settings.h"
#include "map_settings_manager.h"
MapSettingsManager::MapSettingsManager(
Settings *user_settings, const std::string &map_meta_path)
{
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);
}
MapSettingsManager::~MapSettingsManager()
{
delete m_map_settings;
delete mapgen_params;
}
bool MapSettingsManager::getMapSetting(
const std::string &name, std::string *value_out)
{
if (m_map_settings->getNoEx(name, *value_out))
return true;
// Compatibility kludge
if (m_user_settings == g_settings && name == "seed")
return m_user_settings->getNoEx("fixed_map_seed", *value_out);
return m_user_settings->getNoEx(name, *value_out);
}
bool MapSettingsManager::getMapSettingNoiseParams(
const std::string &name, NoiseParams *value_out)
{
return m_map_settings->getNoiseParams(name, *value_out) ||
m_user_settings->getNoiseParams(name, *value_out);
}
bool MapSettingsManager::setMapSetting(
const std::string &name, const std::string &value, bool override_meta)
{
if (mapgen_params)
return false;
if (override_meta)
m_map_settings->set(name, value);
else
m_map_settings->setDefault(name, value);
return true;
}
bool MapSettingsManager::setMapSettingNoiseParams(
const std::string &name, const NoiseParams *value, bool override_meta)
{
if (mapgen_params)
return false;
m_map_settings->setNoiseParams(name, *value, !override_meta);
return true;
}
bool MapSettingsManager::loadMapMeta()
{
std::ifstream is(m_map_meta_path.c_str(), std::ios_base::binary);
if (!is.good()) {
errorstream << "loadMapMeta: could not open "
<< m_map_meta_path << std::endl;
return false;
}
if (!m_map_settings->parseConfigLines(is, "[end_of_params]")) {
errorstream << "loadMapMeta: [end_of_params] not found!" << std::endl;
return false;
}
return true;
}
bool MapSettingsManager::saveMapMeta()
{
// If mapgen params haven't been created yet; abort
if (!mapgen_params)
return false;
if (!fs::CreateAllDirs(fs::RemoveLastPathComponent(m_map_meta_path))) {
errorstream << "saveMapMeta: could not create dirs to "
<< m_map_meta_path;
return false;
}
std::ostringstream oss(std::ios_base::binary);
Settings conf;
mapgen_params->MapgenParams::writeParams(&conf);
mapgen_params->writeParams(&conf);
conf.writeLines(oss);
// NOTE: If there are ever types of map settings other than
// those relating to map generation, save them here
oss << "[end_of_params]\n";
if (!fs::safeWriteToFile(m_map_meta_path, oss.str())) {
errorstream << "saveMapMeta: could not write "
<< m_map_meta_path << std::endl;
return false;
}
return true;
}
MapgenParams *MapSettingsManager::makeMapgenParams()
{
if (mapgen_params)
return mapgen_params;
assert(m_user_settings != NULL);
assert(m_map_settings != NULL);
// At this point, we have (in order of precedence):
// 1). m_mapgen_settings->m_settings containing map_meta.txt settings or
// explicit overrides from scripts
// 2). m_mapgen_settings->m_defaults containing script-set mgparams without
// overrides
// 3). g_settings->m_settings containing all user-specified config file
// settings
// 4). g_settings->m_defaults containing any low-priority settings from
// scripts, e.g. mods using Lua as an enhanced config file)
// Now, get the mapgen type so we can create the appropriate MapgenParams
std::string mg_name;
MapgenType mgtype = getMapSetting("mg_name", &mg_name) ?
Mapgen::getMapgenType(mg_name) : MAPGEN_DEFAULT;
if (mgtype == MAPGEN_INVALID) {
errorstream << "EmergeManager: mapgen '" << mg_name <<
"' not valid; falling back to " <<
Mapgen::getMapgenName(MAPGEN_DEFAULT) << std::endl;
mgtype = MAPGEN_DEFAULT;
}
// Create our MapgenParams
MapgenParams *params = Mapgen::createMapgenParams(mgtype);
if (params == NULL)
return NULL;
params->mgtype = mgtype;
// Load the rest of the mapgen params from our active settings
params->MapgenParams::readParams(m_user_settings);
params->MapgenParams::readParams(m_map_settings);
params->readParams(m_user_settings);
params->readParams(m_map_settings);
// Hold onto our params
mapgen_params = params;
return params;
}

View File

@ -0,0 +1,79 @@
/*
Minetest
Copyright (C) 2010-2013 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
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 MAP_SETTINGS_MANAGER_HEADER
#define MAP_SETTINGS_MANAGER_HEADER
#include <string>
class Settings;
struct NoiseParams;
struct MapgenParams;
/*
MapSettingsManager is a centralized object for management (creating,
loading, storing, saving, etc.) of config settings related to the Map.
It has two phases: the initial r/w "gather and modify settings" state, and
the final r/o "read and save settings" state.
The typical use case is, in order, as follows:
- Create a MapSettingsManager object
- Try to load map metadata into it from the metadata file
- Manually view and modify the current configuration as desired through a
Settings-like interface
- When all modifications are finished, create a 'Parameters' object
containing the finalized, active parameters. This could be passed along
to whichever Map-related objects that may require it.
- Save these active settings to the metadata file when requested
*/
class MapSettingsManager {
public:
// Finalized map generation parameters
MapgenParams *mapgen_params;
MapSettingsManager(Settings *user_settings,
const std::string &map_meta_path);
~MapSettingsManager();
bool getMapSetting(const std::string &name, std::string *value_out);
bool getMapSettingNoiseParams(
const std::string &name, NoiseParams *value_out);
// Note: Map config becomes read-only after makeMapgenParams() gets called
// (i.e. mapgen_params is non-NULL). Attempts to set map config after
// params have been finalized will result in failure.
bool setMapSetting(const std::string &name,
const std::string &value, bool override_meta = false);
bool setMapSettingNoiseParams(const std::string &name,
const NoiseParams *value, bool override_meta = false);
bool loadMapMeta();
bool saveMapMeta();
MapgenParams *makeMapgenParams();
private:
std::string m_map_meta_path;
Settings *m_map_settings;
Settings *m_user_settings;
};
#endif

View File

@ -488,9 +488,9 @@ public:
m_node_timers.remove(p);
}
inline void setNodeTimer(v3s16 p, NodeTimer t)
inline void setNodeTimer(const NodeTimer &t)
{
m_node_timers.set(p,t);
m_node_timers.set(t);
}
inline void clearNodeTimers()

View File

@ -39,6 +39,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/numeric.h"
#include "filesys.h"
#include "log.h"
#include "mapgen_flat.h"
#include "mapgen_fractal.h"
#include "mapgen_v5.h"
#include "mapgen_v6.h"
#include "mapgen_v7.h"
#include "mapgen_valleys.h"
#include "mapgen_singlenode.h"
#include "cavegen.h"
#include "dungeongen.h"
@ -63,6 +70,28 @@ FlagDesc flagdesc_gennotify[] = {
{NULL, 0}
};
struct MapgenDesc {
const char *name;
bool is_user_visible;
};
////
//// Built-in mapgens
////
static MapgenDesc g_reg_mapgens[] = {
{"v5", true},
{"v6", true},
{"v7", true},
{"flat", true},
{"fractal", true},
{"valleys", true},
{"singlenode", false},
};
STATIC_ASSERT(
ARRLEN(g_reg_mapgens) == MAPGEN_INVALID,
registered_mapgens_is_wrong_size);
////
//// Mapgen
@ -89,11 +118,25 @@ Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge) :
{
generating = false;
id = mapgenid;
seed = (int)params->seed;
water_level = params->water_level;
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
preserve reverse compatibility. If the top half of our current 64 bit
seeds ever starts getting used, existing worlds will break due to a
different hash outcome and no way to differentiate between versions.
A solution could be to add a new bit to designate that the top half of
the seed value should be used, essentially a 1-bit version code, but
this would require increasing the total size of a seed to 9 bytes (yuck)
It's probably okay if this never gets fixed. 4.2 billion possibilities
ought to be enough for anyone.
*/
seed = (s32)params->seed;
vm = NULL;
ndef = emerge->ndef;
biomegen = NULL;
@ -107,7 +150,84 @@ Mapgen::~Mapgen()
}
u32 Mapgen::getBlockSeed(v3s16 p, int seed)
MapgenType Mapgen::getMapgenType(const std::string &mgname)
{
for (size_t i = 0; i != ARRLEN(g_reg_mapgens); i++) {
if (mgname == g_reg_mapgens[i].name)
return (MapgenType)i;
}
return MAPGEN_INVALID;
}
const char *Mapgen::getMapgenName(MapgenType mgtype)
{
size_t index = (size_t)mgtype;
if (index == MAPGEN_INVALID || index >= ARRLEN(g_reg_mapgens))
return "invalid";
return g_reg_mapgens[index].name;
}
Mapgen *Mapgen::createMapgen(MapgenType mgtype, int mgid,
MapgenParams *params, EmergeManager *emerge)
{
switch (mgtype) {
case MAPGEN_FLAT:
return new MapgenFlat(mgid, (MapgenFlatParams *)params, emerge);
case MAPGEN_FRACTAL:
return new MapgenFractal(mgid, (MapgenFractalParams *)params, emerge);
case MAPGEN_SINGLENODE:
return new MapgenSinglenode(mgid, (MapgenSinglenodeParams *)params, emerge);
case MAPGEN_V5:
return new MapgenV5(mgid, (MapgenV5Params *)params, emerge);
case MAPGEN_V6:
return new MapgenV6(mgid, (MapgenV6Params *)params, emerge);
case MAPGEN_V7:
return new MapgenV7(mgid, (MapgenV7Params *)params, emerge);
case MAPGEN_VALLEYS:
return new MapgenValleys(mgid, (MapgenValleysParams *)params, emerge);
default:
return NULL;
}
}
MapgenParams *Mapgen::createMapgenParams(MapgenType mgtype)
{
switch (mgtype) {
case MAPGEN_FLAT:
return new MapgenFlatParams;
case MAPGEN_FRACTAL:
return new MapgenFractalParams;
case MAPGEN_SINGLENODE:
return new MapgenSinglenodeParams;
case MAPGEN_V5:
return new MapgenV5Params;
case MAPGEN_V6:
return new MapgenV6Params;
case MAPGEN_V7:
return new MapgenV7Params;
case MAPGEN_VALLEYS:
return new MapgenValleysParams;
default:
return NULL;
}
}
void Mapgen::getMapgenNames(std::vector<const char *> *mgnames, bool include_hidden)
{
for (u32 i = 0; i != ARRLEN(g_reg_mapgens); i++) {
if (include_hidden || g_reg_mapgens[i].is_user_visible)
mgnames->push_back(g_reg_mapgens[i].name);
}
}
u32 Mapgen::getBlockSeed(v3s16 p, s32 seed)
{
return (u32)seed +
p.Z * 38134234 +
@ -116,7 +236,7 @@ u32 Mapgen::getBlockSeed(v3s16 p, int seed)
}
u32 Mapgen::getBlockSeed2(v3s16 p, int seed)
u32 Mapgen::getBlockSeed2(v3s16 p, s32 seed)
{
u32 n = 1619 * p.X + 31337 * p.Y + 52591 * p.Z + 1013 * seed;
n = (n >> 13) ^ n;
@ -199,27 +319,86 @@ void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax)
//printf("updateHeightmap: %dus\n", t.stop());
}
inline bool Mapgen::isLiquidHorizontallyFlowable(u32 vi, v3s16 em)
{
u32 vi_neg_x = vi;
vm->m_area.add_x(em, vi_neg_x, -1);
if (vm->m_data[vi_neg_x].getContent() != CONTENT_IGNORE) {
const ContentFeatures &c_nx = ndef->get(vm->m_data[vi_neg_x]);
if (c_nx.floodable && !c_nx.isLiquid())
return true;
}
u32 vi_pos_x = vi;
vm->m_area.add_x(em, vi_pos_x, +1);
if (vm->m_data[vi_pos_x].getContent() != CONTENT_IGNORE) {
const ContentFeatures &c_px = ndef->get(vm->m_data[vi_pos_x]);
if (c_px.floodable && !c_px.isLiquid())
return true;
}
u32 vi_neg_z = vi;
vm->m_area.add_z(em, vi_neg_z, -1);
if (vm->m_data[vi_neg_z].getContent() != CONTENT_IGNORE) {
const ContentFeatures &c_nz = ndef->get(vm->m_data[vi_neg_z]);
if (c_nz.floodable && !c_nz.isLiquid())
return true;
}
u32 vi_pos_z = vi;
vm->m_area.add_z(em, vi_pos_z, +1);
if (vm->m_data[vi_pos_z].getContent() != CONTENT_IGNORE) {
const ContentFeatures &c_pz = ndef->get(vm->m_data[vi_pos_z]);
if (c_pz.floodable && !c_pz.isLiquid())
return true;
}
return false;
}
void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax)
{
bool isliquid, wasliquid;
bool isignored, isliquid, wasignored, wasliquid, waschecked, waspushed;
v3s16 em = vm->m_area.getExtent();
for (s16 z = nmin.Z; z <= nmax.Z; z++) {
for (s16 x = nmin.X; x <= nmax.X; x++) {
wasliquid = true;
for (s16 z = nmin.Z + 1; z <= nmax.Z - 1; z++)
for (s16 x = nmin.X + 1; x <= nmax.X - 1; x++) {
wasignored = true;
wasliquid = false;
waschecked = false;
waspushed = false;
u32 i = vm->m_area.index(x, nmax.Y, z);
for (s16 y = nmax.Y; y >= nmin.Y; y--) {
isliquid = ndef->get(vm->m_data[i]).isLiquid();
u32 vi = vm->m_area.index(x, nmax.Y, z);
for (s16 y = nmax.Y; y >= nmin.Y; y--) {
isignored = vm->m_data[vi].getContent() == CONTENT_IGNORE;
isliquid = ndef->get(vm->m_data[vi]).isLiquid();
// there was a change between liquid and nonliquid, add to queue.
if (isliquid != wasliquid)
if (isignored || wasignored || isliquid == wasliquid) {
// Neither topmost node of liquid column nor topmost node below column
waschecked = false;
waspushed = false;
} else if (isliquid) {
// This is the topmost node in the column
bool ispushed = false;
if (isLiquidHorizontallyFlowable(vi, em)) {
trans_liquid->push_back(v3s16(x, y, z));
wasliquid = isliquid;
vm->m_area.add_y(em, i, -1);
ispushed = true;
}
// Remember waschecked and waspushed to avoid repeated
// checks/pushes in case the column consists of only this node
waschecked = true;
waspushed = ispushed;
} else {
// This is the topmost node below a liquid column
u32 vi_above = vi;
vm->m_area.add_y(em, vi_above, 1);
if (!waspushed && (ndef->get(vm->m_data[vi]).floodable ||
(!waschecked && isLiquidHorizontallyFlowable(vi_above, em)))) {
// Push back the lowest node in the column which is one
// node above this one
trans_liquid->push_back(v3s16(x, y + 1, z));
}
}
wasliquid = isliquid;
wasignored = isignored;
vm->m_area.add_y(em, vi, -1);
}
}
}
@ -451,6 +630,10 @@ MapgenBasic::~MapgenBasic()
MgStoneType MapgenBasic::generateBiomes()
{
// can't generate biomes without a biome generator!
assert(biomegen);
assert(biomemap);
v3s16 em = vm->m_area.getExtent();
u32 index = 0;
MgStoneType stone_type = MGSTONE_STONE;
@ -463,13 +646,17 @@ MgStoneType MapgenBasic::generateBiomes()
u16 depth_top = 0;
u16 base_filler = 0;
u16 depth_water_top = 0;
u16 depth_riverbed = 0;
u32 vi = vm->m_area.index(x, node_max.Y, z);
// Check node at base of mapchunk above, either a node of a previously
// generated mapchunk or if not, a node of overgenerated base terrain.
content_t c_above = vm->m_data[vi + em.X].getContent();
bool air_above = c_above == CONTENT_AIR;
bool water_above = (c_above == c_water_source || c_above == c_river_water_source);
bool river_water_above = c_above == c_river_water_source;
bool water_above = c_above == c_water_source || river_water_above;
biomemap[index] = BIOME_NONE;
// If there is air or water above enable top/filler placement, otherwise force
// nplaced to stone level by setting a number exceeding any possible filler depth.
@ -485,16 +672,25 @@ MgStoneType MapgenBasic::generateBiomes()
// 1. At the surface of stone below air or water.
// 2. At the surface of water below air.
// 3. When stone or water is detected but biome has not yet been calculated.
if ((c == c_stone && (air_above || water_above || !biome))
|| ((c == c_water_source || c == c_river_water_source)
&& (air_above || !biome))) {
bool is_stone_surface = (c == c_stone) &&
(air_above || water_above || !biome);
bool is_water_surface =
(c == c_water_source || c == c_river_water_source) &&
(air_above || !biome);
if (is_stone_surface || is_water_surface) {
biome = biomegen->getBiomeAtIndex(index, y);
if (biomemap[index] == BIOME_NONE && is_stone_surface)
biomemap[index] = biome->index;
depth_top = biome->depth_top;
base_filler = MYMAX(depth_top
+ biome->depth_filler
+ noise_filler_depth->result[index], 0.f);
base_filler = MYMAX(depth_top +
biome->depth_filler +
noise_filler_depth->result[index], 0.f);
depth_water_top = biome->depth_water_top;
depth_riverbed = biome->depth_riverbed;
// Detect stone type for dungeons during every biome calculation.
// This is more efficient than detecting per-node and will not
@ -517,7 +713,15 @@ MgStoneType MapgenBasic::generateBiomes()
|| c_below == c_river_water_source)
nplaced = U16_MAX;
if (nplaced < depth_top) {
if (river_water_above) {
if (nplaced < depth_riverbed) {
vm->m_data[vi] = MapNode(biome->c_riverbed);
nplaced++;
} else {
nplaced = U16_MAX; // Disable top/filler placement
river_water_above = false;
}
} else if (nplaced < depth_top) {
vm->m_data[vi] = MapNode(biome->c_top);
nplaced++;
} else if (nplaced < base_filler) {
@ -537,9 +741,10 @@ MgStoneType MapgenBasic::generateBiomes()
water_above = true;
} else if (c == c_river_water_source) {
vm->m_data[vi] = MapNode(biome->c_river_water);
nplaced = depth_top; // Enable filler placement for next surface
nplaced = 0; // Enable riverbed placement for next surface
air_above = false;
water_above = true;
river_water_above = true;
} else if (c == CONTENT_AIR) {
nplaced = 0; // Enable top/filler placement for next surface
air_above = true;
@ -639,44 +844,44 @@ void MapgenBasic::generateDungeons(s16 max_stone_y, MgStoneType stone_type)
DungeonParams dp;
dp.seed = seed;
dp.np_rarity = nparams_dungeon_rarity;
dp.np_density = nparams_dungeon_density;
dp.np_wetness = nparams_dungeon_wetness;
dp.c_water = c_water_source;
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;
switch (stone_type) {
default:
case MGSTONE_STONE:
dp.c_cobble = c_cobble;
dp.c_moss = c_mossycobble;
dp.c_stair = c_stair_cobble;
dp.c_wall = c_cobble;
dp.c_alt_wall = c_mossycobble;
dp.c_stair = c_stair_cobble;
dp.diagonal_dirs = false;
dp.mossratio = 3.0;
dp.holesize = v3s16(1, 2, 1);
dp.roomsize = v3s16(0, 0, 0);
dp.notifytype = GENNOTIFY_DUNGEON;
break;
case MGSTONE_DESERT_STONE:
dp.c_cobble = c_desert_stone;
dp.c_moss = c_desert_stone;
dp.c_stair = c_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.mossratio = 0.0;
dp.holesize = v3s16(2, 3, 2);
dp.roomsize = v3s16(2, 5, 2);
dp.notifytype = GENNOTIFY_TEMPLE;
break;
case MGSTONE_SANDSTONE:
dp.c_cobble = c_sandstonebrick;
dp.c_moss = c_sandstonebrick;
dp.c_stair = c_sandstonebrick;
dp.c_wall = c_sandstonebrick;
dp.c_alt_wall = CONTENT_IGNORE;
dp.c_stair = c_sandstonebrick;
dp.diagonal_dirs = false;
dp.mossratio = 0.0;
dp.holesize = v3s16(2, 2, 2);
dp.roomsize = v3s16(2, 0, 2);
dp.notifytype = GENNOTIFY_DUNGEON;
@ -765,52 +970,46 @@ void GenerateNotifier::getEvents(
MapgenParams::~MapgenParams()
{
delete bparams;
delete sparams;
}
void MapgenParams::load(const Settings &settings)
void MapgenParams::readParams(const Settings *settings)
{
std::string seed_str;
const char *seed_name = (&settings == g_settings) ? "fixed_map_seed" : "seed";
const char *seed_name = (settings == g_settings) ? "fixed_map_seed" : "seed";
if (settings.getNoEx(seed_name, seed_str) && !seed_str.empty())
seed = read_seed(seed_str.c_str());
else
myrand_bytes(&seed, sizeof(seed));
if (settings->getNoEx(seed_name, seed_str)) {
if (!seed_str.empty())
seed = read_seed(seed_str.c_str());
else
myrand_bytes(&seed, sizeof(seed));
}
settings.getNoEx("mg_name", mg_name);
settings.getS16NoEx("water_level", water_level);
settings.getS16NoEx("chunksize", chunksize);
settings.getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
std::string mg_name;
if (settings->getNoEx("mg_name", mg_name))
this->mgtype = Mapgen::getMapgenType(mg_name);
settings->getS16NoEx("water_level", water_level);
settings->getS16NoEx("chunksize", chunksize);
settings->getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
delete bparams;
bparams = BiomeManager::createBiomeParams(BIOMEGEN_ORIGINAL);
if (bparams) {
bparams->readParams(&settings);
bparams->readParams(settings);
bparams->seed = seed;
}
delete sparams;
MapgenFactory *mgfactory = EmergeManager::getMapgenFactory(mg_name);
if (mgfactory) {
sparams = mgfactory->createMapgenParams();
sparams->readParams(&settings);
}
}
void MapgenParams::save(Settings &settings) const
void MapgenParams::writeParams(Settings *settings) const
{
settings.set("mg_name", mg_name);
settings.setU64("seed", seed);
settings.setS16("water_level", water_level);
settings.setS16("chunksize", chunksize);
settings.setFlagStr("mg_flags", flags, flagdesc_mapgen, U32_MAX);
settings->set("mg_name", Mapgen::getMapgenName(mgtype));
settings->setU64("seed", seed);
settings->setS16("water_level", water_level);
settings->setS16("chunksize", chunksize);
settings->setFlagStr("mg_flags", flags, flagdesc_mapgen, U32_MAX);
if (bparams)
bparams->writeParams(&settings);
if (sparams)
sparams->writeParams(&settings);
bparams->writeParams(settings);
}

View File

@ -26,7 +26,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h"
#include "util/container.h"
#define DEFAULT_MAPGEN "v6"
#define MAPGEN_DEFAULT MAPGEN_V6
#define MAPGEN_DEFAULT_NAME "v6"
/////////////////// Mapgen flags
#define MG_TREES 0x01
@ -36,6 +37,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MG_LIGHT 0x10
#define MG_DECORATIONS 0x20
typedef u8 biome_t; // copy from mg_biome.h to avoid an unnecessary include
class Settings;
class MMVManip;
class INodeDefManager;
@ -105,37 +108,40 @@ private:
std::list<GenNotifyEvent> m_notify_events;
};
struct MapgenSpecificParams {
virtual void readParams(const Settings *settings) = 0;
virtual void writeParams(Settings *settings) const = 0;
virtual ~MapgenSpecificParams() {}
enum MapgenType {
MAPGEN_V5,
MAPGEN_V6,
MAPGEN_V7,
MAPGEN_FLAT,
MAPGEN_FRACTAL,
MAPGEN_VALLEYS,
MAPGEN_SINGLENODE,
MAPGEN_INVALID,
};
struct MapgenParams {
std::string mg_name;
MapgenType mgtype;
s16 chunksize;
u64 seed;
s16 water_level;
u32 flags;
BiomeParams *bparams;
MapgenSpecificParams *sparams;
MapgenParams() :
mg_name(DEFAULT_MAPGEN),
mgtype(MAPGEN_DEFAULT),
chunksize(5),
seed(0),
water_level(1),
flags(MG_CAVES | MG_LIGHT | MG_DECORATIONS),
bparams(NULL),
sparams(NULL)
bparams(NULL)
{
}
virtual ~MapgenParams();
void load(const Settings &settings);
void save(Settings &settings) const;
virtual void readParams(const Settings *settings);
virtual void writeParams(Settings *settings) const;
};
@ -150,7 +156,7 @@ struct MapgenParams {
*/
class Mapgen {
public:
int seed;
s32 seed;
int water_level;
u32 flags;
bool generating;
@ -161,7 +167,7 @@ public:
u32 blockseed;
s16 *heightmap;
u8 *biomemap;
biome_t *biomemap;
v3s16 csize;
BiomeGen *biomegen;
@ -171,8 +177,10 @@ public:
Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge);
virtual ~Mapgen();
static u32 getBlockSeed(v3s16 p, int seed);
static u32 getBlockSeed2(v3s16 p, int seed);
virtual MapgenType getType() const { return MAPGEN_INVALID; }
static u32 getBlockSeed(v3s16 p, s32 seed);
static u32 getBlockSeed2(v3s16 p, s32 seed);
s16 findGroundLevelFull(v2s16 p2d);
s16 findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax);
s16 findLiquidSurface(v2s16 p2d, s16 ymin, s16 ymax);
@ -196,8 +204,21 @@ public:
// signify this and to cause Server::findSpawnPos() to try another (X, Z).
virtual int getSpawnLevelAtPoint(v2s16 p) { return 0; }
// Mapgen management functions
static MapgenType getMapgenType(const std::string &mgname);
static const char *getMapgenName(MapgenType mgtype);
static Mapgen *createMapgen(MapgenType mgtype, int mgid,
MapgenParams *params, EmergeManager *emerge);
static MapgenParams *createMapgenParams(MapgenType mgtype);
static void getMapgenNames(std::vector<const char *> *mgnames, bool include_hidden);
private:
// isLiquidHorizontallyFlowable() is a helper function for updateLiquid()
// that checks whether there are floodable nodes without liquid beneath
// the node at index vi.
inline bool isLiquidHorizontallyFlowable(u32 vi, v3s16 em);
//DISABLE_CLASS_COPY(Mapgen);
};
/*
@ -261,11 +282,4 @@ protected:
float cave_width;
};
struct MapgenFactory {
virtual Mapgen *createMapgen(int mgid, MapgenParams *params,
EmergeManager *emerge) = 0;
virtual MapgenSpecificParams *createMapgenParams() = 0;
virtual ~MapgenFactory() {}
};
#endif

View File

@ -49,26 +49,24 @@ FlagDesc flagdesc_mapgen_flat[] = {
///////////////////////////////////////////////////////////////////////////////////////
MapgenFlat::MapgenFlat(int mapgenid, MapgenParams *params, EmergeManager *emerge)
MapgenFlat::MapgenFlat(int mapgenid, MapgenFlatParams *params, EmergeManager *emerge)
: MapgenBasic(mapgenid, params, emerge)
{
MapgenFlatParams *sp = (MapgenFlatParams *)params->sparams;
this->spflags = sp->spflags;
this->ground_level = sp->ground_level;
this->large_cave_depth = sp->large_cave_depth;
this->cave_width = sp->cave_width;
this->lake_threshold = sp->lake_threshold;
this->lake_steepness = sp->lake_steepness;
this->hill_threshold = sp->hill_threshold;
this->hill_steepness = sp->hill_steepness;
this->spflags = params->spflags;
this->ground_level = params->ground_level;
this->large_cave_depth = params->large_cave_depth;
this->cave_width = params->cave_width;
this->lake_threshold = params->lake_threshold;
this->lake_steepness = params->lake_steepness;
this->hill_threshold = params->hill_threshold;
this->hill_steepness = params->hill_steepness;
//// 2D noise
noise_terrain = new Noise(&sp->np_terrain, seed, csize.X, csize.Z);
noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
noise_terrain = new Noise(&params->np_terrain, seed, csize.X, csize.Z);
noise_filler_depth = new Noise(&params->np_filler_depth, seed, csize.X, csize.Z);
MapgenBasic::np_cave1 = sp->np_cave1;
MapgenBasic::np_cave2 = sp->np_cave2;
MapgenBasic::np_cave1 = params->np_cave1;
MapgenBasic::np_cave2 = params->np_cave2;
}
@ -84,7 +82,7 @@ MapgenFlatParams::MapgenFlatParams()
spflags = 0;
ground_level = 8;
large_cave_depth = -33;
cave_width = 0.3;
cave_width = 0.2;
lake_threshold = -0.45;
lake_steepness = 48.0;
hill_threshold = 0.45;
@ -92,8 +90,8 @@ MapgenFlatParams::MapgenFlatParams()
np_terrain = NoiseParams(0, 1, v3f(600, 600, 600), 7244, 5, 0.6, 2.0);
np_filler_depth = NoiseParams(0, 1.2, v3f(150, 150, 150), 261, 3, 0.7, 2.0);
np_cave1 = NoiseParams(0, 12, v3f(96, 96, 96), 52534, 4, 0.5, 2.0);
np_cave2 = NoiseParams(0, 12, v3f(96, 96, 96), 10325, 4, 0.5, 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);
}
@ -192,7 +190,6 @@ void MapgenFlat::makeChunk(BlockMakeData *data)
// Init biome generator, place biome-specific nodes, and build biomemap
biomegen->calcBiomeNoise(node_min);
biomegen->getBiomes(heightmap);
MgStoneType stone_type = generateBiomes();
if (flags & MG_CAVES)

View File

@ -32,7 +32,7 @@ class BiomeManager;
extern FlagDesc flagdesc_mapgen_flat[];
struct MapgenFlatParams : public MapgenSpecificParams {
struct MapgenFlatParams : public MapgenParams {
u32 spflags;
s16 ground_level;
s16 large_cave_depth;
@ -55,9 +55,11 @@ struct MapgenFlatParams : public MapgenSpecificParams {
class MapgenFlat : public MapgenBasic {
public:
MapgenFlat(int mapgenid, MapgenParams *params, EmergeManager *emerge);
MapgenFlat(int mapgenid, MapgenFlatParams *params, EmergeManager *emerge);
~MapgenFlat();
virtual MapgenType getType() const { return MAPGEN_FLAT; }
virtual void makeChunk(BlockMakeData *data);
int getSpawnLevelAtPoint(v2s16 p);
s16 generateTerrain();
@ -72,16 +74,4 @@ private:
Noise *noise_terrain;
};
struct MapgenFactoryFlat : public MapgenFactory {
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge)
{
return new MapgenFlat(mgid, params, emerge);
};
MapgenSpecificParams *createMapgenParams()
{
return new MapgenFlatParams();
};
};
#endif

View File

@ -47,29 +47,27 @@ FlagDesc flagdesc_mapgen_fractal[] = {
///////////////////////////////////////////////////////////////////////////////////////
MapgenFractal::MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *emerge)
MapgenFractal::MapgenFractal(int mapgenid, MapgenFractalParams *params, EmergeManager *emerge)
: MapgenBasic(mapgenid, params, emerge)
{
MapgenFractalParams *sp = (MapgenFractalParams *)params->sparams;
this->spflags = sp->spflags;
this->cave_width = sp->cave_width;
this->fractal = sp->fractal;
this->iterations = sp->iterations;
this->scale = sp->scale;
this->offset = sp->offset;
this->slice_w = sp->slice_w;
this->julia_x = sp->julia_x;
this->julia_y = sp->julia_y;
this->julia_z = sp->julia_z;
this->julia_w = sp->julia_w;
this->spflags = params->spflags;
this->cave_width = params->cave_width;
this->fractal = params->fractal;
this->iterations = params->iterations;
this->scale = params->scale;
this->offset = params->offset;
this->slice_w = params->slice_w;
this->julia_x = params->julia_x;
this->julia_y = params->julia_y;
this->julia_z = params->julia_z;
this->julia_w = params->julia_w;
//// 2D terrain noise
noise_seabed = new Noise(&sp->np_seabed, seed, csize.X, csize.Z);
noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
noise_seabed = new Noise(&params->np_seabed, seed, csize.X, csize.Z);
noise_filler_depth = new Noise(&params->np_filler_depth, seed, csize.X, csize.Z);
MapgenBasic::np_cave1 = sp->np_cave1;
MapgenBasic::np_cave2 = sp->np_cave2;
MapgenBasic::np_cave1 = params->np_cave1;
MapgenBasic::np_cave2 = params->np_cave2;
this->formula = fractal / 2 + fractal % 2;
this->julia = fractal % 2 == 0;
@ -86,7 +84,7 @@ MapgenFractal::~MapgenFractal()
MapgenFractalParams::MapgenFractalParams()
{
spflags = 0;
cave_width = 0.3;
cave_width = 0.2;
fractal = 1;
iterations = 11;
scale = v3f(4096.0, 1024.0, 4096.0);
@ -99,8 +97,8 @@ MapgenFractalParams::MapgenFractalParams()
np_seabed = NoiseParams(-14, 9, v3f(600, 600, 600), 41900, 5, 0.6, 2.0);
np_filler_depth = NoiseParams(0, 1.2, v3f(150, 150, 150), 261, 3, 0.7, 2.0);
np_cave1 = NoiseParams(0, 12, v3f(96, 96, 96), 52534, 4, 0.5, 2.0);
np_cave2 = NoiseParams(0, 12, v3f(96, 96, 96), 10325, 4, 0.5, 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);
}
@ -208,7 +206,6 @@ void MapgenFractal::makeChunk(BlockMakeData *data)
// Init biome generator, place biome-specific nodes, and build biomemap
biomegen->calcBiomeNoise(node_min);
biomegen->getBiomes(heightmap);
MgStoneType stone_type = generateBiomes();
if (flags & MG_CAVES)

View File

@ -33,7 +33,7 @@ class BiomeManager;
extern FlagDesc flagdesc_mapgen_fractal[];
struct MapgenFractalParams : public MapgenSpecificParams {
struct MapgenFractalParams : public MapgenParams {
u32 spflags;
float cave_width;
u16 fractal;
@ -59,9 +59,11 @@ struct MapgenFractalParams : public MapgenSpecificParams {
class MapgenFractal : public MapgenBasic {
public:
MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *emerge);
MapgenFractal(int mapgenid, MapgenFractalParams *params, EmergeManager *emerge);
~MapgenFractal();
virtual MapgenType getType() const { return MAPGEN_FRACTAL; }
virtual void makeChunk(BlockMakeData *data);
int getSpawnLevelAtPoint(v2s16 p);
bool getFractalAtPoint(s16 x, s16 y, s16 z);
@ -83,16 +85,4 @@ private:
Noise *noise_seabed;
};
struct MapgenFactoryFractal : public MapgenFactory {
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge)
{
return new MapgenFractal(mgid, params, emerge);
};
MapgenSpecificParams *createMapgenParams()
{
return new MapgenFractalParams();
};
};
#endif

View File

@ -22,11 +22,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapgen.h"
struct MapgenSinglenodeParams : public MapgenSpecificParams {
struct MapgenSinglenodeParams : public MapgenParams {
MapgenSinglenodeParams() {}
~MapgenSinglenodeParams() {}
void readParams(const Settings *settings) {}
void writeParams(Settings *settings) const {}
};
@ -39,19 +38,11 @@ public:
MapgenSinglenode(int mapgenid, MapgenParams *params, EmergeManager *emerge);
~MapgenSinglenode();
virtual MapgenType getType() const { return MAPGEN_SINGLENODE; }
void makeChunk(BlockMakeData *data);
int getSpawnLevelAtPoint(v2s16 p);
};
struct MapgenFactorySinglenode : public MapgenFactory {
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge) {
return new MapgenSinglenode(mgid, params, emerge);
};
MapgenSpecificParams *createMapgenParams() {
return new MapgenSinglenodeParams();
};
};
#endif

View File

@ -45,25 +45,23 @@ FlagDesc flagdesc_mapgen_v5[] = {
};
MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge)
MapgenV5::MapgenV5(int mapgenid, MapgenV5Params *params, EmergeManager *emerge)
: MapgenBasic(mapgenid, params, emerge)
{
MapgenV5Params *sp = (MapgenV5Params *)params->sparams;
this->spflags = sp->spflags;
this->cave_width = sp->cave_width;
this->spflags = params->spflags;
this->cave_width = params->cave_width;
// Terrain noise
noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
noise_factor = new Noise(&sp->np_factor, seed, csize.X, csize.Z);
noise_height = new Noise(&sp->np_height, seed, csize.X, csize.Z);
noise_filler_depth = new Noise(&params->np_filler_depth, seed, csize.X, csize.Z);
noise_factor = new Noise(&params->np_factor, seed, csize.X, csize.Z);
noise_height = new Noise(&params->np_height, seed, csize.X, csize.Z);
// 3D terrain noise
// 1-up 1-down overgeneration
noise_ground = new Noise(&sp->np_ground, seed, csize.X, csize.Y + 2, csize.Z);
noise_ground = new Noise(&params->np_ground, seed, csize.X, csize.Y + 2, csize.Z);
MapgenBasic::np_cave1 = sp->np_cave1;
MapgenBasic::np_cave2 = sp->np_cave2;
MapgenBasic::np_cave1 = params->np_cave1;
MapgenBasic::np_cave2 = params->np_cave2;
}
@ -190,7 +188,6 @@ void MapgenV5::makeChunk(BlockMakeData *data)
// Init biome generator, place biome-specific nodes, and build biomemap
biomegen->calcBiomeNoise(node_min);
biomegen->getBiomes(heightmap);
MgStoneType stone_type = generateBiomes();
// Generate caves

View File

@ -30,7 +30,7 @@ class BiomeManager;
extern FlagDesc flagdesc_mapgen_v5[];
struct MapgenV5Params : public MapgenSpecificParams {
struct MapgenV5Params : public MapgenParams {
u32 spflags;
float cave_width;
NoiseParams np_filler_depth;
@ -50,9 +50,11 @@ struct MapgenV5Params : public MapgenSpecificParams {
class MapgenV5 : public MapgenBasic {
public:
MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge);
MapgenV5(int mapgenid, MapgenV5Params *params, EmergeManager *emerge);
~MapgenV5();
virtual MapgenType getType() const { return MAPGEN_V5; }
virtual void makeChunk(BlockMakeData *data);
int getSpawnLevelAtPoint(v2s16 p);
int generateBaseTerrain();
@ -63,17 +65,4 @@ private:
Noise *noise_ground;
};
struct MapgenFactoryV5 : public MapgenFactory {
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge)
{
return new MapgenV5(mgid, params, emerge);
};
MapgenSpecificParams *createMapgenParams()
{
return new MapgenV5Params();
};
};
#endif

View File

@ -53,7 +53,7 @@ FlagDesc flagdesc_mapgen_v6[] = {
/////////////////////////////////////////////////////////////////////////////
MapgenV6::MapgenV6(int mapgenid, MapgenParams *params, EmergeManager *emerge)
MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge)
: Mapgen(mapgenid, params, emerge)
{
this->m_emerge = emerge;
@ -61,26 +61,25 @@ MapgenV6::MapgenV6(int mapgenid, MapgenParams *params, EmergeManager *emerge)
this->heightmap = new s16[csize.X * csize.Z];
MapgenV6Params *sp = (MapgenV6Params *)params->sparams;
this->spflags = sp->spflags;
this->freq_desert = sp->freq_desert;
this->freq_beach = sp->freq_beach;
this->spflags = params->spflags;
this->freq_desert = params->freq_desert;
this->freq_beach = params->freq_beach;
np_cave = &sp->np_cave;
np_humidity = &sp->np_humidity;
np_trees = &sp->np_trees;
np_apple_trees = &sp->np_apple_trees;
np_cave = &params->np_cave;
np_humidity = &params->np_humidity;
np_trees = &params->np_trees;
np_apple_trees = &params->np_apple_trees;
//// Create noise objects
noise_terrain_base = new Noise(&sp->np_terrain_base, seed, csize.X, csize.Y);
noise_terrain_higher = new Noise(&sp->np_terrain_higher, seed, csize.X, csize.Y);
noise_steepness = new Noise(&sp->np_steepness, seed, csize.X, csize.Y);
noise_height_select = new Noise(&sp->np_height_select, seed, csize.X, csize.Y);
noise_mud = new Noise(&sp->np_mud, seed, csize.X, csize.Y);
noise_beach = new Noise(&sp->np_beach, seed, csize.X, csize.Y);
noise_biome = new Noise(&sp->np_biome, seed,
noise_terrain_base = new Noise(&params->np_terrain_base, seed, csize.X, csize.Y);
noise_terrain_higher = new Noise(&params->np_terrain_higher, seed, csize.X, csize.Y);
noise_steepness = new Noise(&params->np_steepness, seed, csize.X, csize.Y);
noise_height_select = new Noise(&params->np_height_select, seed, csize.X, csize.Y);
noise_mud = new Noise(&params->np_mud, seed, csize.X, csize.Y);
noise_beach = new Noise(&params->np_beach, seed, csize.X, csize.Y);
noise_biome = new Noise(&params->np_biome, seed,
csize.X + 2 * MAP_BLOCKSIZE, csize.Y + 2 * MAP_BLOCKSIZE);
noise_humidity = new Noise(&sp->np_humidity, seed,
noise_humidity = new Noise(&params->np_humidity, seed,
csize.X + 2 * MAP_BLOCKSIZE, csize.Y + 2 * MAP_BLOCKSIZE);
//// Resolve nodes to be used
@ -560,28 +559,30 @@ void MapgenV6::makeChunk(BlockMakeData *data)
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.np_rarity = nparams_dungeon_rarity;
dp.np_density = nparams_dungeon_density;
dp.np_wetness = nparams_dungeon_wetness;
dp.c_water = c_water_source;
if (getBiome(0, v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
dp.c_cobble = c_desert_stone;
dp.c_moss = c_desert_stone;
dp.c_stair = c_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.mossratio = 0.0;
dp.holesize = v3s16(2, 3, 2);
dp.roomsize = v3s16(2, 5, 2);
dp.notifytype = GENNOTIFY_TEMPLE;
} else {
dp.c_cobble = c_cobble;
dp.c_moss = c_mossycobble;
dp.c_stair = c_stair_cobble;
dp.c_wall = c_cobble;
dp.c_alt_wall = c_mossycobble;
dp.c_stair = c_stair_cobble;
dp.diagonal_dirs = false;
dp.mossratio = 3.0;
dp.holesize = v3s16(1, 2, 1);
dp.roomsize = v3s16(0, 0, 0);
dp.notifytype = GENNOTIFY_DUNGEON;

View File

@ -53,7 +53,7 @@ enum BiomeV6Type
};
struct MapgenV6Params : public MapgenSpecificParams {
struct MapgenV6Params : public MapgenParams {
u32 spflags;
float freq_desert;
float freq_beach;
@ -124,9 +124,11 @@ public:
content_t c_mossycobble;
content_t c_stair_cobble;
MapgenV6(int mapgenid, MapgenParams *params, EmergeManager *emerge);
MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge);
~MapgenV6();
virtual MapgenType getType() const { return MAPGEN_V6; }
void makeChunk(BlockMakeData *data);
int getGroundLevelAtPoint(v2s16 p);
int getSpawnLevelAtPoint(v2s16 p);
@ -162,18 +164,4 @@ public:
virtual void generateCaves(int max_stone_y);
};
struct MapgenFactoryV6 : public MapgenFactory {
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge)
{
return new MapgenV6(mgid, params, emerge);
};
MapgenSpecificParams *createMapgenParams()
{
return new MapgenV6Params();
};
};
#endif

View File

@ -50,30 +50,28 @@ FlagDesc flagdesc_mapgen_v7[] = {
///////////////////////////////////////////////////////////////////////////////
MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge)
MapgenV7::MapgenV7(int mapgenid, MapgenV7Params *params, EmergeManager *emerge)
: MapgenBasic(mapgenid, params, emerge)
{
MapgenV7Params *sp = (MapgenV7Params *)params->sparams;
this->spflags = sp->spflags;
this->cave_width = sp->cave_width;
this->spflags = params->spflags;
this->cave_width = params->cave_width;
//// Terrain noise
noise_terrain_base = new Noise(&sp->np_terrain_base, seed, csize.X, csize.Z);
noise_terrain_alt = new Noise(&sp->np_terrain_alt, seed, csize.X, csize.Z);
noise_terrain_persist = new Noise(&sp->np_terrain_persist, seed, csize.X, csize.Z);
noise_height_select = new Noise(&sp->np_height_select, seed, csize.X, csize.Z);
noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
noise_mount_height = new Noise(&sp->np_mount_height, seed, csize.X, csize.Z);
noise_ridge_uwater = new Noise(&sp->np_ridge_uwater, seed, csize.X, csize.Z);
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);
//// 3d terrain noise
// 1-up 1-down overgeneration
noise_mountain = new Noise(&sp->np_mountain, seed, csize.X, csize.Y + 2, csize.Z);
noise_ridge = new Noise(&sp->np_ridge, seed, csize.X, csize.Y + 2, csize.Z);
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 = sp->np_cave1;
MapgenBasic::np_cave2 = sp->np_cave2;
MapgenBasic::np_cave1 = params->np_cave1;
MapgenBasic::np_cave2 = params->np_cave2;
}
@ -94,7 +92,7 @@ MapgenV7::~MapgenV7()
MapgenV7Params::MapgenV7Params()
{
spflags = MGV7_MOUNTAINS | MGV7_RIDGES;
cave_width = 0.3;
cave_width = 0.2;
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);
@ -105,8 +103,8 @@ MapgenV7Params::MapgenV7Params()
np_ridge_uwater = NoiseParams(0, 1, v3f(1000, 1000, 1000), 85039, 5, 0.6, 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_cave1 = NoiseParams(0, 12, v3f(96, 96, 96), 52534, 4, 0.5, 2.0);
np_cave2 = NoiseParams(0, 12, v3f(96, 96, 96), 10325, 4, 0.5, 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);
}
@ -219,7 +217,6 @@ void MapgenV7::makeChunk(BlockMakeData *data)
// Init biome generator, place biome-specific nodes, and build biomemap
biomegen->calcBiomeNoise(node_min);
biomegen->getBiomes(heightmap);
MgStoneType stone_type = generateBiomes();
if (flags & MG_CAVES)

View File

@ -32,7 +32,7 @@ class BiomeManager;
extern FlagDesc flagdesc_mapgen_v7[];
struct MapgenV7Params : public MapgenSpecificParams {
struct MapgenV7Params : public MapgenParams {
u32 spflags;
float cave_width;
NoiseParams np_terrain_base;
@ -56,9 +56,11 @@ struct MapgenV7Params : public MapgenSpecificParams {
class MapgenV7 : public MapgenBasic {
public:
MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge);
MapgenV7(int mapgenid, MapgenV7Params *params, EmergeManager *emerge);
~MapgenV7();
virtual MapgenType getType() const { return MAPGEN_V7; }
virtual void makeChunk(BlockMakeData *data);
int getSpawnLevelAtPoint(v2s16 p);
@ -80,16 +82,4 @@ private:
Noise *noise_ridge;
};
struct MapgenFactoryV7 : public MapgenFactory {
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge)
{
return new MapgenV7(mgid, params, emerge);
};
MapgenSpecificParams *createMapgenParams()
{
return new MapgenV7Params();
};
};
#endif

View File

@ -64,7 +64,7 @@ static FlagDesc flagdesc_mapgen_valleys[] = {
///////////////////////////////////////////////////////////////////////////////
MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *emerge)
MapgenValleys::MapgenValleys(int mapgenid, MapgenValleysParams *params, EmergeManager *emerge)
: MapgenBasic(mapgenid, params, emerge)
{
// NOTE: MapgenValleys has a hard dependency on BiomeGenOriginal
@ -73,34 +73,33 @@ MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *
this->map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
g_settings->getU16("map_generation_limit"));
MapgenValleysParams *sp = (MapgenValleysParams *)params->sparams;
BiomeParamsOriginal *bp = (BiomeParamsOriginal *)params->bparams;
this->spflags = sp->spflags;
this->altitude_chill = sp->altitude_chill;
this->large_cave_depth = sp->large_cave_depth;
this->lava_features_lim = rangelim(sp->lava_features, 0, 10);
this->massive_cave_depth = sp->massive_cave_depth;
this->river_depth_bed = sp->river_depth + 1.f;
this->river_size_factor = sp->river_size / 100.f;
this->water_features_lim = rangelim(sp->water_features, 0, 10);
this->cave_width = sp->cave_width;
this->spflags = params->spflags;
this->altitude_chill = params->altitude_chill;
this->large_cave_depth = params->large_cave_depth;
this->lava_features_lim = rangelim(params->lava_features, 0, 10);
this->massive_cave_depth = params->massive_cave_depth;
this->river_depth_bed = params->river_depth + 1.f;
this->river_size_factor = params->river_size / 100.f;
this->water_features_lim = rangelim(params->water_features, 0, 10);
this->cave_width = params->cave_width;
//// 2D Terrain noise
noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
noise_inter_valley_slope = new Noise(&sp->np_inter_valley_slope, seed, csize.X, csize.Z);
noise_rivers = new Noise(&sp->np_rivers, seed, csize.X, csize.Z);
noise_terrain_height = new Noise(&sp->np_terrain_height, seed, csize.X, csize.Z);
noise_valley_depth = new Noise(&sp->np_valley_depth, seed, csize.X, csize.Z);
noise_valley_profile = new Noise(&sp->np_valley_profile, seed, csize.X, csize.Z);
noise_filler_depth = new Noise(&params->np_filler_depth, seed, csize.X, csize.Z);
noise_inter_valley_slope = new Noise(&params->np_inter_valley_slope, seed, csize.X, csize.Z);
noise_rivers = new Noise(&params->np_rivers, seed, csize.X, csize.Z);
noise_terrain_height = new Noise(&params->np_terrain_height, seed, csize.X, csize.Z);
noise_valley_depth = new Noise(&params->np_valley_depth, seed, csize.X, csize.Z);
noise_valley_profile = new Noise(&params->np_valley_profile, seed, csize.X, csize.Z);
//// 3D Terrain noise
// 1-up 1-down overgeneration
noise_inter_valley_fill = new Noise(&sp->np_inter_valley_fill, seed, csize.X, csize.Y + 2, csize.Z);
noise_inter_valley_fill = new Noise(&params->np_inter_valley_fill, seed, csize.X, csize.Y + 2, csize.Z);
// 1-down overgeneraion
noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z);
noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z);
noise_massive_caves = new Noise(&sp->np_massive_caves, seed, csize.X, csize.Y + 1, csize.Z);
noise_cave1 = new Noise(&params->np_cave1, seed, csize.X, csize.Y + 1, csize.Z);
noise_cave2 = new Noise(&params->np_cave2, seed, csize.X, csize.Y + 1, csize.Z);
noise_massive_caves = new Noise(&params->np_massive_caves, seed, csize.X, csize.Y + 1, csize.Z);
this->humid_rivers = (spflags & MGVALLEYS_HUMID_RIVERS);
this->use_altitude_chill = (spflags & MGVALLEYS_ALT_CHILL);
@ -114,11 +113,6 @@ MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *
// Resolve content to be used
c_lava_source = ndef->getId("mapgen_lava_source");
c_sand = ndef->getId("mapgen_sand");
// Fall back to more basic content if not defined
if (c_sand == CONTENT_IGNORE)
c_sand = c_stone;
}
@ -149,10 +143,10 @@ MapgenValleysParams::MapgenValleysParams()
river_depth = 4; // How deep to carve river channels.
river_size = 5; // How wide to make rivers.
water_features = 0; // How often water will occur in caves.
cave_width = 0.3;
cave_width = 0.2;
np_cave1 = NoiseParams(0, 12, v3f(96, 96, 96), 52534, 4, 0.5, 2.0);
np_cave2 = NoiseParams(0, 12, v3f(96, 96, 96), 10325, 4, 0.5, 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);
np_filler_depth = NoiseParams(0.f, 1.2f, v3f(256, 256, 256), 1605, 3, 0.5f, 2.f);
np_inter_valley_fill = NoiseParams(0.f, 1.f, v3f(256, 512, 256), 1993, 6, 0.8f, 2.f);
np_inter_valley_slope = NoiseParams(0.5f, 0.5f, v3f(128, 128, 128), 746, 1, 1.f, 2.f);
@ -255,10 +249,7 @@ void MapgenValleys::makeChunk(BlockMakeData *data)
// Generate base terrain with initial heightmaps
s16 stone_surface_max_y = generateTerrain();
// Build biomemap
m_bgen->getBiomes(heightmap);
// Place biome-specific nodes
// Place biome-specific nodes and build biomemap
MgStoneType stone_type = generateBiomes();
// Cave creation.
@ -493,7 +484,6 @@ int MapgenValleys::generateTerrain()
MapNode n_air(CONTENT_AIR);
MapNode n_river_water(c_river_water_source);
MapNode n_sand(c_sand);
MapNode n_stone(c_stone);
MapNode n_water(c_water_source);
@ -537,10 +527,7 @@ int MapgenValleys::generateTerrain()
float surface_delta = (float)y - surface_y;
bool river = y + 1 < river_y;
if (fabs(surface_delta) <= 0.5f && y > water_level && river) {
// river bottom
vm->m_data[index_data] = n_sand;
} else if (slope * fill > surface_delta) {
if (slope * fill > surface_delta) {
// ground
vm->m_data[index_data] = n_stone;
if (y > heightmap[index_2d])
@ -553,7 +540,7 @@ int MapgenValleys::generateTerrain()
} else if (river) {
// river
vm->m_data[index_data] = n_river_water;
} else {
} else { // air
vm->m_data[index_data] = n_air;
}
}

View File

@ -46,7 +46,7 @@ class BiomeGenOriginal;
//extern Profiler *mapgen_profiler;
struct MapgenValleysParams : public MapgenSpecificParams {
struct MapgenValleysParams : public MapgenParams {
u32 spflags;
s16 large_cave_depth;
s16 massive_cave_depth;
@ -88,9 +88,11 @@ struct TerrainNoise {
class MapgenValleys : public MapgenBasic {
public:
MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *emerge);
MapgenValleys(int mapgenid, MapgenValleysParams *params, EmergeManager *emerge);
~MapgenValleys();
virtual MapgenType getType() const { return MAPGEN_VALLEYS; }
virtual void makeChunk(BlockMakeData *data);
int getSpawnLevelAtPoint(v2s16 p);
@ -125,7 +127,6 @@ private:
Noise *noise_valley_profile;
content_t c_lava_source;
content_t c_sand;
float terrainLevelAtPoint(s16 x, s16 z);
@ -138,16 +139,4 @@ private:
virtual void generateCaves(s16 max_stone_y, s16 large_cave_depth);
};
struct MapgenFactoryValleys : public MapgenFactory {
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge)
{
return new MapgenValleys(mgid, params, emerge);
};
MapgenSpecificParams *createMapgenParams()
{
return new MapgenValleysParams();
};
};
#endif

View File

@ -46,6 +46,7 @@ BiomeManager::BiomeManager(IGameDef *gamedef) :
b->depth_top = 0;
b->depth_filler = -MAX_MAP_GENERATION_LIMIT;
b->depth_water_top = 0;
b->depth_riverbed = 0;
b->y_min = -MAX_MAP_GENERATION_LIMIT;
b->y_max = MAX_MAP_GENERATION_LIMIT;
b->heat_point = 0.0;
@ -57,6 +58,7 @@ BiomeManager::BiomeManager(IGameDef *gamedef) :
b->m_nodenames.push_back("mapgen_water_source");
b->m_nodenames.push_back("mapgen_water_source");
b->m_nodenames.push_back("mapgen_river_water_source");
b->m_nodenames.push_back("mapgen_stone");
b->m_nodenames.push_back("ignore");
m_ndef->pendNodeResolve(b);
@ -128,7 +130,7 @@ BiomeGenOriginal::BiomeGenOriginal(BiomeManager *biomemgr,
heatmap = noise_heat->result;
humidmap = noise_humidity->result;
biomemap = new u8[m_csize.X * m_csize.Z];
biomemap = new biome_t[m_csize.X * m_csize.Z];
}
BiomeGenOriginal::~BiomeGenOriginal()
@ -171,7 +173,7 @@ void BiomeGenOriginal::calcBiomeNoise(v3s16 pmin)
}
u8 *BiomeGenOriginal::getBiomes(s16 *heightmap)
biome_t *BiomeGenOriginal::getBiomes(s16 *heightmap)
{
for (s32 i = 0; i != m_csize.X * m_csize.Z; i++) {
Biome *biome = calcBiomeFromNoise(
@ -237,5 +239,6 @@ void Biome::resolveNodeNames()
getIdFromNrBacklog(&c_water_top, "mapgen_water_source", CONTENT_AIR);
getIdFromNrBacklog(&c_water, "mapgen_water_source", CONTENT_AIR);
getIdFromNrBacklog(&c_river_water, "mapgen_river_water_source", CONTENT_AIR);
getIdFromNrBacklog(&c_riverbed, "mapgen_stone", CONTENT_AIR);
getIdFromNrBacklog(&c_dust, "ignore", CONTENT_IGNORE);
}

View File

@ -31,7 +31,9 @@ class BiomeManager;
//// Biome
////
#define BIOME_NONE ((u8)0)
typedef u8 biome_t;
#define BIOME_NONE ((biome_t)0)
// TODO(hmmmm): Decide whether this is obsolete or will be used in the future
enum BiomeType {
@ -52,11 +54,13 @@ public:
content_t c_water_top;
content_t c_water;
content_t c_river_water;
content_t c_riverbed;
content_t c_dust;
s16 depth_top;
s16 depth_filler;
s16 depth_water_top;
s16 depth_riverbed;
s16 y_min;
s16 y_max;
@ -80,7 +84,7 @@ struct BiomeParams {
virtual void writeParams(Settings *settings) const = 0;
virtual ~BiomeParams() {}
int seed;
s32 seed;
};
class BiomeGen {
@ -101,7 +105,7 @@ public:
// Gets all biomes in current chunk using each corresponding element of
// heightmap as the y position, then stores the results by biome index in
// biomemap (also returned)
virtual u8 *getBiomes(s16 *heightmap) = 0;
virtual biome_t *getBiomes(s16 *heightmap) = 0;
// Gets a single biome at the specified position, which must be contained
// in the region formed by m_pmin and (m_pmin + m_csize - 1).
@ -111,7 +115,7 @@ public:
virtual Biome *getBiomeAtIndex(size_t index, s16 y) const = 0;
// Result of calcBiomes bulk computation.
u8 *biomemap;
biome_t *biomemap;
protected:
BiomeManager *m_bmgr;
@ -157,7 +161,7 @@ public:
Biome *calcBiomeAtPoint(v3s16 pos) const;
void calcBiomeNoise(v3s16 pmin);
u8 *getBiomes(s16 *heightmap);
biome_t *getBiomes(s16 *heightmap);
Biome *getBiomeAtPoint(v3s16 pos) const;
Biome *getBiomeAtIndex(size_t index, s16 y) const;
@ -218,9 +222,6 @@ public:
virtual void clear();
// Looks for pos in the biome cache, and if non-existent, looks up by noise
u8 getBiomeAtPoint(v3s16 pos);
private:
IGameDef *m_gamedef;

View File

@ -1107,7 +1107,7 @@ void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath
content_t id;
if (!getId(splitted[0], id)) {
errorstream << override_filepath
infostream << override_filepath
<< ":" << line_c << " Could not apply texture override \""
<< line << "\": Unknown node \""
<< splitted[0] << "\"" << std::endl;

View File

@ -47,36 +47,38 @@ void NodeTimerList::serialize(std::ostream &os, u8 map_format_version) const
{
if (map_format_version == 24) {
// Version 0 is a placeholder for "nothing to see here; go away."
if (m_data.empty()) {
if (m_timers.empty()) {
writeU8(os, 0); // version
return;
}
writeU8(os, 1); // version
writeU16(os, m_data.size());
writeU16(os, m_timers.size());
}
if (map_format_version >= 25) {
writeU8(os, 2 + 4 + 4); // length of the data for a single timer
writeU16(os, m_data.size());
writeU16(os, m_timers.size());
}
for (std::map<v3s16, NodeTimer>::const_iterator
i = m_data.begin();
i != m_data.end(); ++i) {
v3s16 p = i->first;
for (std::multimap<double, NodeTimer>::const_iterator
i = m_timers.begin();
i != m_timers.end(); ++i) {
NodeTimer t = i->second;
NodeTimer nt = NodeTimer(t.timeout,
t.timeout - (f32)(i->first - m_time), t.position);
v3s16 p = t.position;
u16 p16 = p.Z * MAP_BLOCKSIZE * MAP_BLOCKSIZE + p.Y * MAP_BLOCKSIZE + p.X;
writeU16(os, p16);
t.serialize(os);
nt.serialize(os);
}
}
void NodeTimerList::deSerialize(std::istream &is, u8 map_format_version)
{
m_data.clear();
clear();
if(map_format_version == 24){
if (map_format_version == 24) {
u8 timer_version = readU8(is);
if(timer_version == 0)
return;
@ -84,7 +86,7 @@ void NodeTimerList::deSerialize(std::istream &is, u8 map_format_version)
throw SerializationError("unsupported NodeTimerList version");
}
if(map_format_version >= 25){
if (map_format_version >= 25) {
u8 timer_data_len = readU8(is);
if(timer_data_len != 2+4+4)
throw SerializationError("unsupported NodeTimer data length");
@ -92,8 +94,7 @@ void NodeTimerList::deSerialize(std::istream &is, u8 map_format_version)
u16 count = readU16(is);
for(u16 i=0; i<count; i++)
{
for (u16 i = 0; i < count; i++) {
u16 p16 = readU16(is);
v3s16 p;
@ -103,11 +104,10 @@ void NodeTimerList::deSerialize(std::istream &is, u8 map_format_version)
p16 &= MAP_BLOCKSIZE - 1;
p.X = p16;
NodeTimer t;
NodeTimer t(p);
t.deSerialize(is);
if(t.timeout <= 0)
{
if (t.timeout <= 0) {
warningstream<<"NodeTimerList::deSerialize(): "
<<"invalid data at position"
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<"): Ignoring."
@ -115,8 +115,7 @@ void NodeTimerList::deSerialize(std::istream &is, u8 map_format_version)
continue;
}
if(m_data.find(p) != m_data.end())
{
if (m_iterators.find(p) != m_iterators.end()) {
warningstream<<"NodeTimerList::deSerialize(): "
<<"already set data at position"
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<"): Ignoring."
@ -124,31 +123,30 @@ void NodeTimerList::deSerialize(std::istream &is, u8 map_format_version)
continue;
}
m_data.insert(std::make_pair(p, t));
insert(t);
}
}
std::map<v3s16, NodeTimer> NodeTimerList::step(float dtime)
std::vector<NodeTimer> NodeTimerList::step(float dtime)
{
std::map<v3s16, NodeTimer> elapsed_timers;
// Increment timers
for(std::map<v3s16, NodeTimer>::iterator
i = m_data.begin();
i != m_data.end(); ++i){
v3s16 p = i->first;
std::vector<NodeTimer> elapsed_timers;
m_time += dtime;
if (m_next_trigger_time == -1. || m_time < m_next_trigger_time) {
return elapsed_timers;
}
std::multimap<double, NodeTimer>::iterator i = m_timers.begin();
// Process timers
for (; i != m_timers.end() && i->first <= m_time; ++i) {
NodeTimer t = i->second;
t.elapsed += dtime;
if(t.elapsed >= t.timeout)
elapsed_timers.insert(std::make_pair(p, t));
else
i->second = t;
t.elapsed = t.timeout + (f32)(m_time - i->first);
elapsed_timers.push_back(t);
m_iterators.erase(t.position);
}
// Delete elapsed timers
for(std::map<v3s16, NodeTimer>::const_iterator
i = elapsed_timers.begin();
i != elapsed_timers.end(); ++i){
v3s16 p = i->first;
m_data.erase(p);
}
m_timers.erase(m_timers.begin(), i);
if (m_timers.empty())
m_next_trigger_time = -1.;
else
m_next_trigger_time = m_timers.begin()->first;
return elapsed_timers;
}

View File

@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irr_v3d.h"
#include <iostream>
#include <map>
#include <vector>
/*
NodeTimer provides per-node timed callback functionality.
@ -36,8 +37,10 @@ class NodeTimer
{
public:
NodeTimer(): timeout(0.), elapsed(0.) {}
NodeTimer(f32 timeout_, f32 elapsed_):
timeout(timeout_), elapsed(elapsed_) {}
NodeTimer(const v3s16 &position_):
timeout(0.), elapsed(0.), position(position_) {}
NodeTimer(f32 timeout_, f32 elapsed_, v3s16 position_):
timeout(timeout_), elapsed(elapsed_), position(position_) {}
~NodeTimer() {}
void serialize(std::ostream &os) const;
@ -45,6 +48,7 @@ public:
f32 timeout;
f32 elapsed;
v3s16 position;
};
/*
@ -54,37 +58,78 @@ public:
class NodeTimerList
{
public:
NodeTimerList() {}
NodeTimerList(): m_next_trigger_time(-1.), m_time(0.) {}
~NodeTimerList() {}
void serialize(std::ostream &os, u8 map_format_version) const;
void deSerialize(std::istream &is, u8 map_format_version);
// Get timer
NodeTimer get(v3s16 p){
std::map<v3s16, NodeTimer>::iterator n = m_data.find(p);
if(n == m_data.end())
NodeTimer get(const v3s16 &p) {
std::map<v3s16, std::multimap<double, NodeTimer>::iterator>::iterator n =
m_iterators.find(p);
if (n == m_iterators.end())
return NodeTimer();
return n->second;
NodeTimer t = n->second->second;
t.elapsed = t.timeout - (n->second->first - m_time);
return t;
}
// Deletes timer
void remove(v3s16 p){
m_data.erase(p);
void remove(v3s16 p) {
std::map<v3s16, std::multimap<double, NodeTimer>::iterator>::iterator n =
m_iterators.find(p);
if(n != m_iterators.end()) {
double removed_time = n->second->first;
m_timers.erase(n->second);
m_iterators.erase(n);
// Yes, this is float equality, but it is not a problem
// since we only test equality of floats as an ordered type
// and thus we never lose precision
if (removed_time == m_next_trigger_time) {
if (m_timers.empty())
m_next_trigger_time = -1.;
else
m_next_trigger_time = m_timers.begin()->first;
}
}
}
// Undefined behaviour if there already is a timer
void insert(NodeTimer timer) {
v3s16 p = timer.position;
double trigger_time = m_time + (double)(timer.timeout - timer.elapsed);
std::multimap<double, NodeTimer>::iterator it =
m_timers.insert(std::pair<double, NodeTimer>(
trigger_time, timer
));
m_iterators.insert(
std::pair<v3s16, std::multimap<double, NodeTimer>::iterator>(p, it));
if (m_next_trigger_time == -1. || trigger_time < m_next_trigger_time)
m_next_trigger_time = trigger_time;
}
// Deletes old timer and sets a new one
void set(v3s16 p, NodeTimer t){
m_data[p] = t;
inline void set(const NodeTimer &timer) {
remove(timer.position);
insert(timer);
}
// Deletes all timers
void clear(){
m_data.clear();
void clear() {
m_timers.clear();
m_iterators.clear();
m_next_trigger_time = -1.;
}
// A step in time. Returns map of elapsed timers.
std::map<v3s16, NodeTimer> step(float dtime);
inline double getNextTriggerTime() {
return m_next_trigger_time;
}
// Move forward in time, returns elapsed timers
std::vector<NodeTimer> step(float dtime);
private:
std::map<v3s16, NodeTimer> m_data;
std::multimap<double, NodeTimer> m_timers;
std::map<v3s16, std::multimap<double, NodeTimer>::iterator> m_iterators;
double m_next_trigger_time;
double m_time;
};
#endif

View File

@ -93,22 +93,31 @@ u32 PcgRandom::range(u32 bound)
// If the bound is 0, we cover the whole RNG's range
if (bound == 0)
return next();
/*
If the bound is not a multiple of the RNG's range, it may cause bias,
e.g. a RNG has a range from 0 to 3 and we take want a number 0 to 2.
Using rand() % 3, the number 0 would be twice as likely to appear.
With a very large RNG range, the effect becomes less prevalent but
still present. This can be solved by modifying the range of the RNG
to become a multiple of bound by dropping values above the a threshold.
In our example, threshold == 4 - 3 = 1 % 3 == 1, so reject 0, thus
making the range 3 with no bias.
This loop looks dangerous, but will always terminate due to the
RNG's property of uniformity.
/*
This is an optimization of the expression:
0x100000000ull % bound
since 64-bit modulo operations typically much slower than 32.
*/
u32 threshold = -bound % bound;
u32 r;
/*
If the bound is not a multiple of the RNG's range, it may cause bias,
e.g. a RNG has a range from 0 to 3 and we take want a number 0 to 2.
Using rand() % 3, the number 0 would be twice as likely to appear.
With a very large RNG range, the effect becomes less prevalent but
still present.
This can be solved by modifying the range of the RNG to become a
multiple of bound by dropping values above the a threshold.
In our example, threshold == 4 % 3 == 1, so reject values < 1
(that is, 0), thus making the range == 3 with no bias.
This loop may look dangerous, but will always terminate due to the
RNG's property of uniformity.
*/
while ((r = next()) < threshold)
;
@ -156,7 +165,7 @@ s32 PcgRandom::randNormalDist(s32 min, s32 max, int num_trials)
///////////////////////////////////////////////////////////////////////////////
float noise2d(int x, int y, int seed)
float noise2d(int x, int y, s32 seed)
{
unsigned int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y
+ NOISE_MAGIC_SEED * seed) & 0x7fffffff;
@ -166,7 +175,7 @@ float noise2d(int x, int y, int seed)
}
float noise3d(int x, int y, int z, int seed)
float noise3d(int x, int y, int z, s32 seed)
{
unsigned int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y + NOISE_MAGIC_Z * z
+ NOISE_MAGIC_SEED * seed) & 0x7fffffff;
@ -235,7 +244,7 @@ float triLinearInterpolationNoEase(
return linearInterpolation(u, v, z);
}
float noise2d_gradient(float x, float y, int seed, bool eased)
float noise2d_gradient(float x, float y, s32 seed, bool eased)
{
// Calculate the integer coordinates
int x0 = myfloor(x);
@ -256,7 +265,7 @@ float noise2d_gradient(float x, float y, int seed, bool eased)
}
float noise3d_gradient(float x, float y, float z, int seed, bool eased)
float noise3d_gradient(float x, float y, float z, s32 seed, bool eased)
{
// Calculate the integer coordinates
int x0 = myfloor(x);
@ -290,7 +299,7 @@ float noise3d_gradient(float x, float y, float z, int seed, bool eased)
}
float noise2d_perlin(float x, float y, int seed,
float noise2d_perlin(float x, float y, s32 seed,
int octaves, float persistence, bool eased)
{
float a = 0;
@ -306,7 +315,7 @@ float noise2d_perlin(float x, float y, int seed,
}
float noise2d_perlin_abs(float x, float y, int seed,
float noise2d_perlin_abs(float x, float y, s32 seed,
int octaves, float persistence, bool eased)
{
float a = 0;
@ -321,7 +330,7 @@ float noise2d_perlin_abs(float x, float y, int seed,
}
float noise3d_perlin(float x, float y, float z, int seed,
float noise3d_perlin(float x, float y, float z, s32 seed,
int octaves, float persistence, bool eased)
{
float a = 0;
@ -336,7 +345,7 @@ float noise3d_perlin(float x, float y, float z, int seed,
}
float noise3d_perlin_abs(float x, float y, float z, int seed,
float noise3d_perlin_abs(float x, float y, float z, s32 seed,
int octaves, float persistence, bool eased)
{
float a = 0;
@ -363,7 +372,7 @@ float contour(float v)
///////////////////////// [ New noise ] ////////////////////////////
float NoisePerlin2D(NoiseParams *np, float x, float y, int seed)
float NoisePerlin2D(NoiseParams *np, float x, float y, s32 seed)
{
float a = 0;
float f = 1.0;
@ -389,7 +398,7 @@ float NoisePerlin2D(NoiseParams *np, float x, float y, int seed)
}
float NoisePerlin3D(NoiseParams *np, float x, float y, float z, int seed)
float NoisePerlin3D(NoiseParams *np, float x, float y, float z, s32 seed)
{
float a = 0;
float f = 1.0;
@ -416,7 +425,7 @@ float NoisePerlin3D(NoiseParams *np, float x, float y, float z, int seed)
}
Noise::Noise(NoiseParams *np_, int seed, u32 sx, u32 sy, u32 sz)
Noise::Noise(NoiseParams *np_, s32 seed, u32 sx, u32 sy, u32 sz)
{
memcpy(&np, np_, sizeof(np));
this->seed = seed;
@ -543,7 +552,7 @@ void Noise::resizeNoiseBuf(bool is3d)
void Noise::gradientMap2D(
float x, float y,
float step_x, float step_y,
int seed)
s32 seed)
{
float v00, v01, v10, v11, u, v, orig_u;
u32 index, i, j, noisex, noisey;
@ -607,7 +616,7 @@ void Noise::gradientMap2D(
void Noise::gradientMap3D(
float x, float y, float z,
float step_x, float step_y, float step_z,
int seed)
s32 seed)
{
float v000, v010, v100, v110;
float v001, v011, v101, v111;

View File

@ -148,7 +148,7 @@ struct NoiseParams {
class Noise {
public:
NoiseParams np;
int seed;
s32 seed;
u32 sx;
u32 sy;
u32 sz;
@ -157,7 +157,7 @@ public:
float *persist_buf;
float *result;
Noise(NoiseParams *np, int seed, u32 sx, u32 sy, u32 sz=1);
Noise(NoiseParams *np, s32 seed, u32 sx, u32 sy, u32 sz=1);
~Noise();
void setSize(u32 sx, u32 sy, u32 sz=1);
@ -167,11 +167,11 @@ public:
void gradientMap2D(
float x, float y,
float step_x, float step_y,
int seed);
s32 seed);
void gradientMap3D(
float x, float y, float z,
float step_x, float step_y, float step_z,
int seed);
s32 seed);
float *perlinMap2D(float x, float y, float *persistence_map=NULL);
float *perlinMap3D(float x, float y, float z, float *persistence_map=NULL);
@ -202,11 +202,11 @@ private:
};
float NoisePerlin2D(NoiseParams *np, float x, float y, int seed);
float NoisePerlin3D(NoiseParams *np, float x, float y, float z, int seed);
float NoisePerlin2D(NoiseParams *np, float x, float y, s32 seed);
float NoisePerlin3D(NoiseParams *np, float x, float y, float z, s32 seed);
inline float NoisePerlin2D_PO(NoiseParams *np, float x, float xoff,
float y, float yoff, int seed)
float y, float yoff, s32 seed)
{
return NoisePerlin2D(np,
x + xoff * np->spread.X,
@ -215,7 +215,7 @@ inline float NoisePerlin2D_PO(NoiseParams *np, float x, float xoff,
}
inline float NoisePerlin3D_PO(NoiseParams *np, float x, float xoff,
float y, float yoff, float z, float zoff, int seed)
float y, float yoff, float z, float zoff, s32 seed)
{
return NoisePerlin3D(np,
x + xoff * np->spread.X,
@ -225,22 +225,22 @@ inline float NoisePerlin3D_PO(NoiseParams *np, float x, float xoff,
}
// Return value: -1 ... 1
float noise2d(int x, int y, int seed);
float noise3d(int x, int y, int z, int seed);
float noise2d(int x, int y, s32 seed);
float noise3d(int x, int y, int z, s32 seed);
float noise2d_gradient(float x, float y, int seed, bool eased=true);
float noise3d_gradient(float x, float y, float z, int seed, bool eased=false);
float noise2d_gradient(float x, float y, s32 seed, bool eased=true);
float noise3d_gradient(float x, float y, float z, s32 seed, bool eased=false);
float noise2d_perlin(float x, float y, int seed,
float noise2d_perlin(float x, float y, s32 seed,
int octaves, float persistence, bool eased=true);
float noise2d_perlin_abs(float x, float y, int seed,
float noise2d_perlin_abs(float x, float y, s32 seed,
int octaves, float persistence, bool eased=true);
float noise3d_perlin(float x, float y, float z, int seed,
float noise3d_perlin(float x, float y, float z, s32 seed,
int octaves, float persistence, bool eased=false);
float noise3d_perlin_abs(float x, float y, float z, int seed,
float noise3d_perlin_abs(float x, float y, float z, s32 seed,
int octaves, float persistence, bool eased=false);
inline float easeCurve(float t)

View File

@ -46,6 +46,8 @@ struct PlayerControl
RMB = false;
pitch = 0;
yaw = 0;
sidew_move_joystick_axis = .0f;
forw_move_joystick_axis = .0f;
}
PlayerControl(
bool a_up,
@ -58,7 +60,9 @@ struct PlayerControl
bool a_LMB,
bool a_RMB,
float a_pitch,
float a_yaw
float a_yaw,
float a_sidew_move_joystick_axis,
float a_forw_move_joystick_axis
)
{
up = a_up;
@ -72,6 +76,8 @@ struct PlayerControl
RMB = a_RMB;
pitch = a_pitch;
yaw = a_yaw;
sidew_move_joystick_axis = a_sidew_move_joystick_axis;
forw_move_joystick_axis = a_forw_move_joystick_axis;
}
bool up;
bool down;
@ -84,6 +90,8 @@ struct PlayerControl
bool RMB;
float pitch;
float yaw;
float sidew_move_joystick_axis;
float forw_move_joystick_axis;
};
class Map;
@ -180,16 +188,28 @@ public:
m_breath = breath;
}
f32 getRadPitch()
// Deprecated
f32 getRadPitchDep()
{
return -1.0 * m_pitch * core::DEGTORAD;
}
f32 getRadYaw()
// Deprecated
f32 getRadYawDep()
{
return (m_yaw + 90.) * core::DEGTORAD;
}
f32 getRadPitch()
{
return m_pitch * core::DEGTORAD;
}
f32 getRadYaw()
{
return m_yaw * core::DEGTORAD;
}
const char *getName() const
{
return m_name;

View File

@ -75,11 +75,16 @@ bool * signal_handler_killstatus(void)
#if !defined(_WIN32) // POSIX
#include <signal.h>
void sigint_handler(int sig)
void signal_handler(int sig)
{
if (!g_killed) {
dstream << "INFO: sigint_handler(): "
<< "Ctrl-C pressed, shutting down." << std::endl;
if (sig == SIGINT) {
dstream << "INFO: signal_handler(): "
<< "Ctrl-C pressed, shutting down." << std::endl;
} else if (sig == SIGTERM) {
dstream << "INFO: signal_handler(): "
<< "got SIGTERM, shutting down." << std::endl;
}
// Comment out for less clutter when testing scripts
/*dstream << "INFO: sigint_handler(): "
@ -88,13 +93,14 @@ void sigint_handler(int sig)
g_killed = true;
} else {
(void)signal(SIGINT, SIG_DFL);
(void)signal(sig, SIG_DFL);
}
}
void signal_handler_init(void)
{
(void)signal(SIGINT, sigint_handler);
(void)signal(SIGINT, signal_handler);
(void)signal(SIGTERM, signal_handler);
}
#else // _WIN32
@ -252,7 +258,7 @@ bool getCurrentExecPath(char *buf, size_t len)
//// Linux
#elif defined(linux) || defined(__linux) || defined(__linux__)
#elif defined(__linux__)
bool getCurrentExecPath(char *buf, size_t len)
{
@ -368,7 +374,7 @@ bool setSystemPaths()
//// Linux
#elif defined(linux) || defined(__linux)
#elif defined(__linux__)
bool setSystemPaths()
{
@ -605,6 +611,93 @@ void setXorgClassHint(const video::SExposedVideoData &video_data,
#endif
}
bool setXorgWindowIcon(IrrlichtDevice *device,
const std::string &icon_file)
{
#ifdef XORG_USED
video::IVideoDriver *v_driver = device->getVideoDriver();
video::IImageLoader *image_loader = NULL;
for (u32 i = v_driver->getImageLoaderCount() - 1; i >= 0; i--) {
if (v_driver->getImageLoader(i)->isALoadableFileExtension(icon_file.c_str())) {
image_loader = v_driver->getImageLoader(i);
break;
}
}
if (!image_loader) {
warningstream << "Could not find image loader for file '"
<< icon_file << "'" << std::endl;
return false;
}
io::IReadFile *icon_f = device->getFileSystem()->createAndOpenFile(icon_file.c_str());
if (!icon_f) {
warningstream << "Could not load icon file '"
<< icon_file << "'" << std::endl;
return false;
}
video::IImage *img = image_loader->loadImage(icon_f);
if (!img) {
warningstream << "Could not load icon file '"
<< icon_file << "'" << std::endl;
icon_f->drop();
return false;
}
u32 height = img->getDimension().Height;
u32 width = img->getDimension().Width;
size_t icon_buffer_len = 2 + height * width;
long *icon_buffer = new long[icon_buffer_len];
icon_buffer[0] = width;
icon_buffer[1] = height;
for (u32 x = 0; x < width; x++) {
for (u32 y = 0; y < height; y++) {
video::SColor col = img->getPixel(x, y);
long pixel_val = 0;
pixel_val |= (u8)col.getAlpha() << 24;
pixel_val |= (u8)col.getRed() << 16;
pixel_val |= (u8)col.getGreen() << 8;
pixel_val |= (u8)col.getBlue();
icon_buffer[2 + x + y * width] = pixel_val;
}
}
img->drop();
icon_f->drop();
const video::SExposedVideoData &video_data = v_driver->getExposedVideoData();
Display *x11_dpl = (Display *)video_data.OpenGLLinux.X11Display;
if (x11_dpl == NULL) {
warningstream << "Could not find x11 display for setting its icon."
<< std::endl;
delete [] icon_buffer;
return false;
}
Window x11_win = (Window)video_data.OpenGLLinux.X11Window;
Atom net_wm_icon = XInternAtom(x11_dpl, "_NET_WM_ICON", False);
Atom cardinal = XInternAtom(x11_dpl, "CARDINAL", False);
XChangeProperty(x11_dpl, x11_win,
net_wm_icon, cardinal, 32,
PropModeReplace, (const unsigned char *)icon_buffer,
icon_buffer_len);
delete [] icon_buffer;
#endif
return true;
}
////
//// Video/Display Information (Client-only)

View File

@ -60,7 +60,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <unistd.h>
#include <stdint.h> //for uintptr_t
#if (defined(linux) || defined(__linux) || defined(__GNU__)) && !defined(_GNU_SOURCE)
// Use standard Posix macro for Linux
#if (defined(linux) || defined(__linux)) && !defined(__linux__)
#define __linux__
#endif
#if (defined(__linux__) || defined(__GNU__)) && !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
@ -321,7 +325,7 @@ inline const char *getPlatformName()
return
#if defined(ANDROID)
"Android"
#elif defined(linux) || defined(__linux) || defined(__linux__)
#elif defined(__linux__)
"Linux"
#elif defined(_WIN32) || defined(_WIN64)
"Windows"
@ -363,6 +367,9 @@ inline const char *getPlatformName()
void setXorgClassHint(const video::SExposedVideoData &video_data,
const std::string &name);
bool setXorgWindowIcon(IrrlichtDevice *device,
const std::string &icon_file);
// This only needs to be called at the start of execution, since all future
// threads in the process inherit this exception handler
void setWin32ExceptionHandler();

View File

@ -42,6 +42,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
}
#define SQLOK(f) SQLRES(f, SQLITE_OK)
#define SQLOK_ERRSTREAM(s, m) \
if ((s) != SQLITE_OK) { \
errorstream << "RollbackManager: " << (m) << ": " \
<< sqlite3_errmsg(db) << std::endl; \
}
#define FINALIZE_STATEMENT(statement) \
SQLOK_ERRSTREAM(sqlite3_finalize(statement), "Failed to finalize " #statement)
class ItemStackRow : public ItemStack {
public:
@ -109,17 +117,17 @@ RollbackManager::~RollbackManager()
{
flush();
SQLOK(sqlite3_finalize(stmt_insert));
SQLOK(sqlite3_finalize(stmt_replace));
SQLOK(sqlite3_finalize(stmt_select));
SQLOK(sqlite3_finalize(stmt_select_range));
SQLOK(sqlite3_finalize(stmt_select_withActor));
SQLOK(sqlite3_finalize(stmt_knownActor_select));
SQLOK(sqlite3_finalize(stmt_knownActor_insert));
SQLOK(sqlite3_finalize(stmt_knownNode_select));
SQLOK(sqlite3_finalize(stmt_knownNode_insert));
FINALIZE_STATEMENT(stmt_insert);
FINALIZE_STATEMENT(stmt_replace);
FINALIZE_STATEMENT(stmt_select);
FINALIZE_STATEMENT(stmt_select_range);
FINALIZE_STATEMENT(stmt_select_withActor);
FINALIZE_STATEMENT(stmt_knownActor_select);
FINALIZE_STATEMENT(stmt_knownActor_insert);
FINALIZE_STATEMENT(stmt_knownNode_select);
FINALIZE_STATEMENT(stmt_knownNode_insert);
SQLOK(sqlite3_close(db));
SQLOK_ERRSTREAM(sqlite3_close(db), "Could not close db");
}

View File

@ -135,7 +135,8 @@ void ScriptApiPlayer::on_joinplayer(ServerActiveObject *player)
runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
}
void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player)
void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player,
bool timeout)
{
SCRIPTAPI_PRECHECKHEADER
@ -144,7 +145,8 @@ void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player)
lua_getfield(L, -1, "registered_on_leaveplayers");
// Call callbacks
objectrefGetOrCreate(L, player);
runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
lua_pushboolean(L, timeout);
runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
}
void ScriptApiPlayer::on_cheat(ServerActiveObject *player,

View File

@ -38,7 +38,7 @@ public:
bool on_prejoinplayer(const std::string &name, const std::string &ip,
std::string *reason);
void on_joinplayer(ServerActiveObject *player);
void on_leaveplayer(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,

View File

@ -34,7 +34,6 @@ struct EnumString ModApiCraft::es_CraftMethod[] =
{0, NULL},
};
// helper for register_craft
bool ModApiCraft::readCraftRecipeShaped(lua_State *L, int index,
int &width, std::vector<std::string> &recipe)
@ -281,6 +280,80 @@ int ModApiCraft::l_register_craft(lua_State *L)
return 0; /* number of results */
}
// clear_craft({[output=item], [recipe={{item00,item10},{item01,item11}}])
int ModApiCraft::l_clear_craft(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
luaL_checktype(L, 1, LUA_TTABLE);
int table = 1;
// Get the writable craft definition manager from the server
IWritableCraftDefManager *craftdef =
getServer(L)->getWritableCraftDefManager();
std::string output = getstringfield_default(L, table, "output", "");
std::string type = getstringfield_default(L, table, "type", "shaped");
CraftOutput c_output(output, 0);
if (output != "") {
if (craftdef->clearCraftRecipesByOutput(c_output, getServer(L)))
return 0;
else
throw LuaError("No craft recipe known for output"
" (output=\"" + output + "\")");
}
std::vector<std::string> recipe;
int width = 0;
CraftMethod method = CRAFT_METHOD_NORMAL;
/*
CraftDefinitionShaped
*/
if (type == "shaped") {
lua_getfield(L, table, "recipe");
if (lua_isnil(L, -1))
throw LuaError("Either output or recipe has to be defined");
if (!readCraftRecipeShaped(L, -1, width, recipe))
throw LuaError("Invalid crafting recipe");
}
/*
CraftDefinitionShapeless
*/
else if (type == "shapeless") {
lua_getfield(L, table, "recipe");
if (lua_isnil(L, -1))
throw LuaError("Either output or recipe has to be defined");
if (!readCraftRecipeShapeless(L, -1, recipe))
throw LuaError("Invalid crafting recipe");
}
/*
CraftDefinitionCooking
*/
else if (type == "cooking") {
method = CRAFT_METHOD_COOKING;
std::string rec = getstringfield_default(L, table, "recipe", "");
if (rec == "")
throw LuaError("Crafting definition (cooking)"
" is missing a recipe");
recipe.push_back(rec);
}
/*
CraftDefinitionFuel
*/
else if (type == "fuel") {
method = CRAFT_METHOD_FUEL;
std::string rec = getstringfield_default(L, table, "recipe", "");
if (rec == "")
throw LuaError("Crafting definition (fuel)"
" is missing a recipe");
recipe.push_back(rec);
} else {
throw LuaError("Unknown crafting definition type: \"" + type + "\"");
}
if (!craftdef->clearCraftRecipesByInput(method, width, recipe, getServer(L)))
throw LuaError("No crafting specified for input");
lua_pop(L, 1);
return 0;
}
// get_craft_result(input)
int ModApiCraft::l_get_craft_result(lua_State *L)
{
@ -431,4 +504,5 @@ void ModApiCraft::Initialize(lua_State *L, int top)
API_FCT(get_craft_recipe);
API_FCT(get_craft_result);
API_FCT(register_craft);
API_FCT(clear_craft);
}

View File

@ -33,6 +33,7 @@ private:
static int l_get_craft_recipe(lua_State *L);
static int l_get_all_craft_recipes(lua_State *L);
static int l_get_craft_result(lua_State *L);
static int l_clear_craft(lua_State *L);
static bool readCraftReplacements(lua_State *L, int index,
CraftReplacements &replacements);

View File

@ -758,7 +758,7 @@ int ModApiEnvMod::l_get_perlin_map(lua_State *L)
return 0;
v3s16 size = read_v3s16(L, 2);
int seed = (int)(env->getServerMap().getSeed());
s32 seed = (s32)(env->getServerMap().getSeed());
LuaPerlinNoiseMap *n = new LuaPerlinNoiseMap(&np, seed, size);
*(void **)(lua_newuserdata(L, sizeof(void *))) = n;
luaL_getmetatable(L, "PerlinNoiseMap");

View File

@ -31,7 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "filesys.h"
#include "convert_json.h"
#include "serverlist.h"
#include "emerge.h"
#include "mapgen.h"
#include "sound.h"
#include "settings.h"
#include "log.h"
@ -707,7 +707,7 @@ int ModApiMainMenu::l_set_topleft_text(lua_State *L)
int ModApiMainMenu::l_get_mapgen_names(lua_State *L)
{
std::vector<const char *> names;
EmergeManager::getMapgenNames(&names, lua_toboolean(L, 1));
Mapgen::getMapgenNames(&names, lua_toboolean(L, 1));
lua_newtable(L);
for (size_t i = 0; i != names.size(); i++) {

View File

@ -378,6 +378,7 @@ Biome *read_biome_def(lua_State *L, int index, INodeDefManager *ndef)
b->depth_top = getintfield_default(L, index, "depth_top", 0);
b->depth_filler = getintfield_default(L, index, "depth_filler", -31000);
b->depth_water_top = getintfield_default(L, index, "depth_water_top", 0);
b->depth_riverbed = getintfield_default(L, index, "depth_riverbed", 0);
b->y_min = getintfield_default(L, index, "y_min", -31000);
b->y_max = getintfield_default(L, index, "y_max", 31000);
b->heat_point = getfloatfield_default(L, index, "heat_point", 0.f);
@ -391,6 +392,7 @@ Biome *read_biome_def(lua_State *L, int index, INodeDefManager *ndef)
nn.push_back(getstringfield_default(L, index, "node_water_top", ""));
nn.push_back(getstringfield_default(L, index, "node_water", ""));
nn.push_back(getstringfield_default(L, index, "node_river_water", ""));
nn.push_back(getstringfield_default(L, index, "node_riverbed", ""));
nn.push_back(getstringfield_default(L, index, "node_dust", ""));
ndef->pendNodeResolve(b);
@ -598,24 +600,37 @@ int ModApiMapgen::l_get_mapgen_params(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
MapgenParams *params = &getServer(L)->getEmergeManager()->params;
log_deprecated(L, "get_mapgen_params is deprecated; "
"use get_mapgen_setting instead");
std::string value;
MapSettingsManager *settingsmgr =
getServer(L)->getEmergeManager()->map_settings_mgr;
lua_newtable(L);
lua_pushstring(L, params->mg_name.c_str());
settingsmgr->getMapSetting("mg_name", &value);
lua_pushstring(L, value.c_str());
lua_setfield(L, -2, "mgname");
lua_pushinteger(L, params->seed);
settingsmgr->getMapSetting("seed", &value);
std::istringstream ss(value);
u64 seed;
ss >> seed;
lua_pushinteger(L, seed);
lua_setfield(L, -2, "seed");
lua_pushinteger(L, params->water_level);
settingsmgr->getMapSetting("water_level", &value);
lua_pushinteger(L, stoi(value, -32768, 32767));
lua_setfield(L, -2, "water_level");
lua_pushinteger(L, params->chunksize);
settingsmgr->getMapSetting("chunksize", &value);
lua_pushinteger(L, stoi(value, -32768, 32767));
lua_setfield(L, -2, "chunksize");
std::string flagstr = writeFlagString(params->flags, flagdesc_mapgen, U32_MAX);
lua_pushstring(L, flagstr.c_str());
settingsmgr->getMapSetting("mg_flags", &value);
lua_pushstring(L, value.c_str());
lua_setfield(L, -2, "flags");
return 1;
@ -628,44 +643,120 @@ int ModApiMapgen::l_set_mapgen_params(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
log_deprecated(L, "set_mapgen_params is deprecated; "
"use set_mapgen_setting instead");
if (!lua_istable(L, 1))
return 0;
EmergeManager *emerge = getServer(L)->getEmergeManager();
if (emerge->isRunning())
throw LuaError("Cannot set parameters while mapgen is running");
MapgenParams *params = &emerge->params;
u32 flags = 0, flagmask = 0;
MapSettingsManager *settingsmgr =
getServer(L)->getEmergeManager()->map_settings_mgr;
lua_getfield(L, 1, "mgname");
if (lua_isstring(L, -1)) {
params->mg_name = lua_tostring(L, -1);
delete params->sparams;
params->sparams = NULL;
}
if (lua_isstring(L, -1))
settingsmgr->setMapSetting("mg_name", lua_tostring(L, -1), true);
lua_getfield(L, 1, "seed");
if (lua_isnumber(L, -1))
params->seed = lua_tointeger(L, -1);
settingsmgr->setMapSetting("seed", lua_tostring(L, -1), true);
lua_getfield(L, 1, "water_level");
if (lua_isnumber(L, -1))
params->water_level = lua_tointeger(L, -1);
settingsmgr->setMapSetting("water_level", lua_tostring(L, -1), true);
lua_getfield(L, 1, "chunksize");
if (lua_isnumber(L, -1))
params->chunksize = lua_tointeger(L, -1);
settingsmgr->setMapSetting("chunksize", lua_tostring(L, -1), true);
warn_if_field_exists(L, 1, "flagmask",
"Deprecated: flags field now includes unset flags.");
lua_getfield(L, 1, "flagmask");
if (lua_isstring(L, -1))
params->flags &= ~readFlagString(lua_tostring(L, -1), flagdesc_mapgen, NULL);
if (getflagsfield(L, 1, "flags", flagdesc_mapgen, &flags, &flagmask)) {
params->flags &= ~flagmask;
params->flags |= flags;
lua_getfield(L, 1, "flags");
if (lua_isstring(L, -1))
settingsmgr->setMapSetting("mg_flags", lua_tostring(L, -1), true);
return 0;
}
// get_mapgen_setting(name)
int ModApiMapgen::l_get_mapgen_setting(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
std::string value;
MapSettingsManager *settingsmgr =
getServer(L)->getEmergeManager()->map_settings_mgr;
const char *name = luaL_checkstring(L, 1);
if (!settingsmgr->getMapSetting(name, &value))
return 0;
lua_pushstring(L, value.c_str());
return 1;
}
// get_mapgen_setting_noiseparams(name)
int ModApiMapgen::l_get_mapgen_setting_noiseparams(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
NoiseParams np;
MapSettingsManager *settingsmgr =
getServer(L)->getEmergeManager()->map_settings_mgr;
const char *name = luaL_checkstring(L, 1);
if (!settingsmgr->getMapSettingNoiseParams(name, &np))
return 0;
push_noiseparams(L, &np);
return 1;
}
// set_mapgen_setting(name, value, override_meta)
// set mapgen config values
int ModApiMapgen::l_set_mapgen_setting(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
MapSettingsManager *settingsmgr =
getServer(L)->getEmergeManager()->map_settings_mgr;
const char *name = luaL_checkstring(L, 1);
const char *value = luaL_checkstring(L, 2);
bool override_meta = lua_isboolean(L, 3) ? lua_toboolean(L, 3) : false;
if (!settingsmgr->setMapSetting(name, value, override_meta)) {
errorstream << "set_mapgen_setting: cannot set '"
<< name << "' after initialization" << std::endl;
}
return 0;
}
// set_mapgen_setting_noiseparams(name, noiseparams, set_default)
// set mapgen config values for noise parameters
int ModApiMapgen::l_set_mapgen_setting_noiseparams(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
MapSettingsManager *settingsmgr =
getServer(L)->getEmergeManager()->map_settings_mgr;
const char *name = luaL_checkstring(L, 1);
NoiseParams np;
if (!read_noiseparams(L, 2, &np)) {
errorstream << "set_mapgen_setting_noiseparams: cannot set '" << name
<< "'; invalid noiseparams table" << std::endl;
return 0;
}
bool override_meta = lua_isboolean(L, 3) ? lua_toboolean(L, 3) : false;
if (!settingsmgr->setMapSettingNoiseParams(name, &np, override_meta)) {
errorstream << "set_mapgen_setting_noiseparams: cannot set '"
<< name << "' after initialization" << std::endl;
}
return 0;
@ -681,8 +772,11 @@ int ModApiMapgen::l_set_noiseparams(lua_State *L)
const char *name = luaL_checkstring(L, 1);
NoiseParams np;
if (!read_noiseparams(L, 2, &np))
if (!read_noiseparams(L, 2, &np)) {
errorstream << "set_noiseparams: cannot set '" << name
<< "'; invalid noiseparams table" << std::endl;
return 0;
}
bool set_default = lua_isboolean(L, 3) ? lua_toboolean(L, 3) : true;
@ -1141,7 +1235,7 @@ int ModApiMapgen::l_generate_ores(lua_State *L)
EmergeManager *emerge = getServer(L)->getEmergeManager();
Mapgen mg;
mg.seed = emerge->params.seed;
mg.seed = emerge->mgparams->seed;
mg.vm = LuaVoxelManip::checkobject(L, 1)->vm;
mg.ndef = getServer(L)->getNodeDefManager();
@ -1167,7 +1261,7 @@ int ModApiMapgen::l_generate_decorations(lua_State *L)
EmergeManager *emerge = getServer(L)->getEmergeManager();
Mapgen mg;
mg.seed = emerge->params.seed;
mg.seed = emerge->mgparams->seed;
mg.vm = LuaVoxelManip::checkobject(L, 1)->vm;
mg.ndef = getServer(L)->getNodeDefManager();
@ -1391,6 +1485,10 @@ void ModApiMapgen::Initialize(lua_State *L, int top)
API_FCT(get_mapgen_params);
API_FCT(set_mapgen_params);
API_FCT(get_mapgen_setting);
API_FCT(set_mapgen_setting);
API_FCT(get_mapgen_setting_noiseparams);
API_FCT(set_mapgen_setting_noiseparams);
API_FCT(set_noiseparams);
API_FCT(get_noiseparams);
API_FCT(set_gen_notify);

View File

@ -40,6 +40,18 @@ private:
// set mapgen parameters
static int l_set_mapgen_params(lua_State *L);
// get_mapgen_setting(name)
static int l_get_mapgen_setting(lua_State *L);
// set_mapgen_setting(name, value, override_meta)
static int l_set_mapgen_setting(lua_State *L);
// get_mapgen_setting_noiseparams(name)
static int l_get_mapgen_setting_noiseparams(lua_State *L);
// set_mapgen_setting_noiseparams(name, value, override_meta)
static int l_set_mapgen_setting_noiseparams(lua_State *L);
// set_noiseparam_defaults(name, noiseparams, set_default)
static int l_set_noiseparams(lua_State *L);

View File

@ -45,7 +45,7 @@ int NodeTimerRef::l_set(lua_State *L)
if(env == NULL) return 0;
f32 t = luaL_checknumber(L,2);
f32 e = luaL_checknumber(L,3);
env->getMap().setNodeTimer(o->m_p,NodeTimer(t,e));
env->getMap().setNodeTimer(NodeTimer(t, e, o->m_p));
return 0;
}
@ -56,7 +56,7 @@ int NodeTimerRef::l_start(lua_State *L)
ServerEnvironment *env = o->m_env;
if(env == NULL) return 0;
f32 t = luaL_checknumber(L,2);
env->getMap().setNodeTimer(o->m_p,NodeTimer(t,0));
env->getMap().setNodeTimer(NodeTimer(t, 0, o->m_p));
return 0;
}

View File

@ -146,7 +146,7 @@ const luaL_reg LuaPerlinNoise::methods[] = {
LuaPerlinNoiseMap
*/
LuaPerlinNoiseMap::LuaPerlinNoiseMap(NoiseParams *params, int seed, v3s16 size)
LuaPerlinNoiseMap::LuaPerlinNoiseMap(NoiseParams *params, s32 seed, v3s16 size)
{
m_is3d = size.Z > 1;
np = *params;

View File

@ -79,7 +79,7 @@ class LuaPerlinNoiseMap : public ModApiBase {
static int l_getMapSlice(lua_State *L);
public:
LuaPerlinNoiseMap(NoiseParams *np, int seed, v3s16 size);
LuaPerlinNoiseMap(NoiseParams *np, s32 seed, v3s16 size);
~LuaPerlinNoiseMap();
@ -111,7 +111,7 @@ private:
static int l_next(lua_State *L);
public:
LuaPseudoRandom(int seed) :
LuaPseudoRandom(s32 seed) :
m_pseudo(seed) {}
// LuaPseudoRandom(seed)

View File

@ -1016,15 +1016,49 @@ int ObjectRef::l_get_look_dir(lua_State *L)
Player *player = getplayer(ref);
if (player == NULL) return 0;
// Do it
float pitch = player->getRadPitch();
float yaw = player->getRadYaw();
float pitch = player->getRadPitchDep();
float yaw = player->getRadYawDep();
v3f v(cos(pitch)*cos(yaw), sin(pitch), cos(pitch)*sin(yaw));
push_v3f(L, v);
return 1;
}
// DEPRECATED
// get_look_pitch(self)
int ObjectRef::l_get_look_pitch(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
log_deprecated(L,
"Deprecated call to get_look_pitch, use get_look_vertical instead");
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL) return 0;
// Do it
lua_pushnumber(L, player->getRadPitchDep());
return 1;
}
// DEPRECATED
// get_look_yaw(self)
int ObjectRef::l_get_look_yaw(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
log_deprecated(L,
"Deprecated call to get_look_yaw, use get_look_horizontal instead");
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL) return 0;
// Do it
lua_pushnumber(L, player->getRadYawDep());
return 1;
}
// get_look_pitch2(self)
int ObjectRef::l_get_look_vertical(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
@ -1035,8 +1069,8 @@ int ObjectRef::l_get_look_pitch(lua_State *L)
return 1;
}
// get_look_yaw(self)
int ObjectRef::l_get_look_yaw(lua_State *L)
// get_look_yaw2(self)
int ObjectRef::l_get_look_horizontal(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
@ -1047,8 +1081,8 @@ int ObjectRef::l_get_look_yaw(lua_State *L)
return 1;
}
// set_look_pitch(self, radians)
int ObjectRef::l_set_look_pitch(lua_State *L)
// set_look_vertical(self, radians)
int ObjectRef::l_set_look_vertical(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
@ -1060,10 +1094,46 @@ int ObjectRef::l_set_look_pitch(lua_State *L)
return 1;
}
// set_look_horizontal(self, radians)
int ObjectRef::l_set_look_horizontal(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
PlayerSAO* co = getplayersao(ref);
if (co == NULL) return 0;
float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
// Do it
co->setYaw(yaw);
return 1;
}
// DEPRECATED
// set_look_pitch(self, radians)
int ObjectRef::l_set_look_pitch(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
log_deprecated(L,
"Deprecated call to set_look_pitch, use set_look_vertical instead.");
ObjectRef *ref = checkobject(L, 1);
PlayerSAO* co = getplayersao(ref);
if (co == NULL) return 0;
float pitch = luaL_checknumber(L, 2) * core::RADTODEG;
// Do it
co->setPitch(pitch);
return 1;
}
// DEPRECATED
// set_look_yaw(self, radians)
int ObjectRef::l_set_look_yaw(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
log_deprecated(L,
"Deprecated call to set_look_yaw, use set_look_horizontal instead.");
ObjectRef *ref = checkobject(L, 1);
PlayerSAO* co = getplayersao(ref);
if (co == NULL) return 0;
@ -1754,6 +1824,10 @@ const luaL_reg ObjectRef::methods[] = {
luamethod(ObjectRef, get_look_dir),
luamethod(ObjectRef, get_look_pitch),
luamethod(ObjectRef, get_look_yaw),
luamethod(ObjectRef, get_look_vertical),
luamethod(ObjectRef, get_look_horizontal),
luamethod(ObjectRef, set_look_horizontal),
luamethod(ObjectRef, set_look_vertical),
luamethod(ObjectRef, set_look_yaw),
luamethod(ObjectRef, set_look_pitch),
luamethod(ObjectRef, get_breath),

View File

@ -189,15 +189,31 @@ private:
// get_look_dir(self)
static int l_get_look_dir(lua_State *L);
// DEPRECATED
// get_look_pitch(self)
static int l_get_look_pitch(lua_State *L);
// DEPRECATED
// get_look_yaw(self)
static int l_get_look_yaw(lua_State *L);
// get_look_pitch2(self)
static int l_get_look_vertical(lua_State *L);
// get_look_yaw2(self)
static int l_get_look_horizontal(lua_State *L);
// set_look_vertical(self, radians)
static int l_set_look_vertical(lua_State *L);
// set_look_horizontal(self, radians)
static int l_set_look_horizontal(lua_State *L);
// DEPRECATED
// set_look_pitch(self, radians)
static int l_set_look_pitch(lua_State *L);
// DEPRECATED
// set_look_yaw(self, radians)
static int l_set_look_yaw(lua_State *L);

View File

@ -190,7 +190,7 @@ int LuaVoxelManip::l_calc_lighting(lua_State *L)
Mapgen mg;
mg.vm = vm;
mg.ndef = ndef;
mg.water_level = emerge->params.water_level;
mg.water_level = emerge->mgparams->water_level;
mg.calcLighting(pmin, pmax, fpmin, fpmax, propagate_shadow);

View File

@ -266,9 +266,6 @@ Server::Server(
//lock environment
MutexAutoLock envlock(m_env_mutex);
// Load mapgen params from Settings
m_emerge->loadMapgenParams();
// Create the Map (loads map_meta.txt, overriding configured mapgen params)
ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
@ -331,8 +328,11 @@ Server::Server(
m_clients.setEnv(m_env);
if (!servermap->settings_mgr.makeMapgenParams())
FATAL_ERROR("Couldn't create any mapgen type");
// Initialize mapgens
m_emerge->initMapgens();
m_emerge->initMapgens(servermap->getMapgenParams());
m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
if (m_enable_rollback_recording) {
@ -402,11 +402,8 @@ Server::~Server()
m_emerge->stopThreads();
// Delete things in the reverse order of creation
delete m_env;
// N.B. the EmergeManager should be deleted after the Environment since Map
// depends on EmergeManager to write its current params to the map meta
delete m_emerge;
delete m_env;
delete m_rollback;
delete m_banmanager;
delete m_event;
@ -655,7 +652,7 @@ void Server::AsyncRunStep(bool initial_step)
m_env->getGameTime(),
m_lag,
m_gamespec.id,
m_emerge->params.mg_name,
Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
m_mods);
counter = 0.01;
}
@ -2683,7 +2680,7 @@ void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
PlayerSAO *playersao = player->getPlayerSAO();
assert(playersao);
m_script->on_leaveplayer(playersao);
m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
playersao->disconnected();
}

View File

@ -985,39 +985,38 @@ void Settings::clearDefaultsNoLock()
}
void Settings::registerChangedCallback(std::string name,
setting_changed_callback cbf, void *userdata)
void Settings::registerChangedCallback(const std::string &name,
SettingsChangedCallback cbf, void *userdata)
{
MutexAutoLock lock(m_callbackMutex);
MutexAutoLock lock(m_callback_mutex);
m_callbacks[name].push_back(std::make_pair(cbf, userdata));
}
void Settings::deregisterChangedCallback(std::string name, setting_changed_callback cbf, void *userdata)
void Settings::deregisterChangedCallback(const std::string &name,
SettingsChangedCallback cbf, void *userdata)
{
MutexAutoLock lock(m_callbackMutex);
std::map<std::string, std::vector<std::pair<setting_changed_callback, void*> > >::iterator iterToVector = m_callbacks.find(name);
if (iterToVector != m_callbacks.end())
{
std::vector<std::pair<setting_changed_callback, void*> > &vector = iterToVector->second;
MutexAutoLock lock(m_callback_mutex);
SettingsCallbackMap::iterator it_cbks = m_callbacks.find(name);
std::vector<std::pair<setting_changed_callback, void*> >::iterator position =
std::find(vector.begin(), vector.end(), std::make_pair(cbf, userdata));
if (it_cbks != m_callbacks.end()) {
SettingsCallbackList &cbks = it_cbks->second;
if (position != vector.end())
vector.erase(position);
SettingsCallbackList::iterator position =
std::find(cbks.begin(), cbks.end(), std::make_pair(cbf, userdata));
if (position != cbks.end())
cbks.erase(position);
}
}
void Settings::doCallbacks(const std::string name)
void Settings::doCallbacks(const std::string &name) const
{
MutexAutoLock lock(m_callbackMutex);
std::map<std::string, std::vector<std::pair<setting_changed_callback, void*> > >::iterator iterToVector = m_callbacks.find(name);
if (iterToVector != m_callbacks.end())
{
std::vector<std::pair<setting_changed_callback, void*> >::iterator iter;
for (iter = iterToVector->second.begin(); iter != iterToVector->second.end(); ++iter)
{
(iter->first)(name, iter->second);
}
MutexAutoLock lock(m_callback_mutex);
SettingsCallbackMap::const_iterator it_cbks = m_callbacks.find(name);
if (it_cbks != m_callbacks.end()) {
SettingsCallbackList::const_iterator it;
for (it = it_cbks->second.begin(); it != it_cbks->second.end(); ++it)
(it->first)(name, it->second);
}
}

View File

@ -35,8 +35,17 @@ struct NoiseParams;
extern Settings *g_settings;
extern std::string g_settings_path;
/** function type to register a changed callback */
typedef void (*setting_changed_callback)(const std::string &name, void *data);
// Type for a settings changed callback function
typedef void (*SettingsChangedCallback)(const std::string &name, void *data);
typedef std::vector<
std::pair<
SettingsChangedCallback,
void *
>
> SettingsCallbackList;
typedef std::map<std::string, SettingsCallbackList> SettingsCallbackMap;
enum ValueType {
VALUETYPE_STRING,
@ -209,24 +218,28 @@ public:
void clearDefaults();
void updateValue(const Settings &other, const std::string &name);
void update(const Settings &other);
void registerChangedCallback(std::string name, setting_changed_callback cbf, void *userdata = NULL);
void deregisterChangedCallback(std::string name, setting_changed_callback cbf, void *userdata = NULL);
void registerChangedCallback(const std::string &name,
SettingsChangedCallback cbf, void *userdata = NULL);
void deregisterChangedCallback(const std::string &name,
SettingsChangedCallback cbf, void *userdata = NULL);
private:
void updateNoLock(const Settings &other);
void clearNoLock();
void clearDefaultsNoLock();
void doCallbacks(std::string name);
void doCallbacks(const std::string &name) const;
std::map<std::string, SettingsEntry> m_settings;
std::map<std::string, SettingsEntry> m_defaults;
std::map<std::string, std::vector<std::pair<setting_changed_callback,void*> > > m_callbacks;
SettingsCallbackMap m_callbacks;
mutable Mutex m_callbackMutex;
mutable Mutex m_mutex; // All methods that access m_settings/m_defaults directly should lock this.
mutable Mutex m_callback_mutex;
// All methods that access m_settings/m_defaults directly should lock this.
mutable Mutex m_mutex;
};

View File

@ -4,37 +4,37 @@
#include "ICameraSceneNode.h"
#include "S3DVertex.h"
#include "client/tile.h"
#include "noise.h" // easeCurve
#include "noise.h" // easeCurve
#include "profiler.h"
#include "util/numeric.h"
#include <cmath>
#include "settings.h"
#include "camera.h" // CameraModes
#include "camera.h" // CameraModes
//! constructor
Sky::Sky(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id,
ITextureSource *tsrc):
scene::ISceneNode(parent, mgr, id),
m_visible(true),
m_fallback_bg_color(255,255,255,255),
m_fallback_bg_color(255, 255, 255, 255),
m_first_update(true),
m_brightness(0.5),
m_cloud_brightness(0.5),
m_bgcolor_bright_f(1,1,1,1),
m_skycolor_bright_f(1,1,1,1),
m_cloudcolor_bright_f(1,1,1,1)
m_bgcolor_bright_f(1, 1, 1, 1),
m_skycolor_bright_f(1, 1, 1, 1),
m_cloudcolor_bright_f(1, 1, 1, 1)
{
setAutomaticCulling(scene::EAC_OFF);
m_box.MaxEdge.set(0,0,0);
m_box.MinEdge.set(0,0,0);
m_box.MaxEdge.set(0, 0, 0);
m_box.MinEdge.set(0, 0, 0);
// create material
// Create material
video::SMaterial mat;
mat.Lighting = false;
mat.ZBuffer = video::ECFN_NEVER;
mat.ZWriteEnable = false;
mat.AntiAliasing=0;
mat.AntiAliasing = 0;
mat.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
mat.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
mat.BackfaceCulling = false;
@ -59,14 +59,15 @@ Sky::Sky(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id,
m_moon_tonemap = tsrc->isKnownSourceImage("moon_tonemap.png") ?
tsrc->getTexture("moon_tonemap.png") : NULL;
if (m_sun_texture){
if (m_sun_texture) {
m_materials[3] = mat;
m_materials[3].setTexture(0, m_sun_texture);
m_materials[3].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
if (m_sun_tonemap)
m_materials[3].Lighting = true;
}
if (m_moon_texture){
if (m_moon_texture) {
m_materials[4] = mat;
m_materials[4].setTexture(0, m_moon_texture);
m_materials[4].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
@ -74,11 +75,11 @@ Sky::Sky(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id,
m_materials[4].Lighting = true;
}
for(u32 i=0; i<SKY_STAR_COUNT; i++){
for (u32 i = 0; i < SKY_STAR_COUNT; i++) {
m_stars[i] = v3f(
myrand_range(-10000,10000),
myrand_range(-10000,10000),
myrand_range(-10000,10000)
myrand_range(-10000, 10000),
myrand_range(-10000, 10000),
myrand_range(-10000, 10000)
);
m_stars[i].normalize();
}
@ -86,6 +87,7 @@ Sky::Sky(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id,
m_directional_colored_fog = g_settings->getBool("directional_colored_fog");
}
void Sky::OnRegisterSceneNode()
{
if (IsVisible)
@ -94,10 +96,10 @@ void Sky::OnRegisterSceneNode()
scene::ISceneNode::OnRegisterSceneNode();
}
//! renders the node.
void Sky::render()
{
if(!m_visible)
if (!m_visible)
return;
video::IVideoDriver* driver = SceneManager->getVideoDriver();
@ -108,7 +110,7 @@ void Sky::render()
ScopeProfiler sp(g_profiler, "Sky::render()", SPT_AVG);
// draw perspective skybox
// Draw perspective skybox
core::matrix4 translate(AbsoluteTransformation);
translate.setTranslation(camera->getAbsolutePosition());
@ -120,16 +122,15 @@ void Sky::render()
driver->setTransform(video::ETS_WORLD, translate * scale);
if(m_sunlight_seen)
{
if (m_sunlight_seen) {
float sunsize = 0.07;
video::SColorf suncolor_f(1, 1, 0, 1);
suncolor_f.r = 1;
suncolor_f.g = MYMAX(0.3, MYMIN(1.0, 0.7+m_time_brightness*(0.5)));
suncolor_f.b = MYMAX(0.0, m_brightness*0.95);
suncolor_f.g = MYMAX(0.3, MYMIN(1.0, 0.7 + m_time_brightness * 0.5));
suncolor_f.b = MYMAX(0.0, m_brightness * 0.95);
video::SColorf suncolor2_f(1, 1, 1, 1);
suncolor_f.r = 1;
suncolor_f.g = MYMAX(0.3, MYMIN(1.0, 0.85+m_time_brightness*(0.5)));
suncolor_f.g = MYMAX(0.3, MYMIN(1.0, 0.85 + m_time_brightness * 0.5));
suncolor_f.b = MYMAX(0.0, m_brightness);
float moonsize = 0.04;
@ -139,12 +140,12 @@ void Sky::render()
float nightlength = 0.415;
float wn = nightlength / 2;
float wicked_time_of_day = 0;
if(m_time_of_day > wn && m_time_of_day < 1.0 - wn)
wicked_time_of_day = (m_time_of_day - wn)/(1.0-wn*2)*0.5 + 0.25;
else if(m_time_of_day < 0.5)
if (m_time_of_day > wn && m_time_of_day < 1.0 - wn)
wicked_time_of_day = (m_time_of_day - wn) / (1.0 - wn * 2) * 0.5 + 0.25;
else if (m_time_of_day < 0.5)
wicked_time_of_day = m_time_of_day / wn * 0.25;
else
wicked_time_of_day = 1.0 - ((1.0-m_time_of_day) / wn * 0.25);
wicked_time_of_day = 1.0 - ((1.0 - m_time_of_day) / wn * 0.25);
/*std::cerr<<"time_of_day="<<m_time_of_day<<" -> "
<<"wicked_time_of_day="<<wicked_time_of_day<<std::endl;*/
@ -154,77 +155,78 @@ void Sky::render()
video::SColor mooncolor2 = mooncolor2_f.toSColor();
// Calculate offset normalized to the X dimension of a 512x1 px tonemap
float offset=(1.0-fabs(sin((m_time_of_day - 0.5)*irr::core::PI)))*511;
float offset = (1.0 - fabs(sin((m_time_of_day - 0.5) * irr::core::PI))) * 511;
if (m_sun_tonemap){
if (m_sun_tonemap) {
u8 * texels = (u8 *)m_sun_tonemap->lock();
video::SColor* texel = (video::SColor *)(texels + (u32)offset * 4);
video::SColor texel_color (255,texel->getRed(),texel->getGreen(), texel->getBlue());
video::SColor texel_color (255, texel->getRed(),
texel->getGreen(), texel->getBlue());
m_sun_tonemap->unlock();
m_materials[3].EmissiveColor = texel_color;
}
if (m_moon_tonemap){
if (m_moon_tonemap) {
u8 * texels = (u8 *)m_moon_tonemap->lock();
video::SColor* texel = (video::SColor *)(texels + (u32)offset * 4);
video::SColor texel_color (255,texel->getRed(),texel->getGreen(), texel->getBlue());
video::SColor texel_color (255, texel->getRed(),
texel->getGreen(), texel->getBlue());
m_moon_tonemap->unlock();
m_materials[4].EmissiveColor = texel_color;
}
const f32 t = 1.0f;
const f32 o = 0.0f;
static const u16 indices[4] = {0,1,2,3};
static const u16 indices[4] = {0, 1, 2, 3};
video::S3DVertex vertices[4];
driver->setMaterial(m_materials[1]);
//video::SColor cloudyfogcolor(255,255,255,255);
video::SColor cloudyfogcolor = m_bgcolor;
//video::SColor cloudyfogcolor = m_bgcolor.getInterpolated(m_skycolor, 0.5);
// Draw far cloudy fog thing
for(u32 j=0; j<4; j++)
{
// Draw far cloudy fog thing blended with skycolor
for (u32 j = 0; j < 4; j++) {
video::SColor c = cloudyfogcolor.getInterpolated(m_skycolor, 0.45);
vertices[0] = video::S3DVertex(-1, 0.08,-1, 0,0,1, c, t, t);
vertices[1] = video::S3DVertex( 1, 0.08,-1, 0,0,1, c, o, t);
vertices[2] = video::S3DVertex( 1, 0.12,-1, 0,0,1, c, o, o);
vertices[3] = video::S3DVertex(-1, 0.12,-1, 0,0,1, c, t, o);
for(u32 i=0; i<4; i++){
if(j==0)
vertices[0] = video::S3DVertex(-1, 0.08, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( 1, 0.08, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( 1, 0.12, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-1, 0.12, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
if (j == 0)
// Don't switch
{}
else if(j==1)
else if (j == 1)
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
else if(j==2)
else if (j == 2)
// Switch from -Z (south) to -X (west)
vertices[i].Pos.rotateXZBy(-90);
else
// Switch from -Z (south) to -Z (north)
// Switch from -Z (south) to +Z (north)
vertices[i].Pos.rotateXZBy(-180);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
}
for(u32 j=0; j<4; j++)
{
// Draw far cloudy fog thing
for (u32 j = 0; j < 4; j++) {
video::SColor c = cloudyfogcolor;
vertices[0] = video::S3DVertex(-1,-1.0,-1, 0,0,1, c, t, t);
vertices[1] = video::S3DVertex( 1,-1.0,-1, 0,0,1, c, o, t);
vertices[2] = video::S3DVertex( 1, 0.08,-1, 0,0,1, c, o, o);
vertices[3] = video::S3DVertex(-1, 0.08,-1, 0,0,1, c, t, o);
for(u32 i=0; i<4; i++){
if(j==0)
vertices[0] = video::S3DVertex(-1, -1.0, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( 1, -1.0, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( 1, 0.08, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-1, 0.08, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
if (j == 0)
// Don't switch
{}
else if(j==1)
else if (j == 1)
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
else if(j==2)
else if (j == 2)
// Switch from -Z (south) to -X (west)
vertices[i].Pos.rotateXZBy(-90);
else
// Switch from -Z (south) to -Z (north)
// Switch from -Z (south) to +Z (north)
vertices[i].Pos.rotateXZBy(-180);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
@ -232,20 +234,21 @@ void Sky::render()
driver->setMaterial(m_materials[2]);
// Draw sunrise/sunset horizon glow texture (textures/base/pack/sunrisebg.png)
{
float mid1 = 0.25;
float mid = (wicked_time_of_day < 0.5 ? mid1 : (1.0 - mid1));
float mid = wicked_time_of_day < 0.5 ? mid1 : (1.0 - mid1);
float a_ = 1.0 - fabs(wicked_time_of_day - mid) * 35.0;
float a = easeCurve(MYMAX(0, MYMIN(1, a_)));
//std::cerr<<"a_="<<a_<<" a="<<a<<std::endl;
video::SColor c(255,255,255,255);
float y = -(1.0 - a) * 0.2;
vertices[0] = video::S3DVertex(-1,-0.05+y,-1, 0,0,1, c, t, t);
vertices[1] = video::S3DVertex( 1,-0.05+y,-1, 0,0,1, c, o, t);
vertices[2] = video::S3DVertex( 1, 0.2+y,-1, 0,0,1, c, o, o);
vertices[3] = video::S3DVertex(-1, 0.2+y,-1, 0,0,1, c, t, o);
for(u32 i=0; i<4; i++){
if(wicked_time_of_day < 0.5)
video::SColor c(255, 255, 255, 255);
float y = -(1.0 - a) * 0.22;
vertices[0] = video::S3DVertex(-1, -0.05 + y, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( 1, -0.05 + y, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( 1, 0.2 + y, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-1, 0.2 + y, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
if (wicked_time_of_day < 0.5)
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
else
@ -256,17 +259,17 @@ void Sky::render()
}
// Draw sun
if(wicked_time_of_day > 0.15 && wicked_time_of_day < 0.85){
if (!m_sun_texture){
if (wicked_time_of_day > 0.15 && wicked_time_of_day < 0.85) {
if (!m_sun_texture) {
driver->setMaterial(m_materials[1]);
float d = sunsize * 1.7;
video::SColor c = suncolor;
c.setAlpha(0.05*255);
vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t);
vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t);
vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o);
vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o);
for(u32 i=0; i<4; i++){
c.setAlpha(0.05 * 255);
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
@ -275,12 +278,12 @@ void Sky::render()
d = sunsize * 1.2;
c = suncolor;
c.setAlpha(0.15*255);
vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t);
vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t);
vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o);
vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o);
for(u32 i=0; i<4; i++){
c.setAlpha(0.15 * 255);
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
@ -288,11 +291,11 @@ void Sky::render()
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
d = sunsize;
vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, suncolor, t, t);
vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, suncolor, o, t);
vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, suncolor, o, o);
vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, suncolor, t, o);
for(u32 i=0; i<4; i++){
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, suncolor, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, suncolor, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, suncolor, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, suncolor, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
@ -300,11 +303,11 @@ void Sky::render()
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
d = sunsize * 0.7;
vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, suncolor2, t, t);
vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, suncolor2, o, t);
vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, suncolor2, o, o);
vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, suncolor2, t, o);
for(u32 i=0; i<4; i++){
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, suncolor2, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, suncolor2, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, suncolor2, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, suncolor2, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
@ -315,14 +318,14 @@ void Sky::render()
float d = sunsize * 1.7;
video::SColor c;
if (m_sun_tonemap)
c = video::SColor (0,0,0,0);
c = video::SColor (0, 0, 0, 0);
else
c = video::SColor (255,255,255,255);
vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t);
vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t);
vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o);
vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o);
for(u32 i=0; i<4; i++){
c = video::SColor (255, 255, 255, 255);
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
for(u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
@ -332,18 +335,17 @@ void Sky::render()
}
// Draw moon
if(wicked_time_of_day < 0.3 || wicked_time_of_day > 0.7)
{
if (!m_moon_texture){
if (wicked_time_of_day < 0.3 || wicked_time_of_day > 0.7) {
if (!m_moon_texture) {
driver->setMaterial(m_materials[1]);
float d = moonsize * 1.9;
video::SColor c = mooncolor;
c.setAlpha(0.05*255);
vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t);
vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t);
vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o);
vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o);
for(u32 i=0; i<4; i++){
c.setAlpha(0.05 * 255);
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to -X (west)
vertices[i].Pos.rotateXZBy(-90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
@ -352,12 +354,12 @@ void Sky::render()
d = moonsize * 1.3;
c = mooncolor;
c.setAlpha(0.15*255);
vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t);
vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t);
vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o);
vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o);
for(u32 i=0; i<4; i++){
c.setAlpha(0.15 * 255);
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to -X (west)
vertices[i].Pos.rotateXZBy(-90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
@ -365,11 +367,11 @@ void Sky::render()
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
d = moonsize;
vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, mooncolor, t, t);
vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, mooncolor, o, t);
vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, mooncolor, o, o);
vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, mooncolor, t, o);
for(u32 i=0; i<4; i++){
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, mooncolor, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, mooncolor, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, mooncolor, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, mooncolor, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to -X (west)
vertices[i].Pos.rotateXZBy(-90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
@ -377,11 +379,11 @@ void Sky::render()
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
float d2 = moonsize * 0.6;
vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, mooncolor2, t, t);
vertices[1] = video::S3DVertex( d2,-d,-1, 0,0,1, mooncolor2, o, t);
vertices[2] = video::S3DVertex( d2, d2,-1, 0,0,1, mooncolor2, o, o);
vertices[3] = video::S3DVertex(-d, d2,-1, 0,0,1, mooncolor2, t, o);
for(u32 i=0; i<4; i++){
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, mooncolor2, t, t);
vertices[1] = video::S3DVertex( d2,-d, -1, 0, 0, 1, mooncolor2, o, t);
vertices[2] = video::S3DVertex( d2, d2, -1, 0, 0, 1, mooncolor2, o, o);
vertices[3] = video::S3DVertex(-d, d2, -1, 0, 0, 1, mooncolor2, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to -X (west)
vertices[i].Pos.rotateXZBy(-90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
@ -392,14 +394,14 @@ void Sky::render()
float d = moonsize * 1.9;
video::SColor c;
if (m_moon_tonemap)
c = video::SColor (0,0,0,0);
c = video::SColor (0, 0, 0, 0);
else
c = video::SColor (255,255,255,255);
vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t);
vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t);
vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o);
vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o);
for(u32 i=0; i<4; i++){
c = video::SColor (255, 255, 255, 255);
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to -X (west)
vertices[i].Pos.rotateXZBy(-90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
@ -408,64 +410,63 @@ void Sky::render()
}
}
// Stars
// Draw stars
driver->setMaterial(m_materials[1]);
do{
do {
float starbrightness = MYMAX(0, MYMIN(1,
(0.285 - fabs(wicked_time_of_day < 0.5 ?
wicked_time_of_day : (1.0 - wicked_time_of_day))) * 10));
(0.285 - fabs(wicked_time_of_day < 0.5 ?
wicked_time_of_day : (1.0 - wicked_time_of_day))) * 10));
float f = starbrightness;
float d = 0.007;
video::SColor starcolor(255, f*90,f*90,f*90);
if(starcolor.getBlue() < m_skycolor.getBlue())
video::SColor starcolor(255, f * 90, f * 90, f * 90);
if (starcolor.getBlue() < m_skycolor.getBlue())
break;
u16 indices[SKY_STAR_COUNT*4];
video::S3DVertex vertices[SKY_STAR_COUNT*4];
for(u32 i=0; i<SKY_STAR_COUNT; i++){
indices[i*4+0] = i*4+0;
indices[i*4+1] = i*4+1;
indices[i*4+2] = i*4+2;
indices[i*4+3] = i*4+3;
u16 indices[SKY_STAR_COUNT * 4];
video::S3DVertex vertices[SKY_STAR_COUNT * 4];
for (u32 i = 0; i < SKY_STAR_COUNT; i++) {
indices[i * 4 + 0] = i * 4 + 0;
indices[i * 4 + 1] = i * 4 + 1;
indices[i * 4 + 2] = i * 4 + 2;
indices[i * 4 + 3] = i * 4 + 3;
v3f p = m_stars[i];
core::CMatrix4<f32> a;
a.buildRotateFromTo(v3f(0,1,0), v3f(d,1+d/2,0));
a.buildRotateFromTo(v3f(0, 1, 0), v3f(d, 1 + d / 2, 0));
v3f p1 = p;
a.rotateVect(p1);
a.buildRotateFromTo(v3f(0,1,0), v3f(d,1,d));
a.buildRotateFromTo(v3f(0, 1, 0), v3f(d, 1, d));
v3f p2 = p;
a.rotateVect(p2);
a.buildRotateFromTo(v3f(0,1,0), v3f(0,1-d/2,d));
a.buildRotateFromTo(v3f(0, 1, 0), v3f(0, 1 - d / 2, d));
v3f p3 = p;
a.rotateVect(p3);
p.rotateXYBy(wicked_time_of_day * 360 - 90);
p1.rotateXYBy(wicked_time_of_day * 360 - 90);
p2.rotateXYBy(wicked_time_of_day * 360 - 90);
p3.rotateXYBy(wicked_time_of_day * 360 - 90);
vertices[i*4+0].Pos = p;
vertices[i*4+0].Color = starcolor;
vertices[i*4+1].Pos = p1;
vertices[i*4+1].Color = starcolor;
vertices[i*4+2].Pos = p2;
vertices[i*4+2].Color = starcolor;
vertices[i*4+3].Pos = p3;
vertices[i*4+3].Color = starcolor;
vertices[i * 4 + 0].Pos = p;
vertices[i * 4 + 0].Color = starcolor;
vertices[i * 4 + 1].Pos = p1;
vertices[i * 4 + 1].Color = starcolor;
vertices[i * 4 + 2].Pos = p2;
vertices[i * 4 + 2].Color = starcolor;
vertices[i * 4 + 3].Pos = p3;
vertices[i * 4 + 3].Color = starcolor;
}
driver->drawVertexPrimitiveList(vertices, SKY_STAR_COUNT*4,
indices, SKY_STAR_COUNT, video::EVT_STANDARD,
scene::EPT_QUADS, video::EIT_16BIT);
}while(0);
driver->drawVertexPrimitiveList(vertices, SKY_STAR_COUNT * 4,
indices, SKY_STAR_COUNT, video::EVT_STANDARD,
scene::EPT_QUADS, video::EIT_16BIT);
} while(0);
for(u32 j=0; j<2; j++)
{
//video::SColor c = m_skycolor;
// Draw far cloudy fog thing below east and west horizons
for (u32 j = 0; j < 2; j++) {
video::SColor c = cloudyfogcolor;
vertices[0] = video::S3DVertex(-1,-1.0,-1, 0,0,1, c, t, t);
vertices[1] = video::S3DVertex( 1,-1.0,-1, 0,0,1, c, o, t);
vertices[2] = video::S3DVertex( 1,-0.02,-1, 0,0,1, c, o, o);
vertices[3] = video::S3DVertex(-1,-0.02,-1, 0,0,1, c, t, o);
for(u32 i=0; i<4; i++){
//if(wicked_time_of_day < 0.5)
if(j==0)
vertices[0] = video::S3DVertex(-1, -1.0, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( 1, -1.0, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( 1, -0.02, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-1, -0.02, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
//if (wicked_time_of_day < 0.5)
if (j == 0)
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
else
@ -477,20 +478,21 @@ void Sky::render()
}
}
void Sky::update(float time_of_day, float time_brightness,
float direct_brightness, bool sunlight_seen,
CameraMode cam_mode, float yaw, float pitch)
{
// Stabilize initial brightness and color values by flooding updates
if(m_first_update){
if (m_first_update) {
/*dstream<<"First update with time_of_day="<<time_of_day
<<" time_brightness="<<time_brightness
<<" direct_brightness="<<direct_brightness
<<" sunlight_seen="<<sunlight_seen<<std::endl;*/
m_first_update = false;
for(u32 i=0; i<100; i++){
for (u32 i = 0; i < 100; i++) {
update(time_of_day, time_brightness, direct_brightness,
sunlight_seen, cam_mode, yaw, pitch);
sunlight_seen, cam_mode, yaw, pitch);
}
return;
}
@ -501,39 +503,42 @@ void Sky::update(float time_of_day, float time_brightness,
bool is_dawn = (time_brightness >= 0.20 && time_brightness < 0.35);
//video::SColorf bgcolor_bright_normal_f(170./255,200./255,230./255, 1.0);
video::SColorf bgcolor_bright_normal_f(155./255,193./255,240./255, 1.0);
video::SColorf bgcolor_bright_indoor_f(100./255,100./255,100./255, 1.0);
//video::SColorf bgcolor_bright_dawn_f(0.666,200./255*0.7,230./255*0.5,1.0);
//video::SColorf bgcolor_bright_dawn_f(0.666,0.549,0.220,1.0);
//video::SColorf bgcolor_bright_dawn_f(0.666*1.2,0.549*1.0,0.220*1.0, 1.0);
//video::SColorf bgcolor_bright_dawn_f(0.666*1.2,0.549*1.0,0.220*1.2,1.0);
video::SColorf bgcolor_bright_dawn_f
(155./255*1.2,193./255,240./255, 1.0);
/*
Development colours
video::SColorf skycolor_bright_normal_f =
video::SColor(255, 140, 186, 250);
video::SColorf skycolor_bright_dawn_f =
video::SColor(255, 180, 186, 250);
video::SColorf bgcolor_bright_normal_f(170. / 255, 200. / 255, 230. / 255, 1.0);
video::SColorf bgcolor_bright_dawn_f(0.666, 200. / 255 * 0.7, 230. / 255 * 0.5, 1.0);
video::SColorf bgcolor_bright_dawn_f(0.666, 0.549, 0.220, 1.0);
video::SColorf bgcolor_bright_dawn_f(0.666 * 1.2, 0.549 * 1.0, 0.220 * 1.0, 1.0);
video::SColorf bgcolor_bright_dawn_f(0.666 * 1.2, 0.549 * 1.0, 0.220 * 1.2, 1.0);
video::SColorf cloudcolor_bright_dawn_f(1.0, 0.591, 0.4);
video::SColorf cloudcolor_bright_dawn_f(1.0, 0.65, 0.44);
video::SColorf cloudcolor_bright_dawn_f(1.0, 0.7, 0.5);
*/
video::SColorf bgcolor_bright_normal_f = video::SColor(255, 155, 193, 240);
video::SColorf bgcolor_bright_indoor_f = video::SColor(255, 100, 100, 100);
video::SColorf bgcolor_bright_dawn_f = video::SColor(255, 186, 193, 240);
video::SColorf bgcolor_bright_night_f = video::SColor(255, 64, 144, 255);
video::SColorf skycolor_bright_normal_f = video::SColor(255, 140, 186, 250);
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(1.0, 0.591, 0.4);
//video::SColorf cloudcolor_bright_dawn_f(1.0, 0.65, 0.44);
//video::SColorf cloudcolor_bright_dawn_f(1.0, 0.7, 0.5);
video::SColorf cloudcolor_bright_dawn_f(1.0, 0.875, 0.75);
video::SColorf cloudcolor_bright_normal_f = video::SColor(255, 240, 240, 255);
video::SColorf cloudcolor_bright_dawn_f = video::SColor(255, 255, 223, 191);
float cloud_color_change_fraction = 0.95;
if(sunlight_seen){
if(fabs(time_brightness - m_brightness) < 0.2){
if (sunlight_seen) {
if (fabs(time_brightness - m_brightness) < 0.2) {
m_brightness = m_brightness * 0.95 + time_brightness * 0.05;
} else {
m_brightness = m_brightness * 0.80 + time_brightness * 0.20;
cloud_color_change_fraction = 0.0;
}
}
else{
if(direct_brightness < m_brightness)
} else {
if (direct_brightness < m_brightness)
m_brightness = m_brightness * 0.95 + direct_brightness * 0.05;
else
m_brightness = m_brightness * 0.98 + direct_brightness * 0.02;
@ -541,29 +546,37 @@ void Sky::update(float time_of_day, float time_brightness,
m_clouds_visible = true;
float color_change_fraction = 0.98;
if(sunlight_seen){
if(is_dawn){
if (sunlight_seen) {
if (is_dawn) { // Dawn
m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
bgcolor_bright_dawn_f, color_change_fraction);
bgcolor_bright_dawn_f, color_change_fraction);
m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
skycolor_bright_dawn_f, color_change_fraction);
skycolor_bright_dawn_f, color_change_fraction);
m_cloudcolor_bright_f = m_cloudcolor_bright_f.getInterpolated(
cloudcolor_bright_dawn_f, color_change_fraction);
cloudcolor_bright_dawn_f, color_change_fraction);
} else {
m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
if (time_brightness < 0.07) { // Night
m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
bgcolor_bright_night_f, color_change_fraction);
m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
skycolor_bright_night_f, color_change_fraction);
} else { // Day
m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
bgcolor_bright_normal_f, color_change_fraction);
m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
skycolor_bright_normal_f, color_change_fraction);
}
m_cloudcolor_bright_f = m_cloudcolor_bright_f.getInterpolated(
cloudcolor_bright_normal_f, color_change_fraction);
cloudcolor_bright_normal_f, color_change_fraction);
}
} else {
m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
bgcolor_bright_indoor_f, color_change_fraction);
bgcolor_bright_indoor_f, color_change_fraction);
m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
bgcolor_bright_indoor_f, color_change_fraction);
bgcolor_bright_indoor_f, color_change_fraction);
m_cloudcolor_bright_f = m_cloudcolor_bright_f.getInterpolated(
cloudcolor_bright_normal_f, color_change_fraction);
cloudcolor_bright_normal_f, color_change_fraction);
m_clouds_visible = false;
}
@ -572,63 +585,71 @@ void Sky::update(float time_of_day, float time_brightness,
255,
bgcolor_bright.getRed() * m_brightness,
bgcolor_bright.getGreen() * m_brightness,
bgcolor_bright.getBlue() * m_brightness);
bgcolor_bright.getBlue() * m_brightness
);
video::SColor skycolor_bright = m_skycolor_bright_f.toSColor();
m_skycolor = video::SColor(
255,
skycolor_bright.getRed() * m_brightness,
skycolor_bright.getGreen() * m_brightness,
skycolor_bright.getBlue() * m_brightness);
skycolor_bright.getBlue() * m_brightness
);
// Horizon coloring based on sun and moon direction during sunset and sunrise
video::SColor pointcolor = video::SColor(255, 255, 255, m_bgcolor.getAlpha());
if (m_directional_colored_fog) {
if (m_horizon_blend() != 0)
{
// calculate hemisphere value from yaw, (inverted in third person front view)
if (m_horizon_blend() != 0) {
// Calculate hemisphere value from yaw, (inverted in third person front view)
s8 dir_factor = 1;
if (cam_mode > CAMERA_MODE_THIRD)
dir_factor = -1;
f32 pointcolor_blend = wrapDegrees_0_360( yaw*dir_factor + 90);
f32 pointcolor_blend = wrapDegrees_0_360(yaw * dir_factor + 90);
if (pointcolor_blend > 180)
pointcolor_blend = 360 - pointcolor_blend;
pointcolor_blend /= 180;
// bound view angle to determine where transition starts and ends
pointcolor_blend = rangelim(1 - pointcolor_blend * 1.375, 0, 1 / 1.375) * 1.375;
// combine the colors when looking up or down, otherwise turning looks weird
pointcolor_blend += (0.5 - pointcolor_blend) * (1 - MYMIN((90 - std::abs(pitch)) / 90 * 1.5, 1));
// invert direction to match where the sun and moon are rising
// Bound view angle to determine where transition starts and ends
pointcolor_blend = rangelim(1 - pointcolor_blend * 1.375, 0, 1 / 1.375) *
1.375;
// Combine the colors when looking up or down, otherwise turning looks weird
pointcolor_blend += (0.5 - pointcolor_blend) *
(1 - MYMIN((90 - std::fabs(pitch)) / 90 * 1.5, 1));
// Invert direction to match where the sun and moon are rising
if (m_time_of_day > 0.5)
pointcolor_blend = 1 - pointcolor_blend;
// horizon colors of sun and moon
// Horizon colors of sun and moon
f32 pointcolor_light = rangelim(m_time_brightness * 3, 0.2, 1);
video::SColorf pointcolor_sun_f(1, 1, 1, 1);
if (m_sun_tonemap)
{
pointcolor_sun_f.r = pointcolor_light * (float)m_materials[3].EmissiveColor.getRed() / 255;
pointcolor_sun_f.b = pointcolor_light * (float)m_materials[3].EmissiveColor.getBlue() / 255;
pointcolor_sun_f.g = pointcolor_light * (float)m_materials[3].EmissiveColor.getGreen() / 255;
}
else
{
if (m_sun_tonemap) {
pointcolor_sun_f.r = pointcolor_light *
(float)m_materials[3].EmissiveColor.getRed() / 255;
pointcolor_sun_f.b = pointcolor_light *
(float)m_materials[3].EmissiveColor.getBlue() / 255;
pointcolor_sun_f.g = pointcolor_light *
(float)m_materials[3].EmissiveColor.getGreen() / 255;
} else {
pointcolor_sun_f.r = pointcolor_light * 1;
pointcolor_sun_f.b = pointcolor_light * (0.25 + (rangelim(m_time_brightness, 0.25, 0.75) - 0.25) * 2 * 0.75);
pointcolor_sun_f.g = pointcolor_light * (pointcolor_sun_f.b * 0.375 + (rangelim(m_time_brightness, 0.05, 0.15) - 0.05) * 10 * 0.625);
pointcolor_sun_f.b = pointcolor_light *
(0.25 + (rangelim(m_time_brightness, 0.25, 0.75) - 0.25) * 2 * 0.75);
pointcolor_sun_f.g = pointcolor_light * (pointcolor_sun_f.b * 0.375 +
(rangelim(m_time_brightness, 0.05, 0.15) - 0.05) * 10 * 0.625);
}
video::SColorf pointcolor_moon_f(0.5 * pointcolor_light, 0.6 * pointcolor_light, 0.8 * pointcolor_light, 1);
if (m_moon_tonemap)
{
pointcolor_moon_f.r = pointcolor_light * (float)m_materials[4].EmissiveColor.getRed() / 255;
pointcolor_moon_f.b = pointcolor_light * (float)m_materials[4].EmissiveColor.getBlue() / 255;
pointcolor_moon_f.g = pointcolor_light * (float)m_materials[4].EmissiveColor.getGreen() / 255;
video::SColorf pointcolor_moon_f(0.5 * pointcolor_light,
0.6 * pointcolor_light, 0.8 * pointcolor_light, 1);
if (m_moon_tonemap) {
pointcolor_moon_f.r = pointcolor_light *
(float)m_materials[4].EmissiveColor.getRed() / 255;
pointcolor_moon_f.b = pointcolor_light *
(float)m_materials[4].EmissiveColor.getBlue() / 255;
pointcolor_moon_f.g = pointcolor_light *
(float)m_materials[4].EmissiveColor.getGreen() / 255;
}
video::SColor pointcolor_sun = pointcolor_sun_f.toSColor();
video::SColor pointcolor_moon = pointcolor_moon_f.toSColor();
// calculate the blend color
// Calculate the blend color
pointcolor = m_mix_scolor(pointcolor_moon, pointcolor_sun, pointcolor_blend);
}
m_bgcolor = m_mix_scolor(m_bgcolor, pointcolor, m_horizon_blend() * 0.5);
@ -636,29 +657,29 @@ void Sky::update(float time_of_day, float time_brightness,
}
float cloud_direct_brightness = 0;
if(sunlight_seen) {
if (sunlight_seen) {
if (!m_directional_colored_fog) {
cloud_direct_brightness = time_brightness;
if(time_brightness >= 0.2 && time_brightness < 0.7)
if (time_brightness >= 0.2 && time_brightness < 0.7)
cloud_direct_brightness *= 1.3;
}
else {
cloud_direct_brightness = MYMIN(m_horizon_blend() * 0.15 + m_time_brightness, 1);
} else {
cloud_direct_brightness = MYMIN(m_horizon_blend() * 0.15 +
m_time_brightness, 1);
}
} else {
cloud_direct_brightness = direct_brightness;
}
m_cloud_brightness = m_cloud_brightness * cloud_color_change_fraction +
cloud_direct_brightness * (1.0 - cloud_color_change_fraction);
cloud_direct_brightness * (1.0 - cloud_color_change_fraction);
m_cloudcolor_f = video::SColorf(
m_cloudcolor_bright_f.r * m_cloud_brightness,
m_cloudcolor_bright_f.g * m_cloud_brightness,
m_cloudcolor_bright_f.b * m_cloud_brightness,
1.0);
m_cloudcolor_bright_f.r * m_cloud_brightness,
m_cloudcolor_bright_f.g * m_cloud_brightness,
m_cloudcolor_bright_f.b * m_cloud_brightness,
1.0
);
if (m_directional_colored_fog) {
m_cloudcolor_f = m_mix_scolorf(m_cloudcolor_f, video::SColorf(pointcolor), m_horizon_blend() * 0.25);
m_cloudcolor_f = m_mix_scolorf(m_cloudcolor_f,
video::SColorf(pointcolor), m_horizon_blend() * 0.25);
}
}

View File

@ -313,8 +313,8 @@ bool loadGameConfAndInitWorld(const std::string &path, const SubgameSpec &gamesp
Settings conf;
MapgenParams params;
params.load(*g_settings);
params.save(conf);
params.readParams(g_settings);
params.writeParams(&conf);
conf.writeLines(oss);
oss << "[end_of_params]\n";

View File

@ -54,7 +54,7 @@ DEALINGS IN THE SOFTWARE.
// for setName
#if defined(linux) || defined(__linux)
#if defined(__linux__)
#include <sys/prctl.h>
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
#include <pthread_np.h>
@ -70,7 +70,7 @@ DEALINGS IN THE SOFTWARE.
// for bindToProcessor
#if __FreeBSD_version >= 702106
typedef cpuset_t cpu_set_t;
#elif defined(__linux) || defined(linux)
#elif defined(__linux__)
#include <sched.h>
#elif defined(__sun) || defined(sun)
#include <sys/types.h>
@ -261,7 +261,7 @@ DWORD WINAPI Thread::threadProc(LPVOID param)
void Thread::setName(const std::string &name)
{
#if defined(linux) || defined(__linux)
#if defined(__linux__)
// It would be cleaner to do this with pthread_setname_np,
// which was added to glibc in version 2.12, but some major
@ -363,7 +363,7 @@ bool Thread::bindToProcessor(unsigned int proc_number)
return SetThreadAffinityMask(getThreadHandle(), 1 << proc_number);
#elif __FreeBSD_version >= 702106 || defined(__linux) || defined(linux)
#elif __FreeBSD_version >= 702106 || defined(__linux__)
cpu_set_t cpuset;

View File

@ -31,7 +31,7 @@ namespace treegen
{
void make_tree(MMVManip &vmanip, v3s16 p0,
bool is_apple_tree, INodeDefManager *ndef, int seed)
bool is_apple_tree, INodeDefManager *ndef, s32 seed)
{
/*
NOTE: Tree-placing code is currently duplicated in the engine
@ -149,7 +149,7 @@ treegen::error make_ltree(MMVManip &vmanip, v3s16 p0,
INodeDefManager *ndef, TreeDef tree_definition)
{
MapNode dirtnode(ndef->getId("mapgen_dirt"));
int seed;
s32 seed;
if (tree_definition.explicit_seed)
seed = tree_definition.seed + 14002;
else
@ -649,7 +649,7 @@ v3f transposeMatrix(irr::core::matrix4 M, v3f v)
}
void make_jungletree(MMVManip &vmanip, v3s16 p0, INodeDefManager *ndef, int seed)
void make_jungletree(MMVManip &vmanip, v3s16 p0, INodeDefManager *ndef, s32 seed)
{
/*
NOTE: Tree-placing code is currently duplicated in the engine
@ -748,7 +748,7 @@ void make_jungletree(MMVManip &vmanip, v3s16 p0, INodeDefManager *ndef, int seed
}
void make_pine_tree(MMVManip &vmanip, v3s16 p0, INodeDefManager *ndef, int seed)
void make_pine_tree(MMVManip &vmanip, v3s16 p0, INodeDefManager *ndef, s32 seed)
{
/*
NOTE: Tree-placing code is currently duplicated in the engine

View File

@ -54,19 +54,19 @@ namespace treegen {
bool thin_branches;
MapNode fruitnode;
int fruit_chance;
int seed;
s32 seed;
bool explicit_seed;
};
// Add default tree
void make_tree(MMVManip &vmanip, v3s16 p0,
bool is_apple_tree, INodeDefManager *ndef, int seed);
bool is_apple_tree, INodeDefManager *ndef, s32 seed);
// Add jungle tree
void make_jungletree(MMVManip &vmanip, v3s16 p0,
INodeDefManager *ndef, int seed);
INodeDefManager *ndef, s32 seed);
// Add pine tree
void make_pine_tree(MMVManip &vmanip, v3s16 p0,
INodeDefManager *ndef, int seed);
INodeDefManager *ndef, s32 seed);
// Add L-Systems tree (used by engine)
treegen::error make_ltree(MMVManip &vmanip, v3s16 p0, INodeDefManager *ndef,

View File

@ -6,6 +6,7 @@ set (UNITTEST_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/test_connection.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_filepath.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_inventory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_map_settings_manager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_mapnode.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_nodedef.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_noderesolver.cpp

View File

@ -0,0 +1,255 @@
/*
Minetest
Copyright (C) 2010-2014 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
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 "test.h"
#include "noise.h"
#include "settings.h"
#include "mapgen_v5.h"
#include "util/sha1.h"
#include "map_settings_manager.h"
class TestMapSettingsManager : public TestBase {
public:
TestMapSettingsManager() { TestManager::registerTestModule(this); }
const char *getName() { return "TestMapSettingsManager"; }
void makeUserConfig(Settings *conf);
std::string makeMetaFile(bool make_corrupt);
void runTests(IGameDef *gamedef);
void testMapSettingsManager();
void testMapMetaSaveLoad();
void testMapMetaFailures();
};
static TestMapSettingsManager g_test_instance;
void TestMapSettingsManager::runTests(IGameDef *gamedef)
{
TEST(testMapSettingsManager);
TEST(testMapMetaSaveLoad);
TEST(testMapMetaFailures);
}
////////////////////////////////////////////////////////////////////////////////
void check_noise_params(const NoiseParams *np1, const NoiseParams *np2)
{
UASSERTEQ(float, np1->offset, np2->offset);
UASSERTEQ(float, np1->scale, np2->scale);
UASSERT(np1->spread == np2->spread);
UASSERTEQ(s32, np1->seed, np2->seed);
UASSERTEQ(u16, np1->octaves, np2->octaves);
UASSERTEQ(float, np1->persist, np2->persist);
UASSERTEQ(float, np1->lacunarity, np2->lacunarity);
UASSERTEQ(u32, np1->flags, np2->flags);
}
std::string read_file_to_string(const std::string &filepath)
{
std::string buf;
FILE *f = fopen(filepath.c_str(), "rb");
if (!f)
return "";
fseek(f, 0, SEEK_END);
long filesize = ftell(f);
if (filesize == -1)
return "";
rewind(f);
buf.resize(filesize);
fread(&buf[0], 1, filesize, f);
fclose(f);
return buf;
}
void TestMapSettingsManager::makeUserConfig(Settings *conf)
{
conf->set("mg_name", "v7");
conf->set("seed", "5678");
conf->set("water_level", "20");
conf->set("mgv5_np_factor", "0, 12, (500, 250, 500), 920382, 5, 0.45, 3.0");
conf->set("mgv5_np_height", "0, 15, (500, 250, 500), 841746, 5, 0.5, 3.0");
conf->set("mgv5_np_filler_depth", "20, 1, (150, 150, 150), 261, 4, 0.7, 1.0");
conf->set("mgv5_np_ground", "-43, 40, (80, 80, 80), 983240, 4, 0.55, 2.0");
}
std::string TestMapSettingsManager::makeMetaFile(bool make_corrupt)
{
std::string metafile = getTestTempFile();
const char *metafile_contents =
"mg_name = v5\n"
"seed = 1234\n"
"mg_flags = light\n"
"mgv5_np_filler_depth = 20, 1, (150, 150, 150), 261, 4, 0.7, 1.0\n"
"mgv5_np_height = 20, 10, (250, 250, 250), 84174, 4, 0.5, 1.0\n";
FILE *f = fopen(metafile.c_str(), "wb");
UASSERT(f != NULL);
fputs(metafile_contents, f);
if (!make_corrupt)
fputs("[end_of_params]\n", f);
fclose(f);
return metafile;
}
void TestMapSettingsManager::testMapSettingsManager()
{
Settings user_settings;
makeUserConfig(&user_settings);
std::string test_mapmeta_path = makeMetaFile(false);
MapSettingsManager mgr(&user_settings, test_mapmeta_path);
std::string value;
UASSERT(mgr.getMapSetting("mg_name", &value));
UASSERT(value == "v7");
// Pretend we're initializing the ServerMap
UASSERT(mgr.loadMapMeta());
// Pretend some scripts are requesting mapgen params
UASSERT(mgr.getMapSetting("mg_name", &value));
UASSERT(value == "v5");
UASSERT(mgr.getMapSetting("seed", &value));
UASSERT(value == "1234");
UASSERT(mgr.getMapSetting("water_level", &value));
UASSERT(value == "20");
// Pretend we have some mapgen settings configured from the scripting
UASSERT(mgr.setMapSetting("water_level", "15"));
UASSERT(mgr.setMapSetting("seed", "02468"));
UASSERT(mgr.setMapSetting("mg_flags", "nolight", true));
NoiseParams script_np_filler_depth(0, 100, v3f(200, 100, 200), 261, 4, 0.7, 2.0);
NoiseParams script_np_factor(0, 100, v3f(50, 50, 50), 920381, 3, 0.45, 2.0);
NoiseParams script_np_height(0, 100, v3f(450, 450, 450), 84174, 4, 0.5, 2.0);
NoiseParams meta_np_height(20, 10, v3f(250, 250, 250), 84174, 4, 0.5, 1.0);
NoiseParams user_np_ground(-43, 40, v3f(80, 80, 80), 983240, 4, 0.55, 2.0, NOISE_FLAG_EASED);
mgr.setMapSettingNoiseParams("mgv5_np_filler_depth", &script_np_filler_depth, true);
mgr.setMapSettingNoiseParams("mgv5_np_height", &script_np_height);
mgr.setMapSettingNoiseParams("mgv5_np_factor", &script_np_factor);
// Now make our Params and see if the values are correctly sourced
MapgenParams *params = mgr.makeMapgenParams();
UASSERT(params->mgtype == MAPGEN_V5);
UASSERT(params->chunksize == 5);
UASSERT(params->water_level == 15);
UASSERT(params->seed == 1234);
UASSERT((params->flags & MG_LIGHT) == 0);
MapgenV5Params *v5params = (MapgenV5Params *)params;
check_noise_params(&v5params->np_filler_depth, &script_np_filler_depth);
check_noise_params(&v5params->np_factor, &script_np_factor);
check_noise_params(&v5params->np_height, &meta_np_height);
check_noise_params(&v5params->np_ground, &user_np_ground);
UASSERT(mgr.setMapSetting("foobar", "25") == false);
// Pretend the ServerMap is shutting down
UASSERT(mgr.saveMapMeta());
// Make sure our interface expectations are met
UASSERT(mgr.mapgen_params == params);
UASSERT(mgr.makeMapgenParams() == params);
// Load the resulting map_meta.txt and make sure it contains what we expect
unsigned char expected_contents_hash[20] = {
0xf6, 0x44, 0x90, 0xb7, 0xab, 0xd8, 0x91, 0xf4, 0x08, 0x96,
0xfc, 0x7e, 0xed, 0x01, 0xc5, 0x9a, 0xfd, 0x2f, 0x2d, 0x79
};
SHA1 ctx;
std::string metafile_contents = read_file_to_string(test_mapmeta_path);
ctx.addBytes(&metafile_contents[0], metafile_contents.size());
unsigned char *sha1_result = ctx.getDigest();
int resultdiff = memcmp(sha1_result, expected_contents_hash, 20);
free(sha1_result);
UASSERT(!resultdiff);
}
void TestMapSettingsManager::testMapMetaSaveLoad()
{
Settings conf;
std::string path = getTestTempDirectory()
+ DIR_DELIM + "foobar" + DIR_DELIM + "map_meta.txt";
// Create a set of mapgen params and save them to map meta
conf.set("seed", "12345");
conf.set("water_level", "5");
MapSettingsManager mgr1(&conf, path);
MapgenParams *params1 = mgr1.makeMapgenParams();
UASSERT(params1);
UASSERT(mgr1.saveMapMeta());
// Now try loading the map meta to mapgen params
conf.set("seed", "67890");
conf.set("water_level", "32");
MapSettingsManager mgr2(&conf, path);
UASSERT(mgr2.loadMapMeta());
MapgenParams *params2 = mgr2.makeMapgenParams();
UASSERT(params2);
// Check that both results are correct
UASSERTEQ(u64, params1->seed, 12345);
UASSERTEQ(s16, params1->water_level, 5);
UASSERTEQ(u64, params2->seed, 12345);
UASSERTEQ(s16, params2->water_level, 5);
}
void TestMapSettingsManager::testMapMetaFailures()
{
std::string test_mapmeta_path;
Settings conf;
// Check to see if it'll fail on a non-existent map meta file
test_mapmeta_path = "woobawooba/fgdfg/map_meta.txt";
UASSERT(!fs::PathExists(test_mapmeta_path));
MapSettingsManager mgr1(&conf, test_mapmeta_path);
UASSERT(!mgr1.loadMapMeta());
// Check to see if it'll fail on a corrupt map meta file
test_mapmeta_path = makeMetaFile(true);
UASSERT(fs::PathExists(test_mapmeta_path));
MapSettingsManager mgr2(&conf, test_mapmeta_path);
UASSERT(!mgr2.loadMapMeta());
}

View File

@ -39,7 +39,9 @@ static TestThreading g_test_instance;
void TestThreading::runTests(IGameDef *gamedef)
{
#if !(defined(__MACH__) && defined(__APPLE__))
TEST(testStartStopWait);
#endif
TEST(testThreadKill);
TEST(testAtomicSemaphoreThread);
}

View File

@ -314,7 +314,7 @@ std::string wide_to_narrow(const std::wstring &wcs)
#endif
std::string urlencode(std::string str)
std::string urlencode(const std::string &str)
{
// Encodes non-unreserved URI characters by a percent sign
// followed by two hex digits. See RFC 3986, section 2.3.
@ -322,17 +322,18 @@ std::string urlencode(std::string str)
std::ostringstream oss(std::ios::binary);
for (u32 i = 0; i < str.size(); i++) {
unsigned char c = str[i];
if (isalnum(c) || c == '-' || c == '.' || c == '_' || c == '~')
if (isalnum(c) || c == '-' || c == '.' || c == '_' || c == '~') {
oss << c;
else
} else {
oss << "%"
<< url_hex_chars[(c & 0xf0) >> 4]
<< url_hex_chars[c & 0x0f];
}
}
return oss.str();
}
std::string urldecode(std::string str)
std::string urldecode(const std::string &str)
{
// Inverse of urlencode
std::ostringstream oss(std::ios::binary);
@ -343,18 +344,20 @@ std::string urldecode(std::string str)
hex_digit_decode(str[i+2], lowvalue)) {
oss << (char) ((highvalue << 4) | lowvalue);
i += 2;
}
else
} else {
oss << str[i];
}
}
return oss.str();
}
u32 readFlagString(std::string str, const FlagDesc *flagdesc, u32 *flagmask)
{
u32 result = 0, mask = 0;
u32 result = 0;
u32 mask = 0;
char *s = &str[0];
char *flagstr, *strpos = NULL;
char *flagstr;
char *strpos = NULL;
while ((flagstr = strtok_r(s, ",", &strpos))) {
s = NULL;

View File

@ -77,8 +77,8 @@ wchar_t *narrow_to_wide_c(const char *str);
std::wstring narrow_to_wide(const std::string &mbs);
std::string wide_to_narrow(const std::wstring &wcs);
std::string urlencode(std::string str);
std::string urldecode(std::string str);
std::string urlencode(const std::string &str);
std::string urldecode(const std::string &str);
u32 readFlagString(std::string str, const FlagDesc *flagdesc, u32 *flagmask);
std::string writeFlagString(u32 flags, const FlagDesc *flagdesc, u32 flagmask);
size_t mystrlcpy(char *dst, const char *src, size_t size);