Grabbing updates

master
Robert Arkenin 2013-03-29 08:57:38 -04:00
parent 13a918d1bb
commit 5f84f82498
46 changed files with 2129 additions and 409 deletions

View File

@ -133,6 +133,11 @@ endif()
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/builtin" DESTINATION "${SHAREDIR}")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/client" DESTINATION "${SHAREDIR}")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games/minimal" DESTINATION "${SHAREDIR}/games")
set(COMMON_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/games/common")
if(EXISTS ${COMMON_SOURCE} AND IS_DIRECTORY ${COMMON_SOURCE})
install(FILES ${COMMON_SOURCE}/README.txt DESTINATION "${SHAREDIR}/games/common/")
install(DIRECTORY ${COMMON_SOURCE}/mods DESTINATION "${SHAREDIR}/games/common")
endif()
set(MINETEST_GAME_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/games/minetest_game")
if(EXISTS ${MINETEST_GAME_SOURCE} AND IS_DIRECTORY ${MINETEST_GAME_SOURCE})
install(FILES ${MINETEST_GAME_SOURCE}/game.conf DESTINATION "${SHAREDIR}/games/minetest_game/")

View File

@ -81,7 +81,7 @@ Compiling on GNU/Linux:
-----------------------
Install dependencies. Here's an example for Debian/Ubuntu:
$ apt-get install build-essential libirrlicht-dev cmake libbz2-dev libpng12-dev libjpeg8-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev
$ apt-get install build-essential libirrlicht-dev cmake libbz2-dev libpng12-dev libjpeg8-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev
Download source, extract (this is the URL to the latest of source repository, which might not work at all times):
$ wget https://github.com/minetest/minetest/tarball/master -O master.tar.gz
@ -115,6 +115,7 @@ $ ./minetest
- You can build a bare server or a bare client by specifying -DBUILD_CLIENT=0 or -DBUILD_SERVER=0
- You can select between Release and Debug build by -DCMAKE_BUILD_TYPE=<Debug or Release>
- Debug build is slower, but gives much more useful output in a debugger
- If you build a bare server, you don't need to have Irrlicht installed. In that case use -DIRRLICHT_SOURCE_DIR=/the/irrlicht/source
Compiling on Windows:
---------------------

View File

@ -1,4 +1,4 @@
Minetest Lua Modding API Reference 0.4.4
Minetest Lua Modding API Reference 0.4.5
==========================================
More information at http://c55.me/minetest/
@ -203,18 +203,18 @@ from the available ones of the following files:
Examples of sound parameter tables:
-- Play locationless on all clients
{
gain = 1.0, -- default
gain = 1.0, -- default
}
-- Play locationless to a player
{
to_player = name,
gain = 1.0, -- default
to_player = name,
gain = 1.0, -- default
}
-- Play in a location
{
pos = {x=1,y=2,z=3},
gain = 1.0, -- default
max_hear_distance = 32, -- default
pos = {x=1,y=2,z=3},
gain = 1.0, -- default
max_hear_distance = 32, -- default
}
-- Play connected to an object, looped
{
@ -266,11 +266,11 @@ local drawtype = get_nodedef_field(nodename, "drawtype")
Example: minetest.get_item_group(name, group) has been implemented as:
function minetest.get_item_group(name, group)
if not minetest.registered_items[name] or not
minetest.registered_items[name].groups[group] then
return 0
end
return minetest.registered_items[name].groups[group]
if not minetest.registered_items[name] or not
minetest.registered_items[name].groups[group] then
return 0
end
return minetest.registered_items[name].groups[group]
end
Nodes
@ -310,6 +310,10 @@ param2 is reserved for the engine when any of these are used:
paramtype2 == "facedir"
^ The rotation of the node is stored in param2. Furnaces and chests are
rotated this way. Can be made by using minetest.dir_to_facedir().
Values range 0 - 23
facedir modulo 4 = axisdir
0 = y+ 1 = z+ 2 = z- 3 = x+ 4 = x- 5 = y-
facedir's two less significant bits are rotation around the axis
Nodes can also contain extra data. See "Node Metadata".
@ -368,6 +372,28 @@ A box is defined as:
A box of a regular node would look like:
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
Ore types
---------------
These tell in what manner the ore is generated.
All default ores are of the uniformly-distributed scatter type.
- scatter
Randomly chooses a location and generates a cluster of ore.
If noise_params is specified, the ore will be placed if the 3d perlin noise at
that point is greater than the noise_threshhold, giving the ability to create a non-equal
distribution of ore.
- sheet
Creates a sheet of ore in a blob shape according to the 2d perlin noise described by noise_params.
The relative height of the sheet can be controlled by the same perlin noise as well, by specifying
a non-zero 'scale' parameter in noise_params. IMPORTANT: The noise is not transformed by offset or
scale when comparing against the noise threshhold, but scale is used to determine relative height.
The height of the blob is randomly scattered, with a maximum height of clust_size.
clust_scarcity and clust_num_ores are ignored.
This is essentially an improved version of the so-called "stratus" ore seen in some unofficial mods.
- claylike - NOT YET IMPLEMENTED
Places ore if there are no more than clust_scarcity number of specified nodes within a Von Neumann
neighborhood of clust_size radius.
Representations of simple things
--------------------------------
Position/vector:
@ -468,7 +494,7 @@ An example: Make meat soup from any meat, any water and any bowl
}
An another example: Make red wool from white wool and red dye
{
type = 'shapeless',
type = 'shapeless',
output = 'wool:red',
recipe = {'wool:white', 'group:dye,basecolor_red'},
}
@ -479,7 +505,7 @@ Special groups
- level: Can be used to give an additional sense of progression in the game.
- A larger level will cause eg. a weapon of a lower level make much less
damage, and get weared out much faster, or not be able to get drops
from destroyed nodes.
from destroyed nodes.
- 0 is something that is directly accessible at the start of gameplay
- There is no upper limit
- dig_immediate: (player can always pick up node without tool wear)
@ -586,11 +612,11 @@ maximum level.
Example definition of the capabilities of a tool
-------------------------------------------------
tool_capabilities = {
full_punch_interval=1.5,
max_drop_level=1,
groupcaps={
crumbly={maxlevel=2, uses=20, times={[1]=1.60, [2]=1.20, [3]=0.80}}
}
full_punch_interval=1.5,
max_drop_level=1,
groupcaps={
crumbly={maxlevel=2, uses=20, times={[1]=1.60, [2]=1.20, [3]=0.80}}
}
}
This makes the tool be able to dig nodes that fullfill both of these:
@ -750,7 +776,7 @@ field[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]
^ default is the default value of the field
^ default may contain variable references such as '${text}' which
will fill the value from the metadata value 'text'
^ Note: no extra text or more than a single variable is supported ATM.
^ Note: no extra text or more than a single variable is supported ATM.
field[<name>;<label>;<default>]
^ as above but without position/size units
@ -840,6 +866,7 @@ minetest.register_tool(name, item definition)
minetest.register_craftitem(name, item definition)
minetest.register_alias(name, convert_to)
minetest.register_craft(recipe)
minetest.register_ore(ore definition)
Global callback registration functions: (Call these only at load time)
minetest.register_globalstep(func(dtime))
@ -1024,6 +1051,37 @@ minetest.get_ban_description(ip_or_name) -> ban description (string)
minetest.ban_player(name) -> ban a player
minetest.unban_player_or_ip(name) -> unban player or IP address
Particles:
minetest.add_particle(pos, velocity, acceleration, expirationtime,
size, collisiondetection, texture, playername)
^ Spawn particle at pos with velocity and acceleration
^ Disappears after expirationtime seconds
^ collisiondetection: if true collides with physical objects
^ Uses texture (string)
^ Playername is optional, if specified spawns particle only on the player's client
minetest.add_particlespawner(amount, time,
minpos, maxpos,
minvel, maxvel,
minacc, maxacc,
minexptime, maxexptime,
minsize, maxsize,
collisiondetection, texture, playername)
^ Add a particlespawner, an object that spawns an amount of particles over time seconds
^ The particle's properties are random values in between the boundings:
^ minpos/maxpos, minvel/maxvel (velocity), minacc/maxacc (acceleration),
^ minsize/maxsize, minexptime/maxexptime (expirationtime)
^ collisiondetection: if true uses collisiondetection
^ Uses texture (string)
^ Playername is optional, if specified spawns particle only on the player's client
^ If time is 0 has infinite lifespan and spawns the amount on a per-second base
^ Returns and id
minetest.delete_particlespawner(id, player)
^ Delete ParticleSpawner with id (return value from add_particlespawner)
^ If playername is specified, only deletes on the player's client,
^ otherwise on all clients
Random:
minetest.get_connected_players() -> list of ObjectRefs
minetest.hash_node_position({x=,y=,z=}) -> 48-bit integer
@ -1237,9 +1295,15 @@ methods:
- set_wielded_item(item): replaces the wielded item, returns true if successful
- set_armor_groups({group1=rating, group2=rating, ...})
- set_animation({x=1,y=1}, frame_speed=15, frame_blend=0)
- set_attach(parent, "", {x=0,y=0,z=0}, {x=0,y=0,z=0})
- set_attach(parent, bone, position, rotation)
^ bone = string
^ position = {x=num, y=num, z=num} (relative)
^ rotation = {x=num, y=num, z=num}
- set_detach()
- set_bone_position("", {x=0,y=0,z=0}, {x=0,y=0,z=0})
- set_bone_position(bone, position, rotation)
^ bone = string
^ position = {x=num, y=num, z=num} (relative)
^ rotation = {x=num, y=num, z=num}
- set_properties(object property table)
LuaEntitySAO-only: (no-op for other objects)
- setvelocity({x=num, y=num, z=num})
@ -1268,10 +1332,10 @@ Player-only: (no-op for other objects)
^ Should usually be called in on_joinplayer
- get_inventory_formspec() -> formspec string
- get_player_control(): returns table with player pressed keys
{jump=bool,right=bool,left=bool,LMB=bool,RMB=bool,sneak=bool,aux1=bool,down=bool,up=bool}
{jump=bool,right=bool,left=bool,LMB=bool,RMB=bool,sneak=bool,aux1=bool,down=bool,up=bool}
- get_player_control_bits(): returns integer with bit packed player pressed keys
bit nr/meaning: 0/up ,1/down ,2/left ,3/right ,4/jump ,5/aux1 ,6/sneak ,7/LMB ,8/RMB
bit nr/meaning: 0/up ,1/down ,2/left ,3/right ,4/jump ,5/aux1 ,6/sneak ,7/LMB ,8/RMB
InvRef: Reference to an inventory
methods:
- is_empty(listname): return true if list is empty
@ -1356,8 +1420,8 @@ Registered entities
^ puncher: ObjectRef (can be nil)
^ time_from_last_punch: Meant for disallowing spamming of clicks (can be nil)
^ tool_capabilities: capability table of used tool (can be nil)
^ dir: unit vector of direction of punch. Always defined. Points from
the puncher to the punched.
^ dir: unit vector of direction of punch. Always defined. Points from
the puncher to the punched.
- on_rightclick(self, clicker)
- get_staticdata(self)
^ Should return a string that will be passed to on_activate when
@ -1478,10 +1542,10 @@ Node definition (register_node)
drawtype = "normal", -- See "Node drawtypes"
visual_scale = 1.0,
tiles = {tile definition 1, def2, def3, def4, def5, def6},
^ Textures of node; +Y, -Y, +X, -X, +Z, -Z (old field name: tile_images)
^ Textures of node; +Y, -Y, +X, -X, +Z, -Z (old field name: tile_images)
^ List can be shortened to needed length
special_tiles = {tile definition 1, Tile definition 2},
^ Special textures of node; used rarely (old field name: special_materials)
^ Special textures of node; used rarely (old field name: special_materials)
^ List can be shortened to needed length
alpha = 255,
post_effect_color = {a=0, r=0, g=0, b=0}, -- If player is inside node
@ -1537,7 +1601,7 @@ Node definition (register_node)
can_dig = function(pos,player)
^ returns true if node can be dug, or false if not
^ default: nil
on_punch = func(pos, node, puncher),
^ default: minetest.node_punch
^ By default: does nothing
@ -1560,32 +1624,32 @@ Node definition (register_node)
^ Called when an UI form (eg. sign text input) returns data
^ default: nil
allow_metadata_inventory_move = func(pos, from_list, from_index,
to_list, to_index, count, player),
^ Called when a player wants to move items inside the inventory
^ Return value: number of items allowed to move
allow_metadata_inventory_put = func(pos, listname, index, stack, player),
^ Called when a player wants to put something into the inventory
^ Return value: number of items allowed to put
^ Return value: -1: Allow and don't modify item count in inventory
allow_metadata_inventory_take = func(pos, listname, index, stack, player),
^ Called when a player wants to take something out of the inventory
^ Return value: number of items allowed to take
^ Return value: -1: Allow and don't modify item count in inventory
on_metadata_inventory_move = func(pos, from_list, from_index,
to_list, to_index, count, player),
on_metadata_inventory_put = func(pos, listname, index, stack, player),
on_metadata_inventory_take = func(pos, listname, index, stack, player),
^ Called after the actual action has happened, according to what was allowed.
^ No return value
allow_metadata_inventory_move = func(pos, from_list, from_index,
to_list, to_index, count, player),
^ Called when a player wants to move items inside the inventory
^ Return value: number of items allowed to move
on_blast = func(pos, intensity),
^ intensity: 1.0 = mid range of regular TNT
^ If defined, called when an explosion touches the node, instead of
removing the node
allow_metadata_inventory_put = func(pos, listname, index, stack, player),
^ Called when a player wants to put something into the inventory
^ Return value: number of items allowed to put
^ Return value: -1: Allow and don't modify item count in inventory
allow_metadata_inventory_take = func(pos, listname, index, stack, player),
^ Called when a player wants to take something out of the inventory
^ Return value: number of items allowed to take
^ Return value: -1: Allow and don't modify item count in inventory
on_metadata_inventory_move = func(pos, from_list, from_index,
to_list, to_index, count, player),
on_metadata_inventory_put = func(pos, listname, index, stack, player),
on_metadata_inventory_take = func(pos, listname, index, stack, player),
^ Called after the actual action has happened, according to what was allowed.
^ No return value
on_blast = func(pos, intensity),
^ intensity: 1.0 = mid range of regular TNT
^ If defined, called when an explosion touches the node, instead of
removing the node
}
Recipe for register_craft: (shaped)
@ -1634,6 +1698,28 @@ Recipe for register_craft (furnace fuel)
burntime = 1,
}
Ore definition (register_ore)
{
ore_type = "scatter" -- See "Ore types"
ore = "default:stone_with_coal",
wherein = "default:stone",
clust_scarcity = 8*8*8,
^ Ore has a 1 out of clust_scarcity chance of spawning in a node
^ This value should be *MUCH* higher than your intuition might tell you!
clust_num_ores = 8,
^ Number of ores in a cluster
clust_size = 3,
^ Size of the bounding box of the cluster
^ In this example, there is a 3x3x3 cluster where 8 out of the 27 nodes are coal ore
height_min = -31000,
height_max = 64,
noise_threshhold = 0.5,
^ If noise is above this threshhold, ore is placed. Not needed for a uniform distribution
noise_params = {offset=0, scale=1, spread={x=100, y=100, z=100}, seed=23, octaves=3, persist=0.70}
^ NoiseParams structure describing the perlin noise used for ore distribution.
^ Needed for sheet ore_type. Omit from scatter ore_type for a uniform ore distribution
}
Chatcommand definition (register_chatcommand)
{
params = "<name> <privilege>", -- short parameter description
@ -1644,24 +1730,24 @@ Chatcommand definition (register_chatcommand)
Detached inventory callbacks
{
allow_move = func(inv, from_list, from_index, to_list, to_index, count, player),
allow_move = func(inv, from_list, from_index, to_list, to_index, count, player),
^ Called when a player wants to move items inside the inventory
^ Return value: number of items allowed to move
^ Return value: number of items allowed to move
allow_put = func(inv, listname, index, stack, player),
^ Called when a player wants to put something into the inventory
^ Return value: number of items allowed to put
^ Return value: -1: Allow and don't modify item count in inventory
^ Return value: number of items allowed to put
^ Return value: -1: Allow and don't modify item count in inventory
allow_take = func(inv, listname, index, stack, player),
^ Called when a player wants to take something out of the inventory
^ Return value: number of items allowed to take
^ Return value: -1: Allow and don't modify item count in inventory
on_move = func(inv, from_list, from_index, to_list, to_index, count, player),
^ Return value: number of items allowed to take
^ Return value: -1: Allow and don't modify item count in inventory
on_move = func(inv, from_list, from_index, to_list, to_index, count, player),
on_put = func(inv, listname, index, stack, player),
on_take = func(inv, listname, index, stack, player),
^ Called after the actual action has happened, according to what was allowed.
^ No return value
^ Called after the actual action has happened, according to what was allowed.
^ No return value
}

View File

@ -27,61 +27,74 @@ minetest.register_alias("mapgen_mese", "default:mese")
-- Ore generation
--
local function generate_ore(name, wherein, minp, maxp, seed, chunks_per_volume, ore_per_chunk, height_min, height_max, param2)
if maxp.y < height_min or minp.y > height_max then
return
end
local y_min = math.max(minp.y, height_min)
local y_max = math.min(maxp.y, height_max)
local volume = (maxp.x-minp.x+1)*(y_max-y_min+1)*(maxp.z-minp.z+1)
local pr = PseudoRandom(seed)
local num_chunks = math.floor(chunks_per_volume * volume)
local chunk_size = 3
if ore_per_chunk <= 4 then
chunk_size = 2
end
local inverse_chance = math.floor(chunk_size*chunk_size*chunk_size / ore_per_chunk)
--print("generate_ore num_chunks: "..dump(num_chunks))
for i=1,num_chunks do
local y0 = pr:next(y_min, y_max-chunk_size+1)
if y0 >= height_min and y0 <= height_max then
local x0 = pr:next(minp.x, maxp.x-chunk_size+1)
local z0 = pr:next(minp.z, maxp.z-chunk_size+1)
local p0 = {x=x0, y=y0, z=z0}
for x1=0,chunk_size-1 do
for y1=0,chunk_size-1 do
for z1=0,chunk_size-1 do
if pr:next(1,inverse_chance) == 1 then
local x2 = x0+x1
local y2 = y0+y1
local z2 = z0+z1
local p2 = {x=x2, y=y2, z=z2}
if minetest.env:get_node(p2).name == wherein then
minetest.env:set_node(p2, {name=name, param2=param2})
end
end
end
end
end
end
end
--print("generate_ore done")
end
minetest.register_ore({
ore_type = "scatter",
ore = "default:stone_with_coal",
wherein = "default:stone",
clust_scarcity = 8*8*8,
clust_num_ores = 5,
clust_size = 3,
height_min = -31000,
height_max = 64,
})
minetest.register_ore({
ore_type = "scatter",
ore = "default:stone_with_iron",
wherein = "default:stone",
clust_scarcity = 16*16*16,
clust_num_ores = 5,
clust_size = 3,
height_min = -5,
height_max = 7,
})
minetest.register_ore({
ore_type = "scatter",
ore = "default:stone_with_iron",
wherein = "default:stone",
clust_scarcity = 12*12*12,
clust_num_ores = 5,
clust_size = 3,
height_min = -16,
height_max = -5,
})
minetest.register_ore({
ore_type = "scatter",
ore = "default:stone_with_iron",
wherein = "default:stone",
clust_scarcity = 9*9*9,
clust_num_ores = 5,
clust_size = 3,
height_min = -31000,
height_max = -17,
})
-- for float islands and far scaled
minetest.register_ore({
ore_type = "scatter",
ore = "default:stone_with_coal",
wherein = "default:stone",
clust_scarcity = 8*8*8,
clust_num_ores = 5,
clust_size = 3,
height_min = 200,
height_max = 31000,
})
minetest.register_ore({
ore_type = "scatter",
ore = "default:stone_with_iron",
wherein = "default:stone",
clust_scarcity = 9*9*9,
clust_num_ores = 5,
clust_size = 3,
height_min = 200,
height_max = 31000,
})
minetest.register_on_generated(function(minp, maxp, seed)
generate_ore("default:stone_with_coal", "default:stone", minp, maxp, seed, 1/8/8/8, 5, -31000, 64 )
generate_ore("default:stone_with_iron", "default:stone", minp, maxp, seed+1, 1/16/16/16, 5, -5, 7 )
generate_ore("default:stone_with_iron", "default:stone", minp, maxp, seed+2, 1/12/12/12, 5, -16, -5 )
generate_ore("default:stone_with_iron", "default:stone", minp, maxp, seed+3, 1/9/9/9, 5, -31000, -17 )
if minetest.setting_getbool("underground_springs") then
generate_ore("default:water_source", "default:stone", minp, maxp, seed+4, 1/24/24/24, 12, -100, -11, 128)
generate_ore("default:water_source", "default:stone", minp, maxp, seed+5, 1/28/28/28, 8, -10000, -101, 128)
generate_ore("default:lava_source", "default:stone", minp, maxp, seed+6, 1/38/38/38, 6, -500, -101, 128)
generate_ore("default:lava_source", "default:stone", minp, maxp, seed+7, 1/30/30/30, 16, -5000, -501, 128)
generate_ore("default:lava_source", "default:stone", minp, maxp, seed+8, 1/24/24/24, 20, -31000, -5001, 128)
end
-- Generate clay
if maxp.y >= 2 and minp.y <= 0 then
-- Assume X and Z lengths are equal

View File

@ -311,7 +311,7 @@
# Mapgen stuff
#
# Name of map generator to be used. Currently v6 and indev are supported.
# Name of map generator to be used. Currently v6, indev and singlenode are supported.
#mg_name = v6
# Water level of map.
#water_level = 1
@ -341,8 +341,15 @@
#mgv7_np_heat = 25, 50, (500, 500, 500), 35293, 1, 0
#mgv7_np_humidity = 50, 31.25, (750, 750, 750), 12094, 2, 0.6
# Offset, scale, spread factor, seed offset, number of octaves, persistence, farscale
#mgindev_np_terrain_base = -4, 20, (250.0, 250, 250), 82341, 5, 0.6, 10
#mgindev_np_terrain_higher = 20, 16, (500, 500, 500), 85039, 5, 0.6, 10
#mgindev_np_steepness = 0.85, 0.5, (125, 125, 125), -932, 5, 0.7, 10
#mgindev_np_mud = 4, 2, (200, 200, 200), 91013, 3, 0.55, 1
# Offset, scale, spread factor, seed offset, number of octaves, persistence, farscale, farspread
#mgindev_np_terrain_base = -4, 20, (250, 250, 250), 82341, 5, 0.6, 10, 10
#mgindev_np_terrain_higher = 20, 16, (500, 500, 500), 85039, 5, 0.6, 10, 10
#mgindev_np_steepness = 0.85, 0.5, (125, 125, 125), -932, 5, 0.7, 2, 10
#mgindev_np_mud = 4, 2, (200, 200, 200), 91013, 3, 0.55, 1, 1
#mgindev_np_float_islands1 = 0, 1, (64, 64, 64 ), 3683, 5, 0.5, 1, 1.5
#mgindev_np_float_islands2 = 0, 1, (8, 8, 8 ), 9292, 2, 0.5, 1, 1.5
#mgindev_np_float_islands3 = 0, 1, (256, 256, 256), 6412, 2, 0.5, 1, 0.5
#mgindev_np_biome = 0, 1, (250, 250, 250), 9130, 3, 0.50, 1, 10
# Float islands starts from height, 0 to disable
#mgindev_float_islands = 500

View File

@ -219,6 +219,7 @@ set(common_SRCS
scriptapi_object.cpp
scriptapi_nodemeta.cpp
scriptapi_inventory.cpp
scriptapi_particles.cpp
scriptapi.cpp
script.cpp
log.cpp
@ -227,6 +228,7 @@ set(common_SRCS
mapgen.cpp
mapgen_v6.cpp
mapgen_indev.cpp
mapgen_singlenode.cpp
treegen.cpp
dungeongen.cpp
content_nodemeta.cpp

View File

@ -61,7 +61,7 @@ public:
}
virtual u8 getType() const = 0;
virtual bool getCollisionBox(aabb3f *toset) = 0;
protected:
u16 m_id; // 0 is invalid, "no id"
};

View File

@ -1937,6 +1937,89 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
event.show_formspec.formname = new std::string(formname);
m_client_event_queue.push_back(event);
}
else if(command == TOCLIENT_SPAWN_PARTICLE)
{
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
v3f pos = readV3F1000(is);
v3f vel = readV3F1000(is);
v3f acc = readV3F1000(is);
float expirationtime = readF1000(is);
float size = readF1000(is);
bool collisiondetection = readU8(is);
std::string texture = deSerializeLongString(is);
ClientEvent event;
event.type = CE_SPAWN_PARTICLE;
event.spawn_particle.pos = new v3f (pos);
event.spawn_particle.vel = new v3f (vel);
event.spawn_particle.acc = new v3f (acc);
event.spawn_particle.expirationtime = expirationtime;
event.spawn_particle.size = size;
event.add_particlespawner.collisiondetection =
collisiondetection;
event.spawn_particle.texture = new std::string(texture);
m_client_event_queue.push_back(event);
}
else if(command == TOCLIENT_ADD_PARTICLESPAWNER)
{
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
u16 amount = readU16(is);
float spawntime = readF1000(is);
v3f minpos = readV3F1000(is);
v3f maxpos = readV3F1000(is);
v3f minvel = readV3F1000(is);
v3f maxvel = readV3F1000(is);
v3f minacc = readV3F1000(is);
v3f maxacc = readV3F1000(is);
float minexptime = readF1000(is);
float maxexptime = readF1000(is);
float minsize = readF1000(is);
float maxsize = readF1000(is);
bool collisiondetection = readU8(is);
std::string texture = deSerializeLongString(is);
u32 id = readU32(is);
ClientEvent event;
event.type = CE_ADD_PARTICLESPAWNER;
event.add_particlespawner.amount = amount;
event.add_particlespawner.spawntime = spawntime;
event.add_particlespawner.minpos = new v3f (minpos);
event.add_particlespawner.maxpos = new v3f (maxpos);
event.add_particlespawner.minvel = new v3f (minvel);
event.add_particlespawner.maxvel = new v3f (maxvel);
event.add_particlespawner.minacc = new v3f (minacc);
event.add_particlespawner.maxacc = new v3f (maxacc);
event.add_particlespawner.minexptime = minexptime;
event.add_particlespawner.maxexptime = maxexptime;
event.add_particlespawner.minsize = minsize;
event.add_particlespawner.maxsize = maxsize;
event.add_particlespawner.collisiondetection = collisiondetection;
event.add_particlespawner.texture = new std::string(texture);
event.add_particlespawner.id = id;
m_client_event_queue.push_back(event);
}
else if(command == TOCLIENT_DELETE_PARTICLESPAWNER)
{
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
u32 id = readU16(is);
ClientEvent event;
event.type = CE_DELETE_PARTICLESPAWNER;
event.delete_particlespawner.id = id;
m_client_event_queue.push_back(event);
}
else
{
infostream<<"Client: Ignoring unknown command "

View File

@ -157,7 +157,10 @@ enum ClientEventType
CE_PLAYER_FORCE_MOVE,
CE_DEATHSCREEN,
CE_TEXTURES_UPDATED,
CE_SHOW_FORMSPEC
CE_SHOW_FORMSPEC,
CE_SPAWN_PARTICLE,
CE_ADD_PARTICLESPAWNER,
CE_DELETE_PARTICLESPAWNER
};
struct ClientEvent
@ -185,6 +188,35 @@ struct ClientEvent
} show_formspec;
struct{
} textures_updated;
struct{
v3f *pos;
v3f *vel;
v3f *acc;
f32 expirationtime;
f32 size;
bool collisiondetection;
std::string *texture;
} spawn_particle;
struct{
u16 amount;
f32 spawntime;
v3f *minpos;
v3f *maxpos;
v3f *minvel;
v3f *maxvel;
v3f *minacc;
v3f *maxacc;
f32 minexptime;
f32 maxexptime;
f32 minsize;
f32 maxsize;
bool collisiondetection;
std::string *texture;
u32 id;
} add_particlespawner;
struct{
u32 id;
} delete_particlespawner;
};
};

View File

@ -79,9 +79,15 @@ SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time, float time_speed);
Serialization format changes
PROTOCOL_VERSION 16:
TOCLIENT_SHOW_FORMSPEC
PROTOCOL_VERSION 17:
Serialization format change: include backface_culling flag in TileDef
Added rightclickable field in nodedef
TOCLIENT_SPAWN_PARTICLE
TOCLIENT_ADD_PARTICLESPAWNER
TOCLIENT_DELETE_PARTICLESPAWNER
*/
#define LATEST_PROTOCOL_VERSION 16
#define LATEST_PROTOCOL_VERSION 17
// Server's supported network protocol range
#define SERVER_PROTOCOL_VERSION_MIN 13
@ -356,6 +362,7 @@ enum ToClientCommand
u8[len] name
[2] serialized inventory
*/
TOCLIENT_SHOW_FORMSPEC = 0x44,
/*
[0] u16 command
@ -381,6 +388,46 @@ enum ToClientCommand
f1000 movement_liquid_sink
f1000 movement_gravity
*/
TOCLIENT_SPAWN_PARTICLE = 0x46,
/*
u16 command
v3f1000 pos
v3f1000 velocity
v3f1000 acceleration
f1000 expirationtime
f1000 size
u8 bool collisiondetection
u32 len
u8[len] texture
*/
TOCLIENT_ADD_PARTICLESPAWNER = 0x47,
/*
u16 command
u16 amount
f1000 spawntime
v3f1000 minpos
v3f1000 maxpos
v3f1000 minvel
v3f1000 maxvel
v3f1000 minacc
v3f1000 maxacc
f1000 minexptime
f1000 maxexptime
f1000 minsize
f1000 maxsize
u8 bool collisiondetection
u32 len
u8[len] texture
u32 id
*/
TOCLIENT_DELETE_PARTICLESPAWNER = 0x48,
/*
u16 command
u32 id
*/
};
enum ToServerCommand

View File

@ -23,7 +23,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodedef.h"
#include "gamedef.h"
#include "log.h"
#include "environment.h"
#include "serverobject.h"
#include <vector>
#include <set>
#include "util/timetaker.h"
#include "main.h" // g_profiler
#include "profiler.h"
@ -186,11 +189,12 @@ bool wouldCollideWithCeiling(
}
collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
f32 pos_max_d, const aabb3f &box_0,
f32 stepheight, f32 dtime,
v3f &pos_f, v3f &speed_f, v3f &accel_f)
{
Map *map = &env->getMap();
//TimeTaker tt("collisionMoveSimple");
ScopeProfiler sp(g_profiler, "collisionMoveSimple avg", SPT_AVG);
@ -215,6 +219,7 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
std::vector<aabb3f> cboxes;
std::vector<bool> is_unloaded;
std::vector<bool> is_step_up;
std::vector<bool> is_object;
std::vector<int> bouncy_values;
std::vector<v3s16> node_positions;
{
@ -256,6 +261,7 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
is_step_up.push_back(false);
bouncy_values.push_back(n_bouncy_value);
node_positions.push_back(p);
is_object.push_back(false);
}
}
catch(InvalidPositionException &e)
@ -267,14 +273,72 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
is_step_up.push_back(false);
bouncy_values.push_back(0);
node_positions.push_back(p);
is_object.push_back(false);
}
}
} // tt2
{
ScopeProfiler sp(g_profiler, "collisionMoveSimple objects avg", SPT_AVG);
//TimeTaker tt3("collisionMoveSimple collect object boxes");
/* add object boxes to cboxes */
std::list<ActiveObject*> objects;
#ifndef SERVER
ClientEnvironment *c_env = dynamic_cast<ClientEnvironment*>(env);
if (c_env != 0)
{
f32 distance = speed_f.getLength();
std::vector<DistanceSortedActiveObject> clientobjects;
c_env->getActiveObjects(pos_f,distance * 1.5,clientobjects);
for (int i=0; i < clientobjects.size(); i++)
{
objects.push_back((ActiveObject*)clientobjects[i].obj);
}
}
else
#endif
{
ServerEnvironment *s_env = dynamic_cast<ServerEnvironment*>(env);
if (s_env != 0)
{
f32 distance = speed_f.getLength();
std::set<u16> s_objects = s_env->getObjectsInsideRadius(pos_f,distance * 1.5);
for (std::set<u16>::iterator iter = s_objects.begin(); iter != s_objects.end(); iter++)
{
ServerActiveObject *current = s_env->getActiveObject(*iter);
objects.push_back((ActiveObject*)current);
}
}
}
for (std::list<ActiveObject*>::const_iterator iter = objects.begin();iter != objects.end(); ++iter)
{
ActiveObject *object = *iter;
if (object != NULL)
{
aabb3f object_collisionbox;
if (object->getCollisionBox(&object_collisionbox))
{
cboxes.push_back(object_collisionbox);
is_unloaded.push_back(false);
is_step_up.push_back(false);
bouncy_values.push_back(0);
node_positions.push_back(v3s16(0,0,0));
is_object.push_back(true);
}
}
}
} //tt3
assert(cboxes.size() == is_unloaded.size());
assert(cboxes.size() == is_step_up.size());
assert(cboxes.size() == bouncy_values.size());
assert(cboxes.size() == node_positions.size());
assert(cboxes.size() == is_object.size());
/*
Collision detection
@ -386,7 +450,11 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
is_collision = false;
CollisionInfo info;
info.type = COLLISION_NODE;
if (is_object[nearest_boxindex]) {
info.type = COLLISION_OBJECT;
}
else
info.type = COLLISION_NODE;
info.node_p = node_positions[nearest_boxindex];
info.bouncy = bouncy;
info.old_speed = speed_f;

View File

@ -25,10 +25,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Map;
class IGameDef;
class Environment;
enum CollisionType
{
COLLISION_NODE
COLLISION_NODE,
COLLISION_OBJECT,
};
struct CollisionInfo
@ -65,7 +67,7 @@ struct collisionMoveResult
};
// Moves using a single iteration; speed should not exceed pos_max_d/dtime
collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
collisionMoveResult collisionMoveSimple(Environment *env,IGameDef *gamedef,
f32 pos_max_d, const aabb3f &box_0,
f32 stepheight, f32 dtime,
v3f &pos_f, v3f &speed_f, v3f &accel_f);

View File

@ -174,6 +174,7 @@ public:
void processMessage(const std::string &data);
bool getCollisionBox(aabb3f *toset) { return false; }
private:
scene::IMeshSceneNode *m_node;
v3f m_position;
@ -329,6 +330,7 @@ public:
std::string infoText()
{return m_infotext;}
bool getCollisionBox(aabb3f *toset) { return false; }
private:
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
@ -643,6 +645,22 @@ public:
ClientActiveObject::registerType(getType(), create);
}
bool getCollisionBox(aabb3f *toset) {
if (m_prop.physical) {
aabb3f retval;
//update collision box
toset->MinEdge = m_prop.collisionbox.MinEdge * BS;
toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS;
toset->MinEdge += m_position;
toset->MaxEdge += m_position;
return true;
}
return false;
}
void initialize(const std::string &data)
{
infostream<<"GenericCAO: Got init data"<<std::endl;
@ -1127,8 +1145,7 @@ public:
v3f p_pos = m_position;
v3f p_velocity = m_velocity;
v3f p_acceleration = m_acceleration;
IGameDef *gamedef = env->getGameDef();
moveresult = collisionMoveSimple(&env->getMap(), gamedef,
moveresult = collisionMoveSimple(env,env->getGameDef(),
pos_max_d, box, stepheight, dtime,
p_pos, p_velocity, p_acceleration);
// Apply results

View File

@ -42,14 +42,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// (compatible with ContentFeatures). If you specified 0,0,1,1
// for each face, that would be the same as passing NULL.
void makeCuboid(MeshCollector *collector, const aabb3f &box,
const TileSpec *tiles, int tilecount,
TileSpec *tiles, int tilecount,
video::SColor &c, const f32* txc)
{
assert(tilecount >= 1 && tilecount <= 6);
v3f min = box.MinEdge;
v3f max = box.MaxEdge;
if(txc == NULL)
{
static const f32 txc_default[24] = {
@ -97,15 +99,70 @@ void makeCuboid(MeshCollector *collector, const aabb3f &box,
video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[20],txc[23]),
};
for(s32 j=0; j<24; j++)
v2f t;
for(int i = 0; i < tilecount; i++)
{
switch (tiles[i].rotation)
{
case 0:
break;
case 1: //R90
for (int x = 0; x < 4; x++)
vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
break;
case 2: //R180
for (int x = 0; x < 4; x++)
vertices[i*4+x].TCoords.rotateBy(180,irr::core::vector2df(0, 0));
break;
case 3: //R270
for (int x = 0; x < 4; x++)
vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
break;
case 4: //FXR90
for (int x = 0; x < 4; x++)
vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
tiles[i].texture.pos.Y += tiles[i].texture.size.Y;
tiles[i].texture.size.Y *= -1;
break;
case 5: //FXR270
for (int x = 0; x < 4; x++)
vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
t=vertices[i*4].TCoords;
tiles[i].texture.pos.Y += tiles[i].texture.size.Y;
tiles[i].texture.size.Y *= -1;
break;
case 6: //FYR90
for (int x = 0; x < 4; x++)
vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
tiles[i].texture.pos.X += tiles[i].texture.size.X;
tiles[i].texture.size.X *= -1;
break;
case 7: //FYR270
for (int x = 0; x < 4; x++)
vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
tiles[i].texture.pos.X += tiles[i].texture.size.X;
tiles[i].texture.size.X *= -1;
break;
case 8: //FX
tiles[i].texture.pos.Y += tiles[i].texture.size.Y;
tiles[i].texture.size.Y *= -1;
break;
case 9: //FY
tiles[i].texture.pos.X += tiles[i].texture.size.X;
tiles[i].texture.size.X *= -1;
break;
default:
break;
}
}
for(s32 j=0; j<24; j++)
{
int tileindex = MYMIN(j/4, tilecount-1);
vertices[j].TCoords *= tiles[tileindex].texture.size;
vertices[j].TCoords += tiles[tileindex].texture.pos;
}
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
for(s32 j=0; j<24; j+=4)
{
@ -1154,14 +1211,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
v3s16(0, 0, 1),
v3s16(0, 0, -1)
};
TileSpec tiles[6];
for(int i = 0; i < 6; i++)
{
// Handles facedir rotation for textures
tiles[i] = getNodeTile(n, p, tile_dirs[i], data);
}
u16 l = getInteriorLight(n, 0, data);
video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
@ -1172,17 +1223,43 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
i = boxes.begin();
i != boxes.end(); i++)
{
for(int j = 0; j < 6; j++)
{
// Handles facedir rotation for textures
tiles[j] = getNodeTile(n, p, tile_dirs[j], data);
}
aabb3f box = *i;
box.MinEdge += pos;
box.MaxEdge += pos;
f32 temp;
if (box.MinEdge.X > box.MaxEdge.X)
{
temp=box.MinEdge.X;
box.MinEdge.X=box.MaxEdge.X;
box.MaxEdge.X=temp;
}
if (box.MinEdge.Y > box.MaxEdge.Y)
{
temp=box.MinEdge.Y;
box.MinEdge.Y=box.MaxEdge.Y;
box.MaxEdge.Y=temp;
}
if (box.MinEdge.Z > box.MaxEdge.Z)
{
temp=box.MinEdge.Z;
box.MinEdge.Z=box.MaxEdge.Z;
box.MaxEdge.Z=temp;
}
//
// Compute texture coords
f32 tx1 = (i->MinEdge.X/BS)+0.5;
f32 ty1 = (i->MinEdge.Y/BS)+0.5;
f32 tz1 = (i->MinEdge.Z/BS)+0.5;
f32 tx2 = (i->MaxEdge.X/BS)+0.5;
f32 ty2 = (i->MaxEdge.Y/BS)+0.5;
f32 tz2 = (i->MaxEdge.Z/BS)+0.5;
f32 tx1 = (box.MinEdge.X/BS)+0.5;
f32 ty1 = (box.MinEdge.Y/BS)+0.5;
f32 tz1 = (box.MinEdge.Z/BS)+0.5;
f32 tx2 = (box.MaxEdge.X/BS)+0.5;
f32 ty2 = (box.MaxEdge.Y/BS)+0.5;
f32 tz2 = (box.MaxEdge.Z/BS)+0.5;
f32 txc[24] = {
// up
tx1, 1-tz2, tx2, 1-tz1,
@ -1197,7 +1274,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// front
tx1, 1-ty2, tx2, 1-ty1,
};
makeCuboid(&collector, box, tiles, 6, c, txc);
}
break;}

View File

@ -64,6 +64,10 @@ public:
infostream<<"DummyLoadSAO step"<<std::endl;
}
bool getCollisionBox(aabb3f *toset) {
return false;
}
private:
};
@ -132,6 +136,10 @@ public:
}
}
bool getCollisionBox(aabb3f *toset) {
return false;
}
private:
float m_timer1;
float m_age;
@ -208,8 +216,7 @@ public:
v3f pos_f_old = pos_f;
v3f accel_f = v3f(0,0,0);
f32 stepheight = 0;
IGameDef *gamedef = m_env->getGameDef();
moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
moveresult = collisionMoveSimple(m_env,m_env->getGameDef(),
pos_max_d, box, stepheight, dtime,
pos_f, m_speed_f, accel_f);
@ -314,6 +321,10 @@ public:
return 0;
}
bool getCollisionBox(aabb3f *toset) {
return false;
}
private:
std::string m_itemstring;
@ -490,8 +501,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
v3f p_pos = m_base_position;
v3f p_velocity = m_velocity;
v3f p_acceleration = m_acceleration;
IGameDef *gamedef = m_env->getGameDef();
moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
moveresult = collisionMoveSimple(m_env,m_env->getGameDef(),
pos_max_d, box, stepheight, dtime,
p_pos, p_velocity, p_acceleration);
// Apply results
@ -880,6 +890,22 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
m_messages_out.push_back(aom);
}
bool LuaEntitySAO::getCollisionBox(aabb3f *toset) {
if (m_prop.physical)
{
//update collision box
toset->MinEdge = m_prop.collisionbox.MinEdge * BS;
toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS;
toset->MinEdge += m_base_position;
toset->MaxEdge += m_base_position;
return true;
}
return false;
}
/*
PlayerSAO
*/
@ -1434,3 +1460,7 @@ std::string PlayerSAO::getPropertyPacket()
return gob_cmd_set_properties(m_prop);
}
bool PlayerSAO::getCollisionBox(aabb3f *toset) {
//player collision handling is already done clientside no need to do it twice
return false;
}

View File

@ -78,6 +78,7 @@ public:
void setSprite(v2s16 p, int num_frames, float framelength,
bool select_horiz_by_yawpitch);
std::string getName();
bool getCollisionBox(aabb3f *toset);
private:
std::string getPropertyPacket();
void sendPosition(bool do_interpolate, bool is_movement_end);
@ -235,6 +236,8 @@ public:
m_is_singleplayer = is_singleplayer;
}
bool getCollisionBox(aabb3f *toset);
private:
std::string getPropertyPacket();

View File

@ -236,11 +236,16 @@ void set_default_settings(Settings *settings)
settings->setDefault("mgv7_np_heat", "25, 50, (500, 500, 500), 35293, 1, 0");
settings->setDefault("mgv7_np_humidity", "50, 31.25, (750, 750, 750), 12094, 2, 0.6");
settings->setDefault("mgindev_np_terrain_base", "-4, 20, (250.0, 250, 250), 82341, 5, 0.6, 10");
settings->setDefault("mgindev_np_terrain_higher", "20, 16, (500, 500, 500), 85039, 5, 0.6, 10");
settings->setDefault("mgindev_np_steepness", "0.85, 0.5, (125, 125, 125), -932, 5, 0.7, 10");
settings->setDefault("mgindev_np_mud", "4, 2, (200, 200, 200), 91013, 3, 0.55, 1");
settings->setDefault("gravity_acceleration_client", "9.86");
settings->setDefault("mgindev_np_terrain_base", "-4, 20, (250, 250, 250), 82341, 5, 0.6, 10, 10");
settings->setDefault("mgindev_np_terrain_higher", "20, 16, (500, 500, 500), 85039, 5, 0.6, 10, 10");
settings->setDefault("mgindev_np_steepness", "0.85, 0.5, (125, 125, 125), -932, 5, 0.7, 2, 10");
settings->setDefault("mgindev_np_mud", "4, 2, (200, 200, 200), 91013, 3, 0.55, 1, 1");
settings->setDefault("mgindev_np_float_islands1", "0, 1, (64, 64, 64 ), 3683, 5, 0.5, 1, 1.5");
settings->setDefault("mgindev_np_float_islands2", "0, 1, (8, 8, 8 ), 9292, 2, 0.5, 1, 1.5");
settings->setDefault("mgindev_np_float_islands3", "0, 1, (256, 256, 256), 6412, 2, 0.5, 1, 0.5");
settings->setDefault("mgindev_np_biome", "0, 1, (250, 250, 250), 9130, 3, 0.50, 1, 10");
settings->setDefault("mgindev_float_islands", "500");
}
void override_default_settings(Settings *settings, Settings *from)

View File

@ -40,6 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "emerge.h"
#include "mapgen_v6.h"
#include "mapgen_indev.h"
#include "mapgen_singlenode.h"
/////////////////////////////// Emerge Manager ////////////////////////////////
@ -48,6 +49,7 @@ EmergeManager::EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef) {
//register built-in mapgens
registerMapgen("v6", new MapgenFactoryV6());
registerMapgen("indev", new MapgenFactoryIndev());
registerMapgen("singlenode", new MapgenFactorySinglenode());
this->biomedef = bdef ? bdef : new BiomeDefManager(gamedef);
this->params = NULL;

View File

@ -63,8 +63,9 @@ public:
std::map<v3s16, BlockEmergeData *> blocks_enqueued;
std::map<u16, u16> peer_queue_count;
//biome manager
//Mapgen-related structures
BiomeDefManager *biomedef;
std::vector<Ore *> ores;
EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef);
~EmergeManager();

View File

@ -2096,7 +2096,7 @@ void ClientEnvironment::step(float dtime)
Move the lplayer.
This also does collision detection.
*/
lplayer->move(dtime_part, *m_map, position_max_increment,
lplayer->move(dtime_part, this, position_max_increment,
&player_collisions);
}
}

View File

@ -2189,6 +2189,47 @@ void the_game(
{
update_wielded_item_trigger = true;
}
else if(event.type == CE_SPAWN_PARTICLE)
{
LocalPlayer* player = client.getEnv().getLocalPlayer();
AtlasPointer ap =
gamedef->tsrc()->getTexture(*(event.spawn_particle.texture));
new Particle(gamedef, smgr, player, client.getEnv(),
*event.spawn_particle.pos,
*event.spawn_particle.vel,
*event.spawn_particle.acc,
event.spawn_particle.expirationtime,
event.spawn_particle.size,
event.spawn_particle.collisiondetection, ap);
}
else if(event.type == CE_ADD_PARTICLESPAWNER)
{
LocalPlayer* player = client.getEnv().getLocalPlayer();
AtlasPointer ap =
gamedef->tsrc()->getTexture(*(event.add_particlespawner.texture));
new ParticleSpawner(gamedef, smgr, player,
event.add_particlespawner.amount,
event.add_particlespawner.spawntime,
*event.add_particlespawner.minpos,
*event.add_particlespawner.maxpos,
*event.add_particlespawner.minvel,
*event.add_particlespawner.maxvel,
*event.add_particlespawner.minacc,
*event.add_particlespawner.maxacc,
event.add_particlespawner.minexptime,
event.add_particlespawner.maxexptime,
event.add_particlespawner.minsize,
event.add_particlespawner.maxsize,
event.add_particlespawner.collisiondetection,
ap,
event.add_particlespawner.id);
}
else if(event.type == CE_DELETE_PARTICLESPAWNER)
{
delete_particlespawner (event.delete_particlespawner.id);
}
}
}
@ -2418,7 +2459,8 @@ void the_game(
const ContentFeatures &features =
client.getNodeDefManager()->get(n);
addPunchingParticles
(gamedef, smgr, player, nodepos, features.tiles);
(gamedef, smgr, player, client.getEnv(),
nodepos, features.tiles);
}
}
@ -2456,7 +2498,8 @@ void the_game(
const ContentFeatures &features =
client.getNodeDefManager()->get(wasnode);
addDiggingParticles
(gamedef, smgr, player, nodepos, features.tiles);
(gamedef, smgr, player, client.getEnv(),
nodepos, features.tiles);
}
dig_time = 0;
@ -2737,6 +2780,7 @@ void the_game(
*/
allparticles_step(dtime, client.getEnv());
allparticlespawners_step(dtime, client.getEnv());
/*
Fog
@ -3222,6 +3266,7 @@ void the_game(
clouds->drop();
if(gui_chat_console)
gui_chat_console->drop();
clear_particles ();
/*
Draw a "shutting down" screen, which will be shown while the map

View File

@ -43,6 +43,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "subgame.h"
#define ARRAYLEN(x) (sizeof(x) / sizeof((x)[0]))
#define LSTRING(x) LSTRING_(x)
#define LSTRING_(x) L##x
const wchar_t *contrib_core_strs[] = {
L"Perttu Ahola (celeron55) <celeron55@gmail.com>",
@ -142,6 +144,7 @@ enum
GUI_ID_SHADERS_CB,
GUI_ID_PRELOAD_ITEM_VISUALS_CB,
GUI_ID_ENABLE_PARTICLES_CB,
GUI_ID_LIQUID_FINITE_CB,
GUI_ID_DAMAGE_CB,
GUI_ID_CREATIVE_CB,
GUI_ID_PUBLIC_CB,
@ -432,6 +435,10 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
e->setDrawBackground(true);
if (m_data->serverlist_show_available == false)
m_data->servers = ServerList::getLocal();
#if USE_CURL
else
m_data->servers = ServerList::getOnline();
#endif
updateGuiServerList();
e->setSelected(0);
}
@ -724,6 +731,13 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
GUI_ID_ENABLE_PARTICLES_CB, wgettext("Enable Particles"));
}
{
core::rect<s32> rect(0, 0, option_w+20+20, 30);
rect += m_topleft_client + v2s32(option_x+175*2, option_y+20*3);
Environment->addCheckBox(m_data->liquid_finite, rect, this,
GUI_ID_LIQUID_FINITE_CB, wgettext("Finite liquid"));
}
// Key change button
{
core::rect<s32> rect(0, 0, 120, 30);
@ -750,7 +764,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
core::rect<s32> rect(0, 0, 130, 70);
rect += m_topleft_client + v2s32(35, 160);
Environment->addStaticText(
L"Minetest " VERSION_STRING "\nhttp://minetest.net/",
L"Minetest " LSTRING(VERSION_STRING) L"\nhttp://minetest.net/",
rect, false, true, this, -1);
}
{
@ -970,6 +984,12 @@ void GUIMainMenu::readInput(MainMenuData *dst)
dst->enable_particles = ((gui::IGUICheckBox*)e)->isChecked();
}
{
gui::IGUIElement *e = getElementFromId(GUI_ID_LIQUID_FINITE_CB);
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
dst->liquid_finite = ((gui::IGUICheckBox*)e)->isChecked();
}
{
gui::IGUIElement *e = getElementFromId(GUI_ID_WORLD_LISTBOX);
if(e != NULL && e->getType() == gui::EGUIET_LIST_BOX)

View File

@ -52,6 +52,7 @@ struct MainMenuData
int enable_shaders;
bool preload_item_visuals;
bool enable_particles;
bool liquid_finite;
// Server options
bool creative_mode;
bool enable_damage;
@ -71,7 +72,13 @@ struct MainMenuData
MainMenuData():
// Generic
selected_tab(0),
selected_tab(
#if USE_CURL
1
#else
0
#endif
),
// Client opts
fancy_trees(false),
smooth_lighting(false),
@ -84,7 +91,13 @@ struct MainMenuData
// Actions
only_refresh(false),
serverlist_show_available(false)
serverlist_show_available(
#if USE_CURL
true
#else
false
#endif
)
{}
};

View File

@ -903,6 +903,10 @@ void Inventory::deSerialize(std::istream &is)
m_lists.push_back(list);
}
else
{
throw SerializationError("invalid inventory specifier");
}
}
}

View File

@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gamedef.h"
#include "nodedef.h"
#include "settings.h"
#include "environment.h"
#include "map.h"
#include "util/numeric.h"
@ -57,9 +58,10 @@ LocalPlayer::~LocalPlayer()
{
}
void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
void LocalPlayer::move(f32 dtime, ClientEnvironment *env, f32 pos_max_d,
std::list<CollisionInfo> *collision_info)
{
Map *map = &env->getMap();
INodeDefManager *nodemgr = m_gamedef->ndef();
v3f position = getPosition();
@ -97,15 +99,15 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
if(in_liquid)
{
v3s16 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
in_liquid = nodemgr->get(map.getNode(pp).getContent()).isLiquid();
liquid_viscosity = nodemgr->get(map.getNode(pp).getContent()).liquid_viscosity;
in_liquid = nodemgr->get(map->getNode(pp).getContent()).isLiquid();
liquid_viscosity = nodemgr->get(map->getNode(pp).getContent()).liquid_viscosity;
}
// If not in liquid, the threshold of going in is at lower y
else
{
v3s16 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
in_liquid = nodemgr->get(map.getNode(pp).getContent()).isLiquid();
liquid_viscosity = nodemgr->get(map.getNode(pp).getContent()).liquid_viscosity;
in_liquid = nodemgr->get(map->getNode(pp).getContent()).isLiquid();
liquid_viscosity = nodemgr->get(map->getNode(pp).getContent()).liquid_viscosity;
}
}
catch(InvalidPositionException &e)
@ -118,7 +120,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
*/
try{
v3s16 pp = floatToInt(position + v3f(0,0,0), BS);
in_liquid_stable = nodemgr->get(map.getNode(pp).getContent()).isLiquid();
in_liquid_stable = nodemgr->get(map->getNode(pp).getContent()).isLiquid();
}
catch(InvalidPositionException &e)
{
@ -132,8 +134,8 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
try {
v3s16 pp = floatToInt(position + v3f(0,0.5*BS,0), BS);
v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS);
is_climbing = ((nodemgr->get(map.getNode(pp).getContent()).climbable ||
nodemgr->get(map.getNode(pp2).getContent()).climbable) && !free_move);
is_climbing = ((nodemgr->get(map->getNode(pp).getContent()).climbable ||
nodemgr->get(map->getNode(pp2).getContent()).climbable) && !free_move);
}
catch(InvalidPositionException &e)
{
@ -197,7 +199,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
v3f accel_f = v3f(0,0,0);
collisionMoveResult result = collisionMoveSimple(&map, m_gamedef,
collisionMoveResult result = collisionMoveSimple(env, m_gamedef,
pos_max_d, playerbox, player_stepheight, dtime,
position, m_speed, accel_f);
@ -219,7 +221,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
*/
v3s16 current_node = floatToInt(position - v3f(0,BS/2,0), BS);
if(m_sneak_node_exists &&
nodemgr->get(map.getNodeNoEx(m_old_node_below)).name == "air" &&
nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
m_old_node_below_type != "air")
{
// Old node appears to have been removed; that is,
@ -227,7 +229,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
m_need_to_get_new_sneak_node = false;
m_sneak_node_exists = false;
}
else if(nodemgr->get(map.getNodeNoEx(current_node)).name != "air")
else if(nodemgr->get(map->getNodeNoEx(current_node)).name != "air")
{
// We are on something, so make sure to recalculate the sneak
// node.
@ -267,10 +269,10 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
try{
// The node to be sneaked on has to be walkable
if(nodemgr->get(map.getNode(p)).walkable == false)
if(nodemgr->get(map->getNode(p)).walkable == false)
continue;
// And the node above it has to be nonwalkable
if(nodemgr->get(map.getNode(p+v3s16(0,1,0))).walkable == true)
if(nodemgr->get(map->getNode(p+v3s16(0,1,0))).walkable == true)
continue;
}
catch(InvalidPositionException &e)
@ -331,7 +333,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
{
camera_barely_in_ceiling = false;
v3s16 camera_np = floatToInt(getEyePosition(), BS);
MapNode n = map.getNodeNoEx(camera_np);
MapNode n = map->getNodeNoEx(camera_np);
if(n.getContent() != CONTENT_IGNORE){
if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){
camera_barely_in_ceiling = true;
@ -343,21 +345,21 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
Update the node last under the player
*/
m_old_node_below = floatToInt(position - v3f(0,BS/2,0), BS);
m_old_node_below_type = nodemgr->get(map.getNodeNoEx(m_old_node_below)).name;
m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
/*
Check properties of the node on which the player is standing
*/
const ContentFeatures &f = nodemgr->get(map.getNodeNoEx(getStandingNodePos()));
const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
// Determine if jumping is possible
m_can_jump = touching_ground && !in_liquid;
if(itemgroup_get(f.groups, "disable_jump"))
m_can_jump = false;
}
void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
void LocalPlayer::move(f32 dtime, ClientEnvironment *env, f32 pos_max_d)
{
move(dtime, map, pos_max_d, NULL);
move(dtime, env, pos_max_d, NULL);
}
void LocalPlayer::applyControl(float dtime)

View File

@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "player.h"
#include <list>
class ClientEnvironment;
class LocalPlayer : public Player
{
public:
@ -38,9 +40,9 @@ public:
v3f overridePosition;
void move(f32 dtime, Map &map, f32 pos_max_d,
void move(f32 dtime, ClientEnvironment *env, f32 pos_max_d,
std::list<CollisionInfo> *collision_info);
void move(f32 dtime, Map &map, f32 pos_max_d);
void move(f32 dtime, ClientEnvironment *env, f32 pos_max_d);
void applyControl(float dtime);

View File

@ -1557,6 +1557,7 @@ int main(int argc, char *argv[])
menudata.enable_shaders = g_settings->getS32("enable_shaders");
menudata.preload_item_visuals = g_settings->getBool("preload_item_visuals");
menudata.enable_particles = g_settings->getBool("enable_particles");
menudata.liquid_finite = g_settings->getBool("liquid_finite");
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, menudata.mip_map);
menudata.creative_mode = g_settings->getBool("creative_mode");
menudata.enable_damage = g_settings->getBool("enable_damage");
@ -1724,6 +1725,8 @@ int main(int argc, char *argv[])
}
playername = wide_to_narrow(menudata.name);
if (playername == "")
playername = std::string("Guest") + itos(myrand_range(1000,9999));
password = translatePassword(playername, menudata.password);
//infostream<<"Main: password hash: '"<<password<<"'"<<std::endl;
@ -1747,6 +1750,7 @@ int main(int argc, char *argv[])
g_settings->setS32("enable_shaders", menudata.enable_shaders);
g_settings->set("preload_item_visuals", itos(menudata.preload_item_visuals));
g_settings->set("enable_particles", itos(menudata.enable_particles));
g_settings->set("liquid_finite", itos(menudata.liquid_finite));
g_settings->set("creative_mode", itos(menudata.creative_mode));
g_settings->set("enable_damage", itos(menudata.enable_damage));

View File

@ -50,7 +50,7 @@ class NodeMetadata;
class IGameDef;
class IRollbackReportSink;
class EmergeManager;
class BlockMakeData;
struct BlockMakeData;
/*

View File

@ -455,6 +455,80 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
v3f vertex_pos[4];
v3s16 vertex_dirs[4];
getNodeVertexDirs(dir, vertex_dirs);
v3s16 t;
switch (tile.rotation)
{
case 0:
break;
case 1: //R90
t = vertex_dirs[0];
vertex_dirs[0] = vertex_dirs[3];
vertex_dirs[3] = vertex_dirs[2];
vertex_dirs[2] = vertex_dirs[1];
vertex_dirs[1] = t;
break;
case 2: //R180
t = vertex_dirs[0];
vertex_dirs[0] = vertex_dirs[2];
vertex_dirs[2] = t;
t = vertex_dirs[1];
vertex_dirs[1] = vertex_dirs[3];
vertex_dirs[3] = t;
break;
case 3: //R270
t = vertex_dirs[0];
vertex_dirs[0] = vertex_dirs[1];
vertex_dirs[1] = vertex_dirs[2];
vertex_dirs[2] = vertex_dirs[3];
vertex_dirs[3] = t;
break;
case 4: //FXR90
t = vertex_dirs[0];
vertex_dirs[0] = vertex_dirs[3];
vertex_dirs[3] = vertex_dirs[2];
vertex_dirs[2] = vertex_dirs[1];
vertex_dirs[1] = t;
tile.texture.pos.Y += tile.texture.size.Y;
tile.texture.size.Y *= -1;
break;
case 5: //FXR270
t = vertex_dirs[0];
vertex_dirs[0] = vertex_dirs[1];
vertex_dirs[1] = vertex_dirs[2];
vertex_dirs[2] = vertex_dirs[3];
vertex_dirs[3] = t;
tile.texture.pos.Y += tile.texture.size.Y;
tile.texture.size.Y *= -1;
break;
case 6: //FYR90
t = vertex_dirs[0];
vertex_dirs[0] = vertex_dirs[3];
vertex_dirs[3] = vertex_dirs[2];
vertex_dirs[2] = vertex_dirs[1];
vertex_dirs[1] = t;
tile.texture.pos.X += tile.texture.size.X;
tile.texture.size.X *= -1;
break;
case 7: //FYR270
t = vertex_dirs[0];
vertex_dirs[0] = vertex_dirs[1];
vertex_dirs[1] = vertex_dirs[2];
vertex_dirs[2] = vertex_dirs[3];
vertex_dirs[3] = t;
tile.texture.pos.X += tile.texture.size.X;
tile.texture.size.X *= -1;
break;
case 8: //FX
tile.texture.pos.Y += tile.texture.size.Y;
tile.texture.size.Y *= -1;
break;
case 9: //FY
tile.texture.pos.X += tile.texture.size.X;
tile.texture.size.X *= -1;
break;
default:
break;
}
for(u16 i=0; i<4; i++)
{
vertex_pos[i] = v3f(
@ -601,60 +675,50 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
// 5 = (0,0,-1)
// 6 = (0,-1,0)
// 7 = (-1,0,0)
u8 dir_i = (dir.X + 2 * dir.Y + 3 * dir.Z) & 7;
u8 dir_i = ((dir.X + 2 * dir.Y + 3 * dir.Z) & 7)*2;
// Get rotation for things like chests
u8 facedir = mn.getFaceDir(ndef);
assert(facedir <= 3);
static const u8 dir_to_tile[4 * 8] =
assert(facedir <= 23);
static const u16 dir_to_tile[24 * 16] =
{
// 0 +X +Y +Z 0 -Z -Y -X
0, 2, 0, 4, 0, 5, 1, 3, // facedir = 0
0, 4, 0, 3, 0, 2, 1, 5, // facedir = 1
0, 3, 0, 5, 0, 4, 1, 2, // facedir = 2
0, 5, 0, 2, 0, 3, 1, 4, // facedir = 3
// 0 +X +Y +Z -Z -Y -X -> value=tile,rotation
0,0, 2,0 , 0,0 , 4,0 , 0,0, 5,0 , 1,0 , 3,0 , // rotate around y+ 0 - 3
0,0, 4,0 , 0,3 , 3,0 , 0,0, 2,0 , 1,1 , 5,0 ,
0,0, 3,0 , 0,2 , 5,0 , 0,0, 4,0 , 1,2 , 2,0 ,
0,0, 5,0 , 0,1 , 2,0 , 0,0, 3,0 , 1,3 , 4,0 ,
0,0, 2,3 , 5,0 , 0,2 , 0,0, 1,0 , 4,2 , 3,1 , // rotate around z+ 4 - 7
0,0, 4,3 , 2,0 , 0,3 , 0,0, 1,1 , 3,2 , 5,1 ,
0,0, 3,3 , 4,0 , 0,0 , 0,0, 1,2 , 5,2 , 2,1 ,
0,0, 5,3 , 3,0 , 0,1 , 0,0, 1,3 , 2,2 , 4,1 ,
0,0, 2,1 , 4,2 , 1,2 , 0,0, 0,0 , 5,0 , 3,3 , // rotate around z- 8 - 11
0,0, 4,1 , 3,2 , 1,3 , 0,0, 0,3 , 2,0 , 5,3 ,
0,0, 3,1 , 5,2 , 1,0 , 0,0, 0,2 , 4,0 , 2,3 ,
0,0, 5,1 , 2,2 , 1,1 , 0,0, 0,1 , 3,0 , 4,3 ,
0,0, 0,3 , 3,3 , 4,1 , 0,0, 5,3 , 2,3 , 1,3 , // rotate around x+ 12 - 15
0,0, 0,2 , 5,3 , 3,1 , 0,0, 2,3 , 4,3 , 1,0 ,
0,0, 0,1 , 2,3 , 5,1 , 0,0, 4,3 , 3,3 , 1,1 ,
0,0, 0,0 , 4,3 , 2,1 , 0,0, 3,3 , 5,3 , 1,2 ,
0,0, 1,1 , 2,1 , 4,3 , 0,0, 5,1 , 3,1 , 0,1 , // rotate around x- 16 - 19
0,0, 1,2 , 4,1 , 3,3 , 0,0, 2,1 , 5,1 , 0,0 ,
0,0, 1,3 , 3,1 , 5,3 , 0,0, 4,1 , 2,1 , 0,3 ,
0,0, 1,0 , 5,1 , 2,3 , 0,0, 3,1 , 4,1 , 0,2 ,
0,0, 3,2 , 1,2 , 4,2 , 0,0, 5,2 , 0,2 , 2,2 , // rotate around y- 20 - 23
0,0, 5,2 , 1,3 , 3,2 , 0,0, 2,2 , 0,1 , 4,2 ,
0,0, 2,2 , 1,0 , 5,2 , 0,0, 4,2 , 0,0 , 3,2 ,
0,0, 4,2 , 1,1 , 2,2 , 0,0, 3,2 , 0,3 , 5,2
};
u8 tileindex = dir_to_tile[facedir*8 + dir_i];
// If not rotated or is side tile, we're done
if(facedir == 0 || (tileindex != 0 && tileindex != 1))
return getNodeTileN(mn, p, tileindex, data);
// This is the top or bottom tile, and it shall be rotated; thus rotate it
TileSpec spec = getNodeTileN(mn, p, tileindex, data);
if(tileindex == 0){
if(facedir == 1){ // -90
std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
name += "^[transformR270";
spec.texture = data->m_gamedef->tsrc()->getTexture(name);
}
else if(facedir == 2){ // 180
spec.texture.pos += spec.texture.size;
spec.texture.size *= -1;
}
else if(facedir == 3){ // 90
std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
name += "^[transformR90";
spec.texture = data->m_gamedef->tsrc()->getTexture(name);
}
}
else if(tileindex == 1){
if(facedir == 1){ // -90
std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
name += "^[transformR90";
spec.texture = data->m_gamedef->tsrc()->getTexture(name);
}
else if(facedir == 2){ // 180
spec.texture.pos += spec.texture.size;
spec.texture.size *= -1;
}
else if(facedir == 3){ // 90
std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
name += "^[transformR270";
spec.texture = data->m_gamedef->tsrc()->getTexture(name);
}
}
u16 tile_index=facedir*16 + dir_i;
TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data);
spec.rotation=dir_to_tile[tile_index + 1];
std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
spec.texture = data->m_gamedef->tsrc()->getTexture(name);
return spec;
}
@ -794,6 +858,7 @@ static void updateFastFaceRow(
&& next_lights[2] == lights[2]
&& next_lights[3] == lights[3]
&& next_tile == tile
&& tile.rotation == 0
&& next_light_source == light_source)
{
next_is_different = false;

View File

@ -49,6 +49,141 @@ FlagDesc flagdesc_mapgen[] = {
///////////////////////////////////////////////////////////////////////////////
Ore *createOre(OreType type) {
switch (type) {
case ORE_SCATTER:
return new OreScatter;
case ORE_SHEET:
return new OreSheet;
//case ORE_CLAYLIKE: //TODO: implement this!
// return new OreClaylike;
default:
return NULL;
}
}
void Ore::resolveNodeNames(INodeDefManager *ndef) {
if (ore == CONTENT_IGNORE) {
ore = ndef->getId(ore_name);
if (ore == CONTENT_IGNORE) {
errorstream << "Ore::resolveNodeNames: ore node '"
<< ore_name << "' not defined";
ore = CONTENT_AIR;
wherein = CONTENT_AIR;
}
}
if (wherein == CONTENT_IGNORE) {
wherein = ndef->getId(wherein_name);
if (wherein == CONTENT_IGNORE) {
errorstream << "Ore::resolveNodeNames: wherein node '"
<< wherein_name << "' not defined";
ore = CONTENT_AIR;
wherein = CONTENT_AIR;
}
}
}
void OreScatter::generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) {
if (nmin.Y > height_max || nmax.Y < height_min)
return;
resolveNodeNames(mg->ndef);
MapNode n_ore(ore);
ManualMapVoxelManipulator *vm = mg->vm;
PseudoRandom pr(blockseed);
int ymin = MYMAX(nmin.Y, height_min);
int ymax = MYMIN(nmax.Y, height_max);
if (clust_size >= ymax - ymin + 1)
return;
int volume = (nmax.X - nmin.X + 1) *
(nmax.Y - nmin.Y + 1) *
(nmax.Z - nmin.Z + 1);
int csize = clust_size;
int orechance = (csize * csize * csize) / clust_num_ores;
int nclusters = volume / clust_scarcity;
for (int i = 0; i != nclusters; i++) {
int x0 = pr.range(nmin.X, nmax.X - csize + 1);
int y0 = pr.range(ymin, ymax - csize + 1);
int z0 = pr.range(nmin.Z, nmax.Z - csize + 1);
if (np && (NoisePerlin3D(np, x0, y0, z0, mg->seed) < nthresh))
continue;
for (int z1 = 0; z1 != csize; z1++)
for (int y1 = 0; y1 != csize; y1++)
for (int x1 = 0; x1 != csize; x1++) {
if (pr.range(1, orechance) != 1)
continue;
u32 i = vm->m_area.index(x0 + x1, y0 + y1, z0 + z1);
if (vm->m_data[i].getContent() == wherein)
vm->m_data[i] = n_ore;
}
}
}
void OreSheet::generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) {
if (nmin.Y > height_max || nmax.Y < height_min)
return;
resolveNodeNames(mg->ndef);
MapNode n_ore(ore);
ManualMapVoxelManipulator *vm = mg->vm;
PseudoRandom pr(blockseed + 4234);
int ymin = MYMAX(nmin.Y, height_min);
int ymax = MYMIN(nmax.Y, height_max);
if (clust_size >= ymax - ymin + 1)
return;
int x0 = nmin.X;
int z0 = nmin.Z;
int x1 = nmax.X;
int z1 = nmax.Z;
int max_height = clust_size;
int y_start = pr.range(ymin, ymax - max_height);
if (!noise) {
int sx = nmax.X - nmin.X + 1;
int sz = nmax.Z - nmin.Z + 1;
noise = new Noise(np, 0, sx, sz);
}
noise->seed = mg->seed + y_start;
noise->perlinMap2D(x0, z0);
int index = 0;
for (int z = z0; z != z1; z++)
for (int x = x0; x != x1; x++) {
float noiseval = noise->result[index++];
if (noiseval < nthresh)
continue;
int height = max_height * (1. / pr.range(1, 3));
int y0 = y_start + np->scale * noiseval; //pr.range(1, 3) - 1;
int y1 = y0 + height;
for (int y = y0; y != y1; y++) {
u32 i = vm->m_area.index(x, y, z);
if (!vm->m_area.contains(i))
continue;
if (vm->m_data[i].getContent() == wherein)
vm->m_data[i] = n_ore;
}
}
}
void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax) {
bool isliquid, wasliquid;
v3s16 em = vm->m_area.getExtent();

View File

@ -45,7 +45,7 @@ class MapBlock;
class ManualMapVoxelManipulator;
class VoxelManipulator;
class INodeDefManager;
class BlockMakeData;
struct BlockMakeData;
class VoxelArea;
struct MapgenParams {
@ -97,5 +97,48 @@ struct MapgenFactory {
virtual MapgenParams *createMapgenParams() = 0;
};
enum OreType {
ORE_SCATTER,
ORE_SHEET,
ORE_CLAYLIKE
};
class Ore {
public:
std::string ore_name;
std::string wherein_name;
content_t ore;
content_t wherein; // the node to be replaced
s16 clust_scarcity; //
s16 clust_num_ores; // how many ore nodes are in a chunk
s16 clust_size; // how large (in nodes) a chunk of ore is
s16 height_min;
s16 height_max;
float nthresh; // threshhold for noise at which an ore is placed
NoiseParams *np; // noise for distribution of clusters (NULL for uniform scattering)
Noise *noise;
Ore() {
ore = CONTENT_IGNORE;
wherein = CONTENT_IGNORE;
np = NULL;
noise = NULL;
}
void resolveNodeNames(INodeDefManager *ndef);
virtual void generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) = 0;
};
class OreScatter : public Ore {
void generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
};
class OreSheet : public Ore {
void generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
};
Ore *createOre(OreType type);
#endif

View File

@ -19,18 +19,27 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapgen_indev.h"
#include "constants.h"
#include "map.h"
#include "main.h"
#include "log.h"
/////////////////// Mapgen Indev perlin noise default values
/////////////////// Mapgen Indev perlin noise (default values - not used, from config or defaultsettings)
NoiseIndevParams nparams_indev_def_terrain_base
(-AVERAGE_MUD_AMOUNT, 20.0, v3f(250.0, 250.0, 250.0), 82341, 5, 0.6, 1);
NoiseIndevParams nparams_indev_def_terrain_higher
(20.0, 16.0, v3f(500.0, 500.0, 500.0), 85039, 5, 0.6, 1);
NoiseIndevParams nparams_indev_def_steepness
(0.85, 0.5, v3f(125.0, 125.0, 125.0), -932, 5, 0.7, 1);
NoiseIndevParams nparams_indev_def_mud
(AVERAGE_MUD_AMOUNT, 2.0, v3f(200.0, 200.0, 200.0), 91013, 3, 0.55, 1);
NoiseIndevParams nparams_indev_def;
/*
NoiseIndevParams nparams_indev_def_terrain_base;
// (-AVERAGE_MUD_AMOUNT, 20.0, v3f(250.0, 250.0, 250.0), 82341, 5, 0.6, 1);
NoiseIndevParams nparams_indev_def_terrain_higher;
// (20.0, 16.0, v3f(500.0, 500.0, 500.0), 85039, 5, 0.6, 1);
NoiseIndevParams nparams_indev_def_steepness;
// (0.85, 0.5, v3f(125.0, 125.0, 125.0), -932, 5, 0.7, 1);
NoiseIndevParams nparams_indev_def_mud;
// (AVERAGE_MUD_AMOUNT, 2.0, v3f(200.0, 200.0, 200.0), 91013, 3, 0.55, 1);
NoiseIndevParams nparams_indev_def_float_islands;
// (1, 10.0, v3f(500.0, 500.0, 500.0), 32451, 5, 0.6, 1);
NoiseIndevParams nparams_indev_def_biome;
*/
///////////////////////////////////////////////////////////////////////////////
@ -39,46 +48,52 @@ void NoiseIndev::init(NoiseIndevParams *np, int seed, int sx, int sy, int sz) {
this->npindev = np;
}
NoiseIndev::NoiseIndev(NoiseIndevParams *np, int seed, int sx, int sy) : Noise(np, seed, sx, sy) {
init(np, seed, sx, sy, 1);
}
NoiseIndev::NoiseIndev(NoiseIndevParams *np, int seed, int sx, int sy, int sz) : Noise(np, seed, sx, sy, sz) {
init(np, seed, sx, sy, sz);
}
float farscale(float scale, float z) {
return ( 1 + ( 1 - (MAP_GENERATION_LIMIT * 1 - (fabs(z)) ) / (MAP_GENERATION_LIMIT * 1) ) * (scale - 1) );
}
float farscale(float scale, float x, float z) {
return ( 1 + ( 1 - (MAP_GENERATION_LIMIT * 2 - (fabs(x) + fabs(z)) ) / (MAP_GENERATION_LIMIT * 2) ) * (scale - 1) );
}
float farscale(float scale, float x, float y, float z) {
return ( 1 + ( 1 - (MAP_GENERATION_LIMIT * 3 - (fabs(x) + fabs(y) + fabs(z)) ) / (MAP_GENERATION_LIMIT * 3) ) * (scale - 1) );
}
void NoiseIndev::transformNoiseMapFarScale(float xx, float yy, float zz) {
// more correct use distantion from 0,0,0 via pow, but + is faster
//float farscale = ( 1 + ( 1 - (MAP_GENERATION_LIMIT * 3 - (fabs(xx) + fabs(yy) + fabs(zz)) ) / (MAP_GENERATION_LIMIT * 3) ) * ((npindev)->farscale - 1) );
// dstream << "TNM rs=" << farscale << " from=" << (npindev)->farscale << " x=" << xx << " y=" << yy <<" z=" << zz << std::endl;
int i = 0;
for (int z = 0; z != sz; z++) {
for (int y = 0; y != sy; y++) {
for (int x = 0; x != sx; x++) {
//result[i] = result[i] * npindev->scale * farscale + npindev->offset;
result[i] = result[i] * npindev->scale * farscale(npindev->farscale,xx,yy,zz) + npindev->offset;
result[i] = result[i] * npindev->scale * farscale(npindev->farscale, xx, yy, zz) + npindev->offset;
i++;
}
}
}
}
MapgenIndev::MapgenIndev(int mapgenid, MapgenIndevParams *params) : MapgenV6(mapgenid, params) {
noiseindev_terrain_base = new NoiseIndev(params->npindev_terrain_base, seed, csize.X, csize.Y);
noiseindev_terrain_higher = new NoiseIndev(params->npindev_terrain_higher, seed, csize.X, csize.Y);
noiseindev_steepness = new NoiseIndev(params->npindev_steepness, seed, csize.X, csize.Y);
MapgenIndev::MapgenIndev(int mapgenid, MapgenIndevParams *params, EmergeManager *emerge)
: MapgenV6(mapgenid, params, emerge)
{
noiseindev_terrain_base = new NoiseIndev(params->npindev_terrain_base, seed, csize.X, csize.Z);
noiseindev_terrain_higher = new NoiseIndev(params->npindev_terrain_higher, seed, csize.X, csize.Z);
noiseindev_steepness = new NoiseIndev(params->npindev_steepness, seed, csize.X, csize.Z);
// noise_height_select = new Noise(params->np_height_select, seed, csize.X, csize.Y);
// noise_trees = new Noise(params->np_trees, seed, csize.X, csize.Y);
noiseindev_mud = new NoiseIndev(params->npindev_mud, seed, csize.X, csize.Y);
noiseindev_mud = new NoiseIndev(params->npindev_mud, seed, csize.X, csize.Z);
// noise_beach = new Noise(params->np_beach, seed, csize.X, csize.Y);
// noise_biome = new Noise(params->np_biome, seed, csize.X, csize.Y);
noiseindev_float_islands1 = new NoiseIndev(params->npindev_float_islands1, seed, csize.X, csize.Y, csize.Z);
noiseindev_float_islands2 = new NoiseIndev(params->npindev_float_islands2, seed, csize.X, csize.Y, csize.Z);
noiseindev_float_islands3 = new NoiseIndev(params->npindev_float_islands3, seed, csize.X, csize.Z);
noiseindev_biome = new NoiseIndev(params->npindev_biome, seed, csize.X, csize.Z);
}
MapgenIndev::~MapgenIndev() {
@ -89,10 +104,12 @@ MapgenIndev::~MapgenIndev() {
//delete noise_trees;
delete noiseindev_mud;
//delete noise_beach;
//delete noise_biome;
delete noiseindev_float_islands1;
delete noiseindev_float_islands2;
delete noiseindev_float_islands3;
delete noiseindev_biome;
}
void MapgenIndev::calculateNoise() {
int x = node_min.X;
int y = node_min.Y;
@ -100,31 +117,49 @@ void MapgenIndev::calculateNoise() {
// Need to adjust for the original implementation's +.5 offset...
if (!(flags & MG_FLAT)) {
noiseindev_terrain_base->perlinMap2D(
x + 0.5 * noiseindev_terrain_base->npindev->spread.X,
z + 0.5 * noiseindev_terrain_base->npindev->spread.Z);
x + 0.5 * noiseindev_terrain_base->npindev->spread.X * farscale(noiseindev_terrain_base->npindev->farspread, x, z),
z + 0.5 * noiseindev_terrain_base->npindev->spread.Z * farscale(noiseindev_terrain_base->npindev->farspread, x, z));
noiseindev_terrain_base->transformNoiseMapFarScale(x, y, z);
//noise_terrain_base->transformNoiseMap();
noiseindev_terrain_higher->perlinMap2D(
x + 0.5 * noiseindev_terrain_higher->npindev->spread.X,
z + 0.5 * noiseindev_terrain_higher->npindev->spread.Z);
x + 0.5 * noiseindev_terrain_higher->npindev->spread.X * farscale(noiseindev_terrain_higher->npindev->farspread, x, z),
z + 0.5 * noiseindev_terrain_higher->npindev->spread.Z * farscale(noiseindev_terrain_higher->npindev->farspread, x, z));
noiseindev_terrain_higher->transformNoiseMapFarScale(x, y, z);
//noise_terrain_higher->transformNoiseMap();
noiseindev_steepness->perlinMap2D(
x + 0.5 * noiseindev_steepness->npindev->spread.X,
z + 0.5 * noiseindev_steepness->npindev->spread.Z);
x + 0.5 * noiseindev_steepness->npindev->spread.X * farscale(noiseindev_steepness->npindev->farspread, x, z),
z + 0.5 * noiseindev_steepness->npindev->spread.Z * farscale(noiseindev_steepness->npindev->farspread, x, z));
noiseindev_steepness->transformNoiseMapFarScale(x, y, z);
noise_height_select->perlinMap2D(
x + 0.5 * noise_height_select->np->spread.X,
z + 0.5 * noise_height_select->np->spread.Z);
noiseindev_float_islands1->perlinMap3D(
x + 0.33 * noiseindev_float_islands1->npindev->spread.X * farscale(noiseindev_float_islands1->npindev->farspread, x, y, z),
y + 0.33 * noiseindev_float_islands1->npindev->spread.Y * farscale(noiseindev_float_islands1->npindev->farspread, x, y, z),
z + 0.33 * noiseindev_float_islands1->npindev->spread.Z * farscale(noiseindev_float_islands1->npindev->farspread, x, y, z)
);
noiseindev_float_islands1->transformNoiseMapFarScale(x, y, z);
noiseindev_float_islands2->perlinMap3D(
x + 0.33 * noiseindev_float_islands2->npindev->spread.X * farscale(noiseindev_float_islands2->npindev->farspread, x, y, z),
y + 0.33 * noiseindev_float_islands2->npindev->spread.Y * farscale(noiseindev_float_islands2->npindev->farspread, x, y, z),
z + 0.33 * noiseindev_float_islands2->npindev->spread.Z * farscale(noiseindev_float_islands2->npindev->farspread, x, y, z)
);
noiseindev_float_islands2->transformNoiseMapFarScale(x, y, z);
noiseindev_float_islands3->perlinMap2D(
x + 0.5 * noiseindev_float_islands3->npindev->spread.X * farscale(noiseindev_float_islands3->npindev->farspread, x, z),
z + 0.5 * noiseindev_float_islands3->npindev->spread.Z * farscale(noiseindev_float_islands3->npindev->farspread, x, z));
noiseindev_float_islands3->transformNoiseMapFarScale(x, y, z);
}
if (!(flags & MG_FLAT)) {
noiseindev_mud->perlinMap2D(
x + 0.5 * noiseindev_mud->npindev->spread.X,
z + 0.5 * noiseindev_mud->npindev->spread.Z);
x + 0.5 * noiseindev_mud->npindev->spread.X * farscale(noiseindev_mud->npindev->farspread, x, y, z),
z + 0.5 * noiseindev_mud->npindev->spread.Z * farscale(noiseindev_mud->npindev->farspread, x, y, z));
noiseindev_mud->transformNoiseMapFarScale(x, y, z);
}
noise_beach->perlinMap2D(
@ -132,8 +167,8 @@ void MapgenIndev::calculateNoise() {
z + 0.7 * noise_beach->np->spread.Z);
noise_biome->perlinMap2D(
x + 0.6 * noise_biome->np->spread.X,
z + 0.2 * noise_biome->np->spread.Z);
x + 0.6 * noiseindev_biome->npindev->spread.X * farscale(noiseindev_biome->npindev->farspread, x, z),
z + 0.2 * noiseindev_biome->npindev->spread.Z * farscale(noiseindev_biome->npindev->farspread, x, z));
}
bool MapgenIndevParams::readParams(Settings *settings) {
@ -147,17 +182,20 @@ bool MapgenIndevParams::readParams(Settings *settings) {
np_trees = settings->getNoiseParams("mgv6_np_trees");
npindev_mud = settings->getNoiseIndevParams("mgindev_np_mud");
np_beach = settings->getNoiseParams("mgv6_np_beach");
np_biome = settings->getNoiseParams("mgv6_np_biome");
npindev_biome = settings->getNoiseIndevParams("mgindev_np_biome");
np_cave = settings->getNoiseParams("mgv6_np_cave");
npindev_float_islands1 = settings->getNoiseIndevParams("mgindev_np_float_islands1");
npindev_float_islands2 = settings->getNoiseIndevParams("mgindev_np_float_islands2");
npindev_float_islands3 = settings->getNoiseIndevParams("mgindev_np_float_islands3");
bool success =
npindev_terrain_base && npindev_terrain_higher && npindev_steepness &&
np_height_select && np_trees && npindev_mud &&
np_beach && np_biome && np_cave;
np_beach && np_biome && np_cave &&
npindev_float_islands1 && npindev_float_islands2 && npindev_float_islands3;
return success;
}
void MapgenIndevParams::writeParams(Settings *settings) {
settings->setFloat("mgv6_freq_desert", freq_desert);
settings->setFloat("mgv6_freq_beach", freq_beach);
@ -169,8 +207,11 @@ void MapgenIndevParams::writeParams(Settings *settings) {
settings->setNoiseParams("mgv6_np_trees", np_trees);
settings->setNoiseIndevParams("mgindev_np_mud", npindev_mud);
settings->setNoiseParams("mgv6_np_beach", np_beach);
settings->setNoiseParams("mgv6_np_biome", np_biome);
settings->setNoiseIndevParams("mgindev_np_biome", npindev_biome);
settings->setNoiseParams("mgv6_np_cave", np_cave);
settings->setNoiseIndevParams("mgindev_np_float_islands1", npindev_float_islands1);
settings->setNoiseIndevParams("mgindev_np_float_islands2", npindev_float_islands2);
settings->setNoiseIndevParams("mgindev_np_float_islands3", npindev_float_islands3);
}
@ -191,7 +232,6 @@ float MapgenIndev::baseTerrainLevelFromNoise(v2s16 p) {
steepness, height_select);
}
float MapgenIndev::baseTerrainLevelFromMap(int index) {
if (flags & MG_FLAT)
return water_level;
@ -205,9 +245,7 @@ float MapgenIndev::baseTerrainLevelFromMap(int index) {
steepness, height_select);
}
float MapgenIndev::getMudAmount(int index)
{
float MapgenIndev::getMudAmount(int index) {
if (flags & MG_FLAT)
return AVERAGE_MUD_AMOUNT;
@ -218,25 +256,19 @@ float MapgenIndev::getMudAmount(int index)
return noiseindev_mud->result[index];
}
void MapgenIndev::defineCave(Cave & cave, PseudoRandom ps, v3s16 node_min, bool large_cave) {
cave.min_tunnel_diameter = 2;
cave.max_tunnel_diameter = ps.range(2,6);
cave.dswitchint = ps.range(1,14);
//cave.tunnel_routepoints = 0;
//cave.part_max_length_rs = 0;
cave.flooded = large_cave && ps.range(0,4);
if(large_cave){
cave.part_max_length_rs = ps.range(2,4);
//dstream<<"try:"<<farscale(0.2, node_min.X,node_min.Y,node_min.Z)*30<<std::endl;
if (node_min.Y < -500 && !ps.range(0, farscale(0.2, node_min.X,node_min.Y,node_min.Z)*30)) { //huge
cave.flooded = ps.range(0, 1);
//dstream<<"HUGE:"<<cave.flooded<<std::endl;
cave.tunnel_routepoints = ps.range(5, 1522);
if (node_min.Y < -100 && !ps.range(0, farscale(0.2, node_min.X,node_min.Y,node_min.Z)*30)) { //huge
cave.flooded = !ps.range(0, 3);
cave.tunnel_routepoints = ps.range(5, 20);
cave.min_tunnel_diameter = 30;
cave.max_tunnel_diameter = ps.range(30, ps.range(80,120));
cave.max_tunnel_diameter = ps.range(40, ps.range(80,120));
} else {
//dstream<<"large:"<<cave.flooded<<std::endl;
cave.tunnel_routepoints = ps.range(5, ps.range(15,30));
cave.min_tunnel_diameter = 5;
cave.max_tunnel_diameter = ps.range(7, ps.range(8,24));
@ -247,3 +279,93 @@ void MapgenIndev::defineCave(Cave & cave, PseudoRandom ps, v3s16 node_min, bool
}
cave.large_cave_is_flat = (ps.range(0,1) == 0);
}
/*
// version with one perlin3d. use with good params like
settings->setDefault("mgindev_np_float_islands1", "-9.5, 10, (20, 50, 50 ), 45123, 5, 0.6, 1.5, 5");
void MapgenIndev::generateFloatIslands(int min_y) {
if (node_min.Y < min_y) return;
v3s16 p0(node_min.X, node_min.Y, node_min.Z);
MapNode n1(c_stone), n2(c_desert_stone);
int xl = node_max.X - node_min.X;
int yl = node_max.Y - node_min.Y;
int zl = node_max.Z - node_min.Z;
u32 index = 0;
for (int x1 = 0; x1 <= xl; x1++)
{
//int x = x1 + node_min.Y;
for (int z1 = 0; z1 <= zl; z1++)
{
//int z = z1 + node_min.Z;
for (int y1 = 0; y1 <= yl; y1++, index++)
{
//int y = y1 + node_min.Y;
float noise = noiseindev_float_islands1->result[index];
//dstream << " y1="<<y1<< " x1="<<x1<<" z1="<<z1<< " noise="<<noise << std::endl;
if (noise > 0 ) {
v3s16 p = p0 + v3s16(x1, y1, z1);
u32 i = vm->m_area.index(p);
if (!vm->m_area.contains(i))
continue;
// Cancel if not air
if (vm->m_data[i].getContent() != CONTENT_AIR)
continue;
vm->m_data[i] = noise > 1 ? n1 : n2;
}
}
}
}
}
*/
void MapgenIndev::generateFloatIslands(int min_y) {
if (node_min.Y < min_y) return;
PseudoRandom pr(blockseed + 985);
// originally from http://forum.minetest.net/viewtopic.php?id=4776
float RAR = 0.8 * farscale(0.4, node_min.Y); // 0.4; // Island rarity in chunk layer. -0.4 = thick layer with holes, 0 = 50%, 0.4 = desert rarity, 0.7 = very rare.
float AMPY = 24; // 24; // Amplitude of island centre y variation.
float TGRAD = 24; // 24; // Noise gradient to create top surface. Tallness of island top.
float BGRAD = 24; // 24; // Noise gradient to create bottom surface. Tallness of island bottom.
v3s16 p0(node_min.X, node_min.Y, node_min.Z);
MapNode n1(c_stone);
float xl = node_max.X - node_min.X;
float yl = node_max.Y - node_min.Y;
float zl = node_max.Z - node_min.Z;
float midy = node_min.Y + yl * 0.5;
u32 index = 0, index2d = 0;
for (int x1 = 0; x1 <= xl; ++x1)
{
for (int z1 = 0; z1 <= zl; ++z1, ++index2d)
{
float noise3 = noiseindev_float_islands3->result[index2d];
float pmidy = midy + noise3 / 1.5 * AMPY;
for (int y1 = 0; y1 <= yl; ++y1, ++index)
{
int y = y1 + node_min.Y;
float noise1 = noiseindev_float_islands1->result[index];
float offset = y > pmidy ? (y - pmidy) / TGRAD : (pmidy - y) / BGRAD;
float noise1off = noise1 - offset - RAR;
if (noise1off > 0 && noise1off < 0.7) {
float noise2 = noiseindev_float_islands2->result[index];
if (noise2 - noise1off > -0.7){
v3s16 p = p0 + v3s16(x1, y1, z1);
u32 i = vm->m_area.index(p);
if (!vm->m_area.contains(i))
continue;
// Cancel if not air
if (vm->m_data[i].getContent() != CONTENT_AIR)
continue;
vm->m_data[i] = n1;
}
}
}
}
}
}
void MapgenIndev::generateSomething() {
int float_islands = g_settings->getS16("mgindev_float_islands");
if(float_islands) generateFloatIslands(float_islands);
}

View File

@ -23,30 +23,32 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapgen.h"
#include "mapgen_v6.h"
float farscale(float scale, float z);
float farscale(float scale, float x, float z);
float farscale(float scale, float x, float y, float z);
struct NoiseIndevParams : public NoiseParams {
float farscale;
float farspread;
NoiseIndevParams(){}
NoiseIndevParams(float offset_, float scale_, v3f spread_, int seed_, int octaves_, float persist_, float farscale_)
//:NoiseParams(offset_, scale_, spread_, seed_, octaves_, persist_)
NoiseIndevParams(float offset_, float scale_, v3f spread_, int seed_, int octaves_, float persist_, float farscale_ = 1, float farspread_ = 1)
{
//NoiseParams(float offset_, float scale_, v3f spread_, int seed_, int octaves_, float persist_) {
offset = offset_;
scale = scale_;
spread = spread_;
seed = seed_;
octaves = octaves_;
persist = persist_;
//}
farscale = farscale_;
farspread = farspread_;
}
};
#define getNoiseIndevParams(x) getStruct<NoiseIndevParams>((x), "f,f,v3,s32,s32,f,f")
#define setNoiseIndevParams(x, y) setStruct((x), "f,f,v3,s32,s32,f,f", (y))
#define getNoiseIndevParams(x) getStruct<NoiseIndevParams>((x), "f,f,v3,s32,s32,f,f,f")
#define setNoiseIndevParams(x, y) setStruct((x), "f,f,v3,s32,s32,f,f,f", (y))
class NoiseIndev : public Noise {
public:
@ -59,6 +61,8 @@ class NoiseIndev : public Noise {
void transformNoiseMapFarScale(float xx = 0, float yy = 0, float zz = 0);
};
extern NoiseIndevParams nparams_indev_def;
/*
extern NoiseIndevParams nparams_indev_def_terrain_base;
extern NoiseIndevParams nparams_indev_def_terrain_higher;
extern NoiseIndevParams nparams_indev_def_steepness;
@ -66,9 +70,10 @@ extern NoiseIndevParams nparams_indev_def_steepness;
//extern NoiseIndevParams nparams_indev_def_trees;
extern NoiseIndevParams nparams_indev_def_mud;
//extern NoiseIndevParams nparams_indev_def_beach;
//extern NoiseIndevParams nparams_indev_def_biome;
extern NoiseIndevParams nparams_indev_def_biome;
//extern NoiseIndevParams nparams_indev_def_cave;
extern NoiseIndevParams nparams_indev_def_float_islands;
*/
struct MapgenIndevParams : public MapgenV6Params {
NoiseIndevParams *npindev_terrain_base;
@ -78,21 +83,28 @@ struct MapgenIndevParams : public MapgenV6Params {
//NoiseParams *np_trees;
NoiseIndevParams *npindev_mud;
//NoiseParams *np_beach;
//NoiseParams *np_biome;
NoiseIndevParams *npindev_biome;
//NoiseParams *np_cave;
NoiseIndevParams *npindev_float_islands1;
NoiseIndevParams *npindev_float_islands2;
NoiseIndevParams *npindev_float_islands3;
MapgenIndevParams() {
//freq_desert = 0.45;
//freq_beach = 0.15;
npindev_terrain_base = &nparams_indev_def_terrain_base;
npindev_terrain_higher = &nparams_indev_def_terrain_higher;
npindev_steepness = &nparams_indev_def_steepness;
npindev_terrain_base = &nparams_indev_def; //&nparams_indev_def_terrain_base;
npindev_terrain_higher = &nparams_indev_def; //&nparams_indev_def_terrain_higher;
npindev_steepness = &nparams_indev_def; //&nparams_indev_def_steepness;
//np_height_select = &nparams_v6_def_height_select;
//np_trees = &nparams_v6_def_trees;
npindev_mud = &nparams_indev_def_mud;
npindev_mud = &nparams_indev_def; //&nparams_indev_def_mud;
//np_beach = &nparams_v6_def_beach;
//np_biome = &nparams_v6_def_biome;
npindev_biome = &nparams_indev_def; //&nparams_indev_def_biome;
//np_cave = &nparams_v6_def_cave;
npindev_float_islands1 = &nparams_indev_def; //&nparams_indev_def_float_islands;
npindev_float_islands2 = &nparams_indev_def; //&nparams_indev_def_float_islands;
npindev_float_islands3 = &nparams_indev_def; //&nparams_indev_def_float_islands;
}
bool readParams(Settings *settings);
@ -108,10 +120,13 @@ class MapgenIndev : public MapgenV6 {
//NoiseIndev *noise_trees;
NoiseIndev *noiseindev_mud;
//NoiseIndev *noise_beach;
//NoiseIndev *noise_biome;
NoiseIndev *noiseindev_biome;
//NoiseIndevParams *np_cave;
NoiseIndev *noiseindev_float_islands1;
NoiseIndev *noiseindev_float_islands2;
NoiseIndev *noiseindev_float_islands3;
MapgenIndev(int mapgenid, MapgenIndevParams *params);
MapgenIndev(int mapgenid, MapgenIndevParams *params, EmergeManager *emerge);
~MapgenIndev();
void calculateNoise();
@ -119,11 +134,14 @@ class MapgenIndev : public MapgenV6 {
float baseTerrainLevelFromMap(int index);
float getMudAmount(int index);
void defineCave(Cave & cave, PseudoRandom ps, v3s16 node_min, bool large_cave);
void generateSomething();
void generateFloatIslands(int min_y);
};
struct MapgenFactoryIndev : public MapgenFactoryV6 {
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge) {
return new MapgenIndev(mgid, (MapgenIndevParams *)params);
return new MapgenIndev(mgid, (MapgenIndevParams *)params, emerge);
};
MapgenParams *createMapgenParams() {
@ -131,5 +149,4 @@ struct MapgenFactoryIndev : public MapgenFactoryV6 {
};
};
#endif

View File

@ -64,9 +64,10 @@ NoiseParams nparams_v6_def_apple_trees =
///////////////////////////////////////////////////////////////////////////////
MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params) {
MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge) {
this->generating = false;
this->id = mapgenid;
this->emerge = emerge;
this->seed = (int)params->seed;
this->water_level = params->water_level;
@ -422,6 +423,8 @@ void MapgenV6::makeChunk(BlockMakeData *data) {
// Generate general ground level to full area
stone_surface_max_y = generateGround();
generateSomething();
const s16 max_spread_amount = MAP_BLOCKSIZE;
// Limit dirt flow area by 1 because mud is flown into neighbors.
s16 mudflow_minpos = -max_spread_amount + 1;
@ -461,6 +464,12 @@ void MapgenV6::makeChunk(BlockMakeData *data) {
if (flags & MG_TREES)
placeTreesAndJungleGrass();
// Generate the registered ores
for (unsigned int i = 0; i != emerge->ores.size(); i++) {
Ore *ore = emerge->ores[i];
ore->generate(this, blockseed + i, node_min, node_max);
}
// Calculate lighting
calcLighting(node_min, node_max);
@ -492,14 +501,13 @@ void MapgenV6::calculateNoise() {
noise_height_select->perlinMap2D(
x + 0.5 * noise_height_select->np->spread.X,
z + 0.5 * noise_height_select->np->spread.Z);
}
if (!(flags & MG_FLAT)) {
noise_mud->perlinMap2D(
x + 0.5 * noise_mud->np->spread.X,
z + 0.5 * noise_mud->np->spread.Z);
noise_mud->transformNoiseMap();
}
noise_beach->perlinMap2D(
x + 0.2 * noise_beach->np->spread.X,
z + 0.7 * noise_beach->np->spread.Z);

View File

@ -91,6 +91,8 @@ struct MapgenV6Params : public MapgenParams {
class MapgenV6 : public Mapgen {
public:
EmergeManager *emerge;
int ystride;
v3s16 csize;
u32 flags;
@ -128,7 +130,7 @@ public:
content_t c_desert_sand;
content_t c_desert_stone;
MapgenV6(int mapgenid, MapgenV6Params *params);
MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge);
~MapgenV6();
void makeChunk(BlockMakeData *data);
@ -167,11 +169,12 @@ public:
virtual void defineCave(Cave &cave, PseudoRandom ps,
v3s16 node_min, bool large_cave);
void generateCaves(int max_stone_y);
virtual void generateSomething() {}; //for next mapgen
};
struct MapgenFactoryV6 : public MapgenFactory {
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge) {
return new MapgenV6(mgid, (MapgenV6Params *)params);
return new MapgenV6(mgid, (MapgenV6Params *)params, emerge);
};
MapgenParams *createMapgenParams() {

View File

@ -107,7 +107,7 @@ u8 MapNode::getFaceDir(INodeDefManager *nodemgr) const
{
const ContentFeatures &f = nodemgr->get(*this);
if(f.param_type_2 == CPT2_FACEDIR)
return getParam2() & 0x03;
return getParam2() & 0x1F;
return 0;
}
@ -140,29 +140,131 @@ static std::vector<aabb3f> transformNodeBox(const MapNode &n,
{
const std::vector<aabb3f> &fixed = nodebox.fixed;
int facedir = n.getFaceDir(nodemgr);
u8 axisdir = facedir>>2;
facedir&=0x03;
for(std::vector<aabb3f>::const_iterator
i = fixed.begin();
i != fixed.end(); i++)
{
aabb3f box = *i;
if(facedir == 1)
switch (axisdir)
{
box.MinEdge.rotateXZBy(-90);
box.MaxEdge.rotateXZBy(-90);
box.repair();
}
else if(facedir == 2)
{
box.MinEdge.rotateXZBy(180);
box.MaxEdge.rotateXZBy(180);
box.repair();
}
else if(facedir == 3)
{
box.MinEdge.rotateXZBy(90);
box.MaxEdge.rotateXZBy(90);
box.repair();
case 0:
if(facedir == 1)
{
box.MinEdge.rotateXZBy(-90);
box.MaxEdge.rotateXZBy(-90);
}
else if(facedir == 2)
{
box.MinEdge.rotateXZBy(180);
box.MaxEdge.rotateXZBy(180);
}
else if(facedir == 3)
{
box.MinEdge.rotateXZBy(90);
box.MaxEdge.rotateXZBy(90);
}
break;
case 1: // z+
box.MinEdge.rotateYZBy(90);
box.MaxEdge.rotateYZBy(90);
if(facedir == 1)
{
box.MinEdge.rotateXYBy(90);
box.MaxEdge.rotateXYBy(90);
}
else if(facedir == 2)
{
box.MinEdge.rotateXYBy(180);
box.MaxEdge.rotateXYBy(180);
}
else if(facedir == 3)
{
box.MinEdge.rotateXYBy(-90);
box.MaxEdge.rotateXYBy(-90);
}
break;
case 2: //z-
box.MinEdge.rotateYZBy(-90);
box.MaxEdge.rotateYZBy(-90);
if(facedir == 1)
{
box.MinEdge.rotateXYBy(-90);
box.MaxEdge.rotateXYBy(-90);
}
else if(facedir == 2)
{
box.MinEdge.rotateXYBy(180);
box.MaxEdge.rotateXYBy(180);
}
else if(facedir == 3)
{
box.MinEdge.rotateXYBy(90);
box.MaxEdge.rotateXYBy(90);
}
break;
case 3: //x+
box.MinEdge.rotateXYBy(-90);
box.MaxEdge.rotateXYBy(-90);
if(facedir == 1)
{
box.MinEdge.rotateYZBy(90);
box.MaxEdge.rotateYZBy(90);
}
else if(facedir == 2)
{
box.MinEdge.rotateYZBy(180);
box.MaxEdge.rotateYZBy(180);
}
else if(facedir == 3)
{
box.MinEdge.rotateYZBy(-90);
box.MaxEdge.rotateYZBy(-90);
}
break;
case 4: //x-
box.MinEdge.rotateXYBy(90);
box.MaxEdge.rotateXYBy(90);
if(facedir == 1)
{
box.MinEdge.rotateYZBy(-90);
box.MaxEdge.rotateYZBy(-90);
}
else if(facedir == 2)
{
box.MinEdge.rotateYZBy(180);
box.MaxEdge.rotateYZBy(180);
}
else if(facedir == 3)
{
box.MinEdge.rotateYZBy(90);
box.MaxEdge.rotateYZBy(90);
}
break;
case 5:
box.MinEdge.rotateXYBy(-180);
box.MaxEdge.rotateXYBy(-180);
if(facedir == 1)
{
box.MinEdge.rotateXZBy(90);
box.MaxEdge.rotateXZBy(90);
}
else if(facedir == 2)
{
box.MinEdge.rotateXZBy(180);
box.MaxEdge.rotateXZBy(180);
}
else if(facedir == 3)
{
box.MinEdge.rotateXZBy(-90);
box.MaxEdge.rotateXZBy(-90);
}
break;
default:
break;
}
box.repair();
boxes.push_back(box);
}
}

View File

@ -107,26 +107,31 @@ void NodeBox::deSerialize(std::istream &is)
TileDef
*/
void TileDef::serialize(std::ostream &os) const
void TileDef::serialize(std::ostream &os, u16 protocol_version) const
{
writeU8(os, 0); // version
if(protocol_version >= 17)
writeU8(os, 1);
else
writeU8(os, 0);
os<<serializeString(name);
writeU8(os, animation.type);
writeU16(os, animation.aspect_w);
writeU16(os, animation.aspect_h);
writeF1000(os, animation.length);
if(protocol_version >= 17)
writeU8(os, backface_culling);
}
void TileDef::deSerialize(std::istream &is)
{
int version = readU8(is);
if(version != 0)
throw SerializationError("unsupported TileDef version");
name = deSerializeString(is);
animation.type = (TileAnimationType)readU8(is);
animation.aspect_w = readU16(is);
animation.aspect_h = readU16(is);
animation.length = readF1000(is);
if(version >= 1)
backface_culling = readU8(is);
}
/*
@ -235,10 +240,10 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version)
writeF1000(os, visual_scale);
writeU8(os, 6);
for(u32 i=0; i<6; i++)
tiledef[i].serialize(os);
tiledef[i].serialize(os, protocol_version);
writeU8(os, CF_SPECIAL_COUNT);
for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
tiledef_special[i].serialize(os);
tiledef_special[i].serialize(os, protocol_version);
}
writeU8(os, alpha);
writeU8(os, post_effect_color.getAlpha());
@ -270,9 +275,9 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version)
serializeSimpleSoundSpec(sound_footstep, os);
serializeSimpleSoundSpec(sound_dig, os);
serializeSimpleSoundSpec(sound_dug, os);
writeU8(os, rightclickable);
// Stuff below should be moved to correct place in a version that otherwise changes
// the protocol version
writeU8(os, rightclickable);
}
void ContentFeatures::deSerialize(std::istream &is)
@ -331,12 +336,12 @@ void ContentFeatures::deSerialize(std::istream &is)
deSerializeSimpleSoundSpec(sound_footstep, is);
deSerializeSimpleSoundSpec(sound_dig, is);
deSerializeSimpleSoundSpec(sound_dug, is);
rightclickable = readU8(is);
// If you add anything here, insert it primarily inside the try-catch
// block to not need to increase the version.
try{
// Stuff below should be moved to correct place in a version that
// otherwise changes the protocol version
rightclickable = readU8(is);
}catch(SerializationError &e) {};
}
@ -809,10 +814,10 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version)
writeF1000(os, visual_scale);
writeU8(os, 6);
for(u32 i=0; i<6; i++)
tiledef[i].serialize(os);
tiledef[i].serialize(os, protocol_version);
writeU8(os, CF_SPECIAL_COUNT);
for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
tiledef_special[i].serialize(os);
tiledef_special[i].serialize(os, protocol_version);
}
writeU8(os, alpha);
writeU8(os, post_effect_color.getAlpha());

View File

@ -119,7 +119,7 @@ struct TileDef
animation.length = 1.0;
}
void serialize(std::ostream &os) const;
void serialize(std::ostream &os, u16 protocol_version) const;
void deSerialize(std::istream &is);
};

View File

@ -32,19 +32,34 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "clientmap.h"
#include "mapnode.h"
/*
Utility
*/
v3f random_v3f(v3f min, v3f max)
{
return v3f( rand()/(float)RAND_MAX*(max.X-min.X)+min.X,
rand()/(float)RAND_MAX*(max.Y-min.Y)+min.Y,
rand()/(float)RAND_MAX*(max.Z-min.Z)+min.Z);
}
std::vector<Particle*> all_particles;
std::map<u32, ParticleSpawner*> all_particlespawners;
Particle::Particle(
IGameDef *gamedef,
scene::ISceneManager* smgr,
LocalPlayer *player,
s32 id,
ClientEnvironment &env,
v3f pos,
v3f velocity,
v3f acceleration,
float expirationtime,
float size,
bool collisiondetection,
AtlasPointer ap
):
scene::ISceneNode(smgr->getRootSceneNode(), smgr, id)
scene::ISceneNode(smgr->getRootSceneNode(), smgr)
{
// Misc
m_gamedef = gamedef;
@ -57,7 +72,6 @@ Particle::Particle(
m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
m_material.setTexture(0, ap.atlas);
m_ap = ap;
m_light = 0;
// Particle related
@ -68,10 +82,20 @@ Particle::Particle(
m_time = 0;
m_player = player;
m_size = size;
m_collisiondetection = collisiondetection;
// Irrlicht stuff (TODO)
m_collisionbox = core::aabbox3d<f32>(-size/2,-size/2,-size/2,size/2,size/2,size/2);
// Irrlicht stuff
m_collisionbox = core::aabbox3d<f32>
(-size/2,-size/2,-size/2,size/2,size/2,size/2);
this->setAutomaticCulling(scene::EAC_OFF);
// Init lighting
updateLight(env);
// Init model
updateVertices();
all_particles.push_back(this);
}
Particle::~Particle()
@ -82,8 +106,10 @@ void Particle::OnRegisterSceneNode()
{
if (IsVisible)
{
SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
SceneManager->registerNodeForRendering
(this, scene::ESNRP_TRANSPARENT);
SceneManager->registerNodeForRendering
(this, scene::ESNRP_SOLID);
}
ISceneNode::OnRegisterSceneNode();
@ -96,45 +122,45 @@ void Particle::render()
video::IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setMaterial(m_material);
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
video::SColor c(255, m_light, m_light, m_light);
video::S3DVertex vertices[4] =
{
video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0, c, m_ap.x0(), m_ap.y1()),
video::S3DVertex(m_size/2,-m_size/2,0, 0,0,0, c, m_ap.x1(), m_ap.y1()),
video::S3DVertex(m_size/2,m_size/2,0, 0,0,0, c, m_ap.x1(), m_ap.y0()),
video::S3DVertex(-m_size/2,m_size/2,0, 0,0,0, c ,m_ap.x0(), m_ap.y0()),
};
for(u16 i=0; i<4; i++)
{
vertices[i].Pos.rotateYZBy(m_player->getPitch());
vertices[i].Pos.rotateXZBy(m_player->getYaw());
m_box.addInternalPoint(vertices[i].Pos);
vertices[i].Pos += m_pos*BS;
}
u16 indices[] = {0,1,2, 2,3,0};
driver->drawVertexPrimitiveList(vertices, 4, indices, 2,
video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
driver->drawVertexPrimitiveList(m_vertices, 4,
indices, 2, video::EVT_STANDARD,
scene::EPT_TRIANGLES, video::EIT_16BIT);
}
void Particle::step(float dtime, ClientEnvironment &env)
{
core::aabbox3d<f32> box = m_collisionbox;
v3f p_pos = m_pos*BS;
v3f p_velocity = m_velocity*BS;
v3f p_acceleration = m_acceleration*BS;
collisionMoveSimple(&env.getClientMap(), m_gamedef,
BS*0.5, box,
0, dtime,
p_pos, p_velocity, p_acceleration);
m_pos = p_pos/BS;
m_velocity = p_velocity/BS;
m_acceleration = p_acceleration/BS;
m_time += dtime;
if (m_collisiondetection)
{
core::aabbox3d<f32> box = m_collisionbox;
v3f p_pos = m_pos*BS;
v3f p_velocity = m_velocity*BS;
v3f p_acceleration = m_acceleration*BS;
collisionMoveSimple(&env, m_gamedef,
BS*0.5, box,
0, dtime,
p_pos, p_velocity, p_acceleration);
m_pos = p_pos/BS;
m_velocity = p_velocity/BS;
m_acceleration = p_acceleration/BS;
}
else
{
m_velocity += m_acceleration * dtime;
m_pos += m_velocity * dtime;
}
// Update lighting
updateLight(env);
// Update model
updateVertices();
}
void Particle::updateLight(ClientEnvironment &env)
{
u8 light = 0;
try{
v3s16 p = v3s16(
@ -151,11 +177,37 @@ void Particle::step(float dtime, ClientEnvironment &env)
m_light = decode_light(light);
}
std::vector<Particle*> all_particles;
void Particle::updateVertices()
{
video::SColor c(255, m_light, m_light, m_light);
m_vertices[0] = video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0,
c, m_ap.x0(), m_ap.y1());
m_vertices[1] = video::S3DVertex(m_size/2,-m_size/2,0, 0,0,0,
c, m_ap.x1(), m_ap.y1());
m_vertices[2] = video::S3DVertex(m_size/2,m_size/2,0, 0,0,0,
c, m_ap.x1(), m_ap.y0());
m_vertices[3] = video::S3DVertex(-m_size/2,m_size/2,0, 0,0,0,
c ,m_ap.x0(), m_ap.y0());
for(u16 i=0; i<4; i++)
{
m_vertices[i].Pos.rotateYZBy(m_player->getPitch());
m_vertices[i].Pos.rotateXZBy(m_player->getYaw());
m_box.addInternalPoint(m_vertices[i].Pos);
m_vertices[i].Pos += m_pos*BS;
}
}
/*
Helpers
*/
void allparticles_step (float dtime, ClientEnvironment &env)
{
for(std::vector<Particle*>::iterator i = all_particles.begin(); i != all_particles.end();)
for(std::vector<Particle*>::iterator i = all_particles.begin();
i != all_particles.end();)
{
if ((*i)->get_expired())
{
@ -171,22 +223,28 @@ void allparticles_step (float dtime, ClientEnvironment &env)
}
}
void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, const TileSpec tiles[])
void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
const TileSpec tiles[])
{
for (u16 j = 0; j < 32; j++) // set the amount of particles here
{
addNodeParticle(gamedef, smgr, player, pos, tiles);
addNodeParticle(gamedef, smgr, player, env, pos, tiles);
}
}
void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, const TileSpec tiles[])
void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, ClientEnvironment &env,
v3s16 pos, const TileSpec tiles[])
{
addNodeParticle(gamedef, smgr, player, pos, tiles);
addNodeParticle(gamedef, smgr, player, env, pos, tiles);
}
// add a particle of a node
// used by digging and punching particles
void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, const TileSpec tiles[])
void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
const TileSpec tiles[])
{
// Texture
u8 texid = myrand_range(0,5);
@ -205,7 +263,10 @@ void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer
ap.pos.Y = ap.y0() + (y1 - ap.y0()) * ((rand()%64)/64.-texsize);
// Physics
v3f velocity((rand()%100/50.-1)/1.5, rand()%100/35., (rand()%100/50.-1)/1.5);
v3f velocity( (rand()%100/50.-1)/1.5,
rand()%100/35.,
(rand()%100/50.-1)/1.5);
v3f acceleration(0,-9,0);
v3f particlepos = v3f(
(f32)pos.X+rand()%100/200.-0.25,
@ -213,17 +274,180 @@ void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer
(f32)pos.Z+rand()%100/200.-0.25
);
Particle *particle = new Particle(
new Particle(
gamedef,
smgr,
player,
0,
env,
particlepos,
velocity,
acceleration,
rand()%100/100., // expiration time
visual_size,
true,
ap);
all_particles.push_back(particle);
}
/*
ParticleSpawner
*/
ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr, LocalPlayer *player,
u16 amount, float time,
v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
float minexptime, float maxexptime, float minsize, float maxsize,
bool collisiondetection, AtlasPointer ap, u32 id)
{
m_gamedef = gamedef;
m_smgr = smgr;
m_player = player;
m_amount = amount;
m_spawntime = time;
m_minpos = minpos;
m_maxpos = maxpos;
m_minvel = minvel;
m_maxvel = maxvel;
m_minacc = minacc;
m_maxacc = maxacc;
m_minexptime = minexptime;
m_maxexptime = maxexptime;
m_minsize = minsize;
m_maxsize = maxsize;
m_collisiondetection = collisiondetection;
m_ap = ap;
m_time = 0;
for (u16 i = 0; i<=m_amount; i++)
{
float spawntime = (float)rand()/(float)RAND_MAX*m_spawntime;
m_spawntimes.push_back(spawntime);
}
all_particlespawners.insert(std::pair<u32, ParticleSpawner*>(id, this));
}
ParticleSpawner::~ParticleSpawner() {}
void ParticleSpawner::step(float dtime, ClientEnvironment &env)
{
m_time += dtime;
if (m_spawntime != 0) // Spawner exists for a predefined timespan
{
for(std::vector<float>::iterator i = m_spawntimes.begin();
i != m_spawntimes.end();)
{
if ((*i) <= m_time && m_amount > 0)
{
m_amount--;
v3f pos = random_v3f(m_minpos, m_maxpos);
v3f vel = random_v3f(m_minvel, m_maxvel);
v3f acc = random_v3f(m_minacc, m_maxacc);
float exptime = rand()/(float)RAND_MAX
*(m_maxexptime-m_minexptime)
+m_minexptime;
float size = rand()/(float)RAND_MAX
*(m_maxsize-m_minsize)
+m_minsize;
new Particle(
m_gamedef,
m_smgr,
m_player,
env,
pos,
vel,
acc,
exptime,
size,
m_collisiondetection,
m_ap);
m_spawntimes.erase(i);
}
else
{
i++;
}
}
}
else // Spawner exists for an infinity timespan, spawn on a per-second base
{
for (int i = 0; i <= m_amount; i++)
{
if (rand()/(float)RAND_MAX < dtime)
{
v3f pos = random_v3f(m_minpos, m_maxpos);
v3f vel = random_v3f(m_minvel, m_maxvel);
v3f acc = random_v3f(m_minacc, m_maxacc);
float exptime = rand()/(float)RAND_MAX
*(m_maxexptime-m_minexptime)
+m_minexptime;
float size = rand()/(float)RAND_MAX
*(m_maxsize-m_minsize)
+m_minsize;
new Particle(
m_gamedef,
m_smgr,
m_player,
env,
pos,
vel,
acc,
exptime,
size,
m_collisiondetection,
m_ap);
}
}
}
}
void allparticlespawners_step (float dtime, ClientEnvironment &env)
{
for(std::map<u32, ParticleSpawner*>::iterator i =
all_particlespawners.begin();
i != all_particlespawners.end();)
{
if (i->second->get_expired())
{
delete i->second;
all_particlespawners.erase(i++);
}
else
{
i->second->step(dtime, env);
i++;
}
}
}
void delete_particlespawner (u32 id)
{
if (all_particlespawners.find(id) != all_particlespawners.end())
{
delete all_particlespawners.find(id)->second;
all_particlespawners.erase(id);
}
}
void clear_particles ()
{
for(std::map<u32, ParticleSpawner*>::iterator i =
all_particlespawners.begin();
i != all_particlespawners.end();)
{
delete i->second;
all_particlespawners.erase(i++);
}
for(std::vector<Particle*>::iterator i =
all_particles.begin();
i != all_particles.end();)
{
(*i)->remove();
delete *i;
all_particles.erase(i);
}
}

View File

@ -35,12 +35,13 @@ class Particle : public scene::ISceneNode
IGameDef* gamedef,
scene::ISceneManager* mgr,
LocalPlayer *player,
s32 id,
ClientEnvironment &env,
v3f pos,
v3f velocity,
v3f acceleration,
float expirationtime,
float size,
bool collisiondetection,
AtlasPointer texture
);
~Particle();
@ -69,6 +70,10 @@ class Particle : public scene::ISceneNode
{ return m_expiration < m_time; }
private:
void updateLight(ClientEnvironment &env);
void updateVertices();
video::S3DVertex m_vertices[4];
float m_time;
float m_expiration;
@ -87,12 +92,71 @@ private:
float m_size;
AtlasPointer m_ap;
u8 m_light;
bool m_collisiondetection;
};
class ParticleSpawner
{
public:
ParticleSpawner(IGameDef* gamedef,
scene::ISceneManager *smgr,
LocalPlayer *player,
u16 amount,
float time,
v3f minp, v3f maxp,
v3f minvel, v3f maxvel,
v3f minacc, v3f maxacc,
float minexptime, float maxexptime,
float minsize, float maxsize,
bool collisiondetection,
AtlasPointer ap,
u32 id);
~ParticleSpawner();
void step(float dtime, ClientEnvironment &env);
bool get_expired ()
{ return (m_amount <= 0) && m_spawntime != 0; }
private:
float m_time;
IGameDef *m_gamedef;
scene::ISceneManager *m_smgr;
LocalPlayer *m_player;
u16 m_amount;
float m_spawntime;
v3f m_minpos;
v3f m_maxpos;
v3f m_minvel;
v3f m_maxvel;
v3f m_minacc;
v3f m_maxacc;
float m_minexptime;
float m_maxexptime;
float m_minsize;
float m_maxsize;
AtlasPointer m_ap;
std::vector<float> m_spawntimes;
bool m_collisiondetection;
};
void allparticles_step (float dtime, ClientEnvironment &env);
void allparticlespawners_step (float dtime, ClientEnvironment &env);
void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, const TileSpec tiles[]);
void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, const TileSpec tiles[]);
void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, const TileSpec tiles[]);
void delete_particlespawner (u32 id);
void clear_particles ();
void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
const TileSpec tiles[]);
void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
const TileSpec tiles[]);
void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
const TileSpec tiles[]);
#endif

View File

@ -73,7 +73,7 @@ public:
else{
/* No add shall have been used */
assert(n->second != -2);
n->second = std::max(n->second, 0) + 1;
n->second = (std::max)(n->second, 0) + 1;
}
}
{

View File

@ -30,6 +30,7 @@ extern "C" {
#include "settings.h" // For accessing g_settings
#include "main.h" // For g_settings
#include "biome.h"
#include "emerge.h"
#include "script.h"
#include "rollback.h"
@ -44,6 +45,7 @@ extern "C" {
#include "scriptapi_item.h"
#include "scriptapi_content.h"
#include "scriptapi_craft.h"
#include "scriptapi_particles.h"
/*****************************************************************************/
/* Mod related */
@ -241,6 +243,14 @@ struct EnumString es_BiomeTerrainType[] =
{0, NULL},
};
struct EnumString es_OreType[] =
{
{ORE_SCATTER, "scatter"},
{ORE_SHEET, "sheet"},
{ORE_CLAYLIKE, "claylike"},
{0, NULL},
};
/*****************************************************************************/
/* Parameters */
/*****************************************************************************/
@ -611,8 +621,6 @@ static int l_register_biome_groups(lua_State *L)
{
luaL_checktype(L, 1, LUA_TTABLE);
int index = 1;
if (!lua_istable(L, index))
throw LuaError(L, "register_biome_groups: parameter is not a table");
BiomeDefManager *bmgr = get_server(L)->getBiomeDef();
if (!bmgr) {
@ -685,6 +693,52 @@ static int l_register_biome(lua_State *L)
}
static int l_register_ore(lua_State *L)
{
int index = 1;
luaL_checktype(L, index, LUA_TTABLE);
IWritableNodeDefManager *ndef = get_server(L)->getWritableNodeDefManager();
EmergeManager *emerge = get_server(L)->getEmergeManager();
enum OreType oretype = (OreType)getenumfield(L, index,
"ore_type", es_OreType, ORE_SCATTER);
Ore *ore = createOre(oretype);
if (!ore) {
errorstream << "register_ore: ore_type "
<< oretype << " not implemented";
return 0;
}
ore->ore_name = getstringfield_default(L, index, "ore", "");
ore->wherein_name = getstringfield_default(L, index, "wherein", "");
ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1);
ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1);
ore->clust_size = getintfield_default(L, index, "clust_size", 0);
ore->height_min = getintfield_default(L, index, "height_min", 0);
ore->height_max = getintfield_default(L, index, "height_max", 0);
ore->nthresh = getfloatfield_default(L, index, "noise_threshhold", 0.);
lua_getfield(L, index, "noise_params");
ore->np = read_noiseparams(L, -1);
lua_pop(L, 1);
ore->noise = NULL;
if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) {
errorstream << "register_ore: clust_scarcity and clust_num_ores"
"must be greater than 0";
delete ore;
return 0;
}
emerge->ores.push_back(ore);
verbosestream << "register_ore: ore '" << ore->ore_name
<< "' registered" << std::endl;
return 0;
}
// setting_set(name, value)
static int l_setting_set(lua_State *L)
@ -1059,6 +1113,7 @@ static const struct luaL_Reg minetest_f [] = {
{"register_craft", l_register_craft},
{"register_biome", l_register_biome},
{"register_biome_groups", l_register_biome_groups},
{"register_ore", l_register_ore},
{"setting_set", l_setting_set},
{"setting_get", l_setting_get},
{"setting_getbool", l_setting_getbool},
@ -1089,6 +1144,9 @@ static const struct luaL_Reg minetest_f [] = {
{"get_all_craft_recipes", l_get_all_craft_recipes},
{"rollback_get_last_node_actor", l_rollback_get_last_node_actor},
{"rollback_revert_actions_by", l_rollback_revert_actions_by},
{"add_particle", l_add_particle},
{"add_particlespawner", l_add_particlespawner},
{"delete_particlespawner", l_delete_particlespawner},
{NULL, NULL}
};

View File

@ -269,6 +269,7 @@ NoiseParams *read_noiseparams(lua_State *L, int index)
np->scale = getfloatfield_default(L, index, "scale", 0.0);
lua_getfield(L, index, "spread");
np->spread = read_v3f(L, -1);
lua_pop(L, 1);
np->seed = getintfield_default(L, index, "seed", 0);
np->octaves = getintfield_default(L, index, "octaves", 0);
np->persist = getfloatfield_default(L, index, "persist", 0.0);
@ -276,6 +277,7 @@ NoiseParams *read_noiseparams(lua_State *L, int index)
return np;
}
/*
LuaPseudoRandom
*/

View File

@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server.h"
#include <iostream>
#include <queue>
#include <algorithm>
#include "clientserver.h"
#include "map.h"
#include "jmutexautolock.h"
@ -652,7 +653,6 @@ Server::Server(
m_craftdef(createCraftDefManager()),
m_event(new EventManager()),
m_thread(this),
//m_emergethread(this),
m_time_of_day_send_timer(0),
m_uptime(0),
m_shutdown_requested(false),
@ -697,7 +697,10 @@ Server::Server(
// Create biome definition manager
m_biomedef = new BiomeDefManager(this);
// Create emerge manager
m_emerge = new EmergeManager(this, m_biomedef);
// Create rollback manager
std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
m_rollback = createRollbackManager(rollback_path, this);
@ -813,9 +816,6 @@ Server::Server(
// Add default biomes after nodedef had its aliases added
m_biomedef->addDefaultBiomes();
// Create emerge manager
m_emerge = new EmergeManager(this, m_biomedef);
// Initialize Environment
ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
m_env = new ServerEnvironment(servermap, m_lua, this, this);
@ -3474,6 +3474,132 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, co
m_con.Send(peer_id, 0, data, true);
}
// Spawns a particle on peer with peer_id
void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, std::string texture)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_SPAWN_PARTICLE);
writeV3F1000(os, pos);
writeV3F1000(os, velocity);
writeV3F1000(os, acceleration);
writeF1000(os, expirationtime);
writeF1000(os, size);
writeU8(os, collisiondetection);
os<<serializeLongString(texture);
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
m_con.Send(peer_id, 0, data, true);
}
// Spawns a particle on all peers
void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, std::string texture)
{
for(std::map<u16, RemoteClient*>::iterator
i = m_clients.begin();
i != m_clients.end(); i++)
{
// Get client and check that it is valid
RemoteClient *client = i->second;
assert(client->peer_id == i->first);
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
expirationtime, size, collisiondetection, texture);
}
}
// Adds a ParticleSpawner on peer with peer_id
void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
writeU16(os, amount);
writeF1000(os, spawntime);
writeV3F1000(os, minpos);
writeV3F1000(os, maxpos);
writeV3F1000(os, minvel);
writeV3F1000(os, maxvel);
writeV3F1000(os, minacc);
writeV3F1000(os, maxacc);
writeF1000(os, minexptime);
writeF1000(os, maxexptime);
writeF1000(os, minsize);
writeF1000(os, maxsize);
writeU8(os, collisiondetection);
os<<serializeLongString(texture);
writeU32(os, id);
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
m_con.Send(peer_id, 0, data, true);
}
// Adds a ParticleSpawner on all peers
void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
{
for(std::map<u16, RemoteClient*>::iterator
i = m_clients.begin();
i != m_clients.end(); i++)
{
// Get client and check that it is valid
RemoteClient *client = i->second;
assert(client->peer_id == i->first);
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
SendAddParticleSpawner(client->peer_id, amount, spawntime,
minpos, maxpos, minvel, maxvel, minacc, maxacc,
minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
}
}
void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
writeU16(os, id);
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
m_con.Send(peer_id, 0, data, true);
}
void Server::SendDeleteParticleSpawnerAll(u32 id)
{
for(std::map<u16, RemoteClient*>::iterator
i = m_clients.begin();
i != m_clients.end(); i++)
{
// Get client and check that it is valid
RemoteClient *client = i->second;
assert(client->peer_id == i->first);
if(client->serialization_version == SER_FMT_VER_INVALID)
continue;
SendDeleteParticleSpawner(client->peer_id, id);
}
}
void Server::BroadcastChatMessage(const std::wstring &message)
{
for(std::map<u16, RemoteClient*>::iterator
@ -4432,6 +4558,111 @@ void Server::notifyPlayers(const std::wstring msg)
BroadcastChatMessage(msg);
}
void Server::spawnParticle(const char *playername, v3f pos,
v3f velocity, v3f acceleration,
float expirationtime, float size, bool
collisiondetection, std::string texture)
{
Player *player = m_env->getPlayer(playername);
if(!player)
return;
SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
expirationtime, size, collisiondetection, texture);
}
void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
float expirationtime, float size,
bool collisiondetection, std::string texture)
{
SendSpawnParticleAll(pos, velocity, acceleration,
expirationtime, size, collisiondetection, texture);
}
u32 Server::addParticleSpawner(const char *playername,
u16 amount, float spawntime,
v3f minpos, v3f maxpos,
v3f minvel, v3f maxvel,
v3f minacc, v3f maxacc,
float minexptime, float maxexptime,
float minsize, float maxsize,
bool collisiondetection, std::string texture)
{
Player *player = m_env->getPlayer(playername);
if(!player)
return -1;
u32 id = 0;
for(;;) // look for unused particlespawner id
{
id++;
if (std::find(m_particlespawner_ids.begin(),
m_particlespawner_ids.end(), id)
== m_particlespawner_ids.end())
{
m_particlespawner_ids.push_back(id);
break;
}
}
SendAddParticleSpawner(player->peer_id, amount, spawntime,
minpos, maxpos, minvel, maxvel, minacc, maxacc,
minexptime, maxexptime, minsize, maxsize,
collisiondetection, texture, id);
return id;
}
u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
v3f minpos, v3f maxpos,
v3f minvel, v3f maxvel,
v3f minacc, v3f maxacc,
float minexptime, float maxexptime,
float minsize, float maxsize,
bool collisiondetection, std::string texture)
{
u32 id = 0;
for(;;) // look for unused particlespawner id
{
id++;
if (std::find(m_particlespawner_ids.begin(),
m_particlespawner_ids.end(), id)
== m_particlespawner_ids.end())
{
m_particlespawner_ids.push_back(id);
break;
}
}
SendAddParticleSpawnerAll(amount, spawntime,
minpos, maxpos, minvel, maxvel, minacc, maxacc,
minexptime, maxexptime, minsize, maxsize,
collisiondetection, texture, id);
return id;
}
void Server::deleteParticleSpawner(const char *playername, u32 id)
{
Player *player = m_env->getPlayer(playername);
if(!player)
return;
m_particlespawner_ids.erase(
std::remove(m_particlespawner_ids.begin(),
m_particlespawner_ids.end(), id),
m_particlespawner_ids.end());
SendDeleteParticleSpawner(player->peer_id, id);
}
void Server::deleteParticleSpawnerAll(u32 id)
{
m_particlespawner_ids.erase(
std::remove(m_particlespawner_ids.begin(),
m_particlespawner_ids.end(), id),
m_particlespawner_ids.end());
SendDeleteParticleSpawnerAll(id);
}
void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
{
m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);

View File

@ -456,6 +456,35 @@ public:
// Envlock and conlock should be locked when calling this
void notifyPlayer(const char *name, const std::wstring msg);
void notifyPlayers(const std::wstring msg);
void spawnParticle(const char *playername,
v3f pos, v3f velocity, v3f acceleration,
float expirationtime, float size,
bool collisiondetection, std::string texture);
void spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
float expirationtime, float size,
bool collisiondetection, std::string texture);
u32 addParticleSpawner(const char *playername,
u16 amount, float spawntime,
v3f minpos, v3f maxpos,
v3f minvel, v3f maxvel,
v3f minacc, v3f maxacc,
float minexptime, float maxexptime,
float minsize, float maxsize,
bool collisiondetection, std::string texture);
u32 addParticleSpawnerAll(u16 amount, float spawntime,
v3f minpos, v3f maxpos,
v3f minvel, v3f maxvel,
v3f minacc, v3f maxacc,
float minexptime, float maxexptime,
float minsize, float maxsize,
bool collisiondetection, std::string texture);
void deleteParticleSpawner(const char *playername, u32 id);
void deleteParticleSpawnerAll(u32 id);
void queueBlockEmerge(v3s16 blockpos, bool allow_generate);
@ -574,6 +603,41 @@ private:
void sendDetachedInventoryToAll(const std::string &name);
void sendDetachedInventories(u16 peer_id);
// Adds a ParticleSpawner on peer with peer_id
void SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime,
v3f minpos, v3f maxpos,
v3f minvel, v3f maxvel,
v3f minacc, v3f maxacc,
float minexptime, float maxexptime,
float minsize, float maxsize,
bool collisiondetection, std::string texture, u32 id);
// Adds a ParticleSpawner on all peers
void SendAddParticleSpawnerAll(u16 amount, float spawntime,
v3f minpos, v3f maxpos,
v3f minvel, v3f maxvel,
v3f minacc, v3f maxacc,
float minexptime, float maxexptime,
float minsize, float maxsize,
bool collisiondetection, std::string texture, u32 id);
// Deletes ParticleSpawner on a single client
void SendDeleteParticleSpawner(u16 peer_id, u32 id);
// Deletes ParticleSpawner on all clients
void SendDeleteParticleSpawnerAll(u32 id);
// Spawns particle on single client
void SendSpawnParticle(u16 peer_id,
v3f pos, v3f velocity, v3f acceleration,
float expirationtime, float size,
bool collisiondetection, std::string texture);
// Spawns particle on all clients
void SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
float expirationtime, float size,
bool collisiondetection, std::string texture);
/*
Something random
*/
@ -790,6 +854,11 @@ private:
*/
// key = name
std::map<std::string, Inventory*> m_detached_inventories;
/*
Particles
*/
std::vector<u32> m_particlespawner_ids;
};
/*

View File

@ -205,7 +205,8 @@ struct TileSpec
texture == other.texture &&
alpha == other.alpha &&
material_type == other.material_type &&
material_flags == other.material_flags
material_flags == other.material_flags &&
rotation == other.rotation
);
}
@ -264,6 +265,7 @@ struct TileSpec
// Animation parameters
u8 animation_frame_count;
u16 animation_frame_length_ms;
u8 rotation;
};
#endif