Compare commits
119 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab06fca4be | ||
|
|
fd9e226b79 | ||
|
|
7d2f0d7b1b | ||
|
|
870f7bcc93 | ||
|
|
543fc6702f | ||
|
|
5080b63435 | ||
|
|
8bb36f4650 | ||
|
|
a47b829040 | ||
|
|
07632b7d69 | ||
|
|
ec54e35757 | ||
|
|
68e36226b3 | ||
|
|
15b86a6b9b | ||
|
|
eeb0900291 | ||
|
|
804a7875a2 | ||
|
|
041585a78e | ||
|
|
cd1f604ffe | ||
|
|
566f7f638a | ||
|
|
3e07c5bf82 | ||
|
|
ca16119adb | ||
|
|
d0b9b10ee0 | ||
|
|
98fd364672 | ||
|
|
151fad1f2b | ||
|
|
27373919f4 | ||
|
|
22e6fb7056 | ||
|
|
e3258b78e2 | ||
|
|
bee170570d | ||
|
|
ba73e75ef9 | ||
|
|
f4b7e1a570 | ||
|
|
fa50341a71 | ||
|
|
fa76057e7f | ||
|
|
bb454b1846 | ||
|
|
778d9b0cd6 | ||
|
|
84ace27872 | ||
|
|
c1d8eeb70a | ||
|
|
6cf87e1d23 | ||
|
|
8a93581c8a | ||
|
|
6c8fa83ecd | ||
|
|
ab45133ab4 | ||
|
|
7b6d642300 | ||
|
|
96a286dcf5 | ||
|
|
420de7ad5e | ||
|
|
8ccdd3bdb4 | ||
|
|
23913f26cd | ||
|
|
9714612999 | ||
|
|
69cdcea9fc | ||
|
|
30ec69c7d3 | ||
|
|
f720c67f3e | ||
|
|
655bb526f4 | ||
|
|
5c26972cdd | ||
|
|
117f208826 | ||
|
|
5f798d944e | ||
|
|
6b927229f5 | ||
|
|
ffad18e424 | ||
|
|
e0eaed5fdb | ||
|
|
5bd638d4a5 | ||
|
|
eca1c96412 | ||
|
|
2f5686ca48 | ||
|
|
4fa4340b95 | ||
|
|
197542c7ec | ||
|
|
ab507f83e2 | ||
|
|
d67004a3be | ||
|
|
c8acc373c1 | ||
|
|
3d1c481f0b | ||
|
|
756db8174a | ||
|
|
fa67b46c04 | ||
|
|
4d656963e4 | ||
|
|
9259d028ac | ||
|
|
52fcb0b4b9 | ||
|
|
d7d759b43f | ||
|
|
ba3fd63e29 | ||
|
|
948b5a8be7 | ||
|
|
e42eeec8f6 | ||
|
|
118285e6ba | ||
|
|
ba4d93027f | ||
|
|
fb0c431864 | ||
|
|
9c8ba42750 | ||
|
|
f9675bd2b4 | ||
|
|
cb40b3517a | ||
|
|
0a020dbcc8 | ||
|
|
ac97a7f70e | ||
|
|
e02b95741b | ||
|
|
bbd990f2cc | ||
|
|
a0b5605db8 | ||
|
|
3ba9b26310 | ||
|
|
6c43ec2d2b | ||
|
|
9b9eb23b6d | ||
|
|
8b16e5f27d | ||
|
|
5292476841 | ||
|
|
1db0334787 | ||
|
|
6e2ba111af | ||
|
|
5f1d3ad754 | ||
|
|
46f471c89f | ||
|
|
0dd9c14ff8 | ||
|
|
0709918bd8 | ||
|
|
8e5167d726 | ||
|
|
8c3ffa3907 | ||
|
|
8540871ebc | ||
|
|
23837e4352 | ||
|
|
3cab24fbcf | ||
|
|
755df5f659 | ||
|
|
936411e4d1 | ||
|
|
21317be493 | ||
|
|
41c00e87d4 | ||
|
|
2863a3291a | ||
|
|
8adad36a66 | ||
|
|
b701f8a878 | ||
|
|
63e73f29cc | ||
|
|
7fcf153ada | ||
|
|
0443d36abf | ||
|
|
df2ad89518 | ||
|
|
10dc2b30fb | ||
|
|
f9087d14a3 | ||
|
|
25cf3757b2 | ||
|
|
72ef6f637e | ||
|
|
9cadaf824b | ||
|
|
1cc1b93e65 | ||
|
|
c4f400acd0 | ||
|
|
ac628c9b0a | ||
|
|
926830e0df |
@@ -12,7 +12,7 @@ set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
|
||||
# Also remember to set PROTOCOL_VERSION in clientserver.h when releasing
|
||||
set(VERSION_MAJOR 0)
|
||||
set(VERSION_MINOR 4)
|
||||
set(VERSION_PATCH 3)
|
||||
set(VERSION_PATCH 4)
|
||||
if(VERSION_EXTRA)
|
||||
set(VERSION_PATCH ${VERSION_PATCH}-${VERSION_EXTRA})
|
||||
endif()
|
||||
@@ -131,6 +131,7 @@ if(NOT CUSTOM_LOCALEDIR STREQUAL "")
|
||||
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(MINETEST_GAME_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/games/minetest_game")
|
||||
if(EXISTS ${MINETEST_GAME_SOURCE} AND IS_DIRECTORY ${MINETEST_GAME_SOURCE})
|
||||
|
||||
@@ -22,4 +22,5 @@ dofile(minetest.get_modpath("__builtin").."/auth.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/chatcommands.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/static_spawn.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/detached_inventory.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/falling.lua")
|
||||
|
||||
|
||||
@@ -138,6 +138,7 @@ minetest.register_chatcommand("grant", {
|
||||
return
|
||||
end
|
||||
minetest.set_player_privs(grantname, privs)
|
||||
minetest.log(name..' granted ('..minetest.privs_to_string(grantprivs, ', ')..') privileges to '..grantname)
|
||||
minetest.chat_send_player(name, "Privileges of "..grantname..": "..minetest.privs_to_string(minetest.get_player_privs(grantname), ' '))
|
||||
if grantname ~= name then
|
||||
minetest.chat_send_player(grantname, name.." granted you privileges: "..minetest.privs_to_string(grantprivs, ' '))
|
||||
@@ -175,6 +176,7 @@ minetest.register_chatcommand("revoke", {
|
||||
end
|
||||
end
|
||||
minetest.set_player_privs(revokename, privs)
|
||||
minetest.log(name..' revoked ('..minetest.privs_to_string(revokeprivs, ', ')..') privileges from '..revokename)
|
||||
minetest.chat_send_player(name, "Privileges of "..revokename..": "..minetest.privs_to_string(minetest.get_player_privs(revokename), ' '))
|
||||
if revokename ~= name then
|
||||
minetest.chat_send_player(revokename, name.." revoked privileges from you: "..minetest.privs_to_string(revokeprivs, ' '))
|
||||
@@ -215,8 +217,8 @@ minetest.register_chatcommand("clearpassword", {
|
||||
privs = {password=true},
|
||||
func = function(name, param)
|
||||
toname = param
|
||||
if not toname then
|
||||
minetest.chat_send_player(toname, "Name field required")
|
||||
if toname == "" then
|
||||
minetest.chat_send_player(name, "Name field required")
|
||||
return
|
||||
end
|
||||
minetest.set_player_password(toname, '')
|
||||
|
||||
190
builtin/falling.lua
Normal file
@@ -0,0 +1,190 @@
|
||||
-- Minetest: builtin/item.lua
|
||||
|
||||
--
|
||||
-- Falling stuff
|
||||
--
|
||||
|
||||
minetest.register_entity("__builtin:falling_node", {
|
||||
initial_properties = {
|
||||
physical = true,
|
||||
collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
|
||||
visual = "wielditem",
|
||||
textures = {},
|
||||
visual_size = {x=0.667, y=0.667},
|
||||
},
|
||||
|
||||
nodename = "",
|
||||
|
||||
set_node = function(self, nodename)
|
||||
self.nodename = nodename
|
||||
local stack = ItemStack(nodename)
|
||||
local itemtable = stack:to_table()
|
||||
local itemname = nil
|
||||
if itemtable then
|
||||
itemname = stack:to_table().name
|
||||
end
|
||||
local item_texture = nil
|
||||
local item_type = ""
|
||||
if minetest.registered_items[itemname] then
|
||||
item_texture = minetest.registered_items[itemname].inventory_image
|
||||
item_type = minetest.registered_items[itemname].type
|
||||
end
|
||||
prop = {
|
||||
is_visible = true,
|
||||
textures = {nodename},
|
||||
}
|
||||
self.object:set_properties(prop)
|
||||
end,
|
||||
|
||||
get_staticdata = function(self)
|
||||
return self.nodename
|
||||
end,
|
||||
|
||||
on_activate = function(self, staticdata)
|
||||
self.nodename = staticdata
|
||||
self.object:set_armor_groups({immortal=1})
|
||||
--self.object:setacceleration({x=0, y=-10, z=0})
|
||||
self:set_node(self.nodename)
|
||||
end,
|
||||
|
||||
on_step = function(self, dtime)
|
||||
-- Set gravity
|
||||
self.object:setacceleration({x=0, y=-10, z=0})
|
||||
-- Turn to actual sand when collides to ground or just move
|
||||
local pos = self.object:getpos()
|
||||
local bcp = {x=pos.x, y=pos.y-0.7, z=pos.z} -- Position of bottom center point
|
||||
local bcn = minetest.env:get_node(bcp)
|
||||
-- Note: walkable is in the node definition, not in item groups
|
||||
if minetest.registered_nodes[bcn.name] and
|
||||
minetest.registered_nodes[bcn.name].walkable then
|
||||
local np = {x=bcp.x, y=bcp.y+1, z=bcp.z}
|
||||
-- Check what's here
|
||||
local n2 = minetest.env:get_node(np)
|
||||
-- If it's not air or liquid, remove node and replace it with
|
||||
-- it's drops
|
||||
if n2.name ~= "air" and (not minetest.registered_nodes[n2.name] or
|
||||
minetest.registered_nodes[n2.name].liquidtype == "none") then
|
||||
local drops = minetest.get_node_drops(n2.name, "")
|
||||
minetest.env:remove_node(np)
|
||||
-- Add dropped items
|
||||
local _, dropped_item
|
||||
for _, dropped_item in ipairs(drops) do
|
||||
minetest.env:add_item(np, dropped_item)
|
||||
end
|
||||
-- Run script hook
|
||||
local _, callback
|
||||
for _, callback in ipairs(minetest.registered_on_dignodes) do
|
||||
callback(np, n2, nil)
|
||||
end
|
||||
end
|
||||
-- Create node and remove entity
|
||||
minetest.env:add_node(np, {name=self.nodename})
|
||||
self.object:remove()
|
||||
else
|
||||
-- Do nothing
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
function spawn_falling_node(p, nodename)
|
||||
obj = minetest.env:add_entity(p, "__builtin:falling_node")
|
||||
obj:get_luaentity():set_node(nodename)
|
||||
end
|
||||
|
||||
function drop_attached_node(p)
|
||||
local nn = minetest.env:get_node(p).name
|
||||
minetest.env:remove_node(p)
|
||||
for _,item in ipairs(minetest.get_node_drops(nn, "")) do
|
||||
local pos = {
|
||||
x = p.x + math.random(60)/60-0.3,
|
||||
y = p.y + math.random(60)/60-0.3,
|
||||
z = p.z + math.random(60)/60-0.3,
|
||||
}
|
||||
minetest.env:add_item(pos, item)
|
||||
end
|
||||
end
|
||||
|
||||
function check_attached_node(p, n)
|
||||
local def = minetest.registered_nodes[n.name]
|
||||
local d = {x=0, y=0, z=0}
|
||||
if def.paramtype2 == "wallmounted" then
|
||||
if n.param2 == 0 then
|
||||
d.y = 1
|
||||
elseif n.param2 == 1 then
|
||||
d.y = -1
|
||||
elseif n.param2 == 2 then
|
||||
d.x = 1
|
||||
elseif n.param2 == 3 then
|
||||
d.x = -1
|
||||
elseif n.param2 == 4 then
|
||||
d.z = 1
|
||||
elseif n.param2 == 5 then
|
||||
d.z = -1
|
||||
end
|
||||
else
|
||||
d.y = -1
|
||||
end
|
||||
local p2 = {x=p.x+d.x, y=p.y+d.y, z=p.z+d.z}
|
||||
local nn = minetest.env:get_node(p2).name
|
||||
local def2 = minetest.registered_nodes[nn]
|
||||
if def2 and not def2.walkable then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--
|
||||
-- Some common functions
|
||||
--
|
||||
|
||||
function nodeupdate_single(p)
|
||||
n = minetest.env:get_node(p)
|
||||
if minetest.get_node_group(n.name, "falling_node") ~= 0 then
|
||||
p_bottom = {x=p.x, y=p.y-1, z=p.z}
|
||||
n_bottom = minetest.env:get_node(p_bottom)
|
||||
-- Note: walkable is in the node definition, not in item groups
|
||||
if minetest.registered_nodes[n_bottom.name] and
|
||||
not minetest.registered_nodes[n_bottom.name].walkable then
|
||||
minetest.env:remove_node(p)
|
||||
spawn_falling_node(p, n.name)
|
||||
nodeupdate(p)
|
||||
end
|
||||
end
|
||||
|
||||
if minetest.get_node_group(n.name, "attached_node") ~= 0 then
|
||||
if not check_attached_node(p, n) then
|
||||
drop_attached_node(p)
|
||||
nodeupdate(p)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function nodeupdate(p)
|
||||
-- Round p to prevent falling entities to get stuck
|
||||
p.x = math.floor(p.x+0.5)
|
||||
p.y = math.floor(p.y+0.5)
|
||||
p.z = math.floor(p.z+0.5)
|
||||
|
||||
for x = -1,1 do
|
||||
for y = -1,1 do
|
||||
for z = -1,1 do
|
||||
p2 = {x=p.x+x, y=p.y+y, z=p.z+z}
|
||||
nodeupdate_single(p2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Global callbacks
|
||||
--
|
||||
|
||||
function on_placenode(p, node)
|
||||
nodeupdate(p)
|
||||
end
|
||||
minetest.register_on_placenode(on_placenode)
|
||||
|
||||
function on_dignode(p, node)
|
||||
nodeupdate(p)
|
||||
end
|
||||
minetest.register_on_dignode(on_dignode)
|
||||
@@ -76,10 +76,10 @@ function minetest.get_node_drops(nodename, toolname)
|
||||
local drop = ItemStack({name=nodename}):get_definition().drop
|
||||
if drop == nil then
|
||||
-- default drop
|
||||
return {ItemStack({name=nodename})}
|
||||
return {nodename}
|
||||
elseif type(drop) == "string" then
|
||||
-- itemstring drop
|
||||
return {ItemStack(drop)}
|
||||
return {drop}
|
||||
elseif drop.items == nil then
|
||||
-- drop = {} to disable default drop
|
||||
return {}
|
||||
@@ -181,6 +181,14 @@ function minetest.item_place_node(itemstack, placer, pointed_thing)
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if the node is attached and if it can be placed there
|
||||
if minetest.get_item_group(def.name, "attached_node") ~= 0 and
|
||||
not check_attached_node(place_to, newnode) then
|
||||
minetest.log("action", "attached node " .. def.name ..
|
||||
" can not be placed at " .. minetest.pos_to_string(place_to))
|
||||
return
|
||||
end
|
||||
|
||||
-- Add node and update
|
||||
minetest.env:add_node(place_to, newnode)
|
||||
|
||||
|
||||
@@ -57,11 +57,23 @@ minetest.register_entity("__builtin:item", {
|
||||
end,
|
||||
|
||||
get_staticdata = function(self)
|
||||
return self.itemstring
|
||||
--return self.itemstring
|
||||
return minetest.serialize({
|
||||
itemstring = self.itemstring,
|
||||
always_collect = self.always_collect,
|
||||
})
|
||||
end,
|
||||
|
||||
on_activate = function(self, staticdata)
|
||||
self.itemstring = staticdata
|
||||
if string.sub(staticdata, 1, string.len("return")) == "return" then
|
||||
local data = minetest.deserialize(staticdata)
|
||||
if data and type(data) == "table" then
|
||||
self.itemstring = data.itemstring
|
||||
self.always_collect = data.always_collect
|
||||
end
|
||||
else
|
||||
self.itemstring = staticdata
|
||||
end
|
||||
self.object:set_armor_groups({immortal=1})
|
||||
self.object:setvelocity({x=0, y=2, z=0})
|
||||
self.object:setacceleration({x=0, y=-10, z=0})
|
||||
|
||||
@@ -259,6 +259,7 @@ minetest.register_node(":air", {
|
||||
diggable = false,
|
||||
buildable_to = true,
|
||||
air_equivalent = true,
|
||||
drop = "",
|
||||
groups = {not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
@@ -274,6 +275,7 @@ minetest.register_node(":ignore", {
|
||||
diggable = false,
|
||||
buildable_to = true, -- A way to remove accidentally placed ignores
|
||||
air_equivalent = true,
|
||||
drop = "",
|
||||
groups = {not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
@@ -301,6 +303,7 @@ end
|
||||
|
||||
minetest.registered_on_chat_messages, minetest.register_on_chat_message = make_registration()
|
||||
minetest.registered_globalsteps, minetest.register_globalstep = make_registration()
|
||||
minetest.registered_on_shutdown, minetest.register_on_shutdown = make_registration()
|
||||
minetest.registered_on_punchnodes, minetest.register_on_punchnode = make_registration()
|
||||
minetest.registered_on_placenodes, minetest.register_on_placenode = make_registration()
|
||||
minetest.registered_on_dignodes, minetest.register_on_dignode = make_registration()
|
||||
|
||||
1
client/shaders/test_shader_1/base.txt
Normal file
@@ -0,0 +1 @@
|
||||
trans_alphach_ref
|
||||
25
client/shaders/test_shader_1/opengl_fragment.glsl
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
uniform sampler2D myTexture;
|
||||
uniform vec4 skyBgColor;
|
||||
uniform float fogDistance;
|
||||
|
||||
varying vec3 vPosition;
|
||||
|
||||
void main (void)
|
||||
{
|
||||
//vec4 col = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0]));
|
||||
float a = col.a;
|
||||
col *= gl_Color;
|
||||
col = col * col; // SRGB -> Linear
|
||||
col *= 1.8;
|
||||
col.r = 1.0 - exp(1.0 - col.r) / exp(1.0);
|
||||
col.g = 1.0 - exp(1.0 - col.g) / exp(1.0);
|
||||
col.b = 1.0 - exp(1.0 - col.b) / exp(1.0);
|
||||
col = sqrt(col); // Linear -> SRGB
|
||||
if(fogDistance != 0.0){
|
||||
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
|
||||
col = mix(col, skyBgColor, d);
|
||||
}
|
||||
gl_FragColor = vec4(col.r, col.g, col.b, a);
|
||||
}
|
||||
58
client/shaders/test_shader_1/opengl_vertex.glsl
Normal file
@@ -0,0 +1,58 @@
|
||||
|
||||
uniform mat4 mWorldViewProj;
|
||||
uniform mat4 mInvWorld;
|
||||
uniform mat4 mTransWorld;
|
||||
uniform float dayNightRatio;
|
||||
|
||||
varying vec3 vPosition;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_Position = mWorldViewProj * gl_Vertex;
|
||||
|
||||
vPosition = (mWorldViewProj * gl_Vertex).xyz;
|
||||
|
||||
vec4 color;
|
||||
//color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
float day = gl_Color.r;
|
||||
float night = gl_Color.g;
|
||||
float light_source = gl_Color.b;
|
||||
|
||||
/*color.r = mix(night, day, dayNightRatio);
|
||||
color.g = color.r;
|
||||
color.b = color.r;*/
|
||||
|
||||
float rg = mix(night, day, dayNightRatio);
|
||||
rg += light_source * 1.0; // Make light sources brighter
|
||||
float b = rg;
|
||||
|
||||
// Moonlight is blue
|
||||
b += (day - night) / 13.0;
|
||||
rg -= (day - night) / 13.0;
|
||||
|
||||
// Emphase blue a bit in darker places
|
||||
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
|
||||
b += max(0.0, (1.0 - abs(b - 0.13)/0.17) * 0.025);
|
||||
|
||||
// Artificial light is yellow-ish
|
||||
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
|
||||
rg += max(0.0, (1.0 - abs(rg - 0.85)/0.15) * 0.065);
|
||||
|
||||
color.r = rg;
|
||||
color.g = rg;
|
||||
color.b = b;
|
||||
|
||||
// Make sides and bottom darker than the top
|
||||
color = color * color; // SRGB -> Linear
|
||||
if(gl_Normal.y <= 0.5)
|
||||
color *= 0.6;
|
||||
//color *= 0.7;
|
||||
color = sqrt(color); // Linear -> SRGB
|
||||
|
||||
color.a = gl_Color.a;
|
||||
|
||||
gl_FrontColor = gl_BackColor = color;
|
||||
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
}
|
||||
1
client/shaders/test_shader_2/base.txt
Normal file
@@ -0,0 +1 @@
|
||||
trans_alphach
|
||||
23
client/shaders/test_shader_2/opengl_fragment.glsl
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
uniform sampler2D myTexture;
|
||||
uniform float fogDistance;
|
||||
|
||||
varying vec3 vPosition;
|
||||
|
||||
void main (void)
|
||||
{
|
||||
vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0]));
|
||||
col *= gl_Color;
|
||||
float a = gl_Color.a;
|
||||
col = col * col; // SRGB -> Linear
|
||||
col *= 1.8;
|
||||
col.r = 1.0 - exp(1.0 - col.r) / exp(1.0);
|
||||
col.g = 1.0 - exp(1.0 - col.g) / exp(1.0);
|
||||
col.b = 1.0 - exp(1.0 - col.b) / exp(1.0);
|
||||
col = sqrt(col); // Linear -> SRGB
|
||||
if(fogDistance != 0.0){
|
||||
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
|
||||
a = mix(a, 0.0, d);
|
||||
}
|
||||
gl_FragColor = vec4(col.r, col.g, col.b, a);
|
||||
}
|
||||
53
client/shaders/test_shader_2/opengl_vertex.glsl
Normal file
@@ -0,0 +1,53 @@
|
||||
|
||||
uniform mat4 mWorldViewProj;
|
||||
uniform mat4 mInvWorld;
|
||||
uniform mat4 mTransWorld;
|
||||
uniform float dayNightRatio;
|
||||
|
||||
varying vec3 vPosition;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
vec4 pos = gl_Vertex;
|
||||
pos.y -= 2.0;
|
||||
gl_Position = mWorldViewProj * pos;
|
||||
|
||||
vPosition = (mWorldViewProj * gl_Vertex).xyz;
|
||||
|
||||
vec4 color;
|
||||
//color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
float day = gl_Color.r;
|
||||
float night = gl_Color.g;
|
||||
float light_source = gl_Color.b;
|
||||
|
||||
/*color.r = mix(night, day, dayNightRatio);
|
||||
color.g = color.r;
|
||||
color.b = color.r;*/
|
||||
|
||||
float rg = mix(night, day, dayNightRatio);
|
||||
rg += light_source * 1.0; // Make light sources brighter
|
||||
float b = rg;
|
||||
|
||||
// Moonlight is blue
|
||||
b += (day - night) / 13.0;
|
||||
rg -= (day - night) / 13.0;
|
||||
|
||||
// Emphase blue a bit in darker places
|
||||
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
|
||||
b += max(0.0, (1.0 - abs(b - 0.13)/0.17) * 0.025);
|
||||
|
||||
// Artificial light is yellow-ish
|
||||
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
|
||||
rg += max(0.0, (1.0 - abs(rg - 0.85)/0.15) * 0.065);
|
||||
|
||||
color.r = rg;
|
||||
color.g = rg;
|
||||
color.b = b;
|
||||
|
||||
color.a = gl_Color.a;
|
||||
|
||||
gl_FrontColor = gl_BackColor = color;
|
||||
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
Minetest Lua Modding API Reference 0.4.0
|
||||
Minetest Lua Modding API Reference 0.4.4
|
||||
==========================================
|
||||
More information at http://c55.me/minetest/
|
||||
|
||||
@@ -456,6 +456,10 @@ Special groups
|
||||
- disable_jump: Player (and possibly other things) cannot jump from node
|
||||
- fall_damage_add_percent: damage speed = speed * (1 + value/100)
|
||||
- bouncy: value is bounce speed in percent
|
||||
- falling_node: if there is no walkable block under the node it will fall
|
||||
- attached_node: if the node under it is not a walkable block the node will be
|
||||
dropped as an item. If the node is wallmounted the
|
||||
wallmounted direction is checked.
|
||||
|
||||
Known damage and digging time defining groups
|
||||
----------------------------------------------
|
||||
@@ -693,6 +697,15 @@ image[<X>,<Y>;<W>,<H>;<texture name>]
|
||||
^ Show an image
|
||||
^ Position and size units are inventory slots
|
||||
|
||||
item_image[<X>,<Y>;<W>,<H>;<item name>]
|
||||
^ Show an inventory image of registered item/node
|
||||
^ Position and size units are inventory slots
|
||||
|
||||
background[<X>,<Y>;<W>,<H>;<texture name>]
|
||||
^ Use a background. Inventory rectangles are not drawn then.
|
||||
^ Position and size units are inventory slots
|
||||
^ Example for formspec 8x4 in 16x resolution: image shall be sized 8*16px x 4*16px
|
||||
|
||||
field[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]
|
||||
^ Textual field; will be sent to server when a button is clicked
|
||||
^ x and y position the field relative to the top left of the menu
|
||||
@@ -729,6 +742,12 @@ image_button[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>]
|
||||
^ image is the filename of an image
|
||||
^ Position and size units are inventory slots
|
||||
|
||||
item_image_button[<X>,<Y>;<W>,<H>;<item name>;<name>;<label>]
|
||||
^ x, y, w, h, name and label work as per button
|
||||
^ item name is the registered name of an item/node,
|
||||
tooltip will be made out of its descritption
|
||||
^ Position and size units are inventory slots
|
||||
|
||||
button_exit[<X>,<Y>;<W>,<H>;<name>;<label>]
|
||||
^ When clicked, fields will be sent and the form will quit.
|
||||
|
||||
@@ -786,6 +805,11 @@ minetest.register_craft(recipe)
|
||||
Global callback registration functions: (Call these only at load time)
|
||||
minetest.register_globalstep(func(dtime))
|
||||
^ Called every server step, usually interval of 0.05s
|
||||
minetest.register_on_shutdown(func())
|
||||
^ Called before server shutdown
|
||||
^ WARNING: If the server terminates abnormally (i.e. crashes), the registered
|
||||
callbacks WILL LIKELY NOT BE RUN. Data should be saved at
|
||||
semi-frequent intervals as well as on server shutdown.
|
||||
minetest.register_on_placenode(func(pos, newnode, placer, oldnode))
|
||||
^ Called when a node has been placed
|
||||
^ Deprecated: Use on_construct or after_place_node in node definition instead
|
||||
@@ -1087,6 +1111,7 @@ methods:
|
||||
- punch(puncher, time_from_last_punch, tool_capabilities, direction)
|
||||
^ puncher = an another ObjectRef,
|
||||
^ time_from_last_punch = time since last punch action of the puncher
|
||||
^ direction: can be nil
|
||||
- right_click(clicker); clicker = an another ObjectRef
|
||||
- get_hp(): returns number of hitpoints (2 * number of hearts)
|
||||
- set_hp(hp): set number of hitpoints (2 * number of hearts)
|
||||
@@ -1096,6 +1121,10 @@ methods:
|
||||
- get_wielded_item() -> ItemStack
|
||||
- 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_detach()
|
||||
- set_bone_position("", {x=0,y=0,z=0}, {x=0,y=0,z=0})
|
||||
- set_properties(object property table)
|
||||
LuaEntitySAO-only: (no-op for other objects)
|
||||
- setvelocity({x=num, y=num, z=num})
|
||||
@@ -1121,7 +1150,11 @@ Player-only: (no-op for other objects)
|
||||
^ Redefine player's inventory form
|
||||
^ 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}
|
||||
- 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
|
||||
|
||||
InvRef: Reference to an inventory
|
||||
methods:
|
||||
- is_empty(listname): return true if list is empty
|
||||
@@ -1220,9 +1253,11 @@ Object Properties
|
||||
physical = true,
|
||||
weight = 5,
|
||||
collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
|
||||
visual = "cube"/"sprite"/"upright_sprite",
|
||||
visual = "cube"/"sprite"/"upright_sprite"/"mesh",
|
||||
visual_size = {x=1, y=1},
|
||||
mesh = "model",
|
||||
textures = {}, -- number of required textures depends on visual
|
||||
colors = {}, -- number of required colors depends on visual
|
||||
spritediv = {x=1, y=1},
|
||||
initial_sprite_basepos = {x=0, y=0},
|
||||
is_visible = true,
|
||||
@@ -1236,7 +1271,7 @@ Entity definition (register_entity)
|
||||
|
||||
initial_properties = <initial object properties>,
|
||||
|
||||
on_activate = function(self, staticdata),
|
||||
on_activate = function(self, staticdata, dtime_s),
|
||||
on_step = function(self, dtime),
|
||||
on_punch = function(self, hitter),
|
||||
on_rightclick = function(self, clicker),
|
||||
@@ -1345,6 +1380,8 @@ Node definition (register_node)
|
||||
liquid_alternative_flowing = "", -- Flowing version of source liquid
|
||||
liquid_alternative_source = "", -- Source version of flowing liquid
|
||||
liquid_viscosity = 0, -- Higher viscosity = slower flow (max. 7)
|
||||
liquid_renewable = true, -- Can new liquid source be created by placing
|
||||
two or more sources nearly?
|
||||
light_source = 0, -- Amount of light emitted by node
|
||||
damage_per_second = 0, -- If player is inside node, this damage is caused
|
||||
node_box = {type="regular"}, -- See "Node boxes"
|
||||
@@ -1420,6 +1457,11 @@ Node definition (register_node)
|
||||
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)
|
||||
|
||||
@@ -769,7 +769,7 @@ minetest.register_node("default:sand", {
|
||||
description = "Sand",
|
||||
tiles ={"default_sand.png"},
|
||||
is_ground_content = true,
|
||||
groups = {crumbly=3},
|
||||
groups = {crumbly=3, falling_node=1},
|
||||
sounds = default.node_sound_sand_defaults(),
|
||||
})
|
||||
|
||||
@@ -777,7 +777,7 @@ minetest.register_node("default:gravel", {
|
||||
description = "Gravel",
|
||||
tiles ={"default_gravel.png"},
|
||||
is_ground_content = true,
|
||||
groups = {crumbly=2},
|
||||
groups = {crumbly=2, falling_node=1},
|
||||
sounds = default.node_sound_dirt_defaults({
|
||||
footstep = {name="default_gravel_footstep", gain=0.45},
|
||||
}),
|
||||
@@ -837,7 +837,7 @@ minetest.register_node("default:junglegrass", {
|
||||
wield_image = "default_junglegrass.png",
|
||||
paramtype = "light",
|
||||
walkable = false,
|
||||
groups = {snappy=3},
|
||||
groups = {snappy=3,attached_node=1},
|
||||
sounds = default.node_sound_leaves_defaults(),
|
||||
})
|
||||
|
||||
@@ -1106,7 +1106,7 @@ minetest.register_node("default:torch", {
|
||||
wall_bottom = {-0.1, -0.5, -0.1, 0.1, -0.5+0.6, 0.1},
|
||||
wall_side = {-0.5, -0.3, -0.1, -0.5+0.3, 0.3, 0.1},
|
||||
},
|
||||
groups = {choppy=2,dig_immediate=3},
|
||||
groups = {choppy=2,dig_immediate=3,attached_node=1},
|
||||
legacy_wallmounted = true,
|
||||
sounds = default.node_sound_defaults(),
|
||||
})
|
||||
@@ -1127,7 +1127,7 @@ minetest.register_node("default:sign_wall", {
|
||||
--wall_bottom = <default>
|
||||
--wall_side = <default>
|
||||
},
|
||||
groups = {choppy=2,dig_immediate=2},
|
||||
groups = {choppy=2,dig_immediate=2,attached_node=1},
|
||||
legacy_wallmounted = true,
|
||||
sounds = default.node_sound_defaults(),
|
||||
on_construct = function(pos)
|
||||
@@ -1495,7 +1495,7 @@ minetest.register_node("default:sapling", {
|
||||
wield_image = "default_sapling.png",
|
||||
paramtype = "light",
|
||||
walkable = false,
|
||||
groups = {snappy=2,dig_immediate=3},
|
||||
groups = {snappy=2,dig_immediate=3,attached_node=1},
|
||||
sounds = default.node_sound_defaults(),
|
||||
})
|
||||
|
||||
@@ -1586,73 +1586,22 @@ minetest.register_alias("mapgen_stone_with_coal", "default:stone_with_coal")
|
||||
minetest.register_alias("mapgen_stone_with_iron", "default:stone_with_iron")
|
||||
minetest.register_alias("mapgen_mese", "default:mese")
|
||||
|
||||
--
|
||||
-- Some common functions
|
||||
--
|
||||
|
||||
default.falling_node_names = {}
|
||||
|
||||
function nodeupdate_single(p)
|
||||
n = minetest.env:get_node(p)
|
||||
if default.falling_node_names[n.name] ~= nil then
|
||||
p_bottom = {x=p.x, y=p.y-1, z=p.z}
|
||||
n_bottom = minetest.env:get_node(p_bottom)
|
||||
if n_bottom.name == "air" then
|
||||
minetest.env:remove_node(p)
|
||||
minetest.env:add_entity(p, "default:falling_"..n.name)
|
||||
nodeupdate(p)
|
||||
end
|
||||
end
|
||||
-- Support old code
|
||||
function default.spawn_falling_node(p, nodename)
|
||||
spawn_falling_node(p, nodename)
|
||||
end
|
||||
|
||||
function nodeupdate(p)
|
||||
for x = -1,1 do
|
||||
for y = -1,1 do
|
||||
for z = -1,1 do
|
||||
p2 = {x=p.x+x, y=p.y+y, z=p.z+z}
|
||||
nodeupdate_single(p2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Falling stuff
|
||||
--
|
||||
|
||||
-- Horrible crap to support old code
|
||||
-- Don't use this and never do what this does, it's completely wrong!
|
||||
-- (More specifically, the client and the C++ code doesn't get the group)
|
||||
function default.register_falling_node(nodename, texture)
|
||||
default.falling_node_names[nodename] = true
|
||||
-- Override naming conventions for stuff like :default:falling_default:sand
|
||||
minetest.register_entity(":default:falling_"..nodename, {
|
||||
-- Static definition
|
||||
physical = true,
|
||||
collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
|
||||
visual = "cube",
|
||||
textures = {texture,texture,texture,texture,texture,texture},
|
||||
-- State
|
||||
-- Methods
|
||||
on_step = function(self, dtime)
|
||||
-- Set gravity
|
||||
self.object:setacceleration({x=0, y=-10, z=0})
|
||||
-- Turn to actual sand when collides to ground or just move
|
||||
local pos = self.object:getpos()
|
||||
local bcp = {x=pos.x, y=pos.y-0.7, z=pos.z} -- Position of bottom center point
|
||||
local bcn = minetest.env:get_node(bcp)
|
||||
if bcn.name ~= "air" then
|
||||
-- Turn to a sand node
|
||||
local np = {x=bcp.x, y=bcp.y+1, z=bcp.z}
|
||||
minetest.env:add_node(np, {name=nodename})
|
||||
self.object:remove()
|
||||
else
|
||||
-- Do nothing
|
||||
end
|
||||
end
|
||||
})
|
||||
minetest.log("error", debug.traceback())
|
||||
minetest.log('error', "WARNING: default.register_falling_node is deprecated")
|
||||
if minetest.registered_nodes[nodename] then
|
||||
minetest.registered_nodes[nodename].groups.falling_node = 1
|
||||
end
|
||||
end
|
||||
|
||||
default.register_falling_node("default:sand", "default_sand.png")
|
||||
default.register_falling_node("default:gravel", "default_gravel.png")
|
||||
|
||||
--
|
||||
-- Global callbacks
|
||||
--
|
||||
@@ -1665,13 +1614,11 @@ minetest.register_globalstep(on_step)
|
||||
|
||||
function on_placenode(p, node)
|
||||
--print("on_placenode")
|
||||
nodeupdate(p)
|
||||
end
|
||||
minetest.register_on_placenode(on_placenode)
|
||||
|
||||
function on_dignode(p, node)
|
||||
--print("on_dignode")
|
||||
nodeupdate(p)
|
||||
end
|
||||
minetest.register_on_dignode(on_dignode)
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 303 B After Width: | Height: | Size: 317 B |
|
Before Width: | Height: | Size: 410 B After Width: | Height: | Size: 378 B |
|
Before Width: | Height: | Size: 203 B After Width: | Height: | Size: 206 B |
|
Before Width: | Height: | Size: 260 B After Width: | Height: | Size: 231 B |
@@ -117,6 +117,9 @@
|
||||
#screenshot_path = .
|
||||
# Amount of view bobbing (0 = no view bobbing, 1.0 = normal, 2.0 = double)
|
||||
#view_bobbing_amount = 1.0
|
||||
# Anaglyph stereo
|
||||
#anaglyph = false
|
||||
#anaglyph_strength = 0.1
|
||||
# In-game chat console background color (R,G,B)
|
||||
#console_color = (0,0,0)
|
||||
# In-game chat console background alpha (opaqueness, between 0 and 255)
|
||||
@@ -126,6 +129,17 @@
|
||||
#sound_volume = 0.7
|
||||
# Whether node texture animations should be desynchronized per MapBlock
|
||||
#desynchronize_mapblock_texture_animation = true
|
||||
# Texture filtering settings
|
||||
#mip_map = false
|
||||
#anisotropic_filter = false
|
||||
#bilinear_filter = false
|
||||
#trilinear_filter = false
|
||||
# Set to true to pre-generate all item visuals
|
||||
#preload_item_visuals = true
|
||||
# 0: disable shaders
|
||||
# (1: low level shaders; not implemented)
|
||||
# 2: enable high level shaders
|
||||
#enable_shaders = 2
|
||||
|
||||
#
|
||||
# Server stuff
|
||||
@@ -139,8 +153,8 @@
|
||||
#motd = Welcome to this awesome Minetest server!
|
||||
# Maximum number of players connected simultaneously
|
||||
#max_users = 100
|
||||
# Set to false to allow old clients to connect
|
||||
#strict_protocol_version_checking = true
|
||||
# Set to true to disallow old clients from connecting
|
||||
#strict_protocol_version_checking = false
|
||||
# Set to true to enable creative mode (unlimited inventory)
|
||||
#creative_mode = false
|
||||
# Enable players getting damage and dying
|
||||
@@ -194,7 +208,12 @@
|
||||
# To reduce lag, block transfers are slowed down when a player is building something.
|
||||
# This determines how long they are slowed down after placing or removing a node.
|
||||
#full_block_send_enable_min_time_from_building = 2.0
|
||||
# Length of a server tick in dedicated server
|
||||
#dedicated_server_step = 0.05
|
||||
# Length of a server tick and the interval at which objects are generally updated over network
|
||||
#dedicated_server_step = 0.1
|
||||
# Can be set to true to disable shutting down on invalid world data
|
||||
#ignore_world_load_errors = false
|
||||
# Congestion control parameters
|
||||
# time in seconds, rate in ~500B packets
|
||||
#congestion_control_aim_rtt = 0.2
|
||||
#congestion_control_max_rate = 400
|
||||
#congestion_control_min_rate = 10
|
||||
|
||||
@@ -202,6 +202,8 @@ set(common_SRCS
|
||||
sha1.cpp
|
||||
base64.cpp
|
||||
ban.cpp
|
||||
clientserver.cpp
|
||||
staticobject.cpp
|
||||
util/serialize.cpp
|
||||
util/directiontables.cpp
|
||||
util/numeric.cpp
|
||||
@@ -260,6 +262,7 @@ set(minetest_SRCS
|
||||
client.cpp
|
||||
filecache.cpp
|
||||
tile.cpp
|
||||
shader.cpp
|
||||
game.cpp
|
||||
main.cpp
|
||||
)
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#ifndef BASE64_HEADER
|
||||
#define BASE64_HEADER
|
||||
|
||||
#include <string>
|
||||
|
||||
bool base64_is_valid(std::string const& s);
|
||||
std::string base64_encode(unsigned char const* , unsigned int len);
|
||||
std::string base64_decode(std::string const& s);
|
||||
|
||||
#endif // BASE64_HEADER
|
||||
@@ -336,13 +336,13 @@ void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize,
|
||||
if (m_digging_button != -1)
|
||||
{
|
||||
f32 digfrac = m_digging_anim;
|
||||
wield_position.X -= 30 * sin(pow(digfrac, 0.8f) * M_PI);
|
||||
wield_position.Y += 15 * sin(digfrac * 2 * M_PI);
|
||||
wield_position.Z += 5 * digfrac;
|
||||
|
||||
wield_position.X -= 50 * sin(pow(digfrac, 0.8f) * M_PI);
|
||||
wield_position.Y += 24 * sin(digfrac * 1.8 * M_PI);
|
||||
wield_position.Z += 25 * 0.5;
|
||||
|
||||
// Euler angles are PURE EVIL, so why not use quaternions?
|
||||
core::quaternion quat_begin(wield_rotation * core::DEGTORAD);
|
||||
core::quaternion quat_end(v3f(90, -10, -130) * core::DEGTORAD);
|
||||
core::quaternion quat_end(v3f(80, 30, 100) * core::DEGTORAD);
|
||||
core::quaternion quat_slerp;
|
||||
quat_slerp.slerp(quat_begin, quat_end, sin(digfrac * M_PI));
|
||||
quat_slerp.toEuler(wield_rotation);
|
||||
@@ -529,7 +529,7 @@ void Camera::setDigging(s32 button)
|
||||
void Camera::wield(const ItemStack &item)
|
||||
{
|
||||
IItemDefManager *idef = m_gamedef->idef();
|
||||
scene::IMesh *wield_mesh = item.getDefinition(idef).wield_mesh;
|
||||
scene::IMesh *wield_mesh = idef->getWieldMesh(item.getDefinition(idef).name, m_gamedef);
|
||||
if(wield_mesh)
|
||||
{
|
||||
m_wieldnode->setMesh(wield_mesh);
|
||||
@@ -544,7 +544,7 @@ void Camera::wield(const ItemStack &item)
|
||||
void Camera::drawWieldedTool()
|
||||
{
|
||||
// Set vertex colors of wield mesh according to light level
|
||||
u8 li = decode_light(m_wieldlight);
|
||||
u8 li = m_wieldlight;
|
||||
video::SColor color(255,li,li,li);
|
||||
setMeshColor(m_wieldnode->getMesh(), color);
|
||||
|
||||
|
||||
119
src/client.cpp
@@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "nodemetadata.h"
|
||||
#include "nodedef.h"
|
||||
#include "itemdef.h"
|
||||
#include "shader.h"
|
||||
#include <IFileSystem.h>
|
||||
#include "sha1.h"
|
||||
#include "base64.h"
|
||||
@@ -41,6 +42,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "sound.h"
|
||||
#include "util/string.h"
|
||||
#include "hex.h"
|
||||
#include "IMeshCache.h"
|
||||
#include "util/serialize.h"
|
||||
|
||||
static std::string getMediaCacheDir()
|
||||
{
|
||||
@@ -226,12 +229,14 @@ Client::Client(
|
||||
std::string password,
|
||||
MapDrawControl &control,
|
||||
IWritableTextureSource *tsrc,
|
||||
IWritableShaderSource *shsrc,
|
||||
IWritableItemDefManager *itemdef,
|
||||
IWritableNodeDefManager *nodedef,
|
||||
ISoundManager *sound,
|
||||
MtEventManager *event
|
||||
):
|
||||
m_tsrc(tsrc),
|
||||
m_shsrc(shsrc),
|
||||
m_itemdef(itemdef),
|
||||
m_nodedef(nodedef),
|
||||
m_sound(sound),
|
||||
@@ -265,6 +270,7 @@ Client::Client(
|
||||
m_time_of_day_set(false),
|
||||
m_last_time_of_day_f(-1),
|
||||
m_time_of_day_update_timer(0),
|
||||
m_recommended_send_interval(0.1),
|
||||
m_removed_sounds_check_timer(0)
|
||||
{
|
||||
m_packetcounter_timer = 0.0;
|
||||
@@ -498,8 +504,9 @@ void Client::step(float dtime)
|
||||
// [2] u8 SER_FMT_VER_HIGHEST
|
||||
// [3] u8[20] player_name
|
||||
// [23] u8[28] password (new in some version)
|
||||
// [51] u16 client network protocol version (new in some version)
|
||||
SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2);
|
||||
// [51] u16 minimum supported network protocol version (added sometime)
|
||||
// [53] u16 maximum supported network protocol version (added later than the previous one)
|
||||
SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2);
|
||||
writeU16(&data[0], TOSERVER_INIT);
|
||||
writeU8(&data[2], SER_FMT_VER_HIGHEST);
|
||||
|
||||
@@ -512,8 +519,8 @@ void Client::step(float dtime)
|
||||
memset((char*)&data[23], 0, PASSWORD_SIZE);
|
||||
snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
|
||||
|
||||
// This should be incremented in each version
|
||||
writeU16(&data[51], PROTOCOL_VERSION);
|
||||
writeU16(&data[51], CLIENT_PROTOCOL_VERSION_MIN);
|
||||
writeU16(&data[53], CLIENT_PROTOCOL_VERSION_MAX);
|
||||
|
||||
// Send as unreliable
|
||||
Send(0, data, false);
|
||||
@@ -655,7 +662,7 @@ void Client::step(float dtime)
|
||||
{
|
||||
float &counter = m_playerpos_send_timer;
|
||||
counter += dtime;
|
||||
if(counter >= 0.2)
|
||||
if(counter >= m_recommended_send_interval)
|
||||
{
|
||||
counter = 0.0;
|
||||
sendPlayerPos();
|
||||
@@ -821,7 +828,7 @@ bool Client::loadMedia(const std::string &data, const std::string &filename)
|
||||
if(name != "")
|
||||
{
|
||||
verbosestream<<"Client: Attempting to load image "
|
||||
<<"file \""<<filename<<"\""<<std::endl;
|
||||
<<"file \""<<filename<<"\""<<std::endl;
|
||||
|
||||
io::IFileSystem *irrfs = m_device->getFileSystem();
|
||||
video::IVideoDriver *vdrv = m_device->getVideoDriver();
|
||||
@@ -855,11 +862,33 @@ bool Client::loadMedia(const std::string &data, const std::string &filename)
|
||||
if(name != "")
|
||||
{
|
||||
verbosestream<<"Client: Attempting to load sound "
|
||||
<<"file \""<<filename<<"\""<<std::endl;
|
||||
<<"file \""<<filename<<"\""<<std::endl;
|
||||
m_sound->loadSoundData(name, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *model_ext[] = {
|
||||
".x", ".b3d", ".md2", ".obj",
|
||||
NULL
|
||||
};
|
||||
name = removeStringEnd(filename, model_ext);
|
||||
if(name != "")
|
||||
{
|
||||
verbosestream<<"Client: Storing model into Irrlicht: "
|
||||
<<"\""<<filename<<"\""<<std::endl;
|
||||
|
||||
io::IFileSystem *irrfs = m_device->getFileSystem();
|
||||
io::IReadFile *rfile = irrfs->createMemoryReadFile(
|
||||
*data_rw, data_rw.getSize(), filename.c_str());
|
||||
assert(rfile);
|
||||
|
||||
scene::ISceneManager *smgr = m_device->getSceneManager();
|
||||
scene::IAnimatedMesh *mesh = smgr->getMesh(rfile);
|
||||
smgr->getMeshCache()->addMesh(filename.c_str(), mesh);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
errorstream<<"Client: Don't know how to load file \""
|
||||
<<filename<<"\""<<std::endl;
|
||||
return false;
|
||||
@@ -997,6 +1026,14 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||
m_map_seed = readU64(&data[2+1+6]);
|
||||
infostream<<"Client: received map seed: "<<m_map_seed<<std::endl;
|
||||
}
|
||||
|
||||
if(datasize >= 2+1+6+8+4)
|
||||
{
|
||||
// Get map seed
|
||||
m_recommended_send_interval = readF1000(&data[2+1+6+8]);
|
||||
infostream<<"Client: received recommended send interval "
|
||||
<<m_recommended_send_interval<<std::endl;
|
||||
}
|
||||
|
||||
// Reply to server
|
||||
u32 replysize = 2;
|
||||
@@ -1434,8 +1471,8 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||
|
||||
int num_files = readU16(is);
|
||||
|
||||
verbosestream<<"Client received TOCLIENT_ANNOUNCE_MEDIA ("
|
||||
<<num_files<<" files)"<<std::endl;
|
||||
infostream<<"Client: Received media announcement: packet size: "
|
||||
<<datasize<<std::endl;
|
||||
|
||||
core::list<MediaRequest> file_requests;
|
||||
|
||||
@@ -1939,10 +1976,24 @@ void Client::sendPlayerPos()
|
||||
{
|
||||
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
|
||||
|
||||
Player *myplayer = m_env.getLocalPlayer();
|
||||
LocalPlayer *myplayer = m_env.getLocalPlayer();
|
||||
if(myplayer == NULL)
|
||||
return;
|
||||
|
||||
|
||||
// Save bandwidth by only updating position when something changed
|
||||
if(myplayer->last_position == myplayer->getPosition() &&
|
||||
myplayer->last_speed == myplayer->getSpeed() &&
|
||||
myplayer->last_pitch == myplayer->getPitch() &&
|
||||
myplayer->last_yaw == myplayer->getYaw() &&
|
||||
myplayer->last_keyPressed == myplayer->keyPressed)
|
||||
return;
|
||||
|
||||
myplayer->last_position = myplayer->getPosition();
|
||||
myplayer->last_speed = myplayer->getSpeed();
|
||||
myplayer->last_pitch = myplayer->getPitch();
|
||||
myplayer->last_yaw = myplayer->getYaw();
|
||||
myplayer->last_keyPressed = myplayer->keyPressed;
|
||||
|
||||
u16 our_peer_id;
|
||||
{
|
||||
//JMutexAutoLock lock(m_con_mutex); //bulk comment-out
|
||||
@@ -1961,7 +2012,7 @@ void Client::sendPlayerPos()
|
||||
v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
|
||||
s32 pitch = myplayer->getPitch() * 100;
|
||||
s32 yaw = myplayer->getYaw() * 100;
|
||||
|
||||
u32 keyPressed=myplayer->keyPressed;
|
||||
/*
|
||||
Format:
|
||||
[0] u16 command
|
||||
@@ -1969,15 +2020,15 @@ void Client::sendPlayerPos()
|
||||
[2+12] v3s32 speed*100
|
||||
[2+12+12] s32 pitch*100
|
||||
[2+12+12+4] s32 yaw*100
|
||||
[2+12+12+4+4] u32 keyPressed
|
||||
*/
|
||||
|
||||
SharedBuffer<u8> data(2+12+12+4+4);
|
||||
SharedBuffer<u8> data(2+12+12+4+4+4);
|
||||
writeU16(&data[0], TOSERVER_PLAYERPOS);
|
||||
writeV3S32(&data[2], position);
|
||||
writeV3S32(&data[2+12], speed);
|
||||
writeS32(&data[2+12+12], pitch);
|
||||
writeS32(&data[2+12+12+4], yaw);
|
||||
|
||||
writeS32(&data[2+12+12+4], yaw);
|
||||
writeU32(&data[2+12+12+4+4], keyPressed);
|
||||
// Send as unreliable
|
||||
Send(0, data, false);
|
||||
}
|
||||
@@ -2404,7 +2455,7 @@ ClientEvent Client::getClientEvent()
|
||||
|
||||
void Client::afterContentReceived()
|
||||
{
|
||||
verbosestream<<"Client::afterContentReceived() started"<<std::endl;
|
||||
infostream<<"Client::afterContentReceived() started"<<std::endl;
|
||||
assert(m_itemdef_received);
|
||||
assert(m_nodedef_received);
|
||||
assert(m_media_received);
|
||||
@@ -2414,31 +2465,43 @@ void Client::afterContentReceived()
|
||||
m_media_name_sha1_map.clear();
|
||||
|
||||
// Rebuild inherited images and recreate textures
|
||||
verbosestream<<"Rebuilding images and textures"<<std::endl;
|
||||
infostream<<"- Rebuilding images and textures"<<std::endl;
|
||||
m_tsrc->rebuildImagesAndTextures();
|
||||
|
||||
// Update texture atlas
|
||||
verbosestream<<"Updating texture atlas"<<std::endl;
|
||||
infostream<<"- Updating texture atlas"<<std::endl;
|
||||
if(g_settings->getBool("enable_texture_atlas"))
|
||||
m_tsrc->buildMainAtlas(this);
|
||||
|
||||
// Rebuild shaders
|
||||
m_shsrc->rebuildShaders();
|
||||
|
||||
// Update node aliases
|
||||
verbosestream<<"Updating node aliases"<<std::endl;
|
||||
infostream<<"- Updating node aliases"<<std::endl;
|
||||
m_nodedef->updateAliases(m_itemdef);
|
||||
|
||||
// Update node textures
|
||||
verbosestream<<"Updating node textures"<<std::endl;
|
||||
infostream<<"- Updating node textures"<<std::endl;
|
||||
m_nodedef->updateTextures(m_tsrc);
|
||||
|
||||
// Update item textures and meshes
|
||||
verbosestream<<"Updating item textures and meshes"<<std::endl;
|
||||
m_itemdef->updateTexturesAndMeshes(this);
|
||||
// Preload item textures and meshes if configured to
|
||||
if(g_settings->getBool("preload_item_visuals"))
|
||||
{
|
||||
verbosestream<<"Updating item textures and meshes"<<std::endl;
|
||||
std::set<std::string> names = m_itemdef->getAll();
|
||||
for(std::set<std::string>::const_iterator
|
||||
i = names.begin(); i != names.end(); ++i){
|
||||
// Asking for these caches the result
|
||||
m_itemdef->getInventoryTexture(*i, this);
|
||||
m_itemdef->getWieldMesh(*i, this);
|
||||
}
|
||||
}
|
||||
|
||||
// Start mesh update thread after setting up content definitions
|
||||
verbosestream<<"Starting mesh update thread"<<std::endl;
|
||||
infostream<<"- Starting mesh update thread"<<std::endl;
|
||||
m_mesh_update_thread.Start();
|
||||
|
||||
verbosestream<<"Client::afterContentReceived() done"<<std::endl;
|
||||
infostream<<"Client::afterContentReceived() done"<<std::endl;
|
||||
}
|
||||
|
||||
float Client::getRTT(void)
|
||||
@@ -2469,6 +2532,10 @@ ITextureSource* Client::getTextureSource()
|
||||
{
|
||||
return m_tsrc;
|
||||
}
|
||||
IShaderSource* Client::getShaderSource()
|
||||
{
|
||||
return m_shsrc;
|
||||
}
|
||||
u16 Client::allocateUnknownNodeId(const std::string &name)
|
||||
{
|
||||
errorstream<<"Client::allocateUnknownNodeId(): "
|
||||
|
||||
@@ -39,6 +39,7 @@ struct MeshMakeData;
|
||||
class MapBlockMesh;
|
||||
class IGameDef;
|
||||
class IWritableTextureSource;
|
||||
class IWritableShaderSource;
|
||||
class IWritableItemDefManager;
|
||||
class IWritableNodeDefManager;
|
||||
//class IWritableCraftDefManager;
|
||||
@@ -174,6 +175,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
|
||||
std::string password,
|
||||
MapDrawControl &control,
|
||||
IWritableTextureSource *tsrc,
|
||||
IWritableShaderSource *shsrc,
|
||||
IWritableItemDefManager *itemdef,
|
||||
IWritableNodeDefManager *nodedef,
|
||||
ISoundManager *sound,
|
||||
@@ -305,6 +307,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
|
||||
virtual INodeDefManager* getNodeDefManager();
|
||||
virtual ICraftDefManager* getCraftDefManager();
|
||||
virtual ITextureSource* getTextureSource();
|
||||
virtual IShaderSource* getShaderSource();
|
||||
virtual u16 allocateUnknownNodeId(const std::string &name);
|
||||
virtual ISoundManager* getSoundManager();
|
||||
virtual MtEventManager* getEventManager();
|
||||
@@ -337,6 +340,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
|
||||
IntervalLimiter m_map_timer_and_unload_interval;
|
||||
|
||||
IWritableTextureSource *m_tsrc;
|
||||
IWritableShaderSource *m_shsrc;
|
||||
IWritableItemDefManager *m_itemdef;
|
||||
IWritableNodeDefManager *m_nodedef;
|
||||
ISoundManager *m_sound;
|
||||
@@ -382,6 +386,9 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
|
||||
float m_last_time_of_day_f;
|
||||
float m_time_of_day_update_timer;
|
||||
|
||||
// An interval for generally sending object positions and stuff
|
||||
float m_recommended_send_interval;
|
||||
|
||||
// Sounds
|
||||
float m_removed_sounds_check_timer;
|
||||
// Mapping from server sound ids to our sound ids
|
||||
|
||||
@@ -352,13 +352,17 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
|
||||
if(sector_blocks_drawn != 0)
|
||||
m_last_drawn_sectors[sp] = true;
|
||||
}
|
||||
|
||||
|
||||
m_control.blocks_would_have_drawn = blocks_would_have_drawn;
|
||||
m_control.blocks_drawn = blocks_drawn;
|
||||
|
||||
g_profiler->avg("CM: blocks in range", blocks_in_range);
|
||||
g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled);
|
||||
if(blocks_in_range != 0)
|
||||
g_profiler->avg("CM: blocks in range without mesh (frac)",
|
||||
(float)blocks_in_range_without_mesh/blocks_in_range);
|
||||
g_profiler->avg("CM: blocks drawn", blocks_drawn);
|
||||
g_profiler->avg("CM: wanted max blocks", m_control.wanted_max_blocks);
|
||||
}
|
||||
|
||||
struct MeshBufList
|
||||
@@ -413,6 +417,10 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||
m_last_drawn_sectors.clear();
|
||||
}
|
||||
|
||||
bool use_trilinear_filter = g_settings->getBool("trilinear_filter");
|
||||
bool use_bilinear_filter = g_settings->getBool("bilinear_filter");
|
||||
bool use_anisotropic_filter = g_settings->getBool("anisotropic_filter");
|
||||
|
||||
/*
|
||||
Get time for measuring timeout.
|
||||
|
||||
@@ -463,9 +471,6 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||
u32 mesh_animate_count = 0;
|
||||
u32 mesh_animate_count_far = 0;
|
||||
|
||||
// Blocks that had mesh that would have been drawn according to
|
||||
// rendering range (if max blocks limit didn't kick in)
|
||||
u32 blocks_would_have_drawn = 0;
|
||||
// Blocks that were drawn and had a mesh
|
||||
u32 blocks_drawn = 0;
|
||||
// Blocks which had a corresponding meshbuffer for this pass
|
||||
@@ -544,6 +549,11 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||
for(u32 i=0; i<c; i++)
|
||||
{
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
|
||||
|
||||
buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
|
||||
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
|
||||
buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
|
||||
|
||||
const video::SMaterial& material = buf->getMaterial();
|
||||
video::IMaterialRenderer* rnd =
|
||||
driver->getMaterialRenderer(material.MaterialType);
|
||||
@@ -656,9 +666,6 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||
g_profiler->avg(prefix+"empty blocks (frac)",
|
||||
(float)blocks_without_stuff / blocks_drawn);
|
||||
|
||||
m_control.blocks_drawn = blocks_drawn;
|
||||
m_control.blocks_would_have_drawn = blocks_would_have_drawn;
|
||||
|
||||
/*infostream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
|
||||
<<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ ClientActiveObject::ClientActiveObject(u16 id, IGameDef *gamedef,
|
||||
|
||||
ClientActiveObject::~ClientActiveObject()
|
||||
{
|
||||
removeFromScene();
|
||||
removeFromScene(true);
|
||||
}
|
||||
|
||||
ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef,
|
||||
|
||||
@@ -49,13 +49,19 @@ class ClientActiveObject : public ActiveObject
|
||||
|
||||
virtual void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
|
||||
IrrlichtDevice *irr){}
|
||||
virtual void removeFromScene(){}
|
||||
virtual void removeFromScene(bool permanent){}
|
||||
// 0 <= light_at_pos <= LIGHT_SUN
|
||||
virtual void updateLight(u8 light_at_pos){}
|
||||
virtual v3s16 getLightPosition(){return v3s16(0,0,0);}
|
||||
virtual core::aabbox3d<f32>* getSelectionBox(){return NULL;}
|
||||
virtual core::aabbox3d<f32>* getCollisionBox(){return NULL;}
|
||||
virtual v3f getPosition(){return v3f(0,0,0);}
|
||||
virtual scene::IMeshSceneNode *getMeshSceneNode(){return NULL;}
|
||||
virtual scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode(){return NULL;}
|
||||
virtual scene::IBillboardSceneNode *getSpriteSceneNode(){return NULL;}
|
||||
virtual bool isPlayer(){return false;}
|
||||
virtual bool isLocalPlayer(){return false;}
|
||||
virtual void setAttachments(){}
|
||||
virtual bool doShowSelectionBox(){return true;}
|
||||
|
||||
// Step object in time
|
||||
|
||||
31
src/clientserver.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "clientserver.h"
|
||||
#include "util/serialize.h"
|
||||
|
||||
SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time, float time_speed)
|
||||
{
|
||||
SharedBuffer<u8> data(2+2+4);
|
||||
writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
|
||||
writeU16(&data[2], time);
|
||||
writeF1000(&data[4], time_speed);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
@@ -20,7 +20,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#ifndef CLIENTSERVER_HEADER
|
||||
#define CLIENTSERVER_HEADER
|
||||
|
||||
#include "util/serialize.h"
|
||||
#include "util/pointer.h"
|
||||
|
||||
SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time, float time_speed);
|
||||
|
||||
/*
|
||||
changes by PROTOCOL_VERSION:
|
||||
@@ -67,10 +69,27 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
TOCLIENT_DETACHED_INVENTORY
|
||||
PROTOCOL_VERSION 13:
|
||||
InventoryList field "Width" (deserialization fails with old versions)
|
||||
PROTOCOL_VERSION 14:
|
||||
Added transfer of player pressed keys to the server
|
||||
Added new messages for mesh and bone animation, as well as attachments
|
||||
GENERIC_CMD_SET_ANIMATION
|
||||
GENERIC_CMD_SET_BONE_POSITION
|
||||
GENERIC_CMD_SET_ATTACHMENT
|
||||
PROTOCOL_VERSION 15:
|
||||
Serialization format changes
|
||||
*/
|
||||
|
||||
#define PROTOCOL_VERSION 13
|
||||
#define LATEST_PROTOCOL_VERSION 15
|
||||
|
||||
// Server's supported network protocol range
|
||||
#define SERVER_PROTOCOL_VERSION_MIN 13
|
||||
#define SERVER_PROTOCOL_VERSION_MAX LATEST_PROTOCOL_VERSION
|
||||
|
||||
// Client's supported network protocol range
|
||||
#define CLIENT_PROTOCOL_VERSION_MIN 13
|
||||
#define CLIENT_PROTOCOL_VERSION_MAX LATEST_PROTOCOL_VERSION
|
||||
|
||||
// Constant that differentiates the protocol from random data and other protocols
|
||||
#define PROTOCOL_ID 0x4f457403
|
||||
|
||||
#define PASSWORD_SIZE 28 // Maximum password length. Allows for
|
||||
@@ -89,6 +108,7 @@ enum ToClientCommand
|
||||
[2] u8 deployed version
|
||||
[3] v3s16 player's position + v3f(0,BS/2,0) floatToInt'd
|
||||
[12] u64 map seed (new as of 2011-02-27)
|
||||
[20] f1000 recommended send interval (in seconds) (new as of 14)
|
||||
|
||||
NOTE: The position in here is deprecated; position is
|
||||
explicitly sent afterwards
|
||||
@@ -344,7 +364,8 @@ enum ToServerCommand
|
||||
[2] u8 SER_FMT_VER_HIGHEST
|
||||
[3] u8[20] player_name
|
||||
[23] u8[28] password (new in some version)
|
||||
[51] u16 client network protocol version (new in some version)
|
||||
[51] u16 minimum supported network protocol version (added sometime)
|
||||
[53] u16 maximum supported network protocol version (added later than the previous one)
|
||||
*/
|
||||
|
||||
TOSERVER_INIT2 = 0x11,
|
||||
@@ -366,6 +387,7 @@ enum ToServerCommand
|
||||
[2+12] v3s32 speed*100
|
||||
[2+12+12] s32 pitch*100
|
||||
[2+12+12+4] s32 yaw*100
|
||||
[2+12+12+4+4] u32 keyPressed
|
||||
*/
|
||||
|
||||
TOSERVER_GOTBLOCKS = 0x24,
|
||||
@@ -551,14 +573,5 @@ enum ToServerCommand
|
||||
|
||||
};
|
||||
|
||||
inline SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time, float time_speed)
|
||||
{
|
||||
SharedBuffer<u8> data(2+2+4);
|
||||
writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
|
||||
writeU16(&data[2], time);
|
||||
writeF1000(&data[4], time_speed);
|
||||
return data;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "util/serialize.h"
|
||||
#include "util/numeric.h"
|
||||
#include "util/string.h"
|
||||
#include "settings.h"
|
||||
|
||||
namespace con
|
||||
{
|
||||
@@ -466,7 +467,10 @@ Peer::Peer(u16 a_id, Address a_address):
|
||||
m_sendtime_accu(0),
|
||||
m_max_packets_per_second(10),
|
||||
m_num_sent(0),
|
||||
m_max_num_sent(0)
|
||||
m_max_num_sent(0),
|
||||
congestion_control_aim_rtt(0.2),
|
||||
congestion_control_max_rate(400),
|
||||
congestion_control_min_rate(10)
|
||||
{
|
||||
}
|
||||
Peer::~Peer()
|
||||
@@ -477,15 +481,15 @@ void Peer::reportRTT(float rtt)
|
||||
{
|
||||
if(rtt >= 0.0){
|
||||
if(rtt < 0.01){
|
||||
if(m_max_packets_per_second < 400)
|
||||
if(m_max_packets_per_second < congestion_control_max_rate)
|
||||
m_max_packets_per_second += 10;
|
||||
} else if(rtt < 0.2){
|
||||
if(m_max_packets_per_second < 100)
|
||||
} else if(rtt < congestion_control_aim_rtt){
|
||||
if(m_max_packets_per_second < congestion_control_max_rate)
|
||||
m_max_packets_per_second += 2;
|
||||
} else {
|
||||
m_max_packets_per_second *= 0.8;
|
||||
if(m_max_packets_per_second < 10)
|
||||
m_max_packets_per_second = 10;
|
||||
if(m_max_packets_per_second < congestion_control_min_rate)
|
||||
m_max_packets_per_second = congestion_control_min_rate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -891,12 +895,24 @@ void Connection::receive()
|
||||
|
||||
void Connection::runTimeouts(float dtime)
|
||||
{
|
||||
float congestion_control_aim_rtt
|
||||
= g_settings->getFloat("congestion_control_aim_rtt");
|
||||
float congestion_control_max_rate
|
||||
= g_settings->getFloat("congestion_control_max_rate");
|
||||
float congestion_control_min_rate
|
||||
= g_settings->getFloat("congestion_control_min_rate");
|
||||
|
||||
core::list<u16> timeouted_peers;
|
||||
core::map<u16, Peer*>::Iterator j;
|
||||
j = m_peers.getIterator();
|
||||
for(; j.atEnd() == false; j++)
|
||||
{
|
||||
Peer *peer = j.getNode()->getValue();
|
||||
|
||||
// Update congestion control values
|
||||
peer->congestion_control_aim_rtt = congestion_control_aim_rtt;
|
||||
peer->congestion_control_max_rate = congestion_control_max_rate;
|
||||
peer->congestion_control_min_rate = congestion_control_min_rate;
|
||||
|
||||
/*
|
||||
Check peer timeout
|
||||
|
||||
@@ -394,7 +394,11 @@ class Peer
|
||||
float m_max_packets_per_second;
|
||||
int m_num_sent;
|
||||
int m_max_num_sent;
|
||||
|
||||
|
||||
// Updated from configuration by Connection
|
||||
float congestion_control_aim_rtt;
|
||||
float congestion_control_max_rate;
|
||||
float congestion_control_min_rate;
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
@@ -40,6 +40,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "util/serialize.h"
|
||||
#include "util/mathconstants.h"
|
||||
#include "map.h"
|
||||
#include "main.h" // g_settings
|
||||
#include <IMeshManipulator.h>
|
||||
#include <IAnimatedMeshSceneNode.h>
|
||||
#include <IBoneSceneNode.h>
|
||||
|
||||
class Settings;
|
||||
struct ToolCapabilities;
|
||||
@@ -468,7 +472,7 @@ void ItemCAO::updateTexture()
|
||||
IItemDefManager *idef = m_gamedef->idef();
|
||||
ItemStack item;
|
||||
item.deSerialize(is, idef);
|
||||
texture = item.getDefinition(idef).inventory_texture;
|
||||
texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_gamedef);
|
||||
}
|
||||
catch(SerializationError &e)
|
||||
{
|
||||
@@ -551,7 +555,8 @@ class GenericCAO : public ClientActiveObject
|
||||
// Only set at initialization
|
||||
std::string m_name;
|
||||
bool m_is_player;
|
||||
bool m_is_local_player; // determined locally
|
||||
bool m_is_local_player;
|
||||
int m_id;
|
||||
// Property-ish things
|
||||
ObjectProperties m_prop;
|
||||
//
|
||||
@@ -559,6 +564,7 @@ class GenericCAO : public ClientActiveObject
|
||||
IrrlichtDevice *m_irr;
|
||||
core::aabbox3d<f32> m_selection_box;
|
||||
scene::IMeshSceneNode *m_meshnode;
|
||||
scene::IAnimatedMeshSceneNode *m_animated_meshnode;
|
||||
scene::IBillboardSceneNode *m_spritenode;
|
||||
scene::ITextSceneNode* m_textnode;
|
||||
v3f m_position;
|
||||
@@ -572,6 +578,14 @@ class GenericCAO : public ClientActiveObject
|
||||
v2s16 m_tx_basepos;
|
||||
bool m_initial_tx_basepos_set;
|
||||
bool m_tx_select_horiz_by_yawpitch;
|
||||
v2f m_animation_range;
|
||||
int m_animation_speed;
|
||||
int m_animation_blend;
|
||||
std::map<std::string, core::vector2d<v3f> > m_bone_position; // stores position and rotation for each bone name
|
||||
std::string m_attachment_bone;
|
||||
v3f m_attachment_position;
|
||||
v3f m_attachment_rotation;
|
||||
bool m_attached_to_local;
|
||||
int m_anim_frame;
|
||||
int m_anim_num_frames;
|
||||
float m_anim_framelength;
|
||||
@@ -581,6 +595,7 @@ class GenericCAO : public ClientActiveObject
|
||||
bool m_visuals_expired;
|
||||
float m_step_distance_counter;
|
||||
u8 m_last_light;
|
||||
bool m_is_visible;
|
||||
|
||||
public:
|
||||
GenericCAO(IGameDef *gamedef, ClientEnvironment *env):
|
||||
@@ -588,11 +603,13 @@ class GenericCAO : public ClientActiveObject
|
||||
//
|
||||
m_is_player(false),
|
||||
m_is_local_player(false),
|
||||
m_id(0),
|
||||
//
|
||||
m_smgr(NULL),
|
||||
m_irr(NULL),
|
||||
m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.),
|
||||
m_meshnode(NULL),
|
||||
m_animated_meshnode(NULL),
|
||||
m_spritenode(NULL),
|
||||
m_textnode(NULL),
|
||||
m_position(v3f(0,10*BS,0)),
|
||||
@@ -604,6 +621,14 @@ class GenericCAO : public ClientActiveObject
|
||||
m_tx_basepos(0,0),
|
||||
m_initial_tx_basepos_set(false),
|
||||
m_tx_select_horiz_by_yawpitch(false),
|
||||
m_animation_range(v2f(0,0)),
|
||||
m_animation_speed(15),
|
||||
m_animation_blend(0),
|
||||
m_bone_position(std::map<std::string, core::vector2d<v3f> >()),
|
||||
m_attachment_bone(""),
|
||||
m_attachment_position(v3f(0,0,0)),
|
||||
m_attachment_rotation(v3f(0,0,0)),
|
||||
m_attached_to_local(false),
|
||||
m_anim_frame(0),
|
||||
m_anim_num_frames(1),
|
||||
m_anim_framelength(0.2),
|
||||
@@ -611,7 +636,8 @@ class GenericCAO : public ClientActiveObject
|
||||
m_reset_textures_timer(-1),
|
||||
m_visuals_expired(false),
|
||||
m_step_distance_counter(0),
|
||||
m_last_light(255)
|
||||
m_last_light(255),
|
||||
m_is_visible(false)
|
||||
{
|
||||
if(gamedef == NULL)
|
||||
ClientActiveObject::registerType(getType(), create);
|
||||
@@ -621,21 +647,36 @@ class GenericCAO : public ClientActiveObject
|
||||
{
|
||||
infostream<<"GenericCAO: Got init data"<<std::endl;
|
||||
std::istringstream is(data, std::ios::binary);
|
||||
int num_messages = 0;
|
||||
// version
|
||||
u8 version = readU8(is);
|
||||
// check version
|
||||
if(version != 0){
|
||||
if(version == 1) // In PROTOCOL_VERSION 14
|
||||
{
|
||||
m_name = deSerializeString(is);
|
||||
m_is_player = readU8(is);
|
||||
m_id = readS16(is);
|
||||
m_position = readV3F1000(is);
|
||||
m_yaw = readF1000(is);
|
||||
m_hp = readS16(is);
|
||||
num_messages = readU8(is);
|
||||
}
|
||||
else if(version == 0) // In PROTOCOL_VERSION 13
|
||||
{
|
||||
m_name = deSerializeString(is);
|
||||
m_is_player = readU8(is);
|
||||
m_position = readV3F1000(is);
|
||||
m_yaw = readF1000(is);
|
||||
m_hp = readS16(is);
|
||||
num_messages = readU8(is);
|
||||
}
|
||||
else
|
||||
{
|
||||
errorstream<<"GenericCAO: Unsupported init data version"
|
||||
<<std::endl;
|
||||
return;
|
||||
}
|
||||
m_name = deSerializeString(is);
|
||||
m_is_player = readU8(is);
|
||||
m_position = readV3F1000(is);
|
||||
m_yaw = readF1000(is);
|
||||
m_hp = readS16(is);
|
||||
|
||||
int num_messages = readU8(is);
|
||||
|
||||
for(int i=0; i<num_messages; i++){
|
||||
std::string message = deSerializeLongString(is);
|
||||
processMessage(message);
|
||||
@@ -667,21 +708,113 @@ class GenericCAO : public ClientActiveObject
|
||||
}
|
||||
core::aabbox3d<f32>* getSelectionBox()
|
||||
{
|
||||
if(!m_prop.is_visible || m_is_local_player)
|
||||
if(!m_prop.is_visible || !m_is_visible || m_is_local_player || getParent() != NULL)
|
||||
return NULL;
|
||||
return &m_selection_box;
|
||||
}
|
||||
v3f getPosition()
|
||||
{
|
||||
if(getParent() != NULL){
|
||||
if(m_meshnode)
|
||||
return m_meshnode->getAbsolutePosition();
|
||||
if(m_animated_meshnode)
|
||||
return m_animated_meshnode->getAbsolutePosition();
|
||||
if(m_spritenode)
|
||||
return m_spritenode->getAbsolutePosition();
|
||||
return m_position;
|
||||
}
|
||||
return pos_translator.vect_show;
|
||||
}
|
||||
|
||||
void removeFromScene()
|
||||
scene::IMeshSceneNode *getMeshSceneNode()
|
||||
{
|
||||
if(m_meshnode)
|
||||
return m_meshnode;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode()
|
||||
{
|
||||
if(m_animated_meshnode)
|
||||
return m_animated_meshnode;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scene::IBillboardSceneNode *getSpriteSceneNode()
|
||||
{
|
||||
if(m_spritenode)
|
||||
return m_spritenode;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool isPlayer()
|
||||
{
|
||||
return m_is_player;
|
||||
}
|
||||
|
||||
bool isLocalPlayer()
|
||||
{
|
||||
return m_is_local_player;
|
||||
}
|
||||
|
||||
void setAttachments()
|
||||
{
|
||||
updateAttachments();
|
||||
}
|
||||
|
||||
ClientActiveObject *getParent()
|
||||
{
|
||||
ClientActiveObject *obj = NULL;
|
||||
for(std::vector<core::vector2d<int> >::const_iterator cii = m_env->attachment_list.begin(); cii != m_env->attachment_list.end(); cii++)
|
||||
{
|
||||
if(cii->X == getId()){ // This ID is our child
|
||||
if(cii->Y > 0){ // A parent ID exists for our child
|
||||
if(cii->X != cii->Y){ // The parent and child ID are not the same
|
||||
obj = m_env->getActiveObject(cii->Y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(obj)
|
||||
return obj;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void removeFromScene(bool permanent)
|
||||
{
|
||||
if(permanent) // Should be true when removing the object permanently and false when refreshing (eg: updating visuals)
|
||||
{
|
||||
// Detach this object's children
|
||||
for(std::vector<core::vector2d<int> >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++)
|
||||
{
|
||||
if(ii->Y == getId()) // Is a child of our object
|
||||
{
|
||||
ii->Y = 0;
|
||||
ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child
|
||||
if(obj)
|
||||
obj->setAttachments();
|
||||
}
|
||||
}
|
||||
// Delete this object from the attachments list
|
||||
for(std::vector<core::vector2d<int> >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++)
|
||||
{
|
||||
if(ii->X == getId()) // Is our object
|
||||
{
|
||||
m_env->attachment_list.erase(ii);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(m_meshnode){
|
||||
m_meshnode->remove();
|
||||
m_meshnode = NULL;
|
||||
}
|
||||
if(m_animated_meshnode){
|
||||
m_animated_meshnode->remove();
|
||||
m_animated_meshnode = NULL;
|
||||
}
|
||||
if(m_spritenode){
|
||||
m_spritenode->remove();
|
||||
m_spritenode = NULL;
|
||||
@@ -694,7 +827,7 @@ class GenericCAO : public ClientActiveObject
|
||||
m_smgr = smgr;
|
||||
m_irr = irr;
|
||||
|
||||
if(m_meshnode != NULL || m_spritenode != NULL)
|
||||
if(m_meshnode != NULL || m_animated_meshnode != NULL || m_spritenode != NULL)
|
||||
return;
|
||||
|
||||
m_visuals_expired = false;
|
||||
@@ -790,15 +923,49 @@ class GenericCAO : public ClientActiveObject
|
||||
m_prop.visual_size.X));
|
||||
u8 li = m_last_light;
|
||||
setMeshColor(m_meshnode->getMesh(), video::SColor(255,li,li,li));
|
||||
} else if(m_prop.visual == "wielditem"){
|
||||
|
||||
m_meshnode->setMaterialFlag(video::EMF_LIGHTING, false);
|
||||
m_meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
m_meshnode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
|
||||
m_meshnode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
|
||||
}
|
||||
else if(m_prop.visual == "mesh"){
|
||||
infostream<<"GenericCAO::addToScene(): mesh"<<std::endl;
|
||||
scene::IAnimatedMesh *mesh = smgr->getMesh(m_prop.mesh.c_str());
|
||||
if(mesh)
|
||||
{
|
||||
m_animated_meshnode = smgr->addAnimatedMeshSceneNode(mesh, NULL);
|
||||
m_animated_meshnode->animateJoints(); // Needed for some animations
|
||||
m_animated_meshnode->setScale(v3f(m_prop.visual_size.X,
|
||||
m_prop.visual_size.Y,
|
||||
m_prop.visual_size.X));
|
||||
u8 li = m_last_light;
|
||||
setMeshColor(m_animated_meshnode->getMesh(), video::SColor(255,li,li,li));
|
||||
|
||||
m_animated_meshnode->setMaterialFlag(video::EMF_LIGHTING, false);
|
||||
m_animated_meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
m_animated_meshnode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
|
||||
m_animated_meshnode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
|
||||
}
|
||||
else
|
||||
errorstream<<"GenericCAO::addToScene(): Could not load mesh "<<m_prop.mesh<<std::endl;
|
||||
}
|
||||
else if(m_prop.visual == "wielditem"){
|
||||
infostream<<"GenericCAO::addToScene(): node"<<std::endl;
|
||||
infostream<<"textures: "<<m_prop.textures.size()<<std::endl;
|
||||
if(m_prop.textures.size() >= 1){
|
||||
infostream<<"textures[0]: "<<m_prop.textures[0]<<std::endl;
|
||||
IItemDefManager *idef = m_gamedef->idef();
|
||||
ItemStack item(m_prop.textures[0], 1, 0, "", idef);
|
||||
scene::IMesh *mesh = item.getDefinition(idef).wield_mesh;
|
||||
scene::IMesh *item_mesh = idef->getWieldMesh(item.getDefinition(idef).name, m_gamedef);
|
||||
|
||||
// Copy mesh to be able to set unique vertex colors
|
||||
scene::IMeshManipulator *manip =
|
||||
irr->getVideoDriver()->getMeshManipulator();
|
||||
scene::IMesh *mesh = manip->createMeshUniquePrimitives(item_mesh);
|
||||
|
||||
m_meshnode = smgr->addMeshSceneNode(mesh, NULL);
|
||||
mesh->drop();
|
||||
|
||||
m_meshnode->setScale(v3f(m_prop.visual_size.X/2,
|
||||
m_prop.visual_size.Y/2,
|
||||
@@ -815,6 +982,8 @@ class GenericCAO : public ClientActiveObject
|
||||
scene::ISceneNode *node = NULL;
|
||||
if(m_spritenode)
|
||||
node = m_spritenode;
|
||||
else if(m_animated_meshnode)
|
||||
node = m_animated_meshnode;
|
||||
else if(m_meshnode)
|
||||
node = m_meshnode;
|
||||
if(node && m_is_player && !m_is_local_player){
|
||||
@@ -825,8 +994,11 @@ class GenericCAO : public ClientActiveObject
|
||||
wname.c_str(), video::SColor(255,255,255,255), node);
|
||||
m_textnode->setPosition(v3f(0, BS*1.1, 0));
|
||||
}
|
||||
|
||||
|
||||
updateNodePos();
|
||||
updateAnimation();
|
||||
updateBonePosition();
|
||||
updateAttachments();
|
||||
}
|
||||
|
||||
void expireVisuals()
|
||||
@@ -836,17 +1008,16 @@ class GenericCAO : public ClientActiveObject
|
||||
|
||||
void updateLight(u8 light_at_pos)
|
||||
{
|
||||
bool is_visible = (m_hp != 0);
|
||||
u8 li = decode_light(light_at_pos);
|
||||
m_last_light = li;
|
||||
video::SColor color(255,li,li,li);
|
||||
if(m_meshnode){
|
||||
setMeshColor(m_meshnode->getMesh(), color);
|
||||
m_meshnode->setVisible(is_visible);
|
||||
}
|
||||
if(m_spritenode){
|
||||
m_spritenode->setColor(color);
|
||||
m_spritenode->setVisible(is_visible);
|
||||
if(li != m_last_light){
|
||||
m_last_light = li;
|
||||
video::SColor color(255,li,li,li);
|
||||
if(m_meshnode)
|
||||
setMeshColor(m_meshnode->getMesh(), color);
|
||||
if(m_animated_meshnode)
|
||||
setMeshColor(m_animated_meshnode->getMesh(), color);
|
||||
if(m_spritenode)
|
||||
m_spritenode->setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -857,12 +1028,21 @@ class GenericCAO : public ClientActiveObject
|
||||
|
||||
void updateNodePos()
|
||||
{
|
||||
if(getParent() != NULL)
|
||||
return;
|
||||
|
||||
if(m_meshnode){
|
||||
m_meshnode->setPosition(pos_translator.vect_show);
|
||||
v3f rot = m_meshnode->getRotation();
|
||||
rot.Y = -m_yaw;
|
||||
m_meshnode->setRotation(rot);
|
||||
}
|
||||
if(m_animated_meshnode){
|
||||
m_animated_meshnode->setPosition(pos_translator.vect_show);
|
||||
v3f rot = m_animated_meshnode->getRotation();
|
||||
rot.Y = -m_yaw;
|
||||
m_animated_meshnode->setRotation(rot);
|
||||
}
|
||||
if(m_spritenode){
|
||||
m_spritenode->setPosition(pos_translator.vect_show);
|
||||
}
|
||||
@@ -870,56 +1050,116 @@ class GenericCAO : public ClientActiveObject
|
||||
|
||||
void step(float dtime, ClientEnvironment *env)
|
||||
{
|
||||
v3f lastpos = pos_translator.vect_show;
|
||||
|
||||
if(m_visuals_expired && m_smgr && m_irr){
|
||||
m_visuals_expired = false;
|
||||
removeFromScene();
|
||||
|
||||
// Attachments, part 1: All attached objects must be unparented first, or Irrlicht causes a segmentation fault
|
||||
for(std::vector<core::vector2d<int> >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++)
|
||||
{
|
||||
if(ii->Y == getId()) // This is a child of our parent
|
||||
{
|
||||
ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child
|
||||
if(obj)
|
||||
{
|
||||
scene::IMeshSceneNode *m_child_meshnode = obj->getMeshSceneNode();
|
||||
scene::IAnimatedMeshSceneNode *m_child_animated_meshnode = obj->getAnimatedMeshSceneNode();
|
||||
scene::IBillboardSceneNode *m_child_spritenode = obj->getSpriteSceneNode();
|
||||
if(m_child_meshnode)
|
||||
m_child_meshnode->setParent(m_smgr->getRootSceneNode());
|
||||
if(m_child_animated_meshnode)
|
||||
m_child_animated_meshnode->setParent(m_smgr->getRootSceneNode());
|
||||
if(m_child_spritenode)
|
||||
m_child_spritenode->setParent(m_smgr->getRootSceneNode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeFromScene(false);
|
||||
addToScene(m_smgr, m_gamedef->tsrc(), m_irr);
|
||||
|
||||
// Attachments, part 2: Now that the parent has been refreshed, put its attachments back
|
||||
for(std::vector<core::vector2d<int> >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++)
|
||||
{
|
||||
if(ii->Y == getId()) // This is a child of our parent
|
||||
{
|
||||
ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child
|
||||
if(obj)
|
||||
obj->setAttachments();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(m_prop.physical){
|
||||
core::aabbox3d<f32> box = m_prop.collisionbox;
|
||||
box.MinEdge *= BS;
|
||||
box.MaxEdge *= BS;
|
||||
collisionMoveResult moveresult;
|
||||
f32 pos_max_d = BS*0.125; // Distance per iteration
|
||||
f32 stepheight = 0;
|
||||
v3f p_pos = m_position;
|
||||
v3f p_velocity = m_velocity;
|
||||
v3f p_acceleration = m_acceleration;
|
||||
IGameDef *gamedef = env->getGameDef();
|
||||
moveresult = collisionMoveSimple(&env->getMap(), gamedef,
|
||||
pos_max_d, box, stepheight, dtime,
|
||||
p_pos, p_velocity, p_acceleration);
|
||||
// Apply results
|
||||
m_position = p_pos;
|
||||
m_velocity = p_velocity;
|
||||
m_acceleration = p_acceleration;
|
||||
|
||||
bool is_end_position = moveresult.collides;
|
||||
pos_translator.update(m_position, is_end_position, dtime);
|
||||
pos_translator.translate(dtime);
|
||||
updateNodePos();
|
||||
} else {
|
||||
m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration;
|
||||
m_velocity += dtime * m_acceleration;
|
||||
pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time);
|
||||
pos_translator.translate(dtime);
|
||||
updateNodePos();
|
||||
}
|
||||
// Make sure m_is_visible is always applied
|
||||
if(m_meshnode)
|
||||
m_meshnode->setVisible(m_is_visible);
|
||||
if(m_animated_meshnode)
|
||||
m_animated_meshnode->setVisible(m_is_visible);
|
||||
if(m_spritenode)
|
||||
m_spritenode->setVisible(m_is_visible);
|
||||
if(m_textnode)
|
||||
m_textnode->setVisible(m_is_visible);
|
||||
|
||||
float moved = lastpos.getDistanceFrom(pos_translator.vect_show);
|
||||
m_step_distance_counter += moved;
|
||||
if(m_step_distance_counter > 1.5*BS){
|
||||
m_step_distance_counter = 0;
|
||||
if(!m_is_local_player && m_prop.makes_footstep_sound){
|
||||
INodeDefManager *ndef = m_gamedef->ndef();
|
||||
v3s16 p = floatToInt(getPosition() + v3f(0,
|
||||
(m_prop.collisionbox.MinEdge.Y-0.5)*BS, 0), BS);
|
||||
MapNode n = m_env->getMap().getNodeNoEx(p);
|
||||
SimpleSoundSpec spec = ndef->get(n).sound_footstep;
|
||||
m_gamedef->sound()->playSoundAt(spec, false, getPosition());
|
||||
if(getParent() != NULL) // Attachments should be glued to their parent by Irrlicht
|
||||
{
|
||||
// Set these for later
|
||||
m_position = getPosition();
|
||||
m_velocity = v3f(0,0,0);
|
||||
m_acceleration = v3f(0,0,0);
|
||||
pos_translator.vect_show = m_position;
|
||||
|
||||
if(m_is_local_player) // Update local player attachment position
|
||||
{
|
||||
LocalPlayer *player = m_env->getLocalPlayer();
|
||||
player->overridePosition = getParent()->getPosition();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
v3f lastpos = pos_translator.vect_show;
|
||||
|
||||
if(m_prop.physical){
|
||||
core::aabbox3d<f32> box = m_prop.collisionbox;
|
||||
box.MinEdge *= BS;
|
||||
box.MaxEdge *= BS;
|
||||
collisionMoveResult moveresult;
|
||||
f32 pos_max_d = BS*0.125; // Distance per iteration
|
||||
f32 stepheight = 0;
|
||||
v3f p_pos = m_position;
|
||||
v3f p_velocity = m_velocity;
|
||||
v3f p_acceleration = m_acceleration;
|
||||
IGameDef *gamedef = env->getGameDef();
|
||||
moveresult = collisionMoveSimple(&env->getMap(), gamedef,
|
||||
pos_max_d, box, stepheight, dtime,
|
||||
p_pos, p_velocity, p_acceleration);
|
||||
// Apply results
|
||||
m_position = p_pos;
|
||||
m_velocity = p_velocity;
|
||||
m_acceleration = p_acceleration;
|
||||
|
||||
bool is_end_position = moveresult.collides;
|
||||
pos_translator.update(m_position, is_end_position, dtime);
|
||||
pos_translator.translate(dtime);
|
||||
updateNodePos();
|
||||
} else {
|
||||
m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration;
|
||||
m_velocity += dtime * m_acceleration;
|
||||
pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time);
|
||||
pos_translator.translate(dtime);
|
||||
updateNodePos();
|
||||
}
|
||||
|
||||
float moved = lastpos.getDistanceFrom(pos_translator.vect_show);
|
||||
m_step_distance_counter += moved;
|
||||
if(m_step_distance_counter > 1.5*BS){
|
||||
m_step_distance_counter = 0;
|
||||
if(!m_is_local_player && m_prop.makes_footstep_sound){
|
||||
INodeDefManager *ndef = m_gamedef->ndef();
|
||||
v3s16 p = floatToInt(getPosition() + v3f(0,
|
||||
(m_prop.collisionbox.MinEdge.Y-0.5)*BS, 0), BS);
|
||||
MapNode n = m_env->getMap().getNodeNoEx(p);
|
||||
SimpleSoundSpec spec = ndef->get(n).sound_footstep;
|
||||
m_gamedef->sound()->playSoundAt(spec, false, getPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -940,7 +1180,7 @@ class GenericCAO : public ClientActiveObject
|
||||
updateTextures("");
|
||||
}
|
||||
}
|
||||
if(fabs(m_prop.automatic_rotate) > 0.001){
|
||||
if(getParent() == NULL && fabs(m_prop.automatic_rotate) > 0.001){
|
||||
m_yaw += dtime * m_prop.automatic_rotate * 180 / M_PI;
|
||||
updateNodePos();
|
||||
}
|
||||
@@ -998,6 +1238,10 @@ class GenericCAO : public ClientActiveObject
|
||||
{
|
||||
ITextureSource *tsrc = m_gamedef->tsrc();
|
||||
|
||||
bool use_trilinear_filter = g_settings->getBool("trilinear_filter");
|
||||
bool use_bilinear_filter = g_settings->getBool("bilinear_filter");
|
||||
bool use_anisotropic_filter = g_settings->getBool("anisotropic_filter");
|
||||
|
||||
if(m_spritenode)
|
||||
{
|
||||
if(m_prop.visual == "sprite")
|
||||
@@ -1008,6 +1252,58 @@ class GenericCAO : public ClientActiveObject
|
||||
texturestring += mod;
|
||||
m_spritenode->setMaterialTexture(0,
|
||||
tsrc->getTextureRaw(texturestring));
|
||||
|
||||
// This allows setting per-material colors. However, until a real lighting
|
||||
// system is added, the code below will have no effect. Once MineTest
|
||||
// has directional lighting, it should work automatically.
|
||||
if(m_prop.colors.size() >= 1)
|
||||
{
|
||||
m_spritenode->getMaterial(0).AmbientColor = m_prop.colors[0];
|
||||
m_spritenode->getMaterial(0).DiffuseColor = m_prop.colors[0];
|
||||
m_spritenode->getMaterial(0).SpecularColor = m_prop.colors[0];
|
||||
}
|
||||
|
||||
m_spritenode->getMaterial(0).setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
|
||||
m_spritenode->getMaterial(0).setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
|
||||
m_spritenode->getMaterial(0).setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
|
||||
}
|
||||
}
|
||||
if(m_animated_meshnode)
|
||||
{
|
||||
if(m_prop.visual == "mesh")
|
||||
{
|
||||
for (u32 i = 0; i < m_prop.textures.size() && i < m_animated_meshnode->getMaterialCount(); ++i)
|
||||
{
|
||||
std::string texturestring = m_prop.textures[i];
|
||||
if(texturestring == "")
|
||||
continue; // Empty texture string means don't modify that material
|
||||
texturestring += mod;
|
||||
video::ITexture* texture = tsrc->getTextureRaw(texturestring);
|
||||
if(!texture)
|
||||
{
|
||||
errorstream<<"GenericCAO::updateTextures(): Could not load texture "<<texturestring<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set material flags and texture
|
||||
m_animated_meshnode->setMaterialTexture(i, texture);
|
||||
video::SMaterial& material = m_animated_meshnode->getMaterial(i);
|
||||
material.setFlag(video::EMF_LIGHTING, false);
|
||||
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
|
||||
m_animated_meshnode->getMaterial(i).setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
|
||||
m_animated_meshnode->getMaterial(i).setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
|
||||
m_animated_meshnode->getMaterial(i).setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
|
||||
}
|
||||
for (u32 i = 0; i < m_prop.colors.size() && i < m_animated_meshnode->getMaterialCount(); ++i)
|
||||
{
|
||||
// This allows setting per-material colors. However, until a real lighting
|
||||
// system is added, the code below will have no effect. Once MineTest
|
||||
// has directional lighting, it should work automatically.
|
||||
m_animated_meshnode->getMaterial(i).AmbientColor = m_prop.colors[i];
|
||||
m_animated_meshnode->getMaterial(i).DiffuseColor = m_prop.colors[i];
|
||||
m_animated_meshnode->getMaterial(i).SpecularColor = m_prop.colors[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
if(m_meshnode)
|
||||
@@ -1034,6 +1330,20 @@ class GenericCAO : public ClientActiveObject
|
||||
material.setTexture(0, atlas);
|
||||
material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
|
||||
material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
|
||||
|
||||
// This allows setting per-material colors. However, until a real lighting
|
||||
// system is added, the code below will have no effect. Once MineTest
|
||||
// has directional lighting, it should work automatically.
|
||||
if(m_prop.colors.size() > i)
|
||||
{
|
||||
m_meshnode->getMaterial(i).AmbientColor = m_prop.colors[i];
|
||||
m_meshnode->getMaterial(i).DiffuseColor = m_prop.colors[i];
|
||||
m_meshnode->getMaterial(i).SpecularColor = m_prop.colors[i];
|
||||
}
|
||||
|
||||
m_meshnode->getMaterial(i).setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
|
||||
m_meshnode->getMaterial(i).setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
|
||||
m_meshnode->getMaterial(i).setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
|
||||
}
|
||||
}
|
||||
else if(m_prop.visual == "upright_sprite")
|
||||
@@ -1047,6 +1357,20 @@ class GenericCAO : public ClientActiveObject
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
|
||||
buf->getMaterial().setTexture(0,
|
||||
tsrc->getTextureRaw(tname));
|
||||
|
||||
// This allows setting per-material colors. However, until a real lighting
|
||||
// system is added, the code below will have no effect. Once MineTest
|
||||
// has directional lighting, it should work automatically.
|
||||
if(m_prop.colors.size() >= 1)
|
||||
{
|
||||
buf->getMaterial().AmbientColor = m_prop.colors[0];
|
||||
buf->getMaterial().DiffuseColor = m_prop.colors[0];
|
||||
buf->getMaterial().SpecularColor = m_prop.colors[0];
|
||||
}
|
||||
|
||||
buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
|
||||
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
|
||||
buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
|
||||
}
|
||||
{
|
||||
std::string tname = "unknown_object.png";
|
||||
@@ -1058,11 +1382,213 @@ class GenericCAO : public ClientActiveObject
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(1);
|
||||
buf->getMaterial().setTexture(0,
|
||||
tsrc->getTextureRaw(tname));
|
||||
|
||||
// This allows setting per-material colors. However, until a real lighting
|
||||
// system is added, the code below will have no effect. Once MineTest
|
||||
// has directional lighting, it should work automatically.
|
||||
if(m_prop.colors.size() >= 2)
|
||||
{
|
||||
buf->getMaterial().AmbientColor = m_prop.colors[1];
|
||||
buf->getMaterial().DiffuseColor = m_prop.colors[1];
|
||||
buf->getMaterial().SpecularColor = m_prop.colors[1];
|
||||
}
|
||||
else if(m_prop.colors.size() >= 1)
|
||||
{
|
||||
buf->getMaterial().AmbientColor = m_prop.colors[0];
|
||||
buf->getMaterial().DiffuseColor = m_prop.colors[0];
|
||||
buf->getMaterial().SpecularColor = m_prop.colors[0];
|
||||
}
|
||||
|
||||
buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
|
||||
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
|
||||
buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateAnimation()
|
||||
{
|
||||
if(m_animated_meshnode == NULL)
|
||||
return;
|
||||
|
||||
m_animated_meshnode->setFrameLoop((int)m_animation_range.X, (int)m_animation_range.Y);
|
||||
m_animated_meshnode->setAnimationSpeed(m_animation_speed);
|
||||
m_animated_meshnode->setTransitionTime(m_animation_blend);
|
||||
}
|
||||
|
||||
void updateBonePosition()
|
||||
{
|
||||
if(!m_bone_position.size() || m_animated_meshnode == NULL)
|
||||
return;
|
||||
|
||||
m_animated_meshnode->setJointMode(irr::scene::EJUOR_CONTROL); // To write positions to the mesh on render
|
||||
for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
|
||||
std::string bone_name = (*ii).first;
|
||||
v3f bone_pos = (*ii).second.X;
|
||||
v3f bone_rot = (*ii).second.Y;
|
||||
irr::scene::IBoneSceneNode* bone = m_animated_meshnode->getJointNode(bone_name.c_str());
|
||||
if(bone)
|
||||
{
|
||||
bone->setPosition(bone_pos);
|
||||
bone->setRotation(bone_rot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateAttachments()
|
||||
{
|
||||
m_attached_to_local = getParent() != NULL && getParent()->isLocalPlayer();
|
||||
m_is_visible = !m_attached_to_local; // Objects attached to the local player should always be hidden
|
||||
|
||||
if(getParent() == NULL || m_attached_to_local) // Detach or don't attach
|
||||
{
|
||||
if(m_meshnode)
|
||||
{
|
||||
v3f old_position = m_meshnode->getAbsolutePosition();
|
||||
v3f old_rotation = m_meshnode->getRotation();
|
||||
m_meshnode->setParent(m_smgr->getRootSceneNode());
|
||||
m_meshnode->setPosition(old_position);
|
||||
m_meshnode->setRotation(old_rotation);
|
||||
m_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
if(m_animated_meshnode)
|
||||
{
|
||||
v3f old_position = m_animated_meshnode->getAbsolutePosition();
|
||||
v3f old_rotation = m_animated_meshnode->getRotation();
|
||||
m_animated_meshnode->setParent(m_smgr->getRootSceneNode());
|
||||
m_animated_meshnode->setPosition(old_position);
|
||||
m_animated_meshnode->setRotation(old_rotation);
|
||||
m_animated_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
if(m_spritenode)
|
||||
{
|
||||
v3f old_position = m_spritenode->getAbsolutePosition();
|
||||
v3f old_rotation = m_spritenode->getRotation();
|
||||
m_spritenode->setParent(m_smgr->getRootSceneNode());
|
||||
m_spritenode->setPosition(old_position);
|
||||
m_spritenode->setRotation(old_rotation);
|
||||
m_spritenode->updateAbsolutePosition();
|
||||
}
|
||||
if(m_is_local_player)
|
||||
{
|
||||
LocalPlayer *player = m_env->getLocalPlayer();
|
||||
player->isAttached = false;
|
||||
}
|
||||
}
|
||||
else // Attach
|
||||
{
|
||||
scene::IMeshSceneNode *parent_mesh = NULL;
|
||||
if(getParent()->getMeshSceneNode())
|
||||
parent_mesh = getParent()->getMeshSceneNode();
|
||||
scene::IAnimatedMeshSceneNode *parent_animated_mesh = NULL;
|
||||
if(getParent()->getAnimatedMeshSceneNode())
|
||||
parent_animated_mesh = getParent()->getAnimatedMeshSceneNode();
|
||||
scene::IBillboardSceneNode *parent_sprite = NULL;
|
||||
if(getParent()->getSpriteSceneNode())
|
||||
parent_sprite = getParent()->getSpriteSceneNode();
|
||||
|
||||
scene::IBoneSceneNode *parent_bone = NULL;
|
||||
if(parent_animated_mesh && m_attachment_bone != "")
|
||||
parent_bone = parent_animated_mesh->getJointNode(m_attachment_bone.c_str());
|
||||
|
||||
// The spaghetti code below makes sure attaching works if either the parent or child is a spritenode, meshnode, or animatedmeshnode
|
||||
// TODO: Perhaps use polymorphism here to save code duplication
|
||||
if(m_meshnode){
|
||||
if(parent_bone){
|
||||
m_meshnode->setParent(parent_bone);
|
||||
m_meshnode->setPosition(m_attachment_position);
|
||||
m_meshnode->setRotation(m_attachment_rotation);
|
||||
m_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(parent_mesh){
|
||||
m_meshnode->setParent(parent_mesh);
|
||||
m_meshnode->setPosition(m_attachment_position);
|
||||
m_meshnode->setRotation(m_attachment_rotation);
|
||||
m_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
else if(parent_animated_mesh){
|
||||
m_meshnode->setParent(parent_animated_mesh);
|
||||
m_meshnode->setPosition(m_attachment_position);
|
||||
m_meshnode->setRotation(m_attachment_rotation);
|
||||
m_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
else if(parent_sprite){
|
||||
m_meshnode->setParent(parent_sprite);
|
||||
m_meshnode->setPosition(m_attachment_position);
|
||||
m_meshnode->setRotation(m_attachment_rotation);
|
||||
m_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(m_animated_meshnode){
|
||||
if(parent_bone){
|
||||
m_animated_meshnode->setParent(parent_bone);
|
||||
m_animated_meshnode->setPosition(m_attachment_position);
|
||||
m_animated_meshnode->setRotation(m_attachment_rotation);
|
||||
m_animated_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(parent_mesh){
|
||||
m_animated_meshnode->setParent(parent_mesh);
|
||||
m_animated_meshnode->setPosition(m_attachment_position);
|
||||
m_animated_meshnode->setRotation(m_attachment_rotation);
|
||||
m_animated_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
else if(parent_animated_mesh){
|
||||
m_animated_meshnode->setParent(parent_animated_mesh);
|
||||
m_animated_meshnode->setPosition(m_attachment_position);
|
||||
m_animated_meshnode->setRotation(m_attachment_rotation);
|
||||
m_animated_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
else if(parent_sprite){
|
||||
m_animated_meshnode->setParent(parent_sprite);
|
||||
m_animated_meshnode->setPosition(m_attachment_position);
|
||||
m_animated_meshnode->setRotation(m_attachment_rotation);
|
||||
m_animated_meshnode->updateAbsolutePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(m_spritenode){
|
||||
if(parent_bone){
|
||||
m_spritenode->setParent(parent_bone);
|
||||
m_spritenode->setPosition(m_attachment_position);
|
||||
m_spritenode->setRotation(m_attachment_rotation);
|
||||
m_spritenode->updateAbsolutePosition();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(parent_mesh){
|
||||
m_spritenode->setParent(parent_mesh);
|
||||
m_spritenode->setPosition(m_attachment_position);
|
||||
m_spritenode->setRotation(m_attachment_rotation);
|
||||
m_spritenode->updateAbsolutePosition();
|
||||
}
|
||||
else if(parent_animated_mesh){
|
||||
m_spritenode->setParent(parent_animated_mesh);
|
||||
m_spritenode->setPosition(m_attachment_position);
|
||||
m_spritenode->setRotation(m_attachment_rotation);
|
||||
m_spritenode->updateAbsolutePosition();
|
||||
}
|
||||
else if(parent_sprite){
|
||||
m_spritenode->setParent(parent_sprite);
|
||||
m_spritenode->setPosition(m_attachment_position);
|
||||
m_spritenode->setRotation(m_attachment_rotation);
|
||||
m_spritenode->updateAbsolutePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(m_is_local_player)
|
||||
{
|
||||
LocalPlayer *player = m_env->getLocalPlayer();
|
||||
player->isAttached = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processMessage(const std::string &data)
|
||||
{
|
||||
//infostream<<"GenericCAO: Got message"<<std::endl;
|
||||
@@ -1089,6 +1615,8 @@ class GenericCAO : public ClientActiveObject
|
||||
}
|
||||
else if(cmd == GENERIC_CMD_UPDATE_POSITION)
|
||||
{
|
||||
// Not sent by the server if this object is an attachment.
|
||||
// We might however get here if the server notices the object being detached before the client.
|
||||
m_position = readV3F1000(is);
|
||||
m_velocity = readV3F1000(is);
|
||||
m_acceleration = readV3F1000(is);
|
||||
@@ -1102,7 +1630,10 @@ class GenericCAO : public ClientActiveObject
|
||||
// the ground due to sucky collision detection...
|
||||
if(m_prop.physical)
|
||||
m_position += v3f(0,0.002,0);
|
||||
|
||||
|
||||
if(getParent() != NULL) // Just in case
|
||||
return;
|
||||
|
||||
if(do_interpolate){
|
||||
if(!m_prop.physical)
|
||||
pos_translator.update(m_position, is_end_position, update_interval);
|
||||
@@ -1130,6 +1661,41 @@ class GenericCAO : public ClientActiveObject
|
||||
|
||||
updateTexturePos();
|
||||
}
|
||||
else if(cmd == GENERIC_CMD_SET_ANIMATION)
|
||||
{
|
||||
m_animation_range = readV2F1000(is);
|
||||
m_animation_speed = readF1000(is);
|
||||
m_animation_blend = readF1000(is);
|
||||
|
||||
updateAnimation();
|
||||
}
|
||||
else if(cmd == GENERIC_CMD_SET_BONE_POSITION)
|
||||
{
|
||||
std::string bone = deSerializeString(is);
|
||||
v3f position = readV3F1000(is);
|
||||
v3f rotation = readV3F1000(is);
|
||||
m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
|
||||
|
||||
updateBonePosition();
|
||||
}
|
||||
else if(cmd == GENERIC_CMD_SET_ATTACHMENT)
|
||||
{
|
||||
// If an entry already exists for this object, delete it first to avoid duplicates
|
||||
for(std::vector<core::vector2d<int> >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++)
|
||||
{
|
||||
if(ii->X == getId()) // This is the ID of our object
|
||||
{
|
||||
m_env->attachment_list.erase(ii);
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_env->attachment_list.push_back(core::vector2d<int>(getId(), readS16(is)));
|
||||
m_attachment_bone = deSerializeString(is);
|
||||
m_attachment_position = readV3F1000(is);
|
||||
m_attachment_rotation = readV3F1000(is);
|
||||
|
||||
updateAttachments();
|
||||
}
|
||||
else if(cmd == GENERIC_CMD_PUNCHED)
|
||||
{
|
||||
/*s16 damage =*/ readS16(is);
|
||||
|
||||
@@ -26,7 +26,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "tile.h"
|
||||
#include "gamedef.h"
|
||||
#include "util/numeric.h"
|
||||
#include "util/serialize.h"
|
||||
#include "util/directiontables.h"
|
||||
|
||||
// Create a cuboid.
|
||||
@@ -172,7 +171,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
continue;
|
||||
|
||||
u16 l = getInteriorLight(n, 0, data);
|
||||
video::SColor c = MapBlock_LightColor(f.alpha, l);
|
||||
video::SColor c = MapBlock_LightColor(f.alpha, l, decode_light(f.light_source));
|
||||
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
@@ -227,7 +226,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
// Otherwise use the light of this node (the liquid)
|
||||
else
|
||||
l = getInteriorLight(n, 0, data);
|
||||
video::SColor c = MapBlock_LightColor(f.alpha, l);
|
||||
video::SColor c = MapBlock_LightColor(f.alpha, l, decode_light(f.light_source));
|
||||
|
||||
// Neighbor liquid levels (key = relative position)
|
||||
// Includes current node
|
||||
@@ -492,15 +491,15 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
// -Z towards +Z, thus the direction is +Z.
|
||||
// Rotate texture to make animation go in flow direction
|
||||
// Positive if liquid moves towards +Z
|
||||
int dz = (corner_levels[side_corners[2][0]] +
|
||||
corner_levels[side_corners[2][1]] <
|
||||
corner_levels[side_corners[3][0]] +
|
||||
corner_levels[side_corners[3][1]]);
|
||||
int dz = (corner_levels[side_corners[3][0]] +
|
||||
corner_levels[side_corners[3][1]]) -
|
||||
(corner_levels[side_corners[2][0]] +
|
||||
corner_levels[side_corners[2][1]]);
|
||||
// Positive if liquid moves towards +X
|
||||
int dx = (corner_levels[side_corners[0][0]] +
|
||||
corner_levels[side_corners[0][1]] <
|
||||
corner_levels[side_corners[1][0]] +
|
||||
corner_levels[side_corners[1][1]]);
|
||||
int dx = (corner_levels[side_corners[1][0]] +
|
||||
corner_levels[side_corners[1][1]]) -
|
||||
(corner_levels[side_corners[0][0]] +
|
||||
corner_levels[side_corners[0][1]]);
|
||||
// -X
|
||||
if(-dx >= abs(dz))
|
||||
{
|
||||
@@ -545,7 +544,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
AtlasPointer ap = tile.texture;
|
||||
|
||||
u16 l = getInteriorLight(n, 1, data);
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
|
||||
|
||||
for(u32 j=0; j<6; j++)
|
||||
{
|
||||
@@ -605,7 +604,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
AtlasPointer pa_leaves = tile_leaves.texture;
|
||||
|
||||
u16 l = getInteriorLight(n, 1, data);
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
|
||||
|
||||
v3f pos = intToFloat(p, BS);
|
||||
aabb3f box(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2);
|
||||
@@ -639,7 +638,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
|
||||
AtlasPointer ap = tile.texture;
|
||||
|
||||
video::SColor c(255,255,255,255);
|
||||
u16 l = getInteriorLight(n, 1, data);
|
||||
video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
|
||||
|
||||
// Wall at X+ of node
|
||||
video::S3DVertex vertices[4] =
|
||||
@@ -684,7 +684,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
AtlasPointer ap = tile.texture;
|
||||
|
||||
u16 l = getInteriorLight(n, 0, data);
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
|
||||
|
||||
float d = (float)BS/16;
|
||||
// Wall at X+ of node
|
||||
@@ -731,7 +731,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
AtlasPointer ap = tile.texture;
|
||||
|
||||
u16 l = getInteriorLight(n, 1, data);
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
|
||||
|
||||
for(u32 j=0; j<4; j++)
|
||||
{
|
||||
@@ -794,7 +794,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
tile.texture.id) + "^[transformR90");
|
||||
|
||||
u16 l = getInteriorLight(n, 1, data);
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
|
||||
|
||||
const f32 post_rad=(f32)BS/8;
|
||||
const f32 bar_rad=(f32)BS/16;
|
||||
@@ -997,7 +997,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
AtlasPointer ap = tile.texture;
|
||||
|
||||
u16 l = getInteriorLight(n, 0, data);
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
|
||||
|
||||
float d = (float)BS/64;
|
||||
|
||||
@@ -1046,7 +1046,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
}
|
||||
|
||||
u16 l = getInteriorLight(n, 0, data);
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
|
||||
|
||||
v3f pos = intToFloat(p, BS);
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ class ItemSAO : public ServerActiveObject
|
||||
}
|
||||
}
|
||||
|
||||
std::string getClientInitializationData()
|
||||
std::string getClientInitializationData(u16 protocol_version)
|
||||
{
|
||||
std::ostringstream os(std::ios::binary);
|
||||
// version
|
||||
@@ -355,7 +355,10 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
|
||||
m_last_sent_velocity(0,0,0),
|
||||
m_last_sent_position_timer(0),
|
||||
m_last_sent_move_precision(0),
|
||||
m_armor_groups_sent(false)
|
||||
m_armor_groups_sent(false),
|
||||
m_animation_sent(false),
|
||||
m_bone_position_sent(false),
|
||||
m_attachment_sent(false)
|
||||
{
|
||||
// Only register type if no environment supplied
|
||||
if(env == NULL){
|
||||
@@ -376,9 +379,9 @@ LuaEntitySAO::~LuaEntitySAO()
|
||||
}
|
||||
}
|
||||
|
||||
void LuaEntitySAO::addedToEnvironment()
|
||||
void LuaEntitySAO::addedToEnvironment(u32 dtime_s)
|
||||
{
|
||||
ServerActiveObject::addedToEnvironment();
|
||||
ServerActiveObject::addedToEnvironment(dtime_s);
|
||||
|
||||
// Create entity from name
|
||||
lua_State *L = m_env->getLua();
|
||||
@@ -390,7 +393,7 @@ void LuaEntitySAO::addedToEnvironment()
|
||||
// Initialize HP from properties
|
||||
m_hp = m_prop.hp_max;
|
||||
// Activate entity, supplying serialized state
|
||||
scriptapi_luaentity_activate(L, m_id, m_init_state.c_str());
|
||||
scriptapi_luaentity_activate(L, m_id, m_init_state.c_str(), dtime_s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,6 +432,17 @@ ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
|
||||
return sao;
|
||||
}
|
||||
|
||||
bool LuaEntitySAO::isAttached()
|
||||
{
|
||||
if(!m_attachment_parent_id)
|
||||
return false;
|
||||
// Check if the parent still exists
|
||||
ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
|
||||
if(obj)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void LuaEntitySAO::step(float dtime, bool send_recommended)
|
||||
{
|
||||
if(!m_properties_sent)
|
||||
@@ -440,30 +454,52 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
|
||||
// If attached, check that our parent is still there. If it isn't, detach.
|
||||
if(m_attachment_parent_id && !isAttached())
|
||||
{
|
||||
m_attachment_parent_id = 0;
|
||||
m_attachment_bone = "";
|
||||
m_attachment_position = v3f(0,0,0);
|
||||
m_attachment_rotation = v3f(0,0,0);
|
||||
sendPosition(false, true);
|
||||
}
|
||||
|
||||
m_last_sent_position_timer += dtime;
|
||||
|
||||
if(m_prop.physical){
|
||||
core::aabbox3d<f32> box = m_prop.collisionbox;
|
||||
box.MinEdge *= BS;
|
||||
box.MaxEdge *= BS;
|
||||
collisionMoveResult moveresult;
|
||||
f32 pos_max_d = BS*0.25; // Distance per iteration
|
||||
f32 stepheight = 0; // Maximum climbable step height
|
||||
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,
|
||||
pos_max_d, box, stepheight, dtime,
|
||||
p_pos, p_velocity, p_acceleration);
|
||||
// Apply results
|
||||
m_base_position = p_pos;
|
||||
m_velocity = p_velocity;
|
||||
m_acceleration = p_acceleration;
|
||||
} else {
|
||||
m_base_position += dtime * m_velocity + 0.5 * dtime
|
||||
* dtime * m_acceleration;
|
||||
m_velocity += dtime * m_acceleration;
|
||||
|
||||
// Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
|
||||
// If the object gets detached this comes into effect automatically from the last known origin
|
||||
if(isAttached())
|
||||
{
|
||||
v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
|
||||
m_base_position = pos;
|
||||
m_velocity = v3f(0,0,0);
|
||||
m_acceleration = v3f(0,0,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_prop.physical){
|
||||
core::aabbox3d<f32> box = m_prop.collisionbox;
|
||||
box.MinEdge *= BS;
|
||||
box.MaxEdge *= BS;
|
||||
collisionMoveResult moveresult;
|
||||
f32 pos_max_d = BS*0.25; // Distance per iteration
|
||||
f32 stepheight = 0; // Maximum climbable step height
|
||||
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,
|
||||
pos_max_d, box, stepheight, dtime,
|
||||
p_pos, p_velocity, p_acceleration);
|
||||
// Apply results
|
||||
m_base_position = p_pos;
|
||||
m_velocity = p_velocity;
|
||||
m_acceleration = p_acceleration;
|
||||
} else {
|
||||
m_base_position += dtime * m_velocity + 0.5 * dtime
|
||||
* dtime * m_acceleration;
|
||||
m_velocity += dtime * m_acceleration;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_registered){
|
||||
@@ -473,20 +509,23 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
|
||||
|
||||
if(send_recommended == false)
|
||||
return;
|
||||
|
||||
// TODO: force send when acceleration changes enough?
|
||||
float minchange = 0.2*BS;
|
||||
if(m_last_sent_position_timer > 1.0){
|
||||
minchange = 0.01*BS;
|
||||
} else if(m_last_sent_position_timer > 0.2){
|
||||
minchange = 0.05*BS;
|
||||
}
|
||||
float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
|
||||
move_d += m_last_sent_move_precision;
|
||||
float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
|
||||
if(move_d > minchange || vel_d > minchange ||
|
||||
fabs(m_yaw - m_last_sent_yaw) > 1.0){
|
||||
sendPosition(true, false);
|
||||
|
||||
if(!isAttached())
|
||||
{
|
||||
// TODO: force send when acceleration changes enough?
|
||||
float minchange = 0.2*BS;
|
||||
if(m_last_sent_position_timer > 1.0){
|
||||
minchange = 0.01*BS;
|
||||
} else if(m_last_sent_position_timer > 0.2){
|
||||
minchange = 0.05*BS;
|
||||
}
|
||||
float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
|
||||
move_d += m_last_sent_move_precision;
|
||||
float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
|
||||
if(move_d > minchange || vel_d > minchange ||
|
||||
fabs(m_yaw - m_last_sent_yaw) > 1.0){
|
||||
sendPosition(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
if(m_armor_groups_sent == false){
|
||||
@@ -497,20 +536,70 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
|
||||
ActiveObjectMessage aom(getId(), true, str);
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
|
||||
if(m_animation_sent == false){
|
||||
m_animation_sent = true;
|
||||
std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend);
|
||||
// create message and add to list
|
||||
ActiveObjectMessage aom(getId(), true, str);
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
|
||||
if(m_bone_position_sent == false){
|
||||
m_bone_position_sent = true;
|
||||
for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
|
||||
std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
|
||||
// create message and add to list
|
||||
ActiveObjectMessage aom(getId(), true, str);
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
}
|
||||
|
||||
if(m_attachment_sent == false){
|
||||
m_attachment_sent = true;
|
||||
std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
|
||||
// create message and add to list
|
||||
ActiveObjectMessage aom(getId(), true, str);
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
}
|
||||
|
||||
std::string LuaEntitySAO::getClientInitializationData()
|
||||
std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version)
|
||||
{
|
||||
std::ostringstream os(std::ios::binary);
|
||||
writeU8(os, 0); // version
|
||||
os<<serializeString(""); // name
|
||||
writeU8(os, 0); // is_player
|
||||
writeV3F1000(os, m_base_position);
|
||||
writeF1000(os, m_yaw);
|
||||
writeS16(os, m_hp);
|
||||
writeU8(os, 2); // number of messages stuffed in here
|
||||
os<<serializeLongString(getPropertyPacket()); // message 1
|
||||
os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
|
||||
|
||||
if(protocol_version >= 14)
|
||||
{
|
||||
writeU8(os, 1); // version
|
||||
os<<serializeString(""); // name
|
||||
writeU8(os, 0); // is_player
|
||||
writeS16(os, getId()); //id
|
||||
writeV3F1000(os, m_base_position);
|
||||
writeF1000(os, m_yaw);
|
||||
writeS16(os, m_hp);
|
||||
|
||||
writeU8(os, 4 + m_bone_position.size()); // number of messages stuffed in here
|
||||
os<<serializeLongString(getPropertyPacket()); // message 1
|
||||
os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
|
||||
os<<serializeLongString(gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend)); // 3
|
||||
for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
|
||||
os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
|
||||
}
|
||||
os<<serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
|
||||
}
|
||||
else
|
||||
{
|
||||
writeU8(os, 0); // version
|
||||
os<<serializeString(""); // name
|
||||
writeU8(os, 0); // is_player
|
||||
writeV3F1000(os, m_base_position);
|
||||
writeF1000(os, m_yaw);
|
||||
writeS16(os, m_hp);
|
||||
writeU8(os, 2); // number of messages stuffed in here
|
||||
os<<serializeLongString(getPropertyPacket()); // message 1
|
||||
os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
|
||||
}
|
||||
|
||||
// return result
|
||||
return os.str();
|
||||
}
|
||||
@@ -550,6 +639,10 @@ int LuaEntitySAO::punch(v3f dir,
|
||||
m_removed = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// It's best that attachments cannot be punched
|
||||
if(isAttached())
|
||||
return 0;
|
||||
|
||||
ItemStack *punchitem = NULL;
|
||||
ItemStack punchitem_static;
|
||||
@@ -594,18 +687,25 @@ void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
|
||||
{
|
||||
if(!m_registered)
|
||||
return;
|
||||
// It's best that attachments cannot be clicked
|
||||
if(isAttached())
|
||||
return;
|
||||
lua_State *L = m_env->getLua();
|
||||
scriptapi_luaentity_rightclick(L, m_id, clicker);
|
||||
}
|
||||
|
||||
void LuaEntitySAO::setPos(v3f pos)
|
||||
{
|
||||
if(isAttached())
|
||||
return;
|
||||
m_base_position = pos;
|
||||
sendPosition(false, true);
|
||||
}
|
||||
|
||||
void LuaEntitySAO::moveTo(v3f pos, bool continuous)
|
||||
{
|
||||
if(isAttached())
|
||||
return;
|
||||
m_base_position = pos;
|
||||
if(!continuous)
|
||||
sendPosition(true, true);
|
||||
@@ -644,6 +744,37 @@ void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
|
||||
m_armor_groups_sent = false;
|
||||
}
|
||||
|
||||
void LuaEntitySAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend)
|
||||
{
|
||||
m_animation_range = frame_range;
|
||||
m_animation_speed = frame_speed;
|
||||
m_animation_blend = frame_blend;
|
||||
m_animation_sent = false;
|
||||
}
|
||||
|
||||
void LuaEntitySAO::setBonePosition(std::string bone, v3f position, v3f rotation)
|
||||
{
|
||||
m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
|
||||
m_bone_position_sent = false;
|
||||
}
|
||||
|
||||
void LuaEntitySAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
|
||||
{
|
||||
// Attachments need to be handled on both the server and client.
|
||||
// If we just attach on the server, we can only copy the position of the parent. Attachments
|
||||
// are still sent to clients at an interval so players might see them lagging, plus we can't
|
||||
// read and attach to skeletal bones.
|
||||
// If we just attach on the client, the server still sees the child at its original location.
|
||||
// This breaks some things so we also give the server the most accurate representation
|
||||
// even if players only see the client changes.
|
||||
|
||||
m_attachment_parent_id = parent_id;
|
||||
m_attachment_bone = bone;
|
||||
m_attachment_position = position;
|
||||
m_attachment_rotation = rotation;
|
||||
m_attachment_sent = false;
|
||||
}
|
||||
|
||||
ObjectProperties* LuaEntitySAO::accessObjectProperties()
|
||||
{
|
||||
return &m_prop;
|
||||
@@ -718,6 +849,10 @@ std::string LuaEntitySAO::getPropertyPacket()
|
||||
|
||||
void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
|
||||
{
|
||||
// If the object is attached client-side, don't waste bandwidth sending its position to clients
|
||||
if(isAttached())
|
||||
return;
|
||||
|
||||
m_last_sent_move_precision = m_base_position.getDistanceFrom(
|
||||
m_last_sent_position);
|
||||
m_last_sent_position_timer = 0;
|
||||
@@ -765,8 +900,11 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
|
||||
m_properties_sent(true),
|
||||
m_privs(privs),
|
||||
m_is_singleplayer(is_singleplayer),
|
||||
m_animation_sent(false),
|
||||
m_bone_position_sent(false),
|
||||
m_attachment_sent(false),
|
||||
// public
|
||||
m_teleported(false),
|
||||
m_moved(false),
|
||||
m_inventory_not_sent(false),
|
||||
m_hp_not_sent(false),
|
||||
m_wielded_item_not_sent(false)
|
||||
@@ -782,13 +920,17 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
|
||||
m_prop.physical = false;
|
||||
m_prop.weight = 75;
|
||||
m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.);
|
||||
// start of default appearance, this should be overwritten by LUA
|
||||
m_prop.visual = "upright_sprite";
|
||||
m_prop.visual_size = v2f(1, 2);
|
||||
m_prop.textures.clear();
|
||||
m_prop.textures.push_back("player.png");
|
||||
m_prop.textures.push_back("player_back.png");
|
||||
m_prop.colors.clear();
|
||||
m_prop.colors.push_back(video::SColor(255, 255, 255, 255));
|
||||
m_prop.spritediv = v2s16(1,1);
|
||||
m_prop.is_visible = (getHP() != 0);
|
||||
// end of default appearance
|
||||
m_prop.is_visible = true;
|
||||
m_prop.makes_footstep_sound = true;
|
||||
}
|
||||
|
||||
@@ -805,9 +947,9 @@ std::string PlayerSAO::getDescription()
|
||||
}
|
||||
|
||||
// Called after id has been set and has been inserted in environment
|
||||
void PlayerSAO::addedToEnvironment()
|
||||
void PlayerSAO::addedToEnvironment(u32 dtime_s)
|
||||
{
|
||||
ServerActiveObject::addedToEnvironment();
|
||||
ServerActiveObject::addedToEnvironment(dtime_s);
|
||||
ServerActiveObject::setBasePosition(m_player->getPosition());
|
||||
m_player->setPlayerSAO(this);
|
||||
m_player->peer_id = m_peer_id;
|
||||
@@ -836,18 +978,43 @@ bool PlayerSAO::unlimitedTransferDistance() const
|
||||
return g_settings->getBool("unlimited_player_transfer_distance");
|
||||
}
|
||||
|
||||
std::string PlayerSAO::getClientInitializationData()
|
||||
std::string PlayerSAO::getClientInitializationData(u16 protocol_version)
|
||||
{
|
||||
std::ostringstream os(std::ios::binary);
|
||||
writeU8(os, 0); // version
|
||||
os<<serializeString(m_player->getName()); // name
|
||||
writeU8(os, 1); // is_player
|
||||
writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
|
||||
writeF1000(os, m_player->getYaw());
|
||||
writeS16(os, getHP());
|
||||
writeU8(os, 2); // number of messages stuffed in here
|
||||
os<<serializeLongString(getPropertyPacket()); // message 1
|
||||
os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
|
||||
|
||||
if(protocol_version >= 15)
|
||||
{
|
||||
writeU8(os, 1); // version
|
||||
os<<serializeString(m_player->getName()); // name
|
||||
writeU8(os, 1); // is_player
|
||||
writeS16(os, getId()); //id
|
||||
writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
|
||||
writeF1000(os, m_player->getYaw());
|
||||
writeS16(os, getHP());
|
||||
|
||||
writeU8(os, 4 + m_bone_position.size()); // number of messages stuffed in here
|
||||
os<<serializeLongString(getPropertyPacket()); // message 1
|
||||
os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
|
||||
os<<serializeLongString(gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend)); // 3
|
||||
for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
|
||||
os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
|
||||
}
|
||||
os<<serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
|
||||
}
|
||||
else
|
||||
{
|
||||
writeU8(os, 0); // version
|
||||
os<<serializeString(m_player->getName()); // name
|
||||
writeU8(os, 1); // is_player
|
||||
writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
|
||||
writeF1000(os, m_player->getYaw());
|
||||
writeS16(os, getHP());
|
||||
writeU8(os, 2); // number of messages stuffed in here
|
||||
os<<serializeLongString(getPropertyPacket()); // message 1
|
||||
os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
|
||||
}
|
||||
|
||||
// return result
|
||||
return os.str();
|
||||
}
|
||||
|
||||
@@ -857,6 +1024,17 @@ std::string PlayerSAO::getStaticData()
|
||||
return "";
|
||||
}
|
||||
|
||||
bool PlayerSAO::isAttached()
|
||||
{
|
||||
if(!m_attachment_parent_id)
|
||||
return false;
|
||||
// Check if the parent still exists
|
||||
ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
|
||||
if(obj)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void PlayerSAO::step(float dtime, bool send_recommended)
|
||||
{
|
||||
if(!m_properties_sent)
|
||||
@@ -868,73 +1046,102 @@ void PlayerSAO::step(float dtime, bool send_recommended)
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
|
||||
// If attached, check that our parent is still there. If it isn't, detach.
|
||||
if(m_attachment_parent_id && !isAttached())
|
||||
{
|
||||
m_attachment_parent_id = 0;
|
||||
m_attachment_bone = "";
|
||||
m_attachment_position = v3f(0,0,0);
|
||||
m_attachment_rotation = v3f(0,0,0);
|
||||
m_player->setPosition(m_last_good_position);
|
||||
m_moved = true;
|
||||
}
|
||||
|
||||
m_time_from_last_punch += dtime;
|
||||
m_nocheat_dig_time += dtime;
|
||||
|
||||
if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
|
||||
|
||||
// Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
|
||||
// If the object gets detached this comes into effect automatically from the last known origin
|
||||
if(isAttached())
|
||||
{
|
||||
m_last_good_position = m_player->getPosition();
|
||||
v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
|
||||
m_last_good_position = pos;
|
||||
m_last_good_position_age = 0;
|
||||
m_player->setPosition(pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Check player movements
|
||||
|
||||
NOTE: Actually the server should handle player physics like the
|
||||
client does and compare player's position to what is calculated
|
||||
on our side. This is required when eg. players fly due to an
|
||||
explosion. Altough a node-based alternative might be possible
|
||||
too, and much more lightweight.
|
||||
*/
|
||||
|
||||
float player_max_speed = 0;
|
||||
float player_max_speed_up = 0;
|
||||
if(m_privs.count("fast") != 0){
|
||||
// Fast speed
|
||||
player_max_speed = BS * 20;
|
||||
player_max_speed_up = BS * 20;
|
||||
} else {
|
||||
// Normal speed
|
||||
player_max_speed = BS * 4.0;
|
||||
player_max_speed_up = BS * 4.0;
|
||||
}
|
||||
// Tolerance
|
||||
player_max_speed *= 2.5;
|
||||
player_max_speed_up *= 2.5;
|
||||
|
||||
m_last_good_position_age += dtime;
|
||||
if(m_last_good_position_age >= 1.0){
|
||||
float age = m_last_good_position_age;
|
||||
v3f diff = (m_player->getPosition() - m_last_good_position);
|
||||
float d_vert = diff.Y;
|
||||
diff.Y = 0;
|
||||
float d_horiz = diff.getLength();
|
||||
/*infostream<<m_player->getName()<<"'s horizontal speed is "
|
||||
<<(d_horiz/age)<<std::endl;*/
|
||||
if(d_horiz <= age * player_max_speed &&
|
||||
(d_vert < 0 || d_vert < age * player_max_speed_up)){
|
||||
m_last_good_position = m_player->getPosition();
|
||||
} else {
|
||||
actionstream<<"Player "<<m_player->getName()
|
||||
<<" moved too fast; resetting position"
|
||||
<<std::endl;
|
||||
m_player->setPosition(m_last_good_position);
|
||||
m_teleported = true;
|
||||
}
|
||||
if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
|
||||
{
|
||||
m_last_good_position = m_player->getPosition();
|
||||
m_last_good_position_age = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Check player movements
|
||||
|
||||
NOTE: Actually the server should handle player physics like the
|
||||
client does and compare player's position to what is calculated
|
||||
on our side. This is required when eg. players fly due to an
|
||||
explosion. Altough a node-based alternative might be possible
|
||||
too, and much more lightweight.
|
||||
*/
|
||||
|
||||
float player_max_speed = 0;
|
||||
float player_max_speed_up = 0;
|
||||
if(m_privs.count("fast") != 0){
|
||||
// Fast speed
|
||||
player_max_speed = BS * 20;
|
||||
player_max_speed_up = BS * 20;
|
||||
} else {
|
||||
// Normal speed
|
||||
player_max_speed = BS * 4.0;
|
||||
player_max_speed_up = BS * 4.0;
|
||||
}
|
||||
// Tolerance
|
||||
player_max_speed *= 2.5;
|
||||
player_max_speed_up *= 2.5;
|
||||
|
||||
m_last_good_position_age += dtime;
|
||||
if(m_last_good_position_age >= 1.0){
|
||||
float age = m_last_good_position_age;
|
||||
v3f diff = (m_player->getPosition() - m_last_good_position);
|
||||
float d_vert = diff.Y;
|
||||
diff.Y = 0;
|
||||
float d_horiz = diff.getLength();
|
||||
/*infostream<<m_player->getName()<<"'s horizontal speed is "
|
||||
<<(d_horiz/age)<<std::endl;*/
|
||||
if(d_horiz <= age * player_max_speed &&
|
||||
(d_vert < 0 || d_vert < age * player_max_speed_up)){
|
||||
m_last_good_position = m_player->getPosition();
|
||||
} else {
|
||||
actionstream<<"Player "<<m_player->getName()
|
||||
<<" moved too fast; resetting position"
|
||||
<<std::endl;
|
||||
m_player->setPosition(m_last_good_position);
|
||||
m_moved = true;
|
||||
}
|
||||
m_last_good_position_age = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(send_recommended == false)
|
||||
return;
|
||||
|
||||
if(m_position_not_sent)
|
||||
// If the object is attached client-side, don't waste bandwidth sending its position to clients
|
||||
if(m_position_not_sent && !isAttached())
|
||||
{
|
||||
m_position_not_sent = false;
|
||||
float update_interval = m_env->getSendRecommendedInterval();
|
||||
v3f pos;
|
||||
if(isAttached()) // Just in case we ever do send attachment position too
|
||||
pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
|
||||
else
|
||||
pos = m_player->getPosition() + v3f(0,BS*1,0);
|
||||
std::string str = gob_cmd_update_position(
|
||||
m_player->getPosition() + v3f(0,BS*1,0),
|
||||
pos,
|
||||
v3f(0,0,0),
|
||||
v3f(0,0,0),
|
||||
m_player->getYaw(),
|
||||
@@ -961,32 +1168,63 @@ void PlayerSAO::step(float dtime, bool send_recommended)
|
||||
ActiveObjectMessage aom(getId(), true, str);
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
|
||||
if(m_animation_sent == false){
|
||||
m_animation_sent = true;
|
||||
std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend);
|
||||
// create message and add to list
|
||||
ActiveObjectMessage aom(getId(), true, str);
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
|
||||
if(m_bone_position_sent == false){
|
||||
m_bone_position_sent = true;
|
||||
for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
|
||||
std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
|
||||
// create message and add to list
|
||||
ActiveObjectMessage aom(getId(), true, str);
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
}
|
||||
|
||||
if(m_attachment_sent == false){
|
||||
m_attachment_sent = true;
|
||||
std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
|
||||
// create message and add to list
|
||||
ActiveObjectMessage aom(getId(), true, str);
|
||||
m_messages_out.push_back(aom);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerSAO::setBasePosition(const v3f &position)
|
||||
{
|
||||
// This needs to be ran for attachments too
|
||||
ServerActiveObject::setBasePosition(position);
|
||||
m_position_not_sent = true;
|
||||
}
|
||||
|
||||
void PlayerSAO::setPos(v3f pos)
|
||||
{
|
||||
if(isAttached())
|
||||
return;
|
||||
m_player->setPosition(pos);
|
||||
// Movement caused by this command is always valid
|
||||
m_last_good_position = pos;
|
||||
m_last_good_position_age = 0;
|
||||
// Force position change on client
|
||||
m_teleported = true;
|
||||
m_moved = true;
|
||||
}
|
||||
|
||||
void PlayerSAO::moveTo(v3f pos, bool continuous)
|
||||
{
|
||||
if(isAttached())
|
||||
return;
|
||||
m_player->setPosition(pos);
|
||||
// Movement caused by this command is always valid
|
||||
m_last_good_position = pos;
|
||||
m_last_good_position_age = 0;
|
||||
// Force position change on client
|
||||
m_teleported = true;
|
||||
m_moved = true;
|
||||
}
|
||||
|
||||
int PlayerSAO::punch(v3f dir,
|
||||
@@ -994,6 +1232,10 @@ int PlayerSAO::punch(v3f dir,
|
||||
ServerActiveObject *puncher,
|
||||
float time_from_last_punch)
|
||||
{
|
||||
// It's best that attachments cannot be punched
|
||||
if(isAttached())
|
||||
return 0;
|
||||
|
||||
if(!toolcap)
|
||||
return 0;
|
||||
|
||||
@@ -1075,6 +1317,39 @@ void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
|
||||
m_armor_groups_sent = false;
|
||||
}
|
||||
|
||||
void PlayerSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend)
|
||||
{
|
||||
// store these so they can be updated to clients
|
||||
m_animation_range = frame_range;
|
||||
m_animation_speed = frame_speed;
|
||||
m_animation_blend = frame_blend;
|
||||
m_animation_sent = false;
|
||||
}
|
||||
|
||||
void PlayerSAO::setBonePosition(std::string bone, v3f position, v3f rotation)
|
||||
{
|
||||
// store these so they can be updated to clients
|
||||
m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
|
||||
m_bone_position_sent = false;
|
||||
}
|
||||
|
||||
void PlayerSAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
|
||||
{
|
||||
// Attachments need to be handled on both the server and client.
|
||||
// If we just attach on the server, we can only copy the position of the parent. Attachments
|
||||
// are still sent to clients at an interval so players might see them lagging, plus we can't
|
||||
// read and attach to skeletal bones.
|
||||
// If we just attach on the client, the server still sees the child at its original location.
|
||||
// This breaks some things so we also give the server the most accurate representation
|
||||
// even if players only see the client changes.
|
||||
|
||||
m_attachment_parent_id = parent_id;
|
||||
m_attachment_bone = bone;
|
||||
m_attachment_position = position;
|
||||
m_attachment_rotation = rotation;
|
||||
m_attachment_sent = false;
|
||||
}
|
||||
|
||||
ObjectProperties* PlayerSAO::accessObjectProperties()
|
||||
{
|
||||
return &m_prop;
|
||||
@@ -1138,7 +1413,7 @@ void PlayerSAO::disconnected()
|
||||
|
||||
std::string PlayerSAO::getPropertyPacket()
|
||||
{
|
||||
m_prop.is_visible = (getHP() != 0);
|
||||
m_prop.is_visible = (true);
|
||||
return gob_cmd_set_properties(m_prop);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,11 +43,12 @@ class LuaEntitySAO : public ServerActiveObject
|
||||
{ return ACTIVEOBJECT_TYPE_LUAENTITY; }
|
||||
u8 getSendType() const
|
||||
{ return ACTIVEOBJECT_TYPE_GENERIC; }
|
||||
virtual void addedToEnvironment();
|
||||
virtual void addedToEnvironment(u32 dtime_s);
|
||||
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
|
||||
const std::string &data);
|
||||
bool isAttached();
|
||||
void step(float dtime, bool send_recommended);
|
||||
std::string getClientInitializationData();
|
||||
std::string getClientInitializationData(u16 protocol_version);
|
||||
std::string getStaticData();
|
||||
int punch(v3f dir,
|
||||
const ToolCapabilities *toolcap=NULL,
|
||||
@@ -61,6 +62,9 @@ class LuaEntitySAO : public ServerActiveObject
|
||||
void setHP(s16 hp);
|
||||
s16 getHP() const;
|
||||
void setArmorGroups(const ItemGroupList &armor_groups);
|
||||
void setAnimation(v2f frame_range, float frame_speed, float frame_blend);
|
||||
void setBonePosition(std::string bone, v3f position, v3f rotation);
|
||||
void setAttachment(int parent_id, std::string bone, v3f position, v3f rotation);
|
||||
ObjectProperties* accessObjectProperties();
|
||||
void notifyObjectPropertiesModified();
|
||||
/* LuaEntitySAO-specific */
|
||||
@@ -96,6 +100,20 @@ class LuaEntitySAO : public ServerActiveObject
|
||||
float m_last_sent_position_timer;
|
||||
float m_last_sent_move_precision;
|
||||
bool m_armor_groups_sent;
|
||||
|
||||
v2f m_animation_range;
|
||||
float m_animation_speed;
|
||||
float m_animation_blend;
|
||||
bool m_animation_sent;
|
||||
|
||||
std::map<std::string, core::vector2d<v3f> > m_bone_position;
|
||||
bool m_bone_position_sent;
|
||||
|
||||
int m_attachment_parent_id;
|
||||
std::string m_attachment_bone;
|
||||
v3f m_attachment_position;
|
||||
v3f m_attachment_rotation;
|
||||
bool m_attachment_sent;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -118,12 +136,13 @@ class PlayerSAO : public ServerActiveObject
|
||||
Active object <-> environment interface
|
||||
*/
|
||||
|
||||
void addedToEnvironment();
|
||||
void addedToEnvironment(u32 dtime_s);
|
||||
void removingFromEnvironment();
|
||||
bool isStaticAllowed() const;
|
||||
bool unlimitedTransferDistance() const;
|
||||
std::string getClientInitializationData();
|
||||
std::string getClientInitializationData(u16 protocol_version);
|
||||
std::string getStaticData();
|
||||
bool isAttached();
|
||||
void step(float dtime, bool send_recommended);
|
||||
void setBasePosition(const v3f &position);
|
||||
void setPos(v3f pos);
|
||||
@@ -142,6 +161,9 @@ class PlayerSAO : public ServerActiveObject
|
||||
void setHP(s16 hp);
|
||||
|
||||
void setArmorGroups(const ItemGroupList &armor_groups);
|
||||
void setAnimation(v2f frame_range, float frame_speed, float frame_blend);
|
||||
void setBonePosition(std::string bone, v3f position, v3f rotation);
|
||||
void setAttachment(int parent_id, std::string bone, v3f position, v3f rotation);
|
||||
ObjectProperties* accessObjectProperties();
|
||||
void notifyObjectPropertiesModified();
|
||||
|
||||
@@ -229,15 +251,32 @@ class PlayerSAO : public ServerActiveObject
|
||||
bool m_position_not_sent;
|
||||
ItemGroupList m_armor_groups;
|
||||
bool m_armor_groups_sent;
|
||||
|
||||
|
||||
|
||||
bool m_properties_sent;
|
||||
struct ObjectProperties m_prop;
|
||||
// Cached privileges for enforcement
|
||||
std::set<std::string> m_privs;
|
||||
bool m_is_singleplayer;
|
||||
|
||||
v2f m_animation_range;
|
||||
float m_animation_speed;
|
||||
float m_animation_blend;
|
||||
bool m_animation_sent;
|
||||
|
||||
std::map<std::string, core::vector2d<v3f> > m_bone_position; // Stores position and rotation for each bone name
|
||||
bool m_bone_position_sent;
|
||||
|
||||
int m_attachment_parent_id;
|
||||
std::string m_attachment_bone;
|
||||
v3f m_attachment_position;
|
||||
v3f m_attachment_rotation;
|
||||
bool m_attachment_sent;
|
||||
|
||||
public:
|
||||
// Some flags used by Server
|
||||
bool m_teleported;
|
||||
bool m_moved;
|
||||
bool m_inventory_not_sent;
|
||||
bool m_hp_not_sent;
|
||||
bool m_wielded_item_not_sent;
|
||||
|
||||
@@ -20,23 +20,49 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#ifndef DAYNIGHTRATIO_HEADER
|
||||
#define DAYNIGHTRATIO_HEADER
|
||||
|
||||
inline u32 time_to_daynight_ratio(u32 time_of_day)
|
||||
inline u32 time_to_daynight_ratio(float time_of_day, bool smooth)
|
||||
{
|
||||
s32 t = time_of_day%24000;
|
||||
if(t < 4500 || t >= 19500)
|
||||
return 150;
|
||||
else if(t < 4750 || t >= 19250)
|
||||
return 250;
|
||||
else if(t < 5000 || t >= 19000)
|
||||
return 350;
|
||||
else if(t < 5250 || t >= 18750)
|
||||
return 500;
|
||||
else if(t < 5500 || t >= 18500)
|
||||
return 675;
|
||||
else if(t < 5750 || t >= 18250)
|
||||
return 875;
|
||||
else
|
||||
float t = time_of_day;
|
||||
if(t < 0)
|
||||
t += ((int)(-t)/24000)*24000;
|
||||
if(t >= 24000)
|
||||
t -= ((int)(t)/24000)*24000;
|
||||
if(t > 12000)
|
||||
t = 24000 - t;
|
||||
float values[][2] = {
|
||||
{4250+125, 150},
|
||||
{4500+125, 150},
|
||||
{4750+125, 250},
|
||||
{5000+125, 350},
|
||||
{5250+125, 500},
|
||||
{5500+125, 675},
|
||||
{5750+125, 875},
|
||||
{6000+125, 1000},
|
||||
{6250+125, 1000},
|
||||
};
|
||||
if(!smooth){
|
||||
float lastt = values[0][0];
|
||||
for(u32 i=1; i<sizeof(values)/sizeof(*values); i++){
|
||||
float t0 = values[i][0];
|
||||
float switch_t = (t0 + lastt) / 2;
|
||||
lastt = t0;
|
||||
if(switch_t <= t)
|
||||
continue;
|
||||
return values[i][1];
|
||||
}
|
||||
return 1000;
|
||||
} else {
|
||||
for(u32 i=0; i<sizeof(values)/sizeof(*values); i++){
|
||||
if(values[i][0] <= t)
|
||||
continue;
|
||||
if(i == 0)
|
||||
return values[i][1];
|
||||
float td0 = values[i][0] - values[i-1][0];
|
||||
float f = (t - values[i-1][0]) / td0;
|
||||
return f * values[i][1] + (1.0 - f) * values[i-1][1];
|
||||
}
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -52,7 +52,10 @@ void set_default_settings(Settings *settings)
|
||||
settings->setDefault("keymap_toggle_profiler", "KEY_F6");
|
||||
settings->setDefault("keymap_increase_viewing_range_min", "+");
|
||||
settings->setDefault("keymap_decrease_viewing_range_min", "-");
|
||||
settings->setDefault("anaglyph", "false");
|
||||
settings->setDefault("anaglyph_strength", "0.1");
|
||||
settings->setDefault("aux1_descends", "false");
|
||||
|
||||
// Some (temporary) keys for debugging
|
||||
settings->setDefault("keymap_print_debug_stacks", "KEY_KEY_P");
|
||||
settings->setDefault("keymap_quicktune_prev", "KEY_HOME");
|
||||
@@ -70,7 +73,7 @@ void set_default_settings(Settings *settings)
|
||||
settings->setDefault("wanted_fps", "30");
|
||||
settings->setDefault("fps_max", "60");
|
||||
// A bit more than the server will send around the player, to make fog blend well
|
||||
settings->setDefault("viewing_range_nodes_max", "160");
|
||||
settings->setDefault("viewing_range_nodes_max", "240");
|
||||
settings->setDefault("viewing_range_nodes_min", "35");
|
||||
settings->setDefault("screenW", "800");
|
||||
settings->setDefault("screenH", "600");
|
||||
@@ -89,6 +92,7 @@ void set_default_settings(Settings *settings)
|
||||
settings->setDefault("smooth_lighting", "true");
|
||||
settings->setDefault("enable_texture_atlas", "true");
|
||||
settings->setDefault("texture_path", "");
|
||||
settings->setDefault("shader_path", "");
|
||||
settings->setDefault("video_driver", "opengl");
|
||||
settings->setDefault("free_move", "false");
|
||||
settings->setDefault("continuous_forward", "false");
|
||||
@@ -106,12 +110,19 @@ void set_default_settings(Settings *settings)
|
||||
settings->setDefault("sound_volume", "0.8");
|
||||
settings->setDefault("desynchronize_mapblock_texture_animation", "true");
|
||||
|
||||
settings->setDefault("mip_map", "false");
|
||||
settings->setDefault("anisotropic_filter", "false");
|
||||
settings->setDefault("bilinear_filter", "false");
|
||||
settings->setDefault("trilinear_filter", "false");
|
||||
settings->setDefault("preload_item_visuals", "true");
|
||||
settings->setDefault("enable_shaders", "2");
|
||||
|
||||
// Server stuff
|
||||
// "map-dir" doesn't exist by default.
|
||||
settings->setDefault("default_game", "minetest");
|
||||
settings->setDefault("motd", "");
|
||||
settings->setDefault("max_users", "100");
|
||||
settings->setDefault("strict_protocol_version_checking", "true");
|
||||
settings->setDefault("strict_protocol_version_checking", "false");
|
||||
settings->setDefault("creative_mode", "false");
|
||||
settings->setDefault("enable_damage", "true");
|
||||
settings->setDefault("only_peaceful_mobs", "false");
|
||||
@@ -140,7 +151,10 @@ void set_default_settings(Settings *settings)
|
||||
settings->setDefault("server_unload_unused_data_timeout", "29");
|
||||
settings->setDefault("server_map_save_interval", "5.3");
|
||||
settings->setDefault("full_block_send_enable_min_time_from_building", "2.0");
|
||||
settings->setDefault("dedicated_server_step", "0.05");
|
||||
settings->setDefault("dedicated_server_step", "0.1");
|
||||
settings->setDefault("ignore_world_load_errors", "false");
|
||||
settings->setDefault("congestion_control_aim_rtt", "0.2");
|
||||
settings->setDefault("congestion_control_max_rate", "400");
|
||||
settings->setDefault("congestion_control_min_rate", "10");
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#endif
|
||||
#include "daynightratio.h"
|
||||
#include "map.h"
|
||||
#include "util/serialize.h"
|
||||
|
||||
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
|
||||
|
||||
@@ -202,7 +203,8 @@ void Environment::printPlayers(std::ostream &o)
|
||||
|
||||
u32 Environment::getDayNightRatio()
|
||||
{
|
||||
return time_to_daynight_ratio(m_time_of_day);
|
||||
bool smooth = (g_settings->getS32("enable_shaders") != 0);
|
||||
return time_to_daynight_ratio(m_time_of_day_f*24000, smooth);
|
||||
}
|
||||
|
||||
void Environment::stepTimeOfDay(float dtime)
|
||||
@@ -328,7 +330,8 @@ ServerEnvironment::ServerEnvironment(ServerMap *map, lua_State *L,
|
||||
m_send_recommended_timer(0),
|
||||
m_active_block_interval_overload_skip(0),
|
||||
m_game_time(0),
|
||||
m_game_time_fraction_counter(0)
|
||||
m_game_time_fraction_counter(0),
|
||||
m_recommended_send_interval(0.1)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -743,19 +746,25 @@ class ABMHandler
|
||||
u32 active_object_count = block->m_static_objects.m_active.size();
|
||||
// Find out how many objects this and all the neighbors contain
|
||||
u32 active_object_count_wider = 0;
|
||||
u32 wider_unknown_count = 0;
|
||||
for(s16 x=-1; x<=1; x++)
|
||||
for(s16 y=-1; y<=1; y++)
|
||||
for(s16 z=-1; z<=1; z++)
|
||||
{
|
||||
MapBlock *block2 = map->getBlockNoCreateNoEx(
|
||||
block->getPos() + v3s16(x,y,z));
|
||||
if(block2==NULL)
|
||||
if(block2==NULL){
|
||||
wider_unknown_count = 0;
|
||||
continue;
|
||||
}
|
||||
active_object_count_wider +=
|
||||
block2->m_static_objects.m_active.size()
|
||||
+ block2->m_static_objects.m_stored.size();
|
||||
}
|
||||
|
||||
// Extrapolate
|
||||
u32 wider_known_count = 3*3*3 - wider_unknown_count;
|
||||
active_object_count_wider += wider_unknown_count * active_object_count_wider / wider_known_count;
|
||||
|
||||
// Call all the trigger variations
|
||||
i->abm->trigger(m_env, p, n);
|
||||
i->abm->trigger(m_env, p, n,
|
||||
@@ -784,7 +793,7 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
|
||||
<<dtime_s<<" seconds old."<<std::endl;*/
|
||||
|
||||
// Activate stored objects
|
||||
activateObjects(block);
|
||||
activateObjects(block, dtime_s);
|
||||
|
||||
// Run node timers
|
||||
std::map<v3s16, NodeTimer> elapsed_timers =
|
||||
@@ -933,6 +942,11 @@ void ServerEnvironment::step(float dtime)
|
||||
/* Step time of day */
|
||||
stepTimeOfDay(dtime);
|
||||
|
||||
// Update this one
|
||||
// NOTE: This is kind of funny on a singleplayer game, but doesn't
|
||||
// really matter that much.
|
||||
m_recommended_send_interval = g_settings->getFloat("dedicated_server_step");
|
||||
|
||||
/*
|
||||
Increment game time
|
||||
*/
|
||||
@@ -1243,7 +1257,7 @@ u16 getFreeServerActiveObjectId(
|
||||
u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
|
||||
{
|
||||
assert(object);
|
||||
u16 id = addActiveObjectRaw(object, true);
|
||||
u16 id = addActiveObjectRaw(object, true, 0);
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -1402,7 +1416,7 @@ ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
|
||||
*/
|
||||
|
||||
u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
|
||||
bool set_changed)
|
||||
bool set_changed, u32 dtime_s)
|
||||
{
|
||||
assert(object);
|
||||
if(object->getId() == 0){
|
||||
@@ -1442,7 +1456,7 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
|
||||
// Register reference in scripting api (must be done before post-init)
|
||||
scriptapi_add_object_reference(m_lua, object);
|
||||
// Post-initialize object
|
||||
object->addedToEnvironment();
|
||||
object->addedToEnvironment(dtime_s);
|
||||
|
||||
// Add static data to block
|
||||
if(object->isStaticAllowed())
|
||||
@@ -1465,9 +1479,10 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
|
||||
"addActiveObjectRaw");
|
||||
}
|
||||
else{
|
||||
v3s16 p = floatToInt(objectpos, BS);
|
||||
errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
|
||||
<<"could not find block for storing id="<<object->getId()
|
||||
<<" statically"<<std::endl;
|
||||
<<" statically (pos="<<PP(p)<<")"<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1578,7 +1593,7 @@ static void print_hexdump(std::ostream &o, const std::string &data)
|
||||
/*
|
||||
Convert stored objects from blocks near the players to active.
|
||||
*/
|
||||
void ServerEnvironment::activateObjects(MapBlock *block)
|
||||
void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
|
||||
{
|
||||
if(block==NULL)
|
||||
return;
|
||||
@@ -1602,7 +1617,7 @@ void ServerEnvironment::activateObjects(MapBlock *block)
|
||||
"large amount of objects");
|
||||
return;
|
||||
}
|
||||
// A list for objects that couldn't be converted to static for some
|
||||
// A list for objects that couldn't be converted to active for some
|
||||
// reason. They will be stored back.
|
||||
core::list<StaticObject> new_stored;
|
||||
// Loop through stored static objects
|
||||
@@ -1632,7 +1647,7 @@ void ServerEnvironment::activateObjects(MapBlock *block)
|
||||
<<"activated static object pos="<<PP(s_obj.pos/BS)
|
||||
<<" type="<<(int)s_obj.type<<std::endl;
|
||||
// This will also add the object to the active static list
|
||||
addActiveObjectRaw(obj, false);
|
||||
addActiveObjectRaw(obj, false, dtime_s);
|
||||
}
|
||||
// Clear stored list
|
||||
block->m_static_objects.m_stored.clear();
|
||||
@@ -1756,7 +1771,12 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
|
||||
// Add to the block where the object is located in
|
||||
v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
|
||||
// Get or generate the block
|
||||
MapBlock *block = m_map->emergeBlock(blockpos);
|
||||
MapBlock *block = NULL;
|
||||
try{
|
||||
block = m_map->emergeBlock(blockpos);
|
||||
} catch(InvalidPositionException &e){
|
||||
// Handled via NULL pointer
|
||||
}
|
||||
|
||||
if(block)
|
||||
{
|
||||
@@ -1793,9 +1813,10 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
|
||||
}
|
||||
else{
|
||||
if(!force_delete){
|
||||
v3s16 p = floatToInt(objectpos, BS);
|
||||
errorstream<<"ServerEnv: Could not find or generate "
|
||||
<<"a block for storing id="<<obj->getId()
|
||||
<<" statically"<<std::endl;
|
||||
<<" statically (pos="<<PP(p)<<")"<<std::endl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -2112,15 +2133,15 @@ void ClientEnvironment::step(float dtime)
|
||||
}
|
||||
|
||||
// Update lighting on all players on client
|
||||
u8 light = LIGHT_MAX;
|
||||
float light = 1.0;
|
||||
try{
|
||||
// Get node at head
|
||||
v3s16 p = player->getLightPosition();
|
||||
MapNode n = m_map->getNode(p);
|
||||
light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
|
||||
light = n.getLightBlendF1((float)getDayNightRatio()/1000, m_gamedef->ndef());
|
||||
}
|
||||
catch(InvalidPositionException &e){
|
||||
light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
|
||||
light = blend_light_f1((float)getDayNightRatio()/1000, LIGHT_SUN, 0);
|
||||
}
|
||||
player->light = light;
|
||||
}
|
||||
@@ -2129,6 +2150,7 @@ void ClientEnvironment::step(float dtime)
|
||||
Step active objects and update lighting of them
|
||||
*/
|
||||
|
||||
bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21);
|
||||
for(core::map<u16, ClientActiveObject*>::Iterator
|
||||
i = m_active_objects.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
@@ -2137,7 +2159,7 @@ void ClientEnvironment::step(float dtime)
|
||||
// Step object
|
||||
obj->step(dtime, this);
|
||||
|
||||
if(m_active_object_light_update_interval.step(dtime, 0.21))
|
||||
if(update_lighting)
|
||||
{
|
||||
// Update lighting
|
||||
u8 light = 0;
|
||||
@@ -2282,8 +2304,9 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
|
||||
{
|
||||
errorstream<<"ClientEnvironment::addActiveObject():"
|
||||
<<" id="<<id<<" type="<<type
|
||||
<<": SerializationError in initialize(),"
|
||||
<<" init_data="<<serializeJsonString(init_data)
|
||||
<<": SerializationError in initialize(): "
|
||||
<<e.what()
|
||||
<<": init_data="<<serializeJsonString(init_data)
|
||||
<<std::endl;
|
||||
}
|
||||
|
||||
@@ -2301,7 +2324,7 @@ void ClientEnvironment::removeActiveObject(u16 id)
|
||||
<<"id="<<id<<" not found"<<std::endl;
|
||||
return;
|
||||
}
|
||||
obj->removeFromScene();
|
||||
obj->removeFromScene(true);
|
||||
delete obj;
|
||||
m_active_objects.remove(id);
|
||||
}
|
||||
|
||||
@@ -205,9 +205,7 @@ class ServerEnvironment : public Environment
|
||||
{ return m_gamedef; }
|
||||
|
||||
float getSendRecommendedInterval()
|
||||
{
|
||||
return 0.10;
|
||||
}
|
||||
{ return m_recommended_send_interval; }
|
||||
|
||||
/*
|
||||
Save players
|
||||
@@ -312,7 +310,7 @@ class ServerEnvironment : public Environment
|
||||
Returns the id of the object.
|
||||
Returns 0 if not added and thus deleted.
|
||||
*/
|
||||
u16 addActiveObjectRaw(ServerActiveObject *object, bool set_changed);
|
||||
u16 addActiveObjectRaw(ServerActiveObject *object, bool set_changed, u32 dtime_s);
|
||||
|
||||
/*
|
||||
Remove all objects that satisfy (m_removed && m_known_by_count==0)
|
||||
@@ -322,7 +320,7 @@ class ServerEnvironment : public Environment
|
||||
/*
|
||||
Convert stored objects from block to active
|
||||
*/
|
||||
void activateObjects(MapBlock *block);
|
||||
void activateObjects(MapBlock *block, u32 dtime_s);
|
||||
|
||||
/*
|
||||
Convert objects that are not in active blocks to static.
|
||||
@@ -367,6 +365,8 @@ class ServerEnvironment : public Environment
|
||||
// A helper variable for incrementing the latter
|
||||
float m_game_time_fraction_counter;
|
||||
core::list<ABMWithState> m_abms;
|
||||
// An interval for generally sending object positions and stuff
|
||||
float m_recommended_send_interval;
|
||||
};
|
||||
|
||||
#ifndef SERVER
|
||||
@@ -463,6 +463,8 @@ class ClientEnvironment : public Environment
|
||||
|
||||
// Get event from queue. CEE_NONE is returned if queue is empty.
|
||||
ClientEnvEvent getClientEvent();
|
||||
|
||||
std::vector<core::vector2d<int> > attachment_list; // X is child ID, Y is parent ID
|
||||
|
||||
private:
|
||||
ClientMap *m_map;
|
||||
|
||||
186
src/game.cpp
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <IGUIButton.h>
|
||||
#include <IGUIStaticText.h>
|
||||
#include <IGUIFont.h>
|
||||
#include <IMaterialRendererServices.h>
|
||||
#include "client.h"
|
||||
#include "server.h"
|
||||
#include "guiPauseMenu.h"
|
||||
@@ -50,6 +51,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "main.h" // For g_settings
|
||||
#include "itemdef.h"
|
||||
#include "tile.h" // For TextureSource
|
||||
#include "shader.h" // For ShaderSource
|
||||
#include "logoutputbuffer.h"
|
||||
#include "subgame.h"
|
||||
#include "quicktune_shortcutter.h"
|
||||
@@ -834,6 +836,53 @@ class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
|
||||
}
|
||||
};
|
||||
|
||||
class GameGlobalShaderConstantSetter : public IShaderConstantSetter
|
||||
{
|
||||
Sky *m_sky;
|
||||
bool *m_force_fog_off;
|
||||
f32 *m_fog_range;
|
||||
Client *m_client;
|
||||
|
||||
public:
|
||||
GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
|
||||
f32 *fog_range, Client *client):
|
||||
m_sky(sky),
|
||||
m_force_fog_off(force_fog_off),
|
||||
m_fog_range(fog_range),
|
||||
m_client(client)
|
||||
{}
|
||||
~GameGlobalShaderConstantSetter() {}
|
||||
|
||||
virtual void onSetConstants(video::IMaterialRendererServices *services,
|
||||
bool is_highlevel)
|
||||
{
|
||||
if(!is_highlevel)
|
||||
return;
|
||||
|
||||
// Background color
|
||||
video::SColor bgcolor = m_sky->getBgColor();
|
||||
video::SColorf bgcolorf(bgcolor);
|
||||
float bgcolorfa[4] = {
|
||||
bgcolorf.r,
|
||||
bgcolorf.g,
|
||||
bgcolorf.b,
|
||||
bgcolorf.a,
|
||||
};
|
||||
services->setPixelShaderConstant("skyBgColor", bgcolorfa, 4);
|
||||
|
||||
// Fog distance
|
||||
float fog_distance = *m_fog_range;
|
||||
if(*m_force_fog_off)
|
||||
fog_distance = 10000*BS;
|
||||
services->setPixelShaderConstant("fogDistance", &fog_distance, 1);
|
||||
|
||||
// Day-night ratio
|
||||
u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
|
||||
float daynight_ratio_f = (float)daynight_ratio / 1000.0;
|
||||
services->setPixelShaderConstant("dayNightRatio", &daynight_ratio_f, 1);
|
||||
}
|
||||
};
|
||||
|
||||
void the_game(
|
||||
bool &kill,
|
||||
bool random_input,
|
||||
@@ -876,6 +925,9 @@ void the_game(
|
||||
// Create texture source
|
||||
IWritableTextureSource *tsrc = createTextureSource(device);
|
||||
|
||||
// Create shader source
|
||||
IWritableShaderSource *shsrc = createShaderSource(device);
|
||||
|
||||
// These will be filled by data received from the server
|
||||
// Create item definition manager
|
||||
IWritableItemDefManager *itemdef = createItemDefManager();
|
||||
@@ -943,7 +995,7 @@ void the_game(
|
||||
MapDrawControl draw_control;
|
||||
|
||||
Client client(device, playername.c_str(), password, draw_control,
|
||||
tsrc, itemdef, nodedef, sound, &eventmgr);
|
||||
tsrc, shsrc, itemdef, nodedef, sound, &eventmgr);
|
||||
|
||||
// Client acts as our GameDef
|
||||
IGameDef *gamedef = &client;
|
||||
@@ -1162,7 +1214,7 @@ void the_game(
|
||||
|
||||
// First line of debug text
|
||||
gui::IGUIStaticText *guitext = guienv->addStaticText(
|
||||
L"Minetest-c55",
|
||||
L"Minetest",
|
||||
core::rect<s32>(5, 5, 795, 5+text_height),
|
||||
false, false);
|
||||
// Second line of debug text
|
||||
@@ -1246,6 +1298,7 @@ void the_game(
|
||||
bool show_hud = true;
|
||||
bool show_chat = true;
|
||||
bool force_fog_off = false;
|
||||
f32 fog_range = 100*BS;
|
||||
bool disable_camera_update = false;
|
||||
bool show_debug = g_settings->getBool("show_debug");
|
||||
bool show_profiler_graph = false;
|
||||
@@ -1255,6 +1308,12 @@ void the_game(
|
||||
float time_of_day = 0;
|
||||
float time_of_day_smooth = 0;
|
||||
|
||||
/*
|
||||
Shader constants
|
||||
*/
|
||||
shsrc->addGlobalConstantSetter(new GameGlobalShaderConstantSetter(
|
||||
sky, &force_fog_off, &fog_range, &client));
|
||||
|
||||
/*
|
||||
Main loop
|
||||
*/
|
||||
@@ -1416,11 +1475,17 @@ void the_game(
|
||||
g_gamecallback->changepassword_requested = false;
|
||||
}
|
||||
|
||||
/*
|
||||
Process TextureSource's queue
|
||||
*/
|
||||
/* Process TextureSource's queue */
|
||||
tsrc->processQueue();
|
||||
|
||||
/* Process ItemDefManager's queue */
|
||||
itemdef->processQueue(gamedef);
|
||||
|
||||
/*
|
||||
Process ShaderSource's queue
|
||||
*/
|
||||
shsrc->processQueue();
|
||||
|
||||
/*
|
||||
Random calculations
|
||||
*/
|
||||
@@ -1513,7 +1578,7 @@ void the_game(
|
||||
<<"Launching inventory"<<std::endl;
|
||||
|
||||
GUIFormSpecMenu *menu =
|
||||
new GUIFormSpecMenu(guienv, guiroot, -1,
|
||||
new GUIFormSpecMenu(device, guiroot, -1,
|
||||
&g_menumgr,
|
||||
&client, gamedef);
|
||||
|
||||
@@ -1881,6 +1946,8 @@ void the_game(
|
||||
bool a_jump,
|
||||
bool a_superspeed,
|
||||
bool a_sneak,
|
||||
bool a_LMB,
|
||||
bool a_RMB,
|
||||
float a_pitch,
|
||||
float a_yaw*/
|
||||
PlayerControl control(
|
||||
@@ -1891,10 +1958,24 @@ void the_game(
|
||||
input->isKeyDown(getKeySetting("keymap_jump")),
|
||||
input->isKeyDown(getKeySetting("keymap_special1")),
|
||||
input->isKeyDown(getKeySetting("keymap_sneak")),
|
||||
input->getLeftState(),
|
||||
input->getRightState(),
|
||||
camera_pitch,
|
||||
camera_yaw
|
||||
);
|
||||
client.setPlayerControl(control);
|
||||
u32 keyPressed=
|
||||
1*(int)input->isKeyDown(getKeySetting("keymap_forward"))+
|
||||
2*(int)input->isKeyDown(getKeySetting("keymap_backward"))+
|
||||
4*(int)input->isKeyDown(getKeySetting("keymap_left"))+
|
||||
8*(int)input->isKeyDown(getKeySetting("keymap_right"))+
|
||||
16*(int)input->isKeyDown(getKeySetting("keymap_jump"))+
|
||||
32*(int)input->isKeyDown(getKeySetting("keymap_special1"))+
|
||||
64*(int)input->isKeyDown(getKeySetting("keymap_sneak"))+
|
||||
128*(int)input->getLeftState()+
|
||||
256*(int)input->getRightState();
|
||||
LocalPlayer* player = client.getEnv().getLocalPlayer();
|
||||
player->keyPressed=keyPressed;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2280,7 +2361,7 @@ void the_game(
|
||||
/* Create menu */
|
||||
|
||||
GUIFormSpecMenu *menu =
|
||||
new GUIFormSpecMenu(guienv, guiroot, -1,
|
||||
new GUIFormSpecMenu(device, guiroot, -1,
|
||||
&g_menumgr,
|
||||
&client, gamedef);
|
||||
menu->setFormSpec(meta->getString("formspec"),
|
||||
@@ -2408,7 +2489,6 @@ void the_game(
|
||||
Fog range
|
||||
*/
|
||||
|
||||
f32 fog_range;
|
||||
if(farmesh)
|
||||
{
|
||||
fog_range = BS*farmesh_range;
|
||||
@@ -2425,8 +2505,7 @@ void the_game(
|
||||
Calculate general brightness
|
||||
*/
|
||||
u32 daynight_ratio = client.getEnv().getDayNightRatio();
|
||||
float time_brightness = (float)decode_light(
|
||||
(daynight_ratio * LIGHT_SUN) / 1000) / 255.0;
|
||||
float time_brightness = decode_light_f((float)daynight_ratio/1000.0);
|
||||
float direct_brightness = 0;
|
||||
bool sunlight_seen = false;
|
||||
if(g_settings->getBool("free_move")){
|
||||
@@ -2528,7 +2607,7 @@ void the_game(
|
||||
//TimeTaker guiupdatetimer("Gui updating");
|
||||
|
||||
const char program_name_and_version[] =
|
||||
"Minetest-c55 " VERSION_STRING;
|
||||
"Minetest " VERSION_STRING;
|
||||
|
||||
if(show_debug)
|
||||
{
|
||||
@@ -2734,6 +2813,76 @@ void the_game(
|
||||
{
|
||||
TimeTaker timer("smgr");
|
||||
smgr->drawAll();
|
||||
|
||||
if(g_settings->getBool("anaglyph"))
|
||||
{
|
||||
irr::core::vector3df oldPosition = camera.getCameraNode()->getPosition();
|
||||
irr::core::vector3df oldTarget = camera.getCameraNode()->getTarget();
|
||||
|
||||
irr::core::matrix4 startMatrix = camera.getCameraNode()->getAbsoluteTransformation();
|
||||
|
||||
irr::core::vector3df focusPoint = (camera.getCameraNode()->getTarget() -
|
||||
camera.getCameraNode()->getAbsolutePosition()).setLength(1) +
|
||||
camera.getCameraNode()->getAbsolutePosition() ;
|
||||
|
||||
//Left eye...
|
||||
irr::core::vector3df leftEye;
|
||||
irr::core::matrix4 leftMove;
|
||||
|
||||
leftMove.setTranslation( irr::core::vector3df(-g_settings->getFloat("anaglyph_strength"),0.0f,0.0f) );
|
||||
leftEye=(startMatrix*leftMove).getTranslation();
|
||||
|
||||
//clear the depth buffer, and color
|
||||
driver->beginScene( true, true, irr::video::SColor(0,200,200,255) );
|
||||
|
||||
driver->getOverrideMaterial().Material.ColorMask = irr::video::ECP_RED;
|
||||
driver->getOverrideMaterial().EnableFlags = irr::video::EMF_COLOR_MASK;
|
||||
driver->getOverrideMaterial().EnablePasses = irr::scene::ESNRP_SKY_BOX +
|
||||
irr::scene::ESNRP_SOLID +
|
||||
irr::scene::ESNRP_TRANSPARENT +
|
||||
irr::scene::ESNRP_TRANSPARENT_EFFECT +
|
||||
irr::scene::ESNRP_SHADOW;
|
||||
|
||||
camera.getCameraNode()->setPosition( leftEye );
|
||||
camera.getCameraNode()->setTarget( focusPoint );
|
||||
|
||||
smgr->drawAll(); // 'smgr->drawAll();' may go here
|
||||
|
||||
|
||||
//Right eye...
|
||||
irr::core::vector3df rightEye;
|
||||
irr::core::matrix4 rightMove;
|
||||
|
||||
rightMove.setTranslation( irr::core::vector3df(g_settings->getFloat("anaglyph_strength"),0.0f,0.0f) );
|
||||
rightEye=(startMatrix*rightMove).getTranslation();
|
||||
|
||||
//clear the depth buffer
|
||||
driver->clearZBuffer();
|
||||
|
||||
driver->getOverrideMaterial().Material.ColorMask = irr::video::ECP_GREEN + irr::video::ECP_BLUE;
|
||||
driver->getOverrideMaterial().EnableFlags = irr::video::EMF_COLOR_MASK;
|
||||
driver->getOverrideMaterial().EnablePasses = irr::scene::ESNRP_SKY_BOX +
|
||||
irr::scene::ESNRP_SOLID +
|
||||
irr::scene::ESNRP_TRANSPARENT +
|
||||
irr::scene::ESNRP_TRANSPARENT_EFFECT +
|
||||
irr::scene::ESNRP_SHADOW;
|
||||
|
||||
camera.getCameraNode()->setPosition( rightEye );
|
||||
camera.getCameraNode()->setTarget( focusPoint );
|
||||
|
||||
smgr->drawAll(); // 'smgr->drawAll();' may go here
|
||||
|
||||
|
||||
//driver->endScene();
|
||||
|
||||
driver->getOverrideMaterial().Material.ColorMask=irr::video::ECP_ALL;
|
||||
driver->getOverrideMaterial().EnableFlags=0;
|
||||
driver->getOverrideMaterial().EnablePasses=0;
|
||||
|
||||
camera.getCameraNode()->setPosition( oldPosition );
|
||||
camera.getCameraNode()->setTarget( oldTarget );
|
||||
}
|
||||
|
||||
scenetime = timer.stop(true);
|
||||
}
|
||||
|
||||
@@ -2809,11 +2958,6 @@ void the_game(
|
||||
//timer10.stop();
|
||||
//TimeTaker //timer11("//timer11");
|
||||
|
||||
/*
|
||||
Draw gui
|
||||
*/
|
||||
// 0-1ms
|
||||
guienv->drawAll();
|
||||
|
||||
/*
|
||||
Draw hotbar
|
||||
@@ -2839,6 +2983,12 @@ void the_game(
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
Draw gui
|
||||
*/
|
||||
// 0-1ms
|
||||
guienv->drawAll();
|
||||
|
||||
/*
|
||||
End scene
|
||||
*/
|
||||
@@ -2915,9 +3065,11 @@ void the_game(
|
||||
|
||||
if(!sound_is_dummy)
|
||||
delete sound;
|
||||
|
||||
delete tsrc;
|
||||
delete shsrc;
|
||||
delete nodedef;
|
||||
delete itemdef;
|
||||
delete tsrc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ class INodeDefManager;
|
||||
class ICraftDefManager;
|
||||
class ITextureSource;
|
||||
class ISoundManager;
|
||||
class IShaderSource;
|
||||
class MtEventManager;
|
||||
class IRollbackReportSink;
|
||||
|
||||
@@ -48,6 +49,8 @@ class IGameDef
|
||||
// This is always thread-safe, but referencing the irrlicht texture
|
||||
// pointers in other threads than main thread will make things explode.
|
||||
virtual ITextureSource* getTextureSource()=0;
|
||||
|
||||
virtual IShaderSource* getShaderSource()=0;
|
||||
|
||||
// Used for keeping track of names/ids of unknown nodes
|
||||
virtual u16 allocateUnknownNodeId(const std::string &name)=0;
|
||||
@@ -70,6 +73,7 @@ class IGameDef
|
||||
ICraftDefManager* cdef(){return getCraftDefManager();}
|
||||
ITextureSource* tsrc(){return getTextureSource();}
|
||||
ISoundManager* sound(){return getSoundManager();}
|
||||
IShaderSource* shsrc(){return getShaderSource();}
|
||||
MtEventManager* event(){return getEventManager();}
|
||||
IRollbackReportSink* rollback(){return getRollbackReportSink();}
|
||||
};
|
||||
|
||||
@@ -117,4 +117,40 @@ std::string gob_cmd_update_armor_groups(const ItemGroupList &armor_groups)
|
||||
return os.str();
|
||||
}
|
||||
|
||||
std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_blend)
|
||||
{
|
||||
std::ostringstream os(std::ios::binary);
|
||||
// command
|
||||
writeU8(os, GENERIC_CMD_SET_ANIMATION);
|
||||
// parameters
|
||||
writeV2F1000(os, frames);
|
||||
writeF1000(os, frame_speed);
|
||||
writeF1000(os, frame_blend);
|
||||
return os.str();
|
||||
}
|
||||
|
||||
std::string gob_cmd_update_bone_position(std::string bone, v3f position, v3f rotation)
|
||||
{
|
||||
std::ostringstream os(std::ios::binary);
|
||||
// command
|
||||
writeU8(os, GENERIC_CMD_SET_BONE_POSITION);
|
||||
// parameters
|
||||
os<<serializeString(bone);
|
||||
writeV3F1000(os, position);
|
||||
writeV3F1000(os, rotation);
|
||||
return os.str();
|
||||
}
|
||||
|
||||
std::string gob_cmd_update_attachment(int parent_id, std::string bone, v3f position, v3f rotation)
|
||||
{
|
||||
std::ostringstream os(std::ios::binary);
|
||||
// command
|
||||
writeU8(os, GENERIC_CMD_SET_ATTACHMENT);
|
||||
// parameters
|
||||
writeS16(os, parent_id);
|
||||
os<<serializeString(bone);
|
||||
writeV3F1000(os, position);
|
||||
writeV3F1000(os, rotation);
|
||||
return os.str();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#define GENERIC_CMD_SET_SPRITE 3
|
||||
#define GENERIC_CMD_PUNCHED 4
|
||||
#define GENERIC_CMD_UPDATE_ARMOR_GROUPS 5
|
||||
#define GENERIC_CMD_SET_ANIMATION 6
|
||||
#define GENERIC_CMD_SET_BONE_POSITION 7
|
||||
#define GENERIC_CMD_SET_ATTACHMENT 8
|
||||
|
||||
#include "object_properties.h"
|
||||
std::string gob_cmd_set_properties(const ObjectProperties &prop);
|
||||
@@ -59,5 +62,11 @@ std::string gob_cmd_punched(s16 damage, s16 result_hp);
|
||||
#include "itemgroup.h"
|
||||
std::string gob_cmd_update_armor_groups(const ItemGroupList &armor_groups);
|
||||
|
||||
std::string gob_cmd_update_animation(v2f frames, float frame_speed, float frame_blend);
|
||||
|
||||
std::string gob_cmd_update_bone_position(std::string bone, v3f position, v3f rotation);
|
||||
|
||||
std::string gob_cmd_update_attachment(int parent_id, std::string bone, v3f position, v3f rotation);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ void drawItemStack(video::IVideoDriver *driver,
|
||||
return;
|
||||
|
||||
const ItemDefinition &def = item.getDefinition(gamedef->idef());
|
||||
video::ITexture *texture = def.inventory_texture;
|
||||
video::ITexture *texture = gamedef->idef()->getInventoryTexture(def.name, gamedef);
|
||||
|
||||
// Draw the inventory texture
|
||||
if(texture != NULL)
|
||||
@@ -125,13 +125,14 @@ void drawItemStack(video::IVideoDriver *driver,
|
||||
GUIFormSpecMenu
|
||||
*/
|
||||
|
||||
GUIFormSpecMenu::GUIFormSpecMenu(gui::IGUIEnvironment* env,
|
||||
GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev,
|
||||
gui::IGUIElement* parent, s32 id,
|
||||
IMenuManager *menumgr,
|
||||
InventoryManager *invmgr,
|
||||
IGameDef *gamedef
|
||||
):
|
||||
GUIModalMenu(env, parent, id, menumgr),
|
||||
GUIModalMenu(dev->getGUIEnvironment(), parent, id, menumgr),
|
||||
m_device(dev),
|
||||
m_invmgr(invmgr),
|
||||
m_gamedef(gamedef),
|
||||
m_form_src(NULL),
|
||||
@@ -199,6 +200,8 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||
|
||||
m_inventorylists.clear();
|
||||
m_images.clear();
|
||||
m_backgrounds.clear();
|
||||
m_itemimages.clear();
|
||||
m_fields.clear();
|
||||
|
||||
Strfnd f(m_formspec_string);
|
||||
@@ -278,9 +281,43 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||
<<", geom=("<<geom.X<<","<<geom.Y<<")"
|
||||
<<std::endl;
|
||||
if(bp_set != 2)
|
||||
errorstream<<"WARNING: invalid use of button without a size[] element"<<std::endl;
|
||||
errorstream<<"WARNING: invalid use of image without a size[] element"<<std::endl;
|
||||
m_images.push_back(ImageDrawSpec(name, pos, geom));
|
||||
}
|
||||
else if(type == "item_image")
|
||||
{
|
||||
v2s32 pos = basepos;
|
||||
pos.X += stof(f.next(",")) * (float)spacing.X;
|
||||
pos.Y += stof(f.next(";")) * (float)spacing.Y;
|
||||
v2s32 geom;
|
||||
geom.X = stof(f.next(",")) * (float)imgsize.X;
|
||||
geom.Y = stof(f.next(";")) * (float)imgsize.Y;
|
||||
std::string name = f.next("]");
|
||||
errorstream<<"item name="<<name
|
||||
<<", pos=("<<pos.X<<","<<pos.Y<<")"
|
||||
<<", geom=("<<geom.X<<","<<geom.Y<<")"
|
||||
<<std::endl;
|
||||
if(bp_set != 2)
|
||||
errorstream<<"WARNING: invalid use of item_image without a size[] element"<<std::endl;
|
||||
m_itemimages.push_back(ImageDrawSpec(name, pos, geom));
|
||||
}
|
||||
else if(type == "background")
|
||||
{
|
||||
v2s32 pos = basepos;
|
||||
pos.X += stof(f.next(",")) * (float)spacing.X - ((float)spacing.X-(float)imgsize.X)/2;
|
||||
pos.Y += stof(f.next(";")) * (float)spacing.Y - ((float)spacing.Y-(float)imgsize.Y)/2;
|
||||
v2s32 geom;
|
||||
geom.X = stof(f.next(",")) * (float)spacing.X;
|
||||
geom.Y = stof(f.next(";")) * (float)spacing.Y;
|
||||
std::string name = f.next("]");
|
||||
infostream<<"image name="<<name
|
||||
<<", pos=("<<pos.X<<","<<pos.Y<<")"
|
||||
<<", geom=("<<geom.X<<","<<geom.Y<<")"
|
||||
<<std::endl;
|
||||
if(bp_set != 2)
|
||||
errorstream<<"WARNING: invalid use of background without a size[] element"<<std::endl;
|
||||
m_backgrounds.push_back(ImageDrawSpec(name, pos, geom));
|
||||
}
|
||||
else if(type == "field")
|
||||
{
|
||||
std::string fname = f.next(";");
|
||||
@@ -458,12 +495,50 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||
|
||||
video::ITexture *texture = m_gamedef->tsrc()->getTextureRaw(fimage);
|
||||
gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
|
||||
e->setUseAlphaChannel(true);
|
||||
e->setImage(texture);
|
||||
e->setPressedImage(texture);
|
||||
e->setScaleImage(true);
|
||||
|
||||
m_fields.push_back(spec);
|
||||
}
|
||||
else if(type == "item_image_button")
|
||||
{
|
||||
v2s32 pos = padding;
|
||||
pos.X += stof(f.next(",")) * (float)spacing.X;
|
||||
pos.Y += stof(f.next(";")) * (float)spacing.Y;
|
||||
v2s32 geom;
|
||||
geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
|
||||
geom.Y = (stof(f.next(";")) * (float)spacing.Y)-(spacing.Y-imgsize.Y);
|
||||
rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
|
||||
std::string fimage = f.next(";");
|
||||
std::string fname = f.next(";");
|
||||
std::string flabel = f.next("]");
|
||||
if(bp_set != 2)
|
||||
errorstream<<"WARNING: invalid use of item_image_button without a size[] element"<<std::endl;
|
||||
IItemDefManager *idef = m_gamedef->idef();
|
||||
ItemStack item;
|
||||
item.deSerialize(fimage, idef);
|
||||
video::ITexture *texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_gamedef);
|
||||
std::string tooltip = item.getDefinition(idef).description;
|
||||
FieldSpec spec = FieldSpec(
|
||||
narrow_to_wide(fname.c_str()),
|
||||
narrow_to_wide(flabel.c_str()),
|
||||
narrow_to_wide(fimage.c_str()),
|
||||
258+m_fields.size()
|
||||
);
|
||||
gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
|
||||
e->setUseAlphaChannel(true);
|
||||
e->setImage(texture);
|
||||
e->setPressedImage(texture);
|
||||
e->setScaleImage(true);
|
||||
spec.is_button = true;
|
||||
rect+=basepos-padding;
|
||||
spec.rect=rect;
|
||||
if (tooltip!="")
|
||||
spec.tooltip=tooltip;
|
||||
m_fields.push_back(spec);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ignore others
|
||||
@@ -679,6 +754,8 @@ void GUIFormSpecMenu::drawMenu()
|
||||
}
|
||||
}
|
||||
|
||||
m_pointer = m_device->getCursorControl()->getPosition();
|
||||
|
||||
updateSelectedItem();
|
||||
|
||||
gui::IGUISkin* skin = Environment->getSkin();
|
||||
@@ -692,17 +769,28 @@ void GUIFormSpecMenu::drawMenu()
|
||||
m_tooltip_element->setVisible(false);
|
||||
|
||||
/*
|
||||
Draw items
|
||||
Phase 0: Item slot rectangles
|
||||
Phase 1: Item images; prepare tooltip
|
||||
Draw backgrounds
|
||||
*/
|
||||
|
||||
for(int phase=0; phase<=1; phase++)
|
||||
for(u32 i=0; i<m_inventorylists.size(); i++)
|
||||
for(u32 i=0; i<m_backgrounds.size(); i++)
|
||||
{
|
||||
drawList(m_inventorylists[i], phase);
|
||||
const ImageDrawSpec &spec = m_backgrounds[i];
|
||||
video::ITexture *texture =
|
||||
m_gamedef->tsrc()->getTextureRaw(spec.name);
|
||||
// Image size on screen
|
||||
core::rect<s32> imgrect(0, 0, spec.geom.X, spec.geom.Y);
|
||||
// Image rectangle on screen
|
||||
core::rect<s32> rect = imgrect + spec.pos;
|
||||
const video::SColor color(255,255,255,255);
|
||||
const video::SColor colors[] = {color,color,color,color};
|
||||
driver->draw2DImage(texture, rect,
|
||||
core::rect<s32>(core::position2d<s32>(0,0),
|
||||
core::dimension2di(texture->getOriginalSize())),
|
||||
NULL/*&AbsoluteClippingRect*/, colors, true);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Draw images
|
||||
*/
|
||||
for(u32 i=0; i<m_images.size(); i++)
|
||||
{
|
||||
const ImageDrawSpec &spec = m_images[i];
|
||||
@@ -721,14 +809,53 @@ void GUIFormSpecMenu::drawMenu()
|
||||
}
|
||||
|
||||
/*
|
||||
Draw dragged item stack
|
||||
Draw items
|
||||
Phase 0: Item slot rectangles
|
||||
Phase 1: Item images; prepare tooltip
|
||||
If backgrounds used, do not draw Item slot rectangles
|
||||
*/
|
||||
drawSelectedItem();
|
||||
int start_phase=0;
|
||||
if (m_backgrounds.size() > 0) start_phase=1;
|
||||
for(int phase=start_phase; phase<=1; phase++)
|
||||
for(u32 i=0; i<m_inventorylists.size(); i++)
|
||||
{
|
||||
drawList(m_inventorylists[i], phase);
|
||||
}
|
||||
|
||||
/*
|
||||
Call base class
|
||||
*/
|
||||
gui::IGUIElement::draw();
|
||||
|
||||
/*
|
||||
Draw fields/buttons tooltips
|
||||
*/
|
||||
for(u32 i=0; i<m_fields.size(); i++)
|
||||
{
|
||||
const FieldSpec &spec = m_fields[i];
|
||||
if (spec.tooltip != "")
|
||||
{
|
||||
core::rect<s32> rect = spec.rect;
|
||||
if (rect.isPointInside(m_pointer))
|
||||
{
|
||||
m_tooltip_element->setVisible(true);
|
||||
this->bringToFront(m_tooltip_element);
|
||||
m_tooltip_element->setText(narrow_to_wide(spec.tooltip).c_str());
|
||||
s32 tooltip_x = m_pointer.X + 15;
|
||||
s32 tooltip_y = m_pointer.Y + 15;
|
||||
s32 tooltip_width = m_tooltip_element->getTextWidth() + 15;
|
||||
s32 tooltip_height = m_tooltip_element->getTextHeight() + 5;
|
||||
m_tooltip_element->setRelativePosition(core::rect<s32>(
|
||||
core::position2d<s32>(tooltip_x, tooltip_y),
|
||||
core::dimension2d<s32>(tooltip_width, tooltip_height)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Draw dragged item stack
|
||||
*/
|
||||
drawSelectedItem();
|
||||
}
|
||||
|
||||
void GUIFormSpecMenu::updateSelectedItem()
|
||||
@@ -893,24 +1020,15 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(event.EventType==EET_MOUSE_INPUT_EVENT
|
||||
&& event.MouseInput.Event == EMIE_MOUSE_MOVED)
|
||||
{
|
||||
// Mouse moved
|
||||
m_pointer = v2s32(event.MouseInput.X, event.MouseInput.Y);
|
||||
}
|
||||
if(event.EventType==EET_MOUSE_INPUT_EVENT
|
||||
&& event.MouseInput.Event != EMIE_MOUSE_MOVED)
|
||||
{
|
||||
// Mouse event other than movement
|
||||
|
||||
v2s32 p(event.MouseInput.X, event.MouseInput.Y);
|
||||
m_pointer = p;
|
||||
|
||||
// Get selected item and hovered/clicked item (s)
|
||||
|
||||
updateSelectedItem();
|
||||
ItemSpec s = getItemAtPos(p);
|
||||
ItemSpec s = getItemAtPos(m_pointer);
|
||||
|
||||
Inventory *inv_selected = NULL;
|
||||
Inventory *inv_s = NULL;
|
||||
|
||||
@@ -133,6 +133,7 @@ class GUIFormSpecMenu : public GUIModalMenu
|
||||
send = false;
|
||||
is_button = false;
|
||||
is_exit = false;
|
||||
tooltip="";
|
||||
}
|
||||
std::wstring fname;
|
||||
std::wstring flabel;
|
||||
@@ -141,10 +142,12 @@ class GUIFormSpecMenu : public GUIModalMenu
|
||||
bool send;
|
||||
bool is_button;
|
||||
bool is_exit;
|
||||
core::rect<s32> rect;
|
||||
std::string tooltip;
|
||||
};
|
||||
|
||||
public:
|
||||
GUIFormSpecMenu(gui::IGUIEnvironment* env,
|
||||
GUIFormSpecMenu(irr::IrrlichtDevice* dev,
|
||||
gui::IGUIElement* parent, s32 id,
|
||||
IMenuManager *menumgr,
|
||||
InventoryManager *invmgr,
|
||||
@@ -197,6 +200,7 @@ class GUIFormSpecMenu : public GUIModalMenu
|
||||
v2s32 spacing;
|
||||
v2s32 imgsize;
|
||||
|
||||
irr::IrrlichtDevice* m_device;
|
||||
InventoryManager *m_invmgr;
|
||||
IGameDef *m_gamedef;
|
||||
|
||||
@@ -206,7 +210,9 @@ class GUIFormSpecMenu : public GUIModalMenu
|
||||
TextDest *m_text_dst;
|
||||
|
||||
core::array<ListDrawSpec> m_inventorylists;
|
||||
core::array<ImageDrawSpec> m_backgrounds;
|
||||
core::array<ImageDrawSpec> m_images;
|
||||
core::array<ImageDrawSpec> m_itemimages;
|
||||
core::array<FieldSpec> m_fields;
|
||||
|
||||
ItemSpec *m_selected_item;
|
||||
|
||||
@@ -98,6 +98,12 @@ enum
|
||||
GUI_ID_SMOOTH_LIGHTING_CB,
|
||||
GUI_ID_3D_CLOUDS_CB,
|
||||
GUI_ID_OPAQUE_WATER_CB,
|
||||
GUI_ID_MIPMAP_CB,
|
||||
GUI_ID_ANISOTROPIC_CB,
|
||||
GUI_ID_BILINEAR_CB,
|
||||
GUI_ID_TRILINEAR_CB,
|
||||
GUI_ID_SHADERS_CB,
|
||||
GUI_ID_PRELOAD_ITEM_VISUALS_CB,
|
||||
GUI_ID_DAMAGE_CB,
|
||||
GUI_ID_CREATIVE_CB,
|
||||
GUI_ID_JOIN_GAME_BUTTON,
|
||||
@@ -202,7 +208,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
|
||||
core::rect<s32> rect(0, 0, size.X, 40);
|
||||
rect += v2s32(4, 0);
|
||||
Environment->addStaticText(narrow_to_wide(
|
||||
"Minetest-c55 " VERSION_STRING).c_str(),
|
||||
"Minetest " VERSION_STRING).c_str(),
|
||||
rect, false, true, this, -1);
|
||||
}
|
||||
|
||||
@@ -580,6 +586,53 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
|
||||
Environment->addCheckBox(m_data->opaque_water, rect, this,
|
||||
GUI_ID_OPAQUE_WATER_CB, wgettext("Opaque water"));
|
||||
}
|
||||
|
||||
|
||||
// Anisotropic/mipmap/bi-/trilinear settings
|
||||
|
||||
{
|
||||
core::rect<s32> rect(0, 0, option_w+20, 30);
|
||||
rect += m_topleft_client + v2s32(option_x+175, option_y);
|
||||
Environment->addCheckBox(m_data->mip_map, rect, this,
|
||||
GUI_ID_MIPMAP_CB, wgettext("Mip-Mapping"));
|
||||
}
|
||||
|
||||
{
|
||||
core::rect<s32> rect(0, 0, option_w+20, 30);
|
||||
rect += m_topleft_client + v2s32(option_x+175, option_y+20);
|
||||
Environment->addCheckBox(m_data->anisotropic_filter, rect, this,
|
||||
GUI_ID_ANISOTROPIC_CB, wgettext("Anisotropic Filtering"));
|
||||
}
|
||||
|
||||
{
|
||||
core::rect<s32> rect(0, 0, option_w+20, 30);
|
||||
rect += m_topleft_client + v2s32(option_x+175, option_y+20*2);
|
||||
Environment->addCheckBox(m_data->bilinear_filter, rect, this,
|
||||
GUI_ID_BILINEAR_CB, wgettext("Bi-Linear Filtering"));
|
||||
}
|
||||
|
||||
{
|
||||
core::rect<s32> rect(0, 0, option_w+20, 30);
|
||||
rect += m_topleft_client + v2s32(option_x+175, option_y+20*3);
|
||||
Environment->addCheckBox(m_data->trilinear_filter, rect, this,
|
||||
GUI_ID_TRILINEAR_CB, wgettext("Tri-Linear Filtering"));
|
||||
}
|
||||
|
||||
// shader/on demand image loading settings
|
||||
{
|
||||
core::rect<s32> rect(0, 0, option_w+20, 30);
|
||||
rect += m_topleft_client + v2s32(option_x+175*2, option_y);
|
||||
Environment->addCheckBox(m_data->enable_shaders, rect, this,
|
||||
GUI_ID_SHADERS_CB, wgettext("Shaders"));
|
||||
}
|
||||
|
||||
{
|
||||
core::rect<s32> rect(0, 0, option_w+20+20, 30);
|
||||
rect += m_topleft_client + v2s32(option_x+175*2, option_y+20);
|
||||
Environment->addCheckBox(m_data->preload_item_visuals, rect, this,
|
||||
GUI_ID_PRELOAD_ITEM_VISUALS_CB, wgettext("Preload item visuals"));
|
||||
}
|
||||
|
||||
// Key change button
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 120, 30);
|
||||
@@ -606,11 +659,11 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
|
||||
core::rect<s32> rect(0, 0, 454, 250);
|
||||
rect += m_topleft_client + v2s32(110, 50+35);
|
||||
Environment->addStaticText(narrow_to_wide(
|
||||
"Minetest-c55 " VERSION_STRING "\n"
|
||||
"Minetest " VERSION_STRING "\n"
|
||||
"http://minetest.net/\n"
|
||||
"\n"
|
||||
"by Perttu Ahola <celeron55@gmail.com>\n"
|
||||
"and contributors: tango_, kahrl (kaaaaaahrl?), erlehmann (the hippie), SpeedProg, JacobF (sqlite worlds), teddydestodes, marktraceur, darkrose, Jonathan Neuschäfer (who the hell?), Felix Krausse (broke liquids, IIRC), sfan5... and >10 more random people."
|
||||
"and contributors: PilzAdam, Taoki, tango_, kahrl (kaaaaaahrl?), darkrose, matttpt, erlehmann, SpeedProg, JacobF, teddydestodes, marktraceur, Jonathan Neuschäfer, thexyz, VanessaE, sfan5... and tens of more random people."
|
||||
).c_str(), rect, false, true, this, -1);
|
||||
}
|
||||
}
|
||||
@@ -760,6 +813,42 @@ void GUIMainMenu::readInput(MainMenuData *dst)
|
||||
dst->opaque_water = ((gui::IGUICheckBox*)e)->isChecked();
|
||||
}
|
||||
|
||||
{
|
||||
gui::IGUIElement *e = getElementFromId(GUI_ID_MIPMAP_CB);
|
||||
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
|
||||
dst->mip_map = ((gui::IGUICheckBox*)e)->isChecked();
|
||||
}
|
||||
|
||||
{
|
||||
gui::IGUIElement *e = getElementFromId(GUI_ID_ANISOTROPIC_CB);
|
||||
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
|
||||
dst->anisotropic_filter = ((gui::IGUICheckBox*)e)->isChecked();
|
||||
}
|
||||
|
||||
{
|
||||
gui::IGUIElement *e = getElementFromId(GUI_ID_BILINEAR_CB);
|
||||
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
|
||||
dst->bilinear_filter = ((gui::IGUICheckBox*)e)->isChecked();
|
||||
}
|
||||
|
||||
{
|
||||
gui::IGUIElement *e = getElementFromId(GUI_ID_TRILINEAR_CB);
|
||||
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
|
||||
dst->trilinear_filter = ((gui::IGUICheckBox*)e)->isChecked();
|
||||
}
|
||||
|
||||
{
|
||||
gui::IGUIElement *e = getElementFromId(GUI_ID_SHADERS_CB);
|
||||
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
|
||||
dst->enable_shaders = ((gui::IGUICheckBox*)e)->isChecked() ? 2 : 0;
|
||||
}
|
||||
|
||||
{
|
||||
gui::IGUIElement *e = getElementFromId(GUI_ID_PRELOAD_ITEM_VISUALS_CB);
|
||||
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
|
||||
dst->preload_item_visuals = ((gui::IGUICheckBox*)e)->isChecked();
|
||||
}
|
||||
|
||||
{
|
||||
gui::IGUIElement *e = getElementFromId(GUI_ID_WORLD_LISTBOX);
|
||||
if(e != NULL && e->getType() == gui::EGUIET_LIST_BOX)
|
||||
|
||||
@@ -41,6 +41,12 @@ struct MainMenuData
|
||||
bool smooth_lighting;
|
||||
bool clouds_3d;
|
||||
bool opaque_water;
|
||||
bool mip_map;
|
||||
bool anisotropic_filter;
|
||||
bool bilinear_filter;
|
||||
bool trilinear_filter;
|
||||
int enable_shaders;
|
||||
bool preload_item_visuals;
|
||||
// Server options
|
||||
bool creative_mode;
|
||||
bool enable_damage;
|
||||
|
||||
@@ -169,23 +169,8 @@ void GUIPauseMenu::regenerateGui(v2u32 screensize)
|
||||
max_texture_size = driver->getMaxTextureSize();
|
||||
}
|
||||
|
||||
/*wchar_t text[200];
|
||||
swprintf(text, 200,
|
||||
L"Minetest-c55\n"
|
||||
L"by Perttu Ahola\n"
|
||||
L"celeron55@gmail.com\n\n"
|
||||
SWPRINTF_CHARSTRING L"\n"
|
||||
L"userdata path = "
|
||||
SWPRINTF_CHARSTRING
|
||||
,
|
||||
BUILD_INFO,
|
||||
porting::path_user.c_str()
|
||||
);*/
|
||||
|
||||
std::ostringstream os;
|
||||
os<<"Minetest\n";
|
||||
os<<"by Perttu Ahola and contributors\n";
|
||||
os<<"celeron55@gmail.com\n";
|
||||
os<<BUILD_INFO<<"\n";
|
||||
os<<"path_user = "<<wrap_rows(porting::path_user, 20)<<"\n";
|
||||
|
||||
|
||||
445
src/itemdef.cpp
@@ -30,7 +30,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "tile.h"
|
||||
#endif
|
||||
#include "log.h"
|
||||
#include "main.h" // g_settings
|
||||
#include "settings.h"
|
||||
#include "util/serialize.h"
|
||||
#include "util/container.h"
|
||||
#include "util/thread.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
@@ -71,14 +75,6 @@ ItemDefinition& ItemDefinition::operator=(const ItemDefinition &def)
|
||||
}
|
||||
groups = def.groups;
|
||||
node_placement_prediction = def.node_placement_prediction;
|
||||
#ifndef SERVER
|
||||
inventory_texture = def.inventory_texture;
|
||||
if(def.wield_mesh)
|
||||
{
|
||||
wield_mesh = def.wield_mesh;
|
||||
wield_mesh->grab();
|
||||
}
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -91,10 +87,6 @@ void ItemDefinition::resetInitial()
|
||||
{
|
||||
// Initialize pointers to NULL so reset() does not delete undefined pointers
|
||||
tool_capabilities = NULL;
|
||||
#ifndef SERVER
|
||||
inventory_texture = NULL;
|
||||
wield_mesh = NULL;
|
||||
#endif
|
||||
reset();
|
||||
}
|
||||
|
||||
@@ -117,15 +109,6 @@ void ItemDefinition::reset()
|
||||
groups.clear();
|
||||
|
||||
node_placement_prediction = "";
|
||||
|
||||
#ifndef SERVER
|
||||
inventory_texture = NULL;
|
||||
if(wield_mesh)
|
||||
{
|
||||
wield_mesh->drop();
|
||||
wield_mesh = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ItemDefinition::serialize(std::ostream &os) const
|
||||
@@ -203,13 +186,39 @@ void ItemDefinition::deSerialize(std::istream &is)
|
||||
|
||||
class CItemDefManager: public IWritableItemDefManager
|
||||
{
|
||||
#ifndef SERVER
|
||||
struct ClientCached
|
||||
{
|
||||
video::ITexture *inventory_texture;
|
||||
scene::IMesh *wield_mesh;
|
||||
|
||||
ClientCached():
|
||||
inventory_texture(NULL),
|
||||
wield_mesh(NULL)
|
||||
{}
|
||||
};
|
||||
#endif
|
||||
|
||||
public:
|
||||
CItemDefManager()
|
||||
{
|
||||
#ifndef SERVER
|
||||
m_main_thread = get_current_thread_id();
|
||||
#endif
|
||||
|
||||
clear();
|
||||
}
|
||||
virtual ~CItemDefManager()
|
||||
{
|
||||
#ifndef SERVER
|
||||
const core::list<ClientCached*> &values = m_clientcached.getValues();
|
||||
for(core::list<ClientCached*>::ConstIterator
|
||||
i = values.begin(); i != values.end(); ++i)
|
||||
{
|
||||
ClientCached *cc = *i;
|
||||
cc->wield_mesh->drop();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
virtual const ItemDefinition& get(const std::string &name_) const
|
||||
{
|
||||
@@ -256,6 +265,223 @@ class CItemDefManager: public IWritableItemDefManager
|
||||
std::map<std::string, ItemDefinition*>::const_iterator i;
|
||||
return m_item_definitions.find(name) != m_item_definitions.end();
|
||||
}
|
||||
#ifndef SERVER
|
||||
ClientCached* createClientCachedDirect(const std::string &name,
|
||||
IGameDef *gamedef) const
|
||||
{
|
||||
infostream<<"Lazily creating item texture and mesh for \""
|
||||
<<name<<"\""<<std::endl;
|
||||
|
||||
// This is not thread-safe
|
||||
assert(get_current_thread_id() == m_main_thread);
|
||||
|
||||
// Skip if already in cache
|
||||
ClientCached *cc = NULL;
|
||||
m_clientcached.get(name, &cc);
|
||||
if(cc)
|
||||
return cc;
|
||||
|
||||
ITextureSource *tsrc = gamedef->getTextureSource();
|
||||
INodeDefManager *nodedef = gamedef->getNodeDefManager();
|
||||
IrrlichtDevice *device = tsrc->getDevice();
|
||||
video::IVideoDriver *driver = device->getVideoDriver();
|
||||
const ItemDefinition *def = &get(name);
|
||||
|
||||
// Create new ClientCached
|
||||
cc = new ClientCached();
|
||||
|
||||
bool need_node_mesh = false;
|
||||
|
||||
// Create an inventory texture
|
||||
cc->inventory_texture = NULL;
|
||||
if(def->inventory_image != "")
|
||||
{
|
||||
cc->inventory_texture = tsrc->getTextureRaw(def->inventory_image);
|
||||
}
|
||||
else if(def->type == ITEM_NODE)
|
||||
{
|
||||
need_node_mesh = true;
|
||||
}
|
||||
|
||||
// Create a wield mesh
|
||||
if(cc->wield_mesh != NULL)
|
||||
{
|
||||
cc->wield_mesh->drop();
|
||||
cc->wield_mesh = NULL;
|
||||
}
|
||||
if(def->type == ITEM_NODE && def->wield_image == "")
|
||||
{
|
||||
need_node_mesh = true;
|
||||
}
|
||||
else if(def->wield_image != "" || def->inventory_image != "")
|
||||
{
|
||||
// Extrude the wield image into a mesh
|
||||
|
||||
std::string imagename;
|
||||
if(def->wield_image != "")
|
||||
imagename = def->wield_image;
|
||||
else
|
||||
imagename = def->inventory_image;
|
||||
|
||||
cc->wield_mesh = createExtrudedMesh(
|
||||
tsrc->getTextureRaw(imagename),
|
||||
driver,
|
||||
def->wield_scale * v3f(40.0, 40.0, 4.0));
|
||||
if(cc->wield_mesh == NULL)
|
||||
{
|
||||
infostream<<"ItemDefManager: WARNING: "
|
||||
<<"updateTexturesAndMeshes(): "
|
||||
<<"Unable to create extruded mesh for item "
|
||||
<<def->name<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if(need_node_mesh)
|
||||
{
|
||||
/*
|
||||
Get node properties
|
||||
*/
|
||||
content_t id = nodedef->getId(def->name);
|
||||
const ContentFeatures &f = nodedef->get(id);
|
||||
|
||||
u8 param1 = 0;
|
||||
if(f.param_type == CPT_LIGHT)
|
||||
param1 = 0xee;
|
||||
|
||||
/*
|
||||
Make a mesh from the node
|
||||
*/
|
||||
MeshMakeData mesh_make_data(gamedef);
|
||||
MapNode mesh_make_node(id, param1, 0);
|
||||
mesh_make_data.fillSingleNode(&mesh_make_node);
|
||||
MapBlockMesh mapblock_mesh(&mesh_make_data);
|
||||
|
||||
scene::IMesh *node_mesh = mapblock_mesh.getMesh();
|
||||
assert(node_mesh);
|
||||
video::SColor c(255, 255, 255, 255);
|
||||
if(g_settings->getS32("enable_shaders") != 0)
|
||||
c = MapBlock_LightColor(255, 0xffff, decode_light(f.light_source));
|
||||
setMeshColor(node_mesh, c);
|
||||
|
||||
/*
|
||||
Scale and translate the mesh so it's a unit cube
|
||||
centered on the origin
|
||||
*/
|
||||
scaleMesh(node_mesh, v3f(1.0/BS, 1.0/BS, 1.0/BS));
|
||||
translateMesh(node_mesh, v3f(-1.0, -1.0, -1.0));
|
||||
|
||||
/*
|
||||
Draw node mesh into a render target texture
|
||||
*/
|
||||
if(cc->inventory_texture == NULL)
|
||||
{
|
||||
core::dimension2d<u32> dim(64,64);
|
||||
std::string rtt_texture_name = "INVENTORY_"
|
||||
+ def->name + "_RTT";
|
||||
v3f camera_position(0, 1.0, -1.5);
|
||||
camera_position.rotateXZBy(45);
|
||||
v3f camera_lookat(0, 0, 0);
|
||||
core::CMatrix4<f32> camera_projection_matrix;
|
||||
// Set orthogonal projection
|
||||
camera_projection_matrix.buildProjectionMatrixOrthoLH(
|
||||
1.65, 1.65, 0, 100);
|
||||
|
||||
video::SColorf ambient_light(0.2,0.2,0.2);
|
||||
v3f light_position(10, 100, -50);
|
||||
video::SColorf light_color(0.5,0.5,0.5);
|
||||
f32 light_radius = 1000;
|
||||
|
||||
cc->inventory_texture = generateTextureFromMesh(
|
||||
node_mesh, device, dim, rtt_texture_name,
|
||||
camera_position,
|
||||
camera_lookat,
|
||||
camera_projection_matrix,
|
||||
ambient_light,
|
||||
light_position,
|
||||
light_color,
|
||||
light_radius);
|
||||
|
||||
// render-to-target didn't work
|
||||
if(cc->inventory_texture == NULL)
|
||||
{
|
||||
cc->inventory_texture =
|
||||
tsrc->getTextureRaw(f.tiledef[0].name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Use the node mesh as the wield mesh
|
||||
*/
|
||||
if(cc->wield_mesh == NULL)
|
||||
{
|
||||
// Scale to proper wield mesh proportions
|
||||
scaleMesh(node_mesh, v3f(30.0, 30.0, 30.0)
|
||||
* def->wield_scale);
|
||||
cc->wield_mesh = node_mesh;
|
||||
cc->wield_mesh->grab();
|
||||
}
|
||||
|
||||
// falling outside of here deletes node_mesh
|
||||
}
|
||||
|
||||
// Put in cache
|
||||
m_clientcached.set(name, cc);
|
||||
|
||||
return cc;
|
||||
}
|
||||
ClientCached* getClientCached(const std::string &name,
|
||||
IGameDef *gamedef) const
|
||||
{
|
||||
ClientCached *cc = NULL;
|
||||
m_clientcached.get(name, &cc);
|
||||
if(cc)
|
||||
return cc;
|
||||
|
||||
if(get_current_thread_id() == m_main_thread)
|
||||
{
|
||||
return createClientCachedDirect(name, gamedef);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're gonna ask the result to be put into here
|
||||
ResultQueue<std::string, ClientCached*, u8, u8> result_queue;
|
||||
// Throw a request in
|
||||
m_get_clientcached_queue.add(name, 0, 0, &result_queue);
|
||||
try{
|
||||
// Wait result for a second
|
||||
GetResult<std::string, ClientCached*, u8, u8>
|
||||
result = result_queue.pop_front(1000);
|
||||
// Check that at least something worked OK
|
||||
assert(result.key == name);
|
||||
// Return it
|
||||
return result.item;
|
||||
}
|
||||
catch(ItemNotFoundException &e)
|
||||
{
|
||||
errorstream<<"Waiting for clientcached timed out."<<std::endl;
|
||||
return &m_dummy_clientcached;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get item inventory texture
|
||||
virtual video::ITexture* getInventoryTexture(const std::string &name,
|
||||
IGameDef *gamedef) const
|
||||
{
|
||||
ClientCached *cc = getClientCached(name, gamedef);
|
||||
if(!cc)
|
||||
return NULL;
|
||||
return cc->inventory_texture;
|
||||
}
|
||||
// Get item wield mesh
|
||||
virtual scene::IMesh* getWieldMesh(const std::string &name,
|
||||
IGameDef *gamedef) const
|
||||
{
|
||||
ClientCached *cc = getClientCached(name, gamedef);
|
||||
if(!cc)
|
||||
return NULL;
|
||||
return cc->wield_mesh;
|
||||
}
|
||||
#endif
|
||||
void clear()
|
||||
{
|
||||
for(std::map<std::string, ItemDefinition*>::const_iterator
|
||||
@@ -321,157 +547,6 @@ class CItemDefManager: public IWritableItemDefManager
|
||||
m_aliases[name] = convert_to;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void updateTexturesAndMeshes(IGameDef *gamedef)
|
||||
{
|
||||
#ifndef SERVER
|
||||
infostream<<"ItemDefManager::updateTexturesAndMeshes(): Updating "
|
||||
<<"textures and meshes in item definitions"<<std::endl;
|
||||
|
||||
ITextureSource *tsrc = gamedef->getTextureSource();
|
||||
INodeDefManager *nodedef = gamedef->getNodeDefManager();
|
||||
IrrlichtDevice *device = tsrc->getDevice();
|
||||
video::IVideoDriver *driver = device->getVideoDriver();
|
||||
|
||||
for(std::map<std::string, ItemDefinition*>::iterator
|
||||
i = m_item_definitions.begin();
|
||||
i != m_item_definitions.end(); i++)
|
||||
{
|
||||
ItemDefinition *def = i->second;
|
||||
|
||||
bool need_node_mesh = false;
|
||||
|
||||
// Create an inventory texture
|
||||
def->inventory_texture = NULL;
|
||||
if(def->inventory_image != "")
|
||||
{
|
||||
def->inventory_texture = tsrc->getTextureRaw(def->inventory_image);
|
||||
}
|
||||
else if(def->type == ITEM_NODE)
|
||||
{
|
||||
need_node_mesh = true;
|
||||
}
|
||||
|
||||
// Create a wield mesh
|
||||
if(def->wield_mesh != NULL)
|
||||
{
|
||||
def->wield_mesh->drop();
|
||||
def->wield_mesh = NULL;
|
||||
}
|
||||
if(def->type == ITEM_NODE && def->wield_image == "")
|
||||
{
|
||||
need_node_mesh = true;
|
||||
}
|
||||
else if(def->wield_image != "" || def->inventory_image != "")
|
||||
{
|
||||
// Extrude the wield image into a mesh
|
||||
|
||||
std::string imagename;
|
||||
if(def->wield_image != "")
|
||||
imagename = def->wield_image;
|
||||
else
|
||||
imagename = def->inventory_image;
|
||||
|
||||
def->wield_mesh = createExtrudedMesh(
|
||||
tsrc->getTextureRaw(imagename),
|
||||
driver,
|
||||
def->wield_scale * v3f(40.0, 40.0, 4.0));
|
||||
if(def->wield_mesh == NULL)
|
||||
{
|
||||
infostream<<"ItemDefManager: WARNING: "
|
||||
<<"updateTexturesAndMeshes(): "
|
||||
<<"Unable to create extruded mesh for item "
|
||||
<<def->name<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if(need_node_mesh)
|
||||
{
|
||||
/*
|
||||
Get node properties
|
||||
*/
|
||||
content_t id = nodedef->getId(def->name);
|
||||
const ContentFeatures &f = nodedef->get(id);
|
||||
|
||||
u8 param1 = 0;
|
||||
if(f.param_type == CPT_LIGHT)
|
||||
param1 = 0xee;
|
||||
|
||||
/*
|
||||
Make a mesh from the node
|
||||
*/
|
||||
MeshMakeData mesh_make_data(gamedef);
|
||||
MapNode mesh_make_node(id, param1, 0);
|
||||
mesh_make_data.fillSingleNode(&mesh_make_node);
|
||||
MapBlockMesh mapblock_mesh(&mesh_make_data);
|
||||
|
||||
scene::IMesh *node_mesh = mapblock_mesh.getMesh();
|
||||
assert(node_mesh);
|
||||
setMeshColor(node_mesh, video::SColor(255, 255, 255, 255));
|
||||
|
||||
/*
|
||||
Scale and translate the mesh so it's a unit cube
|
||||
centered on the origin
|
||||
*/
|
||||
scaleMesh(node_mesh, v3f(1.0/BS, 1.0/BS, 1.0/BS));
|
||||
translateMesh(node_mesh, v3f(-1.0, -1.0, -1.0));
|
||||
|
||||
/*
|
||||
Draw node mesh into a render target texture
|
||||
*/
|
||||
if(def->inventory_texture == NULL)
|
||||
{
|
||||
core::dimension2d<u32> dim(64,64);
|
||||
std::string rtt_texture_name = "INVENTORY_"
|
||||
+ def->name + "_RTT";
|
||||
v3f camera_position(0, 1.0, -1.5);
|
||||
camera_position.rotateXZBy(45);
|
||||
v3f camera_lookat(0, 0, 0);
|
||||
core::CMatrix4<f32> camera_projection_matrix;
|
||||
// Set orthogonal projection
|
||||
camera_projection_matrix.buildProjectionMatrixOrthoLH(
|
||||
1.65, 1.65, 0, 100);
|
||||
|
||||
video::SColorf ambient_light(0.2,0.2,0.2);
|
||||
v3f light_position(10, 100, -50);
|
||||
video::SColorf light_color(0.5,0.5,0.5);
|
||||
f32 light_radius = 1000;
|
||||
|
||||
def->inventory_texture = generateTextureFromMesh(
|
||||
node_mesh, device, dim, rtt_texture_name,
|
||||
camera_position,
|
||||
camera_lookat,
|
||||
camera_projection_matrix,
|
||||
ambient_light,
|
||||
light_position,
|
||||
light_color,
|
||||
light_radius);
|
||||
|
||||
// render-to-target didn't work
|
||||
if(def->inventory_texture == NULL)
|
||||
{
|
||||
def->inventory_texture =
|
||||
tsrc->getTextureRaw(f.tiledef[0].name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Use the node mesh as the wield mesh
|
||||
*/
|
||||
if(def->wield_mesh == NULL)
|
||||
{
|
||||
// Scale to proper wield mesh proportions
|
||||
scaleMesh(node_mesh, v3f(30.0, 30.0, 30.0)
|
||||
* def->wield_scale);
|
||||
def->wield_mesh = node_mesh;
|
||||
def->wield_mesh->grab();
|
||||
}
|
||||
|
||||
// falling outside of here deletes node_mesh
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void serialize(std::ostream &os)
|
||||
{
|
||||
writeU8(os, 0); // version
|
||||
@@ -521,11 +596,37 @@ class CItemDefManager: public IWritableItemDefManager
|
||||
registerAlias(name, convert_to);
|
||||
}
|
||||
}
|
||||
void processQueue(IGameDef *gamedef)
|
||||
{
|
||||
#ifndef SERVER
|
||||
while(m_get_clientcached_queue.size() > 0)
|
||||
{
|
||||
GetRequest<std::string, ClientCached*, u8, u8>
|
||||
request = m_get_clientcached_queue.pop();
|
||||
GetResult<std::string, ClientCached*, u8, u8>
|
||||
result;
|
||||
result.key = request.key;
|
||||
result.callers = request.callers;
|
||||
result.item = createClientCachedDirect(request.key, gamedef);
|
||||
request.dest->push_back(result);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
private:
|
||||
// Key is name
|
||||
std::map<std::string, ItemDefinition*> m_item_definitions;
|
||||
// Aliases
|
||||
std::map<std::string, std::string> m_aliases;
|
||||
#ifndef SERVER
|
||||
// The id of the thread that is allowed to use irrlicht directly
|
||||
threadid_t m_main_thread;
|
||||
// A reference to this can be returned when nothing is found, to avoid NULLs
|
||||
mutable ClientCached m_dummy_clientcached;
|
||||
// Cached textures and meshes
|
||||
mutable MutexedMap<std::string, ClientCached*> m_clientcached;
|
||||
// Queued clientcached fetches (to be processed by the main thread)
|
||||
mutable RequestQueue<std::string, ClientCached*, u8, u8> m_get_clientcached_queue;
|
||||
#endif
|
||||
};
|
||||
|
||||
IWritableItemDefManager* createItemDefManager()
|
||||
|
||||
@@ -72,14 +72,6 @@ struct ItemDefinition
|
||||
// "" = no prediction
|
||||
std::string node_placement_prediction;
|
||||
|
||||
/*
|
||||
Cached stuff
|
||||
*/
|
||||
#ifndef SERVER
|
||||
video::ITexture *inventory_texture;
|
||||
scene::IMesh *wield_mesh;
|
||||
#endif
|
||||
|
||||
/*
|
||||
Some helpful methods
|
||||
*/
|
||||
@@ -108,6 +100,14 @@ class IItemDefManager
|
||||
virtual std::set<std::string> getAll() const=0;
|
||||
// Check if item is known
|
||||
virtual bool isKnown(const std::string &name) const=0;
|
||||
#ifndef SERVER
|
||||
// Get item inventory texture
|
||||
virtual video::ITexture* getInventoryTexture(const std::string &name,
|
||||
IGameDef *gamedef) const=0;
|
||||
// Get item wield mesh
|
||||
virtual scene::IMesh* getWieldMesh(const std::string &name,
|
||||
IGameDef *gamedef) const=0;
|
||||
#endif
|
||||
|
||||
virtual void serialize(std::ostream &os)=0;
|
||||
};
|
||||
@@ -126,6 +126,14 @@ class IWritableItemDefManager : public IItemDefManager
|
||||
virtual std::set<std::string> getAll() const=0;
|
||||
// Check if item is known
|
||||
virtual bool isKnown(const std::string &name) const=0;
|
||||
#ifndef SERVER
|
||||
// Get item inventory texture
|
||||
virtual video::ITexture* getInventoryTexture(const std::string &name,
|
||||
IGameDef *gamedef) const=0;
|
||||
// Get item wield mesh
|
||||
virtual scene::IMesh* getWieldMesh(const std::string &name,
|
||||
IGameDef *gamedef) const=0;
|
||||
#endif
|
||||
|
||||
// Remove all registered item and node definitions and aliases
|
||||
// Then re-add the builtin item definitions
|
||||
@@ -138,15 +146,11 @@ class IWritableItemDefManager : public IItemDefManager
|
||||
virtual void registerAlias(const std::string &name,
|
||||
const std::string &convert_to)=0;
|
||||
|
||||
/*
|
||||
Update inventory textures and wield meshes to latest
|
||||
return values of ITextureSource and INodeDefManager.
|
||||
Call after updating the texture atlas of a texture source.
|
||||
*/
|
||||
virtual void updateTexturesAndMeshes(IGameDef *gamedef)=0;
|
||||
|
||||
virtual void serialize(std::ostream &os)=0;
|
||||
virtual void deSerialize(std::istream &is)=0;
|
||||
|
||||
// Do stuff asked by threads that can only be done in the main thread
|
||||
virtual void processQueue(IGameDef *gamedef)=0;
|
||||
};
|
||||
|
||||
IWritableItemDefManager* createItemDefManager();
|
||||
|
||||
28
src/light.h
@@ -85,6 +85,24 @@ inline u8 decode_light(u8 light)
|
||||
return light_decode_table[light];
|
||||
}
|
||||
|
||||
// 0.0 <= light <= 1.0
|
||||
// 0.0 <= return value <= 1.0
|
||||
inline float decode_light_f(float light_f)
|
||||
{
|
||||
s32 i = (u32)(light_f * LIGHT_MAX + 0.5);
|
||||
|
||||
if(i <= 0)
|
||||
return (float)light_decode_table[0] / 255.0;
|
||||
if(i >= LIGHT_MAX)
|
||||
return (float)light_decode_table[LIGHT_MAX] / 255.0;
|
||||
|
||||
float v1 = (float)light_decode_table[i-1] / 255.0;
|
||||
float v2 = (float)light_decode_table[i] / 255.0;
|
||||
float f0 = (float)i - 0.5;
|
||||
float f = light_f * LIGHT_MAX - f0;
|
||||
return f * v2 + (1.0 - f) * v1;
|
||||
}
|
||||
|
||||
// 0 <= daylight_factor <= 1000
|
||||
// 0 <= lightday, lightnight <= LIGHT_SUN
|
||||
// 0 <= return value <= LIGHT_SUN
|
||||
@@ -97,5 +115,15 @@ inline u8 blend_light(u32 daylight_factor, u8 lightday, u8 lightnight)
|
||||
return l;
|
||||
}
|
||||
|
||||
// 0.0 <= daylight_factor <= 1.0
|
||||
// 0 <= lightday, lightnight <= LIGHT_SUN
|
||||
// 0 <= return value <= 255
|
||||
inline u8 blend_light_f1(float daylight_factor, u8 lightday, u8 lightnight)
|
||||
{
|
||||
u8 l = ((daylight_factor * decode_light(lightday) +
|
||||
(1.0-daylight_factor) * decode_light(lightnight)));
|
||||
return l;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -34,6 +34,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
LocalPlayer::LocalPlayer(IGameDef *gamedef):
|
||||
Player(gamedef),
|
||||
isAttached(false),
|
||||
overridePosition(v3f(0,0,0)),
|
||||
last_position(v3f(0,0,0)),
|
||||
last_speed(v3f(0,0,0)),
|
||||
last_pitch(0),
|
||||
last_yaw(0),
|
||||
last_keyPressed(0),
|
||||
m_sneak_node(32767,32767,32767),
|
||||
m_sneak_node_exists(false),
|
||||
m_old_node_below(32767,32767,32767),
|
||||
@@ -59,6 +66,13 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
|
||||
|
||||
v3f old_speed = m_speed;
|
||||
|
||||
// Copy parent position if local player is attached
|
||||
if(isAttached)
|
||||
{
|
||||
setPosition(overridePosition);
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip collision detection if a special movement mode is used
|
||||
bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
|
||||
bool free_move = fly_allowed && g_settings->getBool("free_move");
|
||||
@@ -314,7 +328,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
|
||||
v3s16 camera_np = floatToInt(getEyePosition(), BS);
|
||||
MapNode n = map.getNodeNoEx(camera_np);
|
||||
if(n.getContent() != CONTENT_IGNORE){
|
||||
if(nodemgr->get(n).walkable){
|
||||
if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){
|
||||
camera_barely_in_ceiling = true;
|
||||
}
|
||||
}
|
||||
@@ -352,7 +366,14 @@ void LocalPlayer::applyControl(float dtime)
|
||||
|
||||
setPitch(control.pitch);
|
||||
setYaw(control.yaw);
|
||||
|
||||
|
||||
// Nullify speed and don't run positioning code if the player is attached
|
||||
if(isAttached)
|
||||
{
|
||||
setSpeed(v3f(0,0,0));
|
||||
return;
|
||||
}
|
||||
|
||||
v3f move_direction = v3f(0,0,1);
|
||||
move_direction.rotateXZBy(getYaw());
|
||||
|
||||
|
||||
@@ -22,53 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#include "player.h"
|
||||
|
||||
struct PlayerControl
|
||||
{
|
||||
PlayerControl()
|
||||
{
|
||||
up = false;
|
||||
down = false;
|
||||
left = false;
|
||||
right = false;
|
||||
jump = false;
|
||||
aux1 = false;
|
||||
sneak = false;
|
||||
pitch = 0;
|
||||
yaw = 0;
|
||||
}
|
||||
PlayerControl(
|
||||
bool a_up,
|
||||
bool a_down,
|
||||
bool a_left,
|
||||
bool a_right,
|
||||
bool a_jump,
|
||||
bool a_aux1,
|
||||
bool a_sneak,
|
||||
float a_pitch,
|
||||
float a_yaw
|
||||
)
|
||||
{
|
||||
up = a_up;
|
||||
down = a_down;
|
||||
left = a_left;
|
||||
right = a_right;
|
||||
jump = a_jump;
|
||||
aux1 = a_aux1;
|
||||
sneak = a_sneak;
|
||||
pitch = a_pitch;
|
||||
yaw = a_yaw;
|
||||
}
|
||||
bool up;
|
||||
bool down;
|
||||
bool left;
|
||||
bool right;
|
||||
bool jump;
|
||||
bool aux1;
|
||||
bool sneak;
|
||||
float pitch;
|
||||
float yaw;
|
||||
};
|
||||
|
||||
class LocalPlayer : public Player
|
||||
{
|
||||
public:
|
||||
@@ -79,6 +32,10 @@ class LocalPlayer : public Player
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isAttached;
|
||||
|
||||
v3f overridePosition;
|
||||
|
||||
void move(f32 dtime, Map &map, f32 pos_max_d,
|
||||
core::list<CollisionInfo> *collision_info);
|
||||
@@ -87,8 +44,13 @@ class LocalPlayer : public Player
|
||||
void applyControl(float dtime);
|
||||
|
||||
v3s16 getStandingNodePos();
|
||||
|
||||
PlayerControl control;
|
||||
|
||||
// Used to check if anything changed and prevent sending packets if not
|
||||
v3f last_position;
|
||||
v3f last_speed;
|
||||
float last_pitch;
|
||||
float last_yaw;
|
||||
unsigned int last_keyPressed;
|
||||
|
||||
private:
|
||||
// This is used for determining the sneaking range
|
||||
|
||||
27
src/main.cpp
@@ -1292,9 +1292,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
video::IVideoDriver* driver = device->getVideoDriver();
|
||||
|
||||
// Disable mipmaps (because some of them look ugly)
|
||||
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
|
||||
|
||||
/*
|
||||
This changes the minimum allowed number of vertices in a VBO.
|
||||
Default is 500.
|
||||
@@ -1352,7 +1349,13 @@ int main(int argc, char *argv[])
|
||||
skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255,0,0,0));
|
||||
skin->setColor(gui::EGDC_HIGH_LIGHT, video::SColor(255,70,100,50));
|
||||
skin->setColor(gui::EGDC_HIGH_LIGHT_TEXT, video::SColor(255,255,255,255));
|
||||
|
||||
|
||||
#if (IRRLICHT_VERSION_MAJOR >= 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2
|
||||
// Irrlicht 1.8 input colours
|
||||
skin->setColor(gui::EGDC_EDITABLE, video::SColor(255,128,128,128));
|
||||
skin->setColor(gui::EGDC_FOCUSED_EDITABLE, video::SColor(255,96,134,49));
|
||||
#endif
|
||||
|
||||
/*
|
||||
GUI stuff
|
||||
*/
|
||||
@@ -1439,6 +1442,13 @@ int main(int argc, char *argv[])
|
||||
menudata.smooth_lighting = g_settings->getBool("smooth_lighting");
|
||||
menudata.clouds_3d = g_settings->getBool("enable_3d_clouds");
|
||||
menudata.opaque_water = g_settings->getBool("opaque_water");
|
||||
menudata.mip_map = g_settings->getBool("mip_map");
|
||||
menudata.anisotropic_filter = g_settings->getBool("anisotropic_filter");
|
||||
menudata.bilinear_filter = g_settings->getBool("bilinear_filter");
|
||||
menudata.trilinear_filter = g_settings->getBool("trilinear_filter");
|
||||
menudata.enable_shaders = g_settings->getS32("enable_shaders");
|
||||
menudata.preload_item_visuals = g_settings->getBool("preload_item_visuals");
|
||||
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");
|
||||
// Default to selecting nothing
|
||||
@@ -1552,6 +1562,15 @@ int main(int argc, char *argv[])
|
||||
g_settings->set("smooth_lighting", itos(menudata.smooth_lighting));
|
||||
g_settings->set("enable_3d_clouds", itos(menudata.clouds_3d));
|
||||
g_settings->set("opaque_water", itos(menudata.opaque_water));
|
||||
|
||||
g_settings->set("mip_map", itos(menudata.mip_map));
|
||||
g_settings->set("anisotropic_filter", itos(menudata.anisotropic_filter));
|
||||
g_settings->set("bilinear_filter", itos(menudata.bilinear_filter));
|
||||
g_settings->set("trilinear_filter", itos(menudata.trilinear_filter));
|
||||
|
||||
g_settings->setS32("enable_shaders", menudata.enable_shaders);
|
||||
g_settings->set("preload_item_visuals", itos(menudata.preload_item_visuals));
|
||||
|
||||
g_settings->set("creative_mode", itos(menudata.creative_mode));
|
||||
g_settings->set("enable_damage", itos(menudata.enable_damage));
|
||||
g_settings->set("name", playername);
|
||||
|
||||
@@ -1746,12 +1746,12 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
|
||||
content_t new_node_content;
|
||||
s8 new_node_level = -1;
|
||||
s8 max_node_level = -1;
|
||||
if (num_sources >= 2 || liquid_type == LIQUID_SOURCE) {
|
||||
if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
|
||||
// liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
|
||||
// or the flowing alternative of the first of the surrounding sources (if it's air), so
|
||||
// it's perfectly safe to use liquid_kind here to determine the new node content.
|
||||
new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source);
|
||||
} else if (num_sources == 1 && sources[0].t != NEIGHBOR_LOWER) {
|
||||
} else if (num_sources >= 1 && sources[0].t != NEIGHBOR_LOWER) {
|
||||
// liquid_kind is set properly, see above
|
||||
new_node_content = liquid_kind;
|
||||
max_node_level = new_node_level = LIQUID_LEVEL_MAX;
|
||||
|
||||
@@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "mapblock_mesh.h"
|
||||
#endif
|
||||
#include "util/string.h"
|
||||
#include "util/serialize.h"
|
||||
|
||||
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
|
||||
|
||||
|
||||
@@ -28,9 +28,20 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "mesh.h"
|
||||
#include "content_mapblock.h"
|
||||
#include "noise.h"
|
||||
#include "shader.h"
|
||||
#include "settings.h"
|
||||
#include "util/directiontables.h"
|
||||
|
||||
float srgb_linear_multiply(float f, float m, float max)
|
||||
{
|
||||
f = f * f; // SRGB -> Linear
|
||||
f *= m;
|
||||
f = sqrt(f); // Linear -> SRGB
|
||||
if(f > max)
|
||||
f = max;
|
||||
return f;
|
||||
}
|
||||
|
||||
/*
|
||||
MeshMakeData
|
||||
*/
|
||||
@@ -77,9 +88,9 @@ void MeshMakeData::fill(MapBlock *block)
|
||||
// Get map
|
||||
Map *map = block->getParent();
|
||||
|
||||
for(u16 i=0; i<6; i++)
|
||||
for(u16 i=0; i<26; i++)
|
||||
{
|
||||
const v3s16 &dir = g_6dirs[i];
|
||||
const v3s16 &dir = g_26dirs[i];
|
||||
v3s16 bp = m_blockpos + dir;
|
||||
MapBlock *b = map->getBlockNoCreateNoEx(bp);
|
||||
if(b)
|
||||
@@ -434,7 +445,7 @@ struct FastFace
|
||||
};
|
||||
|
||||
static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
|
||||
v3f p, v3s16 dir, v3f scale, core::array<FastFace> &dest)
|
||||
v3f p, v3s16 dir, v3f scale, u8 light_source, core::array<FastFace> &dest)
|
||||
{
|
||||
FastFace face;
|
||||
|
||||
@@ -476,16 +487,16 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
|
||||
float h = tile.texture.size.Y;
|
||||
|
||||
face.vertices[0] = video::S3DVertex(vertex_pos[0], normal,
|
||||
MapBlock_LightColor(alpha, li0),
|
||||
MapBlock_LightColor(alpha, li0, light_source),
|
||||
core::vector2d<f32>(x0+w*abs_scale, y0+h));
|
||||
face.vertices[1] = video::S3DVertex(vertex_pos[1], normal,
|
||||
MapBlock_LightColor(alpha, li1),
|
||||
MapBlock_LightColor(alpha, li1, light_source),
|
||||
core::vector2d<f32>(x0, y0+h));
|
||||
face.vertices[2] = video::S3DVertex(vertex_pos[2], normal,
|
||||
MapBlock_LightColor(alpha, li2),
|
||||
MapBlock_LightColor(alpha, li2, light_source),
|
||||
core::vector2d<f32>(x0, y0));
|
||||
face.vertices[3] = video::S3DVertex(vertex_pos[3], normal,
|
||||
MapBlock_LightColor(alpha, li3),
|
||||
MapBlock_LightColor(alpha, li3, light_source),
|
||||
core::vector2d<f32>(x0+w*abs_scale, y0));
|
||||
|
||||
face.tile = tile;
|
||||
@@ -657,7 +668,8 @@ static void getTileInfo(
|
||||
v3s16 &p_corrected,
|
||||
v3s16 &face_dir_corrected,
|
||||
u16 *lights,
|
||||
TileSpec &tile
|
||||
TileSpec &tile,
|
||||
u8 &light_source
|
||||
)
|
||||
{
|
||||
VoxelManipulator &vmanip = data->m_vmanip;
|
||||
@@ -687,18 +699,20 @@ static void getTileInfo(
|
||||
tile = tile0;
|
||||
p_corrected = p;
|
||||
face_dir_corrected = face_dir;
|
||||
light_source = ndef->get(n0).light_source;
|
||||
}
|
||||
else
|
||||
{
|
||||
tile = tile1;
|
||||
p_corrected = p + face_dir;
|
||||
face_dir_corrected = -face_dir;
|
||||
light_source = ndef->get(n1).light_source;
|
||||
}
|
||||
|
||||
// eg. water and glass
|
||||
if(equivalent)
|
||||
tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
|
||||
|
||||
|
||||
if(data->m_smooth_lighting == false)
|
||||
{
|
||||
lights[0] = lights[1] = lights[2] = lights[3] =
|
||||
@@ -742,9 +756,10 @@ static void updateFastFaceRow(
|
||||
v3s16 face_dir_corrected;
|
||||
u16 lights[4] = {0,0,0,0};
|
||||
TileSpec tile;
|
||||
u8 light_source = 0;
|
||||
getTileInfo(data, p, face_dir,
|
||||
makes_face, p_corrected, face_dir_corrected,
|
||||
lights, tile);
|
||||
lights, tile, light_source);
|
||||
|
||||
for(u16 j=0; j<MAP_BLOCKSIZE; j++)
|
||||
{
|
||||
@@ -758,6 +773,7 @@ static void updateFastFaceRow(
|
||||
v3s16 next_face_dir_corrected;
|
||||
u16 next_lights[4] = {0,0,0,0};
|
||||
TileSpec next_tile;
|
||||
u8 next_light_source = 0;
|
||||
|
||||
// If at last position, there is nothing to compare to and
|
||||
// the face must be drawn anyway
|
||||
@@ -768,7 +784,7 @@ static void updateFastFaceRow(
|
||||
getTileInfo(data, p_next, face_dir,
|
||||
next_makes_face, next_p_corrected,
|
||||
next_face_dir_corrected, next_lights,
|
||||
next_tile);
|
||||
next_tile, next_light_source);
|
||||
|
||||
if(next_makes_face == makes_face
|
||||
&& next_p_corrected == p_corrected + translate_dir
|
||||
@@ -777,7 +793,8 @@ static void updateFastFaceRow(
|
||||
&& next_lights[1] == lights[1]
|
||||
&& next_lights[2] == lights[2]
|
||||
&& next_lights[3] == lights[3]
|
||||
&& next_tile == tile)
|
||||
&& next_tile == tile
|
||||
&& next_light_source == light_source)
|
||||
{
|
||||
next_is_different = false;
|
||||
}
|
||||
@@ -853,7 +870,7 @@ static void updateFastFaceRow(
|
||||
}
|
||||
|
||||
makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
|
||||
sp, face_dir_corrected, scale,
|
||||
sp, face_dir_corrected, scale, light_source,
|
||||
dest);
|
||||
|
||||
g_profiler->avg("Meshgen: faces drawn by tiling", 0);
|
||||
@@ -872,6 +889,7 @@ static void updateFastFaceRow(
|
||||
lights[2] = next_lights[2];
|
||||
lights[3] = next_lights[3];
|
||||
tile = next_tile;
|
||||
light_source = next_light_source;
|
||||
}
|
||||
|
||||
p = p_next;
|
||||
@@ -1011,6 +1029,11 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
|
||||
Convert MeshCollector to SMesh
|
||||
Also store animation info
|
||||
*/
|
||||
bool enable_shaders = (g_settings->getS32("enable_shaders") > 0);
|
||||
video::E_MATERIAL_TYPE shadermat1 = m_gamedef->getShaderSource()->
|
||||
getShader("test_shader_1").material;
|
||||
video::E_MATERIAL_TYPE shadermat2 = m_gamedef->getShaderSource()->
|
||||
getShader("test_shader_2").material;
|
||||
for(u32 i = 0; i < collector.prebuffers.size(); i++)
|
||||
{
|
||||
PreMeshBuffer &p = collector.prebuffers[i];
|
||||
@@ -1052,18 +1075,28 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
|
||||
os<<"^[verticalframe:"<<(int)p.tile.animation_frame_count<<":0";
|
||||
p.tile.texture = tsrc->getTexture(os.str());
|
||||
}
|
||||
// - Lighting
|
||||
for(u32 j = 0; j < p.vertices.size(); j++)
|
||||
// - Classic lighting (shaders handle this by themselves)
|
||||
if(!enable_shaders)
|
||||
{
|
||||
video::SColor &vc = p.vertices[j].Color;
|
||||
u8 day = vc.getRed();
|
||||
u8 night = vc.getGreen();
|
||||
finalColorBlend(vc, day, night, 1000);
|
||||
if(day != night)
|
||||
m_daynight_diffs[i][j] = std::make_pair(day, night);
|
||||
for(u32 j = 0; j < p.vertices.size(); j++)
|
||||
{
|
||||
video::SColor &vc = p.vertices[j].Color;
|
||||
// Set initial real color and store for later updates
|
||||
u8 day = vc.getRed();
|
||||
u8 night = vc.getGreen();
|
||||
finalColorBlend(vc, day, night, 1000);
|
||||
if(day != night)
|
||||
m_daynight_diffs[i][j] = std::make_pair(day, night);
|
||||
// Brighten topside (no shaders)
|
||||
if(p.vertices[j].Normal.Y > 0.5)
|
||||
{
|
||||
vc.setRed (srgb_linear_multiply(vc.getRed(), 1.3, 255.0));
|
||||
vc.setGreen(srgb_linear_multiply(vc.getGreen(), 1.3, 255.0));
|
||||
vc.setBlue (srgb_linear_multiply(vc.getBlue(), 1.3, 255.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create material
|
||||
video::SMaterial material;
|
||||
material.setFlag(video::EMF_LIGHTING, false);
|
||||
@@ -1075,7 +1108,10 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
|
||||
material.MaterialType
|
||||
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
material.setTexture(0, p.tile.texture.atlas);
|
||||
p.tile.applyMaterialOptions(material);
|
||||
if(enable_shaders)
|
||||
p.tile.applyMaterialOptionsWithShaders(material, shadermat1, shadermat2);
|
||||
else
|
||||
p.tile.applyMaterialOptions(material);
|
||||
|
||||
// Create meshbuffer
|
||||
|
||||
@@ -1211,6 +1247,14 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
|
||||
u8 night = j->second.second;
|
||||
finalColorBlend(vertices[vertexIndex].Color,
|
||||
day, night, daynight_ratio);
|
||||
// Brighten topside (no shaders)
|
||||
if(vertices[vertexIndex].Normal.Y > 0.5)
|
||||
{
|
||||
video::SColor &vc = vertices[vertexIndex].Color;
|
||||
vc.setRed (srgb_linear_multiply(vc.getRed(), 1.3, 255.0));
|
||||
vc.setGreen(srgb_linear_multiply(vc.getGreen(), 1.3, 255.0));
|
||||
vc.setBlue (srgb_linear_multiply(vc.getBlue(), 1.3, 255.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
m_last_daynight_ratio = daynight_ratio;
|
||||
|
||||
@@ -160,9 +160,10 @@ struct MeshCollector
|
||||
// alpha in the A channel of the returned SColor
|
||||
// day light (0-255) in the R channel of the returned SColor
|
||||
// night light (0-255) in the G channel of the returned SColor
|
||||
inline video::SColor MapBlock_LightColor(u8 alpha, u16 light)
|
||||
// light source (0-255) in the B channel of the returned SColor
|
||||
inline video::SColor MapBlock_LightColor(u8 alpha, u16 light, u8 light_source=0)
|
||||
{
|
||||
return video::SColor(alpha, (light & 0xff), (light >> 8), 0);
|
||||
return video::SColor(alpha, (light & 0xff), (light >> 8), light_source);
|
||||
}
|
||||
|
||||
// Compute light at node
|
||||
|
||||
@@ -132,7 +132,8 @@ void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
|
||||
for(s16 ii=0; ii<trunk_h; ii++)
|
||||
{
|
||||
if(vmanip.m_area.contains(p1))
|
||||
vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
|
||||
if(ii == 0 || vmanip.getNodeNoExNoEmerge(p1).getContent() == CONTENT_AIR)
|
||||
vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
|
||||
p1.Y++;
|
||||
}
|
||||
|
||||
@@ -1228,7 +1229,7 @@ double base_rock_level_2d(u64 seed, v2s16 p)
|
||||
0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
|
||||
seed-932, 5, 0.7);
|
||||
b = rangelim(b, 0.0, 1000.0);
|
||||
b = pow(b, 7);
|
||||
b = b*b*b*b*b*b*b;
|
||||
b *= 5;
|
||||
b = rangelim(b, 0.5, 1000.0);
|
||||
// Values 1.5...100 give quite horrible looking slopes
|
||||
|
||||
@@ -163,6 +163,16 @@ struct MapNode
|
||||
return blend_light(daylight_factor, lightday, lightnight);
|
||||
}
|
||||
|
||||
// 0.0 <= daylight_factor <= 1.0
|
||||
// 0 <= return value <= LIGHT_SUN
|
||||
u8 getLightBlendF1(float daylight_factor, INodeDefManager *nodemgr) const
|
||||
{
|
||||
u8 lightday = 0;
|
||||
u8 lightnight = 0;
|
||||
getLightBanks(lightday, lightnight, nodemgr);
|
||||
return blend_light_f1(daylight_factor, lightday, lightnight);
|
||||
}
|
||||
|
||||
u8 getFaceDir(INodeDefManager *nodemgr) const;
|
||||
u8 getWallMounted(INodeDefManager *nodemgr) const;
|
||||
v3s16 getWallMountedDir(INodeDefManager *nodemgr) const;
|
||||
|
||||
@@ -443,7 +443,7 @@ video::ITexture *generateTextureFromMesh(scene::IMesh *mesh,
|
||||
}
|
||||
|
||||
// Set render target
|
||||
driver->setRenderTarget(rtt, true, true, video::SColor(0,0,0,0));
|
||||
driver->setRenderTarget(rtt, false, true, video::SColor(0,0,0,0));
|
||||
|
||||
// Get a scene manager
|
||||
scene::ISceneManager *smgr_main = device->getSceneManager();
|
||||
@@ -478,7 +478,7 @@ video::ITexture *generateTextureFromMesh(scene::IMesh *mesh,
|
||||
smgr->drop();
|
||||
|
||||
// Unset render target
|
||||
driver->setRenderTarget(0, true, true, 0);
|
||||
driver->setRenderTarget(0, false, true, 0);
|
||||
|
||||
return rtt;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,10 @@ static void collectMods(const std::string &modspath,
|
||||
if(!dirlist[j].dir)
|
||||
continue;
|
||||
std::string modname = dirlist[j].name;
|
||||
// Ignore all directories beginning with a ".", especially
|
||||
// VCS directories like ".git" or ".svn"
|
||||
if(modname[0] == '.')
|
||||
continue;
|
||||
std::string modpath = modspath + DIR_DELIM + modname;
|
||||
TRACESTREAM(<<indentation<<"collectMods: "<<modname<<" at \""<<modpath<<"\""<<std::endl);
|
||||
// Handle modpacks (defined by containing modpack.txt)
|
||||
|
||||
171
src/nodedef.cpp
@@ -203,6 +203,7 @@ void ContentFeatures::reset()
|
||||
liquid_alternative_flowing = "";
|
||||
liquid_alternative_source = "";
|
||||
liquid_viscosity = 0;
|
||||
liquid_renewable = true;
|
||||
light_source = 0;
|
||||
damage_per_second = 0;
|
||||
node_box = NodeBox();
|
||||
@@ -214,9 +215,14 @@ void ContentFeatures::reset()
|
||||
sound_dug = SimpleSoundSpec();
|
||||
}
|
||||
|
||||
void ContentFeatures::serialize(std::ostream &os)
|
||||
void ContentFeatures::serialize(std::ostream &os, u16 protocol_version)
|
||||
{
|
||||
writeU8(os, 5); // version
|
||||
if(protocol_version < 14){
|
||||
serializeOld(os, protocol_version);
|
||||
return;
|
||||
}
|
||||
|
||||
writeU8(os, 6); // version
|
||||
os<<serializeString(name);
|
||||
writeU16(os, groups.size());
|
||||
for(ItemGroupList::const_iterator
|
||||
@@ -253,6 +259,7 @@ void ContentFeatures::serialize(std::ostream &os)
|
||||
os<<serializeString(liquid_alternative_flowing);
|
||||
os<<serializeString(liquid_alternative_source);
|
||||
writeU8(os, liquid_viscosity);
|
||||
writeU8(os, liquid_renewable);
|
||||
writeU8(os, light_source);
|
||||
writeU32(os, damage_per_second);
|
||||
node_box.serialize(os);
|
||||
@@ -262,13 +269,18 @@ void ContentFeatures::serialize(std::ostream &os)
|
||||
serializeSimpleSoundSpec(sound_footstep, os);
|
||||
serializeSimpleSoundSpec(sound_dig, os);
|
||||
serializeSimpleSoundSpec(sound_dug, os);
|
||||
// Stuff below should be moved to correct place in a version that otherwise changes
|
||||
// the protocol version
|
||||
}
|
||||
|
||||
void ContentFeatures::deSerialize(std::istream &is)
|
||||
{
|
||||
int version = readU8(is);
|
||||
if(version != 5)
|
||||
throw SerializationError("unsupported ContentFeatures version");
|
||||
if(version != 6){
|
||||
deSerializeOld(is, version);
|
||||
return;
|
||||
}
|
||||
|
||||
name = deSerializeString(is);
|
||||
groups.clear();
|
||||
u32 groups_size = readU16(is);
|
||||
@@ -307,6 +319,7 @@ void ContentFeatures::deSerialize(std::istream &is)
|
||||
liquid_alternative_flowing = deSerializeString(is);
|
||||
liquid_alternative_source = deSerializeString(is);
|
||||
liquid_viscosity = readU8(is);
|
||||
liquid_renewable = readU8(is);
|
||||
light_source = readU8(is);
|
||||
damage_per_second = readU32(is);
|
||||
node_box.deSerialize(is);
|
||||
@@ -319,6 +332,8 @@ void ContentFeatures::deSerialize(std::istream &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
|
||||
}catch(SerializationError &e) {};
|
||||
}
|
||||
|
||||
@@ -540,6 +555,7 @@ class CNodeDefManager: public IWritableNodeDefManager
|
||||
tiledef[j].name = "unknown_block.png";
|
||||
}
|
||||
|
||||
bool is_liquid = false;
|
||||
switch(f->drawtype){
|
||||
default:
|
||||
case NDT_NORMAL:
|
||||
@@ -558,12 +574,14 @@ class CNodeDefManager: public IWritableNodeDefManager
|
||||
f->solidness = 1;
|
||||
f->backface_culling = false;
|
||||
}
|
||||
is_liquid = true;
|
||||
break;
|
||||
case NDT_FLOWINGLIQUID:
|
||||
assert(f->liquid_type == LIQUID_FLOWING);
|
||||
f->solidness = 0;
|
||||
if(opaque_water)
|
||||
f->alpha = 255;
|
||||
is_liquid = true;
|
||||
break;
|
||||
case NDT_GLASSLIKE:
|
||||
f->solidness = 0;
|
||||
@@ -596,16 +614,24 @@ class CNodeDefManager: public IWritableNodeDefManager
|
||||
break;
|
||||
}
|
||||
|
||||
u8 material_type = 0;
|
||||
if(is_liquid){
|
||||
if(f->alpha == 255)
|
||||
material_type = TILE_MATERIAL_LIQUID_OPAQUE;
|
||||
else
|
||||
material_type = TILE_MATERIAL_LIQUID_TRANSPARENT;
|
||||
} else{
|
||||
material_type = TILE_MATERIAL_BASIC;
|
||||
}
|
||||
|
||||
// Tiles (fill in f->tiles[])
|
||||
for(u16 j=0; j<6; j++){
|
||||
// Texture
|
||||
f->tiles[j].texture = tsrc->getTexture(tiledef[j].name);
|
||||
// Alpha
|
||||
f->tiles[j].alpha = f->alpha;
|
||||
if(f->alpha == 255)
|
||||
f->tiles[j].material_type = MATERIAL_ALPHA_SIMPLE;
|
||||
else
|
||||
f->tiles[j].material_type = MATERIAL_ALPHA_VERTEX;
|
||||
// Material type
|
||||
f->tiles[j].material_type = material_type;
|
||||
// Material flags
|
||||
f->tiles[j].material_flags = 0;
|
||||
if(f->backface_culling)
|
||||
@@ -646,10 +672,8 @@ class CNodeDefManager: public IWritableNodeDefManager
|
||||
tsrc->getTexture(f->tiledef_special[j].name);
|
||||
// Alpha
|
||||
f->special_tiles[j].alpha = f->alpha;
|
||||
if(f->alpha == 255)
|
||||
f->special_tiles[j].material_type = MATERIAL_ALPHA_SIMPLE;
|
||||
else
|
||||
f->special_tiles[j].material_type = MATERIAL_ALPHA_VERTEX;
|
||||
// Material type
|
||||
f->special_tiles[j].material_type = material_type;
|
||||
// Material flags
|
||||
f->special_tiles[j].material_flags = 0;
|
||||
if(f->tiledef_special[j].backface_culling)
|
||||
@@ -686,7 +710,7 @@ class CNodeDefManager: public IWritableNodeDefManager
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void serialize(std::ostream &os)
|
||||
void serialize(std::ostream &os, u16 protocol_version)
|
||||
{
|
||||
writeU8(os, 1); // version
|
||||
u16 count = 0;
|
||||
@@ -702,7 +726,7 @@ class CNodeDefManager: public IWritableNodeDefManager
|
||||
// Wrap it in a string to allow different lengths without
|
||||
// strict version incompatibilities
|
||||
std::ostringstream wrapper_os(std::ios::binary);
|
||||
f->serialize(wrapper_os);
|
||||
f->serialize(wrapper_os, protocol_version);
|
||||
os2<<serializeString(wrapper_os.str());
|
||||
count++;
|
||||
}
|
||||
@@ -759,3 +783,122 @@ IWritableNodeDefManager* createNodeDefManager()
|
||||
return new CNodeDefManager();
|
||||
}
|
||||
|
||||
/*
|
||||
Serialization of old ContentFeatures formats
|
||||
*/
|
||||
|
||||
void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version)
|
||||
{
|
||||
if(protocol_version == 13)
|
||||
{
|
||||
writeU8(os, 5); // version
|
||||
os<<serializeString(name);
|
||||
writeU16(os, groups.size());
|
||||
for(ItemGroupList::const_iterator
|
||||
i = groups.begin(); i != groups.end(); i++){
|
||||
os<<serializeString(i->first);
|
||||
writeS16(os, i->second);
|
||||
}
|
||||
writeU8(os, drawtype);
|
||||
writeF1000(os, visual_scale);
|
||||
writeU8(os, 6);
|
||||
for(u32 i=0; i<6; i++)
|
||||
tiledef[i].serialize(os);
|
||||
writeU8(os, CF_SPECIAL_COUNT);
|
||||
for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
|
||||
tiledef_special[i].serialize(os);
|
||||
}
|
||||
writeU8(os, alpha);
|
||||
writeU8(os, post_effect_color.getAlpha());
|
||||
writeU8(os, post_effect_color.getRed());
|
||||
writeU8(os, post_effect_color.getGreen());
|
||||
writeU8(os, post_effect_color.getBlue());
|
||||
writeU8(os, param_type);
|
||||
writeU8(os, param_type_2);
|
||||
writeU8(os, is_ground_content);
|
||||
writeU8(os, light_propagates);
|
||||
writeU8(os, sunlight_propagates);
|
||||
writeU8(os, walkable);
|
||||
writeU8(os, pointable);
|
||||
writeU8(os, diggable);
|
||||
writeU8(os, climbable);
|
||||
writeU8(os, buildable_to);
|
||||
os<<serializeString(""); // legacy: used to be metadata_name
|
||||
writeU8(os, liquid_type);
|
||||
os<<serializeString(liquid_alternative_flowing);
|
||||
os<<serializeString(liquid_alternative_source);
|
||||
writeU8(os, liquid_viscosity);
|
||||
writeU8(os, light_source);
|
||||
writeU32(os, damage_per_second);
|
||||
node_box.serialize(os);
|
||||
selection_box.serialize(os);
|
||||
writeU8(os, legacy_facedir_simple);
|
||||
writeU8(os, legacy_wallmounted);
|
||||
serializeSimpleSoundSpec(sound_footstep, os);
|
||||
serializeSimpleSoundSpec(sound_dig, os);
|
||||
serializeSimpleSoundSpec(sound_dug, os);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw SerializationError("ContentFeatures::serialize(): Unsupported version requested");
|
||||
}
|
||||
}
|
||||
|
||||
void ContentFeatures::deSerializeOld(std::istream &is, int version)
|
||||
{
|
||||
if(version == 5) // In PROTOCOL_VERSION 13
|
||||
{
|
||||
name = deSerializeString(is);
|
||||
groups.clear();
|
||||
u32 groups_size = readU16(is);
|
||||
for(u32 i=0; i<groups_size; i++){
|
||||
std::string name = deSerializeString(is);
|
||||
int value = readS16(is);
|
||||
groups[name] = value;
|
||||
}
|
||||
drawtype = (enum NodeDrawType)readU8(is);
|
||||
visual_scale = readF1000(is);
|
||||
if(readU8(is) != 6)
|
||||
throw SerializationError("unsupported tile count");
|
||||
for(u32 i=0; i<6; i++)
|
||||
tiledef[i].deSerialize(is);
|
||||
if(readU8(is) != CF_SPECIAL_COUNT)
|
||||
throw SerializationError("unsupported CF_SPECIAL_COUNT");
|
||||
for(u32 i=0; i<CF_SPECIAL_COUNT; i++)
|
||||
tiledef_special[i].deSerialize(is);
|
||||
alpha = readU8(is);
|
||||
post_effect_color.setAlpha(readU8(is));
|
||||
post_effect_color.setRed(readU8(is));
|
||||
post_effect_color.setGreen(readU8(is));
|
||||
post_effect_color.setBlue(readU8(is));
|
||||
param_type = (enum ContentParamType)readU8(is);
|
||||
param_type_2 = (enum ContentParamType2)readU8(is);
|
||||
is_ground_content = readU8(is);
|
||||
light_propagates = readU8(is);
|
||||
sunlight_propagates = readU8(is);
|
||||
walkable = readU8(is);
|
||||
pointable = readU8(is);
|
||||
diggable = readU8(is);
|
||||
climbable = readU8(is);
|
||||
buildable_to = readU8(is);
|
||||
deSerializeString(is); // legacy: used to be metadata_name
|
||||
liquid_type = (enum LiquidType)readU8(is);
|
||||
liquid_alternative_flowing = deSerializeString(is);
|
||||
liquid_alternative_source = deSerializeString(is);
|
||||
liquid_viscosity = readU8(is);
|
||||
light_source = readU8(is);
|
||||
damage_per_second = readU32(is);
|
||||
node_box.deSerialize(is);
|
||||
selection_box.deSerialize(is);
|
||||
legacy_facedir_simple = readU8(is);
|
||||
legacy_wallmounted = readU8(is);
|
||||
deSerializeSimpleSoundSpec(sound_footstep, is);
|
||||
deSerializeSimpleSoundSpec(sound_dig, is);
|
||||
deSerializeSimpleSoundSpec(sound_dug, is);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw SerializationError("unsupported ContentFeatures version");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -209,6 +209,8 @@ struct ContentFeatures
|
||||
// 1 giving almost instantaneous propagation and 7 being
|
||||
// the slowest possible
|
||||
u8 liquid_viscosity;
|
||||
// Is liquid renewable (new liquid source will be created between 2 existing)
|
||||
bool liquid_renewable;
|
||||
// Amount of light the node emits
|
||||
u8 light_source;
|
||||
u32 damage_per_second;
|
||||
@@ -232,8 +234,10 @@ struct ContentFeatures
|
||||
ContentFeatures();
|
||||
~ContentFeatures();
|
||||
void reset();
|
||||
void serialize(std::ostream &os);
|
||||
void serialize(std::ostream &os, u16 protocol_version);
|
||||
void deSerialize(std::istream &is);
|
||||
void serializeOld(std::ostream &os, u16 protocol_version);
|
||||
void deSerializeOld(std::istream &is, int version);
|
||||
|
||||
/*
|
||||
Some handy methods
|
||||
@@ -262,7 +266,7 @@ class INodeDefManager
|
||||
const=0;
|
||||
virtual const ContentFeatures& get(const std::string &name) const=0;
|
||||
|
||||
virtual void serialize(std::ostream &os)=0;
|
||||
virtual void serialize(std::ostream &os, u16 protocol_version)=0;
|
||||
};
|
||||
|
||||
class IWritableNodeDefManager : public INodeDefManager
|
||||
@@ -303,7 +307,7 @@ class IWritableNodeDefManager : public INodeDefManager
|
||||
*/
|
||||
virtual void updateTextures(ITextureSource *tsrc)=0;
|
||||
|
||||
virtual void serialize(std::ostream &os)=0;
|
||||
virtual void serialize(std::ostream &os, u16 protocol_version)=0;
|
||||
virtual void deSerialize(std::istream &is)=0;
|
||||
};
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ double dotProduct(double vx, double vy, double wx, double wy){
|
||||
}
|
||||
|
||||
double easeCurve(double t){
|
||||
return 6*pow(t,5)-15*pow(t,4)+10*pow(t,3);
|
||||
return t * t * t * (6. * t * t - 15. * t + 10.);
|
||||
}
|
||||
|
||||
double linearInterpolation(double x0, double x1, double t){
|
||||
|
||||
@@ -18,8 +18,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
*/
|
||||
|
||||
#include "object_properties.h"
|
||||
#include "irrlichttypes_bloated.h"
|
||||
#include "util/serialize.h"
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
|
||||
#define PP2(x) "("<<(x).X<<","<<(x).Y<<")"
|
||||
@@ -30,6 +32,7 @@ ObjectProperties::ObjectProperties():
|
||||
weight(5),
|
||||
collisionbox(-0.5,-0.5,-0.5, 0.5,0.5,0.5),
|
||||
visual("sprite"),
|
||||
mesh(""),
|
||||
visual_size(1,1),
|
||||
spritediv(1,1),
|
||||
initial_sprite_basepos(0,0),
|
||||
@@ -38,6 +41,7 @@ ObjectProperties::ObjectProperties():
|
||||
automatic_rotate(0)
|
||||
{
|
||||
textures.push_back("unknown_object.png");
|
||||
colors.push_back(video::SColor(255,255,255,255));
|
||||
}
|
||||
|
||||
std::string ObjectProperties::dump()
|
||||
@@ -48,12 +52,18 @@ std::string ObjectProperties::dump()
|
||||
os<<", weight="<<weight;
|
||||
os<<", collisionbox="<<PP(collisionbox.MinEdge)<<","<<PP(collisionbox.MaxEdge);
|
||||
os<<", visual="<<visual;
|
||||
os<<", mesh="<<mesh;
|
||||
os<<", visual_size="<<PP2(visual_size);
|
||||
os<<", textures=[";
|
||||
for(u32 i=0; i<textures.size(); i++){
|
||||
os<<"\""<<textures[i]<<"\" ";
|
||||
}
|
||||
os<<"]";
|
||||
os<<", colors=[";
|
||||
for(u32 i=0; i<colors.size(); i++){
|
||||
os<<"\""<<colors[i].getAlpha()<<","<<colors[i].getRed()<<","<<colors[i].getGreen()<<","<<colors[i].getBlue()<<"\" ";
|
||||
}
|
||||
os<<"]";
|
||||
os<<", spritediv="<<PP2(spritediv);
|
||||
os<<", initial_sprite_basepos="<<PP2(initial_sprite_basepos);
|
||||
os<<", is_visible="<<is_visible;
|
||||
@@ -81,32 +91,49 @@ void ObjectProperties::serialize(std::ostream &os) const
|
||||
writeU8(os, is_visible);
|
||||
writeU8(os, makes_footstep_sound);
|
||||
writeF1000(os, automatic_rotate);
|
||||
// Added in protocol version 14
|
||||
os<<serializeString(mesh);
|
||||
writeU16(os, colors.size());
|
||||
for(u32 i=0; i<colors.size(); i++){
|
||||
writeARGB8(os, colors[i]);
|
||||
}
|
||||
// Add stuff only at the bottom.
|
||||
// Never remove anything, because we don't want new versions of this
|
||||
}
|
||||
|
||||
void ObjectProperties::deSerialize(std::istream &is)
|
||||
{
|
||||
int version = readU8(is);
|
||||
if(version != 1) throw SerializationError(
|
||||
"unsupported ObjectProperties version");
|
||||
hp_max = readS16(is);
|
||||
physical = readU8(is);
|
||||
weight = readF1000(is);
|
||||
collisionbox.MinEdge = readV3F1000(is);
|
||||
collisionbox.MaxEdge = readV3F1000(is);
|
||||
visual = deSerializeString(is);
|
||||
visual_size = readV2F1000(is);
|
||||
textures.clear();
|
||||
u32 texture_count = readU16(is);
|
||||
for(u32 i=0; i<texture_count; i++){
|
||||
textures.push_back(deSerializeString(is));
|
||||
if(version == 1)
|
||||
{
|
||||
try{
|
||||
hp_max = readS16(is);
|
||||
physical = readU8(is);
|
||||
weight = readF1000(is);
|
||||
collisionbox.MinEdge = readV3F1000(is);
|
||||
collisionbox.MaxEdge = readV3F1000(is);
|
||||
visual = deSerializeString(is);
|
||||
visual_size = readV2F1000(is);
|
||||
textures.clear();
|
||||
u32 texture_count = readU16(is);
|
||||
for(u32 i=0; i<texture_count; i++){
|
||||
textures.push_back(deSerializeString(is));
|
||||
}
|
||||
spritediv = readV2S16(is);
|
||||
initial_sprite_basepos = readV2S16(is);
|
||||
is_visible = readU8(is);
|
||||
makes_footstep_sound = readU8(is);
|
||||
automatic_rotate = readF1000(is);
|
||||
mesh = deSerializeString(is);
|
||||
u32 color_count = readU16(is);
|
||||
for(u32 i=0; i<color_count; i++){
|
||||
colors.push_back(readARGB8(is));
|
||||
}
|
||||
}catch(SerializationError &e){}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw SerializationError("unsupported ObjectProperties version");
|
||||
}
|
||||
spritediv = readV2S16(is);
|
||||
initial_sprite_basepos = readV2S16(is);
|
||||
is_visible = readU8(is);
|
||||
makes_footstep_sound = readU8(is);
|
||||
try{
|
||||
automatic_rotate = readF1000(is);
|
||||
}catch(SerializationError &e){}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <string>
|
||||
#include "irrlichttypes_bloated.h"
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
struct ObjectProperties
|
||||
{
|
||||
@@ -32,14 +33,17 @@ struct ObjectProperties
|
||||
float weight;
|
||||
core::aabbox3d<f32> collisionbox;
|
||||
std::string visual;
|
||||
std::string mesh;
|
||||
v2f visual_size;
|
||||
core::array<std::string> textures;
|
||||
core::array<video::SColor> colors;
|
||||
v2s16 spritediv;
|
||||
v2s16 initial_sprite_basepos;
|
||||
bool is_visible;
|
||||
bool makes_footstep_sound;
|
||||
float automatic_rotate;
|
||||
|
||||
|
||||
ObjectProperties();
|
||||
std::string dump();
|
||||
void serialize(std::ostream &os) const;
|
||||
|
||||
67
src/player.h
@@ -28,6 +28,61 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
|
||||
|
||||
struct PlayerControl
|
||||
{
|
||||
PlayerControl()
|
||||
{
|
||||
up = false;
|
||||
down = false;
|
||||
left = false;
|
||||
right = false;
|
||||
jump = false;
|
||||
aux1 = false;
|
||||
sneak = false;
|
||||
LMB = false;
|
||||
RMB = false;
|
||||
pitch = 0;
|
||||
yaw = 0;
|
||||
}
|
||||
PlayerControl(
|
||||
bool a_up,
|
||||
bool a_down,
|
||||
bool a_left,
|
||||
bool a_right,
|
||||
bool a_jump,
|
||||
bool a_aux1,
|
||||
bool a_sneak,
|
||||
bool a_LMB,
|
||||
bool a_RMB,
|
||||
float a_pitch,
|
||||
float a_yaw
|
||||
)
|
||||
{
|
||||
up = a_up;
|
||||
down = a_down;
|
||||
left = a_left;
|
||||
right = a_right;
|
||||
jump = a_jump;
|
||||
aux1 = a_aux1;
|
||||
sneak = a_sneak;
|
||||
LMB = a_LMB;
|
||||
RMB = a_RMB;
|
||||
pitch = a_pitch;
|
||||
yaw = a_yaw;
|
||||
}
|
||||
bool up;
|
||||
bool down;
|
||||
bool left;
|
||||
bool right;
|
||||
bool jump;
|
||||
bool aux1;
|
||||
bool sneak;
|
||||
bool LMB;
|
||||
bool RMB;
|
||||
float pitch;
|
||||
float yaw;
|
||||
};
|
||||
|
||||
class Map;
|
||||
class IGameDef;
|
||||
struct CollisionInfo;
|
||||
@@ -155,8 +210,16 @@ class Player
|
||||
u16 hp;
|
||||
|
||||
u16 peer_id;
|
||||
|
||||
|
||||
std::string inventory_formspec;
|
||||
|
||||
PlayerControl control;
|
||||
PlayerControl getPlayerControl()
|
||||
{
|
||||
return control;
|
||||
}
|
||||
|
||||
u32 keyPressed;
|
||||
|
||||
protected:
|
||||
IGameDef *m_gamedef;
|
||||
@@ -182,7 +245,7 @@ class RemotePlayer : public Player
|
||||
void setPlayerSAO(PlayerSAO *sao)
|
||||
{ m_sao = sao; }
|
||||
void setPosition(const v3f &position);
|
||||
|
||||
|
||||
private:
|
||||
PlayerSAO *m_sao;
|
||||
};
|
||||
|
||||
@@ -936,6 +936,8 @@ static void read_object_properties(lua_State *L, int index,
|
||||
lua_pop(L, 1);
|
||||
|
||||
getstringfield(L, -1, "visual", prop->visual);
|
||||
|
||||
getstringfield(L, -1, "mesh", prop->mesh);
|
||||
|
||||
lua_getfield(L, -1, "visual_size");
|
||||
if(lua_istable(L, -1))
|
||||
@@ -958,6 +960,23 @@ static void read_object_properties(lua_State *L, int index,
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, -1, "colors");
|
||||
if(lua_istable(L, -1)){
|
||||
prop->colors.clear();
|
||||
int table = lua_gettop(L);
|
||||
lua_pushnil(L);
|
||||
while(lua_next(L, table) != 0){
|
||||
// key at index -2 and value at index -1
|
||||
if(lua_isstring(L, -1))
|
||||
prop->colors.push_back(readARGB8(L, -1));
|
||||
else
|
||||
prop->colors.push_back(video::SColor(255, 255, 255, 255));
|
||||
// removes value, keeps key for next iteration
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, -1, "spritediv");
|
||||
if(lua_istable(L, -1))
|
||||
@@ -1238,6 +1257,7 @@ static ContentFeatures read_content_features(lua_State *L, int index)
|
||||
// the slowest possible
|
||||
f.liquid_viscosity = getintfield_default(L, index,
|
||||
"liquid_viscosity", f.liquid_viscosity);
|
||||
getboolfield(L, index, "liquid_renewable", f.liquid_renewable);
|
||||
// Amount of light the node emits
|
||||
f.light_source = getintfield_default(L, index,
|
||||
"light_source", f.light_source);
|
||||
@@ -2542,7 +2562,7 @@ class ObjectRef
|
||||
return 0;
|
||||
}
|
||||
|
||||
// punch(self, puncher, tool_capabilities, direction, time_from_last_punch)
|
||||
// punch(self, puncher, time_from_last_punch, tool_capabilities, dir)
|
||||
static int l_punch(lua_State *L)
|
||||
{
|
||||
ObjectRef *ref = checkobject(L, 1);
|
||||
@@ -2551,13 +2571,18 @@ class ObjectRef
|
||||
ServerActiveObject *puncher = getobject(puncher_ref);
|
||||
if(co == NULL) return 0;
|
||||
if(puncher == NULL) return 0;
|
||||
ToolCapabilities toolcap = read_tool_capabilities(L, 3);
|
||||
v3f dir = read_v3f(L, 4);
|
||||
v3f dir;
|
||||
if(lua_type(L, 5) != LUA_TTABLE)
|
||||
dir = co->getBasePosition() - puncher->getBasePosition();
|
||||
else
|
||||
dir = read_v3f(L, 5);
|
||||
float time_from_last_punch = 1000000;
|
||||
if(lua_isnumber(L, 5))
|
||||
time_from_last_punch = lua_tonumber(L, 5);
|
||||
if(lua_isnumber(L, 3))
|
||||
time_from_last_punch = lua_tonumber(L, 3);
|
||||
ToolCapabilities toolcap = read_tool_capabilities(L, 4);
|
||||
dir.normalize();
|
||||
// Do it
|
||||
puncher->punch(dir, &toolcap, puncher, time_from_last_punch);
|
||||
co->punch(dir, &toolcap, puncher, time_from_last_punch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2691,6 +2716,80 @@ class ObjectRef
|
||||
return 0;
|
||||
}
|
||||
|
||||
// set_animation(self, frame_range, frame_speed, frame_blend)
|
||||
static int l_set_animation(lua_State *L)
|
||||
{
|
||||
ObjectRef *ref = checkobject(L, 1);
|
||||
ServerActiveObject *co = getobject(ref);
|
||||
if(co == NULL) return 0;
|
||||
// Do it
|
||||
v2f frames = v2f(1, 1);
|
||||
if(!lua_isnil(L, 2))
|
||||
frames = read_v2f(L, 2);
|
||||
float frame_speed = 15;
|
||||
if(!lua_isnil(L, 3))
|
||||
frame_speed = lua_tonumber(L, 3);
|
||||
float frame_blend = 0;
|
||||
if(!lua_isnil(L, 4))
|
||||
frame_blend = lua_tonumber(L, 4);
|
||||
co->setAnimation(frames, frame_speed, frame_blend);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// set_bone_position(self, std::string bone, v3f position, v3f rotation)
|
||||
static int l_set_bone_position(lua_State *L)
|
||||
{
|
||||
ObjectRef *ref = checkobject(L, 1);
|
||||
ServerActiveObject *co = getobject(ref);
|
||||
if(co == NULL) return 0;
|
||||
// Do it
|
||||
std::string bone = "";
|
||||
if(!lua_isnil(L, 2))
|
||||
bone = lua_tostring(L, 2);
|
||||
v3f position = v3f(0, 0, 0);
|
||||
if(!lua_isnil(L, 3))
|
||||
position = read_v3f(L, 3);
|
||||
v3f rotation = v3f(0, 0, 0);
|
||||
if(!lua_isnil(L, 4))
|
||||
rotation = read_v3f(L, 4);
|
||||
co->setBonePosition(bone, position, rotation);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// set_attach(self, parent, bone, position, rotation)
|
||||
static int l_set_attach(lua_State *L)
|
||||
{
|
||||
ObjectRef *ref = checkobject(L, 1);
|
||||
ObjectRef *parent_ref = checkobject(L, 2);
|
||||
ServerActiveObject *co = getobject(ref);
|
||||
ServerActiveObject *parent = getobject(parent_ref);
|
||||
if(co == NULL) return 0;
|
||||
if(parent == NULL) return 0;
|
||||
// Do it
|
||||
std::string bone = "";
|
||||
if(!lua_isnil(L, 3))
|
||||
bone = lua_tostring(L, 3);
|
||||
v3f position = v3f(0, 0, 0);
|
||||
if(!lua_isnil(L, 4))
|
||||
position = read_v3f(L, 4);
|
||||
v3f rotation = v3f(0, 0, 0);
|
||||
if(!lua_isnil(L, 5))
|
||||
rotation = read_v3f(L, 5);
|
||||
co->setAttachment(parent->getId(), bone, position, rotation);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// set_detach(self)
|
||||
static int l_set_detach(lua_State *L)
|
||||
{
|
||||
ObjectRef *ref = checkobject(L, 1);
|
||||
ServerActiveObject *co = getobject(ref);
|
||||
if(co == NULL) return 0;
|
||||
// Do it
|
||||
co->setAttachment(0, "", v3f(0,0,0), v3f(0,0,0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// set_properties(self, properties)
|
||||
static int l_set_properties(lua_State *L)
|
||||
{
|
||||
@@ -2926,7 +3025,54 @@ class ObjectRef
|
||||
lua_pushlstring(L, formspec.c_str(), formspec.size());
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// get_player_control(self)
|
||||
static int l_get_player_control(lua_State *L)
|
||||
{
|
||||
ObjectRef *ref = checkobject(L, 1);
|
||||
Player *player = getplayer(ref);
|
||||
if(player == NULL){
|
||||
lua_pushlstring(L, "", 0);
|
||||
return 1;
|
||||
}
|
||||
// Do it
|
||||
PlayerControl control = player->getPlayerControl();
|
||||
lua_newtable(L);
|
||||
lua_pushboolean(L, control.up);
|
||||
lua_setfield(L, -2, "up");
|
||||
lua_pushboolean(L, control.down);
|
||||
lua_setfield(L, -2, "down");
|
||||
lua_pushboolean(L, control.left);
|
||||
lua_setfield(L, -2, "left");
|
||||
lua_pushboolean(L, control.right);
|
||||
lua_setfield(L, -2, "right");
|
||||
lua_pushboolean(L, control.jump);
|
||||
lua_setfield(L, -2, "jump");
|
||||
lua_pushboolean(L, control.aux1);
|
||||
lua_setfield(L, -2, "aux1");
|
||||
lua_pushboolean(L, control.sneak);
|
||||
lua_setfield(L, -2, "sneak");
|
||||
lua_pushboolean(L, control.LMB);
|
||||
lua_setfield(L, -2, "LMB");
|
||||
lua_pushboolean(L, control.RMB);
|
||||
lua_setfield(L, -2, "RMB");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// get_player_control_bits(self)
|
||||
static int l_get_player_control_bits(lua_State *L)
|
||||
{
|
||||
ObjectRef *ref = checkobject(L, 1);
|
||||
Player *player = getplayer(ref);
|
||||
if(player == NULL){
|
||||
lua_pushlstring(L, "", 0);
|
||||
return 1;
|
||||
}
|
||||
// Do it
|
||||
lua_pushnumber(L, player->keyPressed);
|
||||
return 1;
|
||||
}
|
||||
|
||||
public:
|
||||
ObjectRef(ServerActiveObject *object):
|
||||
m_object(object)
|
||||
@@ -3005,6 +3151,10 @@ const luaL_reg ObjectRef::methods[] = {
|
||||
method(ObjectRef, get_wielded_item),
|
||||
method(ObjectRef, set_wielded_item),
|
||||
method(ObjectRef, set_armor_groups),
|
||||
method(ObjectRef, set_animation),
|
||||
method(ObjectRef, set_bone_position),
|
||||
method(ObjectRef, set_attach),
|
||||
method(ObjectRef, set_detach),
|
||||
method(ObjectRef, set_properties),
|
||||
// LuaEntitySAO-only
|
||||
method(ObjectRef, setvelocity),
|
||||
@@ -3025,6 +3175,8 @@ const luaL_reg ObjectRef::methods[] = {
|
||||
method(ObjectRef, get_look_yaw),
|
||||
method(ObjectRef, set_inventory_formspec),
|
||||
method(ObjectRef, get_inventory_formspec),
|
||||
method(ObjectRef, get_player_control),
|
||||
method(ObjectRef, get_player_control_bits),
|
||||
{0,0}
|
||||
};
|
||||
|
||||
@@ -3452,7 +3604,7 @@ class EnvRef
|
||||
if(lua_isnumber(L, 3))
|
||||
time_of_day = 24000.0 * lua_tonumber(L, 3);
|
||||
time_of_day %= 24000;
|
||||
u32 dnr = time_to_daynight_ratio(time_of_day);
|
||||
u32 dnr = time_to_daynight_ratio(time_of_day, true);
|
||||
MapNode n = env->getMap().getNodeNoEx(pos);
|
||||
try{
|
||||
MapNode n = env->getMap().getNode(pos);
|
||||
@@ -5424,6 +5576,19 @@ bool scriptapi_on_chat_message(lua_State *L, const std::string &name,
|
||||
return ate;
|
||||
}
|
||||
|
||||
void scriptapi_on_shutdown(lua_State *L)
|
||||
{
|
||||
realitycheck(L);
|
||||
assert(lua_checkstack(L, 20));
|
||||
StackUnroller stack_unroller(L);
|
||||
|
||||
// Get registered shutdown hooks
|
||||
lua_getglobal(L, "minetest");
|
||||
lua_getfield(L, -1, "registered_on_shutdown");
|
||||
// Call callbacks
|
||||
scriptapi_run_callbacks(L, 0, RUN_CALLBACKS_MODE_FIRST);
|
||||
}
|
||||
|
||||
void scriptapi_on_newplayer(lua_State *L, ServerActiveObject *player)
|
||||
{
|
||||
realitycheck(L);
|
||||
@@ -6478,7 +6643,7 @@ bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name)
|
||||
}
|
||||
|
||||
void scriptapi_luaentity_activate(lua_State *L, u16 id,
|
||||
const std::string &staticdata)
|
||||
const std::string &staticdata, u32 dtime_s)
|
||||
{
|
||||
realitycheck(L);
|
||||
assert(lua_checkstack(L, 20));
|
||||
@@ -6496,8 +6661,9 @@ void scriptapi_luaentity_activate(lua_State *L, u16 id,
|
||||
luaL_checktype(L, -1, LUA_TFUNCTION);
|
||||
lua_pushvalue(L, object); // self
|
||||
lua_pushlstring(L, staticdata.c_str(), staticdata.size());
|
||||
// Call with 2 arguments, 0 results
|
||||
if(lua_pcall(L, 2, 0, 0))
|
||||
lua_pushinteger(L, dtime_s);
|
||||
// Call with 3 arguments, 0 results
|
||||
if(lua_pcall(L, 3, 0, 0))
|
||||
script_error(L, "error running function on_activate: %s\n",
|
||||
lua_tostring(L, -1));
|
||||
}
|
||||
@@ -6581,6 +6747,8 @@ void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
|
||||
lua_pop(L, 1);
|
||||
|
||||
getstringfield(L, -1, "visual", prop->visual);
|
||||
|
||||
getstringfield(L, -1, "mesh", prop->mesh);
|
||||
|
||||
// Deprecated: read object properties directly
|
||||
read_object_properties(L, -1, prop);
|
||||
|
||||
@@ -55,6 +55,9 @@ void scriptapi_environment_step(lua_State *L, float dtime);
|
||||
void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp,
|
||||
u32 blockseed);
|
||||
|
||||
/* server */
|
||||
void scriptapi_on_shutdown(lua_State *L);
|
||||
|
||||
/* misc */
|
||||
void scriptapi_on_newplayer(lua_State *L, ServerActiveObject *player);
|
||||
void scriptapi_on_dieplayer(lua_State *L, ServerActiveObject *player);
|
||||
@@ -167,7 +170,7 @@ void scriptapi_detached_inventory_on_take(lua_State *L,
|
||||
// Returns true if succesfully added into Lua; false otherwise.
|
||||
bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name);
|
||||
void scriptapi_luaentity_activate(lua_State *L, u16 id,
|
||||
const std::string &staticdata);
|
||||
const std::string &staticdata, u32 dtime_s);
|
||||
void scriptapi_luaentity_rm(lua_State *L, u16 id);
|
||||
std::string scriptapi_luaentity_get_staticdata(lua_State *L, u16 id);
|
||||
void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
|
||||
|
||||
122
src/server.cpp
@@ -54,6 +54,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "util/pointedthing.h"
|
||||
#include "util/mathconstants.h"
|
||||
#include "rollback.h"
|
||||
#include "util/serialize.h"
|
||||
|
||||
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
|
||||
|
||||
@@ -1111,7 +1112,17 @@ Server::~Server()
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
JMutexAutoLock conlock(m_con_mutex);
|
||||
|
||||
/*
|
||||
Execute script shutdown hooks
|
||||
*/
|
||||
scriptapi_on_shutdown(m_lua);
|
||||
}
|
||||
|
||||
{
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
|
||||
@@ -1143,14 +1154,6 @@ Server::~Server()
|
||||
i = m_clients.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
/*// Delete player
|
||||
// NOTE: These are removed by env destructor
|
||||
{
|
||||
u16 peer_id = i.getNode()->getKey();
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
m_env->removePlayer(peer_id);
|
||||
}*/
|
||||
|
||||
// Delete client
|
||||
delete i.getNode()->getValue();
|
||||
}
|
||||
@@ -1371,9 +1374,9 @@ void Server::AsyncRunStep()
|
||||
/*
|
||||
Send player inventories and HPs if necessary
|
||||
*/
|
||||
if(playersao->m_teleported){
|
||||
if(playersao->m_moved){
|
||||
SendMovePlayer(client->peer_id);
|
||||
playersao->m_teleported = false;
|
||||
playersao->m_moved = false;
|
||||
}
|
||||
if(playersao->m_inventory_not_sent){
|
||||
UpdateCrafting(client->peer_id);
|
||||
@@ -1567,7 +1570,7 @@ void Server::AsyncRunStep()
|
||||
|
||||
if(obj)
|
||||
data_buffer.append(serializeLongString(
|
||||
obj->getClientInitializationData()));
|
||||
obj->getClientInitializationData(client->net_proto_version)));
|
||||
else
|
||||
data_buffer.append(serializeLongString(""));
|
||||
|
||||
@@ -2037,40 +2040,74 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
Read and check network protocol version
|
||||
*/
|
||||
|
||||
u16 net_proto_version = 0;
|
||||
u16 min_net_proto_version = 0;
|
||||
if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
|
||||
min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
|
||||
|
||||
// Use same version as minimum and maximum if maximum version field
|
||||
// doesn't exist (backwards compatibility)
|
||||
u16 max_net_proto_version = min_net_proto_version;
|
||||
if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
|
||||
max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
|
||||
|
||||
// Start with client's maximum version
|
||||
u16 net_proto_version = max_net_proto_version;
|
||||
|
||||
// Figure out a working version if it is possible at all
|
||||
if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
|
||||
min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
|
||||
{
|
||||
net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
|
||||
// If maximum is larger than our maximum, go with our maximum
|
||||
if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
|
||||
net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
|
||||
// Else go with client's maximum
|
||||
else
|
||||
net_proto_version = max_net_proto_version;
|
||||
}
|
||||
|
||||
verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
|
||||
<<min_net_proto_version<<", max: "<<max_net_proto_version
|
||||
<<", chosen: "<<net_proto_version<<std::endl;
|
||||
|
||||
getClient(peer_id)->net_proto_version = net_proto_version;
|
||||
|
||||
if(net_proto_version == 0)
|
||||
if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
|
||||
net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
|
||||
{
|
||||
actionstream<<"Server: An old tried to connect from "<<addr_s
|
||||
actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
|
||||
<<std::endl;
|
||||
SendAccessDenied(m_con, peer_id, std::wstring(
|
||||
L"Your client's version is not supported.\n"
|
||||
L"Server version is ")
|
||||
+ narrow_to_wide(VERSION_STRING) + L"."
|
||||
+ narrow_to_wide(VERSION_STRING) + L",\n"
|
||||
+ L"server's PROTOCOL_VERSION is "
|
||||
+ narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
|
||||
+ L"..."
|
||||
+ narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
|
||||
+ L", client's PROTOCOL_VERSION is "
|
||||
+ narrow_to_wide(itos(min_net_proto_version))
|
||||
+ L"..."
|
||||
+ narrow_to_wide(itos(max_net_proto_version))
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if(g_settings->getBool("strict_protocol_version_checking"))
|
||||
{
|
||||
if(net_proto_version != PROTOCOL_VERSION)
|
||||
if(net_proto_version != LATEST_PROTOCOL_VERSION)
|
||||
{
|
||||
actionstream<<"Server: A mismatched client tried to connect"
|
||||
<<" from "<<addr_s<<std::endl;
|
||||
actionstream<<"Server: A mismatched (strict) client tried to "
|
||||
<<"connect from "<<addr_s<<std::endl;
|
||||
SendAccessDenied(m_con, peer_id, std::wstring(
|
||||
L"Your client's version is not supported.\n"
|
||||
L"Server version is ")
|
||||
+ narrow_to_wide(VERSION_STRING) + L",\n"
|
||||
+ L"server's PROTOCOL_VERSION is "
|
||||
+ narrow_to_wide(itos(PROTOCOL_VERSION))
|
||||
+ L"server's PROTOCOL_VERSION (strict) is "
|
||||
+ narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
|
||||
+ L", client's PROTOCOL_VERSION is "
|
||||
+ narrow_to_wide(itos(net_proto_version))
|
||||
+ narrow_to_wide(itos(min_net_proto_version))
|
||||
+ L"..."
|
||||
+ narrow_to_wide(itos(max_net_proto_version))
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -2212,11 +2249,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
Answer with a TOCLIENT_INIT
|
||||
*/
|
||||
{
|
||||
SharedBuffer<u8> reply(2+1+6+8);
|
||||
SharedBuffer<u8> reply(2+1+6+8+4);
|
||||
writeU16(&reply[0], TOCLIENT_INIT);
|
||||
writeU8(&reply[2], deployed);
|
||||
writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
|
||||
writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
|
||||
writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
|
||||
|
||||
// Send as reliable
|
||||
m_con.Send(peer_id, 0, reply, true);
|
||||
@@ -2242,8 +2280,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
return;
|
||||
}
|
||||
|
||||
getClient(peer_id)->serialization_version
|
||||
= getClient(peer_id)->pending_serialization_version;
|
||||
RemoteClient *client = getClient(peer_id);
|
||||
client->serialization_version =
|
||||
getClient(peer_id)->pending_serialization_version;
|
||||
|
||||
/*
|
||||
Send some initialization data
|
||||
@@ -2256,7 +2295,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
SendItemDef(m_con, peer_id, m_itemdef);
|
||||
|
||||
// Send node definitions
|
||||
SendNodeDef(m_con, peer_id, m_nodedef);
|
||||
SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
|
||||
|
||||
// Send media announcement
|
||||
sendMediaAnnouncement(peer_id);
|
||||
@@ -2310,9 +2349,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
}
|
||||
|
||||
// Warnings about protocol version can be issued here
|
||||
if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
|
||||
if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
|
||||
{
|
||||
SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER!");
|
||||
SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
|
||||
L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2377,6 +2417,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
v3s32 ss = readV3S32(&data[start+2+12]);
|
||||
f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
|
||||
f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
|
||||
u32 keyPressed = 0;
|
||||
if(datasize >= 2+12+12+4+4+4)
|
||||
keyPressed = (u32)readU32(&data[2+12+12+4+4]);
|
||||
v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
|
||||
v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
|
||||
pitch = wrapDegrees(pitch);
|
||||
@@ -2386,6 +2429,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
player->setSpeed(speed);
|
||||
player->setPitch(pitch);
|
||||
player->setYaw(yaw);
|
||||
player->keyPressed=keyPressed;
|
||||
player->control.up = (bool)(keyPressed&1);
|
||||
player->control.down = (bool)(keyPressed&2);
|
||||
player->control.left = (bool)(keyPressed&4);
|
||||
player->control.right = (bool)(keyPressed&8);
|
||||
player->control.jump = (bool)(keyPressed&16);
|
||||
player->control.aux1 = (bool)(keyPressed&32);
|
||||
player->control.sneak = (bool)(keyPressed&64);
|
||||
player->control.LMB = (bool)(keyPressed&128);
|
||||
player->control.RMB = (bool)(keyPressed&256);
|
||||
|
||||
/*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
|
||||
<<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
|
||||
@@ -3166,6 +3219,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
}
|
||||
|
||||
} // action == 4
|
||||
|
||||
|
||||
/*
|
||||
Catch invalid actions
|
||||
@@ -3496,7 +3550,7 @@ void Server::SendItemDef(con::Connection &con, u16 peer_id,
|
||||
}
|
||||
|
||||
void Server::SendNodeDef(con::Connection &con, u16 peer_id,
|
||||
INodeDefManager *nodedef)
|
||||
INodeDefManager *nodedef, u16 protocol_version)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
@@ -3508,7 +3562,7 @@ void Server::SendNodeDef(con::Connection &con, u16 peer_id,
|
||||
*/
|
||||
writeU16(os, TOCLIENT_NODEDEF);
|
||||
std::ostringstream tmp_os(std::ios::binary);
|
||||
nodedef->serialize(tmp_os);
|
||||
nodedef->serialize(tmp_os, protocol_version);
|
||||
std::ostringstream tmp_os2(std::ios::binary);
|
||||
compressZlib(tmp_os.str(), tmp_os2);
|
||||
os<<serializeLongString(tmp_os2.str());
|
||||
@@ -4029,6 +4083,7 @@ void Server::fillMediaCache()
|
||||
paths.push_back(mod.path + DIR_DELIM + "textures");
|
||||
paths.push_back(mod.path + DIR_DELIM + "sounds");
|
||||
paths.push_back(mod.path + DIR_DELIM + "media");
|
||||
paths.push_back(mod.path + DIR_DELIM + "models");
|
||||
}
|
||||
std::string path_all = "textures";
|
||||
paths.push_back(path_all + DIR_DELIM + "all");
|
||||
@@ -4054,6 +4109,7 @@ void Server::fillMediaCache()
|
||||
".png", ".jpg", ".bmp", ".tga",
|
||||
".pcx", ".ppm", ".psd", ".wal", ".rgb",
|
||||
".ogg",
|
||||
".x", ".b3d", ".md2", ".obj",
|
||||
NULL
|
||||
};
|
||||
if(removeStringEnd(filename, supported_ext) == ""){
|
||||
@@ -4632,6 +4688,10 @@ ITextureSource* Server::getTextureSource()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
IShaderSource* Server::getShaderSource()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
u16 Server::allocateUnknownNodeId(const std::string &name)
|
||||
{
|
||||
return m_nodedef->allocateDummy(name);
|
||||
|
||||
@@ -560,6 +560,7 @@ class Server : public con::PeerHandler, public MapEventReceiver,
|
||||
virtual INodeDefManager* getNodeDefManager();
|
||||
virtual ICraftDefManager* getCraftDefManager();
|
||||
virtual ITextureSource* getTextureSource();
|
||||
virtual IShaderSource* getShaderSource();
|
||||
virtual u16 allocateUnknownNodeId(const std::string &name);
|
||||
virtual ISoundManager* getSoundManager();
|
||||
virtual MtEventManager* getEventManager();
|
||||
@@ -602,7 +603,7 @@ class Server : public con::PeerHandler, public MapEventReceiver,
|
||||
static void SendItemDef(con::Connection &con, u16 peer_id,
|
||||
IItemDefManager *itemdef);
|
||||
static void SendNodeDef(con::Connection &con, u16 peer_id,
|
||||
INodeDefManager *nodedef);
|
||||
INodeDefManager *nodedef, u16 protocol_version);
|
||||
|
||||
/*
|
||||
Non-static send methods.
|
||||
|
||||
@@ -62,7 +62,7 @@ class ServerActiveObject : public ActiveObject
|
||||
{ return getType(); }
|
||||
|
||||
// Called after id has been set and has been inserted in environment
|
||||
virtual void addedToEnvironment(){};
|
||||
virtual void addedToEnvironment(u32 dtime_s){};
|
||||
// Called before removing from environment
|
||||
virtual void removingFromEnvironment(){};
|
||||
// Returns true if object's deletion is the job of the
|
||||
@@ -118,7 +118,7 @@ class ServerActiveObject : public ActiveObject
|
||||
The return value of this is passed to the client-side object
|
||||
when it is created
|
||||
*/
|
||||
virtual std::string getClientInitializationData(){return "";}
|
||||
virtual std::string getClientInitializationData(u16 protocol_version){return "";}
|
||||
|
||||
/*
|
||||
The return value of this is passed to the server-side object
|
||||
@@ -152,6 +152,12 @@ class ServerActiveObject : public ActiveObject
|
||||
|
||||
virtual void setArmorGroups(const ItemGroupList &armor_groups)
|
||||
{}
|
||||
virtual void setAnimation(v2f frames, float frame_speed, float frame_blend)
|
||||
{}
|
||||
virtual void setBonePosition(std::string bone, v3f position, v3f rotation)
|
||||
{}
|
||||
virtual void setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
|
||||
{}
|
||||
virtual ObjectProperties* accessObjectProperties()
|
||||
{ return NULL; }
|
||||
virtual void notifyObjectPropertiesModified()
|
||||
|
||||
793
src/shader.cpp
Normal file
@@ -0,0 +1,793 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2012 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Copyright (C) 2012 Kahrl <kahrl@gmx.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "shader.h"
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "debug.h"
|
||||
#include "main.h" // for g_settings
|
||||
#include "filesys.h"
|
||||
#include "util/container.h"
|
||||
#include "util/thread.h"
|
||||
#include "settings.h"
|
||||
#include <iterator>
|
||||
#include <ICameraSceneNode.h>
|
||||
#include <IGPUProgrammingServices.h>
|
||||
#include <IMaterialRenderer.h>
|
||||
#include <IMaterialRendererServices.h>
|
||||
#include <IShaderConstantSetCallBack.h>
|
||||
#include "EShaderTypes.h"
|
||||
#include "log.h"
|
||||
#include "gamedef.h"
|
||||
#include "strfnd.h" // trim()
|
||||
|
||||
/*
|
||||
A cache from shader name to shader path
|
||||
*/
|
||||
MutexedMap<std::string, std::string> g_shadername_to_path_cache;
|
||||
|
||||
/*
|
||||
Gets the path to a shader by first checking if the file
|
||||
name_of_shader/filename
|
||||
exists in shader_path and if not, using the data path.
|
||||
|
||||
If not found, returns "".
|
||||
|
||||
Utilizes a thread-safe cache.
|
||||
*/
|
||||
std::string getShaderPath(const std::string &name_of_shader,
|
||||
const std::string &filename)
|
||||
{
|
||||
std::string combined = name_of_shader + DIR_DELIM + filename;
|
||||
std::string fullpath = "";
|
||||
/*
|
||||
Check from cache
|
||||
*/
|
||||
bool incache = g_shadername_to_path_cache.get(combined, &fullpath);
|
||||
if(incache)
|
||||
return fullpath;
|
||||
|
||||
/*
|
||||
Check from shader_path
|
||||
*/
|
||||
std::string shader_path = g_settings->get("shader_path");
|
||||
if(shader_path != "")
|
||||
{
|
||||
std::string testpath = shader_path + DIR_DELIM + combined;
|
||||
if(fs::PathExists(testpath))
|
||||
fullpath = testpath;
|
||||
}
|
||||
|
||||
/*
|
||||
Check from default data directory
|
||||
*/
|
||||
if(fullpath == "")
|
||||
{
|
||||
std::string rel_path = std::string("client") + DIR_DELIM
|
||||
+ "shaders" + DIR_DELIM
|
||||
+ name_of_shader + DIR_DELIM
|
||||
+ filename;
|
||||
std::string testpath = porting::path_share + DIR_DELIM + rel_path;
|
||||
if(fs::PathExists(testpath))
|
||||
fullpath = testpath;
|
||||
}
|
||||
|
||||
// Add to cache (also an empty result is cached)
|
||||
g_shadername_to_path_cache.set(combined, fullpath);
|
||||
|
||||
// Finally return it
|
||||
return fullpath;
|
||||
}
|
||||
|
||||
/*
|
||||
SourceShaderCache: A cache used for storing source shaders.
|
||||
*/
|
||||
|
||||
class SourceShaderCache
|
||||
{
|
||||
public:
|
||||
void insert(const std::string &name_of_shader,
|
||||
const std::string &filename,
|
||||
const std::string &program,
|
||||
bool prefer_local)
|
||||
{
|
||||
std::string combined = name_of_shader + DIR_DELIM + filename;
|
||||
// Try to use local shader instead if asked to
|
||||
if(prefer_local){
|
||||
std::string path = getShaderPath(name_of_shader, filename);
|
||||
if(path != ""){
|
||||
std::string p = readFile(path);
|
||||
if(p != ""){
|
||||
m_programs[combined] = p;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_programs[combined] = program;
|
||||
}
|
||||
std::string get(const std::string &name_of_shader,
|
||||
const std::string &filename)
|
||||
{
|
||||
std::string combined = name_of_shader + DIR_DELIM + filename;
|
||||
core::map<std::string, std::string>::Node *n;
|
||||
n = m_programs.find(combined);
|
||||
if(n)
|
||||
return n->getValue();
|
||||
return "";
|
||||
}
|
||||
// Primarily fetches from cache, secondarily tries to read from filesystem
|
||||
std::string getOrLoad(const std::string &name_of_shader,
|
||||
const std::string &filename)
|
||||
{
|
||||
std::string combined = name_of_shader + DIR_DELIM + filename;
|
||||
core::map<std::string, std::string>::Node *n;
|
||||
n = m_programs.find(combined);
|
||||
if(n)
|
||||
return n->getValue();
|
||||
std::string path = getShaderPath(name_of_shader, filename);
|
||||
if(path == ""){
|
||||
infostream<<"SourceShaderCache::getOrLoad(): No path found for \""
|
||||
<<combined<<"\""<<std::endl;
|
||||
return "";
|
||||
}
|
||||
infostream<<"SourceShaderCache::getOrLoad(): Loading path \""<<path
|
||||
<<"\""<<std::endl;
|
||||
std::string p = readFile(path);
|
||||
if(p != ""){
|
||||
m_programs[combined] = p;
|
||||
return p;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
private:
|
||||
core::map<std::string, std::string> m_programs;
|
||||
std::string readFile(const std::string &path)
|
||||
{
|
||||
std::ifstream is(path.c_str(), std::ios::binary);
|
||||
if(!is.is_open())
|
||||
return "";
|
||||
std::ostringstream tmp_os;
|
||||
tmp_os << is.rdbuf();
|
||||
return tmp_os.str();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
ShaderCallback: Sets constants that can be used in shaders
|
||||
*/
|
||||
|
||||
class IShaderConstantSetterRegistry
|
||||
{
|
||||
public:
|
||||
virtual ~IShaderConstantSetterRegistry(){};
|
||||
virtual void onSetConstants(video::IMaterialRendererServices *services,
|
||||
bool is_highlevel, const std::string &name) = 0;
|
||||
};
|
||||
|
||||
class ShaderCallback : public video::IShaderConstantSetCallBack
|
||||
{
|
||||
IShaderConstantSetterRegistry *m_scsr;
|
||||
std::string m_name;
|
||||
|
||||
public:
|
||||
ShaderCallback(IShaderConstantSetterRegistry *scsr, const std::string &name):
|
||||
m_scsr(scsr),
|
||||
m_name(name)
|
||||
{}
|
||||
~ShaderCallback() {}
|
||||
|
||||
virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
|
||||
{
|
||||
video::IVideoDriver *driver = services->getVideoDriver();
|
||||
assert(driver);
|
||||
|
||||
bool is_highlevel = userData;
|
||||
|
||||
m_scsr->onSetConstants(services, is_highlevel, m_name);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
MainShaderConstantSetter: Set basic constants required for almost everything
|
||||
*/
|
||||
|
||||
class MainShaderConstantSetter : public IShaderConstantSetter
|
||||
{
|
||||
public:
|
||||
MainShaderConstantSetter(IrrlichtDevice *device):
|
||||
m_device(device)
|
||||
{}
|
||||
~MainShaderConstantSetter() {}
|
||||
|
||||
virtual void onSetConstants(video::IMaterialRendererServices *services,
|
||||
bool is_highlevel)
|
||||
{
|
||||
video::IVideoDriver *driver = services->getVideoDriver();
|
||||
assert(driver);
|
||||
|
||||
// set inverted world matrix
|
||||
core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD);
|
||||
invWorld.makeInverse();
|
||||
if(is_highlevel)
|
||||
services->setVertexShaderConstant("mInvWorld", invWorld.pointer(), 16);
|
||||
else
|
||||
services->setVertexShaderConstant(invWorld.pointer(), 0, 4);
|
||||
|
||||
// set clip matrix
|
||||
core::matrix4 worldViewProj;
|
||||
worldViewProj = driver->getTransform(video::ETS_PROJECTION);
|
||||
worldViewProj *= driver->getTransform(video::ETS_VIEW);
|
||||
worldViewProj *= driver->getTransform(video::ETS_WORLD);
|
||||
if(is_highlevel)
|
||||
services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
|
||||
else
|
||||
services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4);
|
||||
|
||||
// set transposed world matrix
|
||||
core::matrix4 world = driver->getTransform(video::ETS_WORLD);
|
||||
world = world.getTransposed();
|
||||
if(is_highlevel)
|
||||
services->setVertexShaderConstant("mTransWorld", world.pointer(), 16);
|
||||
else
|
||||
services->setVertexShaderConstant(world.pointer(), 8, 4);
|
||||
}
|
||||
|
||||
private:
|
||||
IrrlichtDevice *m_device;
|
||||
};
|
||||
|
||||
/*
|
||||
ShaderSource
|
||||
*/
|
||||
|
||||
class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterRegistry
|
||||
{
|
||||
public:
|
||||
ShaderSource(IrrlichtDevice *device);
|
||||
~ShaderSource();
|
||||
|
||||
/*
|
||||
Gets a shader material id from cache or
|
||||
- if main thread, from getShaderIdDirect
|
||||
- if other thread, adds to request queue and waits for main thread
|
||||
*/
|
||||
u32 getShaderId(const std::string &name);
|
||||
|
||||
/*
|
||||
- If shader material specified by name is found from cache,
|
||||
return the cached id.
|
||||
- Otherwise generate the shader material, add to cache and return id.
|
||||
|
||||
The id 0 points to a null shader. Its material is EMT_SOLID.
|
||||
*/
|
||||
u32 getShaderIdDirect(const std::string &name);
|
||||
|
||||
// Finds out the name of a cached shader.
|
||||
std::string getShaderName(u32 id);
|
||||
|
||||
/*
|
||||
If shader specified by the name pointed by the id doesn't
|
||||
exist, create it, then return the cached shader.
|
||||
|
||||
Can be called from any thread. If called from some other thread
|
||||
and not found in cache, the call is queued to the main thread
|
||||
for processing.
|
||||
*/
|
||||
ShaderInfo getShader(u32 id);
|
||||
|
||||
ShaderInfo getShader(const std::string &name)
|
||||
{
|
||||
return getShader(getShaderId(name));
|
||||
}
|
||||
|
||||
// Processes queued shader requests from other threads.
|
||||
// Shall be called from the main thread.
|
||||
void processQueue();
|
||||
|
||||
// Insert a shader program into the cache without touching the
|
||||
// filesystem. Shall be called from the main thread.
|
||||
void insertSourceShader(const std::string &name_of_shader,
|
||||
const std::string &filename, const std::string &program);
|
||||
|
||||
// Rebuild shaders from the current set of source shaders
|
||||
// Shall be called from the main thread.
|
||||
void rebuildShaders();
|
||||
|
||||
void addGlobalConstantSetter(IShaderConstantSetter *setter)
|
||||
{
|
||||
m_global_setters.push_back(setter);
|
||||
}
|
||||
|
||||
void onSetConstants(video::IMaterialRendererServices *services,
|
||||
bool is_highlevel, const std::string &name);
|
||||
|
||||
private:
|
||||
|
||||
// The id of the thread that is allowed to use irrlicht directly
|
||||
threadid_t m_main_thread;
|
||||
// The irrlicht device
|
||||
IrrlichtDevice *m_device;
|
||||
// The set-constants callback
|
||||
ShaderCallback *m_shader_callback;
|
||||
|
||||
// Cache of source shaders
|
||||
// This should be only accessed from the main thread
|
||||
SourceShaderCache m_sourcecache;
|
||||
|
||||
// A shader id is index in this array.
|
||||
// The first position contains a dummy shader.
|
||||
core::array<ShaderInfo> m_shaderinfo_cache;
|
||||
// Maps a shader name to an index in the former.
|
||||
core::map<std::string, u32> m_name_to_id;
|
||||
// The two former containers are behind this mutex
|
||||
JMutex m_shaderinfo_cache_mutex;
|
||||
|
||||
// Queued shader fetches (to be processed by the main thread)
|
||||
RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
|
||||
|
||||
// Global constant setters
|
||||
// TODO: Delete these in the destructor
|
||||
core::array<IShaderConstantSetter*> m_global_setters;
|
||||
};
|
||||
|
||||
IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
|
||||
{
|
||||
return new ShaderSource(device);
|
||||
}
|
||||
|
||||
/*
|
||||
Generate shader given the shader name.
|
||||
*/
|
||||
ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
|
||||
video::IShaderConstantSetCallBack *callback,
|
||||
SourceShaderCache *sourcecache);
|
||||
|
||||
/*
|
||||
Load shader programs
|
||||
*/
|
||||
void load_shaders(std::string name, SourceShaderCache *sourcecache,
|
||||
video::E_DRIVER_TYPE drivertype, s32 enable_shaders,
|
||||
std::string &vertex_program, std::string &pixel_program,
|
||||
std::string &geometry_program, bool &is_highlevel);
|
||||
|
||||
ShaderSource::ShaderSource(IrrlichtDevice *device):
|
||||
m_device(device)
|
||||
{
|
||||
assert(m_device);
|
||||
|
||||
m_shader_callback = new ShaderCallback(this, "default");
|
||||
|
||||
m_shaderinfo_cache_mutex.Init();
|
||||
|
||||
m_main_thread = get_current_thread_id();
|
||||
|
||||
// Add a dummy ShaderInfo as the first index, named ""
|
||||
m_shaderinfo_cache.push_back(ShaderInfo());
|
||||
m_name_to_id[""] = 0;
|
||||
|
||||
// Add main global constant setter
|
||||
addGlobalConstantSetter(new MainShaderConstantSetter(device));
|
||||
}
|
||||
|
||||
ShaderSource::~ShaderSource()
|
||||
{
|
||||
//m_shader_callback->drop();
|
||||
}
|
||||
|
||||
u32 ShaderSource::getShaderId(const std::string &name)
|
||||
{
|
||||
//infostream<<"getShaderId(): \""<<name<<"\""<<std::endl;
|
||||
|
||||
{
|
||||
/*
|
||||
See if shader already exists
|
||||
*/
|
||||
JMutexAutoLock lock(m_shaderinfo_cache_mutex);
|
||||
core::map<std::string, u32>::Node *n;
|
||||
n = m_name_to_id.find(name);
|
||||
if(n != NULL)
|
||||
return n->getValue();
|
||||
}
|
||||
|
||||
/*
|
||||
Get shader
|
||||
*/
|
||||
if(get_current_thread_id() == m_main_thread){
|
||||
return getShaderIdDirect(name);
|
||||
} else {
|
||||
infostream<<"getShaderId(): Queued: name=\""<<name<<"\""<<std::endl;
|
||||
|
||||
// We're gonna ask the result to be put into here
|
||||
ResultQueue<std::string, u32, u8, u8> result_queue;
|
||||
|
||||
// Throw a request in
|
||||
m_get_shader_queue.add(name, 0, 0, &result_queue);
|
||||
|
||||
infostream<<"Waiting for shader from main thread, name=\""
|
||||
<<name<<"\""<<std::endl;
|
||||
|
||||
try{
|
||||
// Wait result for a second
|
||||
GetResult<std::string, u32, u8, u8>
|
||||
result = result_queue.pop_front(1000);
|
||||
|
||||
// Check that at least something worked OK
|
||||
assert(result.key == name);
|
||||
|
||||
return result.item;
|
||||
}
|
||||
catch(ItemNotFoundException &e){
|
||||
infostream<<"Waiting for shader timed out."<<std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
infostream<<"getShaderId(): Failed"<<std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
This method generates all the shaders
|
||||
*/
|
||||
u32 ShaderSource::getShaderIdDirect(const std::string &name)
|
||||
{
|
||||
//infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
|
||||
|
||||
// Empty name means shader 0
|
||||
if(name == ""){
|
||||
infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Calling only allowed from main thread
|
||||
*/
|
||||
if(get_current_thread_id() != m_main_thread){
|
||||
errorstream<<"ShaderSource::getShaderIdDirect() "
|
||||
"called not from main thread"<<std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
See if shader already exists
|
||||
*/
|
||||
{
|
||||
JMutexAutoLock lock(m_shaderinfo_cache_mutex);
|
||||
|
||||
core::map<std::string, u32>::Node *n;
|
||||
n = m_name_to_id.find(name);
|
||||
if(n != NULL){
|
||||
/*infostream<<"getShaderIdDirect(): \""<<name
|
||||
<<"\" found in cache"<<std::endl;*/
|
||||
return n->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
/*infostream<<"getShaderIdDirect(): \""<<name
|
||||
<<"\" NOT found in cache. Creating it."<<std::endl;*/
|
||||
|
||||
ShaderInfo info = generate_shader(name, m_device,
|
||||
m_shader_callback, &m_sourcecache);
|
||||
|
||||
/*
|
||||
Add shader to caches (add dummy shaders too)
|
||||
*/
|
||||
|
||||
JMutexAutoLock lock(m_shaderinfo_cache_mutex);
|
||||
|
||||
u32 id = m_shaderinfo_cache.size();
|
||||
m_shaderinfo_cache.push_back(info);
|
||||
m_name_to_id.insert(name, id);
|
||||
|
||||
/*infostream<<"getShaderIdDirect(): "
|
||||
<<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;*/
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
std::string ShaderSource::getShaderName(u32 id)
|
||||
{
|
||||
JMutexAutoLock lock(m_shaderinfo_cache_mutex);
|
||||
|
||||
if(id >= m_shaderinfo_cache.size()){
|
||||
errorstream<<"ShaderSource::getShaderName(): id="<<id
|
||||
<<" >= m_shaderinfo_cache.size()="
|
||||
<<m_shaderinfo_cache.size()<<std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
return m_shaderinfo_cache[id].name;
|
||||
}
|
||||
|
||||
ShaderInfo ShaderSource::getShader(u32 id)
|
||||
{
|
||||
JMutexAutoLock lock(m_shaderinfo_cache_mutex);
|
||||
|
||||
if(id >= m_shaderinfo_cache.size())
|
||||
return ShaderInfo();
|
||||
|
||||
return m_shaderinfo_cache[id];
|
||||
}
|
||||
|
||||
void ShaderSource::processQueue()
|
||||
{
|
||||
/*
|
||||
Fetch shaders
|
||||
*/
|
||||
if(m_get_shader_queue.size() > 0){
|
||||
GetRequest<std::string, u32, u8, u8>
|
||||
request = m_get_shader_queue.pop();
|
||||
|
||||
/*infostream<<"ShaderSource::processQueue(): "
|
||||
<<"got shader request with "
|
||||
<<"name=\""<<request.key<<"\""
|
||||
<<std::endl;*/
|
||||
|
||||
GetResult<std::string, u32, u8, u8>
|
||||
result;
|
||||
result.key = request.key;
|
||||
result.callers = request.callers;
|
||||
result.item = getShaderIdDirect(request.key);
|
||||
|
||||
request.dest->push_back(result);
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderSource::insertSourceShader(const std::string &name_of_shader,
|
||||
const std::string &filename, const std::string &program)
|
||||
{
|
||||
/*infostream<<"ShaderSource::insertSourceShader(): "
|
||||
"name_of_shader=\""<<name_of_shader<<"\", "
|
||||
"filename=\""<<filename<<"\""<<std::endl;*/
|
||||
|
||||
assert(get_current_thread_id() == m_main_thread);
|
||||
|
||||
m_sourcecache.insert(name_of_shader, filename, program, true);
|
||||
}
|
||||
|
||||
void ShaderSource::rebuildShaders()
|
||||
{
|
||||
JMutexAutoLock lock(m_shaderinfo_cache_mutex);
|
||||
|
||||
/*// Oh well... just clear everything, they'll load sometime.
|
||||
m_shaderinfo_cache.clear();
|
||||
m_name_to_id.clear();*/
|
||||
|
||||
/*
|
||||
FIXME: Old shader materials can't be deleted in Irrlicht,
|
||||
or can they?
|
||||
(This would be nice to do in the destructor too)
|
||||
*/
|
||||
|
||||
// Recreate shaders
|
||||
for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
|
||||
ShaderInfo *info = &m_shaderinfo_cache[i];
|
||||
*info = generate_shader(info->name, m_device,
|
||||
m_shader_callback, &m_sourcecache);
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderSource::onSetConstants(video::IMaterialRendererServices *services,
|
||||
bool is_highlevel, const std::string &name)
|
||||
{
|
||||
for(u32 i=0; i<m_global_setters.size(); i++){
|
||||
IShaderConstantSetter *setter = m_global_setters[i];
|
||||
setter->onSetConstants(services, is_highlevel);
|
||||
}
|
||||
}
|
||||
|
||||
ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
|
||||
video::IShaderConstantSetCallBack *callback,
|
||||
SourceShaderCache *sourcecache)
|
||||
{
|
||||
/*infostream<<"generate_shader(): "
|
||||
"\""<<name<<"\""<<std::endl;*/
|
||||
|
||||
ShaderInfo shaderinfo;
|
||||
shaderinfo.name = name;
|
||||
shaderinfo.material = video::EMT_SOLID;
|
||||
|
||||
/*
|
||||
Get the base material
|
||||
*/
|
||||
std::string base_material_name =
|
||||
trim(sourcecache->getOrLoad(name, "base.txt"));
|
||||
for(s32 i = 0; video::sBuiltInMaterialTypeNames[i] != 0; i++){
|
||||
if(video::sBuiltInMaterialTypeNames[i] == base_material_name){
|
||||
shaderinfo.material = (video::E_MATERIAL_TYPE) i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 0 = off, 1 = assembly shaders only, 2 = highlevel or assembly
|
||||
s32 enable_shaders = g_settings->getS32("enable_shaders");
|
||||
if(enable_shaders <= 0)
|
||||
return shaderinfo;
|
||||
|
||||
video::IVideoDriver* driver = device->getVideoDriver();
|
||||
assert(driver);
|
||||
|
||||
video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
|
||||
if(!gpu){
|
||||
errorstream<<"generate_shader(): "
|
||||
"failed to generate \""<<name<<"\", "
|
||||
"GPU programming not supported."
|
||||
<<std::endl;
|
||||
return shaderinfo;
|
||||
}
|
||||
|
||||
// Choose shader language depending on driver type and settings
|
||||
// Then load shaders
|
||||
std::string vertex_program;
|
||||
std::string pixel_program;
|
||||
std::string geometry_program;
|
||||
bool is_highlevel;
|
||||
load_shaders(name, sourcecache, driver->getDriverType(),
|
||||
enable_shaders, vertex_program, pixel_program,
|
||||
geometry_program, is_highlevel);
|
||||
|
||||
// Check hardware/driver support
|
||||
if(vertex_program != "" &&
|
||||
!driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
|
||||
!driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
|
||||
infostream<<"generate_shader(): vertex shaders disabled "
|
||||
"because of missing driver/hardware support."
|
||||
<<std::endl;
|
||||
vertex_program = "";
|
||||
}
|
||||
if(pixel_program != "" &&
|
||||
!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
|
||||
!driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
|
||||
infostream<<"generate_shader(): pixel shaders disabled "
|
||||
"because of missing driver/hardware support."
|
||||
<<std::endl;
|
||||
pixel_program = "";
|
||||
}
|
||||
if(geometry_program != "" &&
|
||||
!driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
|
||||
infostream<<"generate_shader(): geometry shaders disabled "
|
||||
"because of missing driver/hardware support."
|
||||
<<std::endl;
|
||||
geometry_program = "";
|
||||
}
|
||||
|
||||
// If no shaders are used, don't make a separate material type
|
||||
if(vertex_program == "" && pixel_program == "" && geometry_program == "")
|
||||
return shaderinfo;
|
||||
|
||||
// Call addHighLevelShaderMaterial() or addShaderMaterial()
|
||||
const c8* vertex_program_ptr = 0;
|
||||
const c8* pixel_program_ptr = 0;
|
||||
const c8* geometry_program_ptr = 0;
|
||||
if(vertex_program != "")
|
||||
vertex_program_ptr = vertex_program.c_str();
|
||||
if(pixel_program != "")
|
||||
pixel_program_ptr = pixel_program.c_str();
|
||||
if(geometry_program != "")
|
||||
geometry_program_ptr = geometry_program.c_str();
|
||||
s32 shadermat = -1;
|
||||
if(is_highlevel){
|
||||
infostream<<"Compiling high level shaders for "<<name<<std::endl;
|
||||
shadermat = gpu->addHighLevelShaderMaterial(
|
||||
vertex_program_ptr, // Vertex shader program
|
||||
"vertexMain", // Vertex shader entry point
|
||||
video::EVST_VS_1_1, // Vertex shader version
|
||||
pixel_program_ptr, // Pixel shader program
|
||||
"pixelMain", // Pixel shader entry point
|
||||
video::EPST_PS_1_1, // Pixel shader version
|
||||
geometry_program_ptr, // Geometry shader program
|
||||
"geometryMain", // Geometry shader entry point
|
||||
video::EGST_GS_4_0, // Geometry shader version
|
||||
scene::EPT_TRIANGLES, // Geometry shader input
|
||||
scene::EPT_TRIANGLE_STRIP, // Geometry shader output
|
||||
0, // Support maximum number of vertices
|
||||
callback, // Set-constant callback
|
||||
shaderinfo.material, // Base material
|
||||
1 // Userdata passed to callback
|
||||
);
|
||||
|
||||
if(shadermat == -1){
|
||||
errorstream<<"generate_shader(): "
|
||||
"failed to generate \""<<name<<"\", "
|
||||
"addHighLevelShaderMaterial failed."
|
||||
<<std::endl;
|
||||
return shaderinfo;
|
||||
}
|
||||
}
|
||||
else{
|
||||
infostream<<"Compiling assembly shaders for "<<name<<std::endl;
|
||||
shadermat = gpu->addShaderMaterial(
|
||||
vertex_program_ptr, // Vertex shader program
|
||||
pixel_program_ptr, // Pixel shader program
|
||||
callback, // Set-constant callback
|
||||
shaderinfo.material, // Base material
|
||||
0 // Userdata passed to callback
|
||||
);
|
||||
|
||||
if(shadermat == -1){
|
||||
errorstream<<"generate_shader(): "
|
||||
"failed to generate \""<<name<<"\", "
|
||||
"addShaderMaterial failed."
|
||||
<<std::endl;
|
||||
return shaderinfo;
|
||||
}
|
||||
}
|
||||
|
||||
// HACK, TODO: investigate this better
|
||||
// Grab the material renderer once more so minetest doesn't crash on exit
|
||||
driver->getMaterialRenderer(shadermat)->grab();
|
||||
|
||||
// Apply the newly created material type
|
||||
shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
|
||||
return shaderinfo;
|
||||
}
|
||||
|
||||
void load_shaders(std::string name, SourceShaderCache *sourcecache,
|
||||
video::E_DRIVER_TYPE drivertype, s32 enable_shaders,
|
||||
std::string &vertex_program, std::string &pixel_program,
|
||||
std::string &geometry_program, bool &is_highlevel)
|
||||
{
|
||||
vertex_program = "";
|
||||
pixel_program = "";
|
||||
geometry_program = "";
|
||||
is_highlevel = false;
|
||||
|
||||
if(enable_shaders >= 2){
|
||||
// Look for high level shaders
|
||||
if(drivertype == video::EDT_DIRECT3D9){
|
||||
// Direct3D 9: HLSL
|
||||
// (All shaders in one file)
|
||||
vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
|
||||
pixel_program = vertex_program;
|
||||
geometry_program = vertex_program;
|
||||
}
|
||||
else if(drivertype == video::EDT_OPENGL){
|
||||
// OpenGL: GLSL
|
||||
vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
|
||||
pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
|
||||
geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
|
||||
}
|
||||
if(vertex_program != "" || pixel_program != "" || geometry_program != ""){
|
||||
is_highlevel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(enable_shaders >= 1){
|
||||
// Look for assembly shaders
|
||||
if(drivertype == video::EDT_DIRECT3D8){
|
||||
// Direct3D 8 assembly shaders
|
||||
vertex_program = sourcecache->getOrLoad(name, "d3d8_vertex.asm");
|
||||
pixel_program = sourcecache->getOrLoad(name, "d3d8_pixel.asm");
|
||||
}
|
||||
else if(drivertype == video::EDT_DIRECT3D9){
|
||||
// Direct3D 9 assembly shaders
|
||||
vertex_program = sourcecache->getOrLoad(name, "d3d9_vertex.asm");
|
||||
pixel_program = sourcecache->getOrLoad(name, "d3d9_pixel.asm");
|
||||
}
|
||||
else if(drivertype == video::EDT_OPENGL){
|
||||
// OpenGL assembly shaders
|
||||
vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.asm");
|
||||
pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.asm");
|
||||
}
|
||||
if(vertex_program != "" || pixel_program != "")
|
||||
return;
|
||||
}
|
||||
}
|
||||
106
src/shader.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2012 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
Copyright (C) 2012 Kahrl <kahrl@gmx.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef SHADER_HEADER
|
||||
#define SHADER_HEADER
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "threads.h"
|
||||
#include <string>
|
||||
|
||||
class IGameDef;
|
||||
|
||||
/*
|
||||
shader.{h,cpp}: Shader handling stuff.
|
||||
*/
|
||||
|
||||
/*
|
||||
Gets the path to a shader by first checking if the file
|
||||
name_of_shader/filename
|
||||
exists in shader_path and if not, using the data path.
|
||||
|
||||
If not found, returns "".
|
||||
|
||||
Utilizes a thread-safe cache.
|
||||
*/
|
||||
std::string getShaderPath(const std::string &name_of_shader,
|
||||
const std::string &filename);
|
||||
|
||||
struct ShaderInfo
|
||||
{
|
||||
std::string name;
|
||||
video::E_MATERIAL_TYPE material;
|
||||
|
||||
ShaderInfo(): name(""), material(video::EMT_SOLID) {}
|
||||
};
|
||||
|
||||
/*
|
||||
Setter of constants for shaders
|
||||
*/
|
||||
|
||||
namespace irr { namespace video {
|
||||
class IMaterialRendererServices;
|
||||
} }
|
||||
|
||||
class IShaderConstantSetter
|
||||
{
|
||||
public:
|
||||
virtual ~IShaderConstantSetter(){};
|
||||
virtual void onSetConstants(video::IMaterialRendererServices *services,
|
||||
bool is_highlevel) = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
ShaderSource creates and caches shaders.
|
||||
*/
|
||||
|
||||
class IShaderSource
|
||||
{
|
||||
public:
|
||||
IShaderSource(){}
|
||||
virtual ~IShaderSource(){}
|
||||
virtual u32 getShaderId(const std::string &name){return 0;}
|
||||
virtual u32 getShaderIdDirect(const std::string &name){return 0;}
|
||||
virtual std::string getShaderName(u32 id){return "";}
|
||||
virtual ShaderInfo getShader(u32 id){return ShaderInfo();}
|
||||
virtual ShaderInfo getShader(const std::string &name){return ShaderInfo();}
|
||||
};
|
||||
|
||||
class IWritableShaderSource : public IShaderSource
|
||||
{
|
||||
public:
|
||||
IWritableShaderSource(){}
|
||||
virtual ~IWritableShaderSource(){}
|
||||
virtual u32 getShaderId(const std::string &name){return 0;}
|
||||
virtual u32 getShaderIdDirect(const std::string &name){return 0;}
|
||||
virtual std::string getShaderName(u32 id){return "";}
|
||||
virtual ShaderInfo getShader(u32 id){return ShaderInfo();}
|
||||
virtual ShaderInfo getShader(const std::string &name){return ShaderInfo();}
|
||||
|
||||
virtual void processQueue()=0;
|
||||
virtual void insertSourceShader(const std::string &name_of_shader,
|
||||
const std::string &filename, const std::string &program)=0;
|
||||
virtual void rebuildShaders()=0;
|
||||
virtual void addGlobalConstantSetter(IShaderConstantSetter *setter)=0;
|
||||
};
|
||||
|
||||
IWritableShaderSource* createShaderSource(IrrlichtDevice *device);
|
||||
|
||||
#endif
|
||||
92
src/staticobject.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "staticobject.h"
|
||||
#include "util/serialize.h"
|
||||
|
||||
void StaticObject::serialize(std::ostream &os)
|
||||
{
|
||||
char buf[12];
|
||||
// type
|
||||
buf[0] = type;
|
||||
os.write(buf, 1);
|
||||
// pos
|
||||
writeV3S32((u8*)buf, v3s32(pos.X*1000,pos.Y*1000,pos.Z*1000));
|
||||
os.write(buf, 12);
|
||||
// data
|
||||
os<<serializeString(data);
|
||||
}
|
||||
void StaticObject::deSerialize(std::istream &is, u8 version)
|
||||
{
|
||||
char buf[12];
|
||||
// type
|
||||
is.read(buf, 1);
|
||||
type = buf[0];
|
||||
// pos
|
||||
is.read(buf, 12);
|
||||
v3s32 intp = readV3S32((u8*)buf);
|
||||
pos.X = (f32)intp.X/1000;
|
||||
pos.Y = (f32)intp.Y/1000;
|
||||
pos.Z = (f32)intp.Z/1000;
|
||||
// data
|
||||
data = deSerializeString(is);
|
||||
}
|
||||
|
||||
void StaticObjectList::serialize(std::ostream &os)
|
||||
{
|
||||
char buf[12];
|
||||
// version
|
||||
buf[0] = 0;
|
||||
os.write(buf, 1);
|
||||
// count
|
||||
u16 count = m_stored.size() + m_active.size();
|
||||
writeU16((u8*)buf, count);
|
||||
os.write(buf, 2);
|
||||
for(core::list<StaticObject>::Iterator
|
||||
i = m_stored.begin();
|
||||
i != m_stored.end(); i++)
|
||||
{
|
||||
StaticObject &s_obj = *i;
|
||||
s_obj.serialize(os);
|
||||
}
|
||||
for(core::map<u16, StaticObject>::Iterator
|
||||
i = m_active.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
StaticObject s_obj = i.getNode()->getValue();
|
||||
s_obj.serialize(os);
|
||||
}
|
||||
}
|
||||
void StaticObjectList::deSerialize(std::istream &is)
|
||||
{
|
||||
char buf[12];
|
||||
// version
|
||||
is.read(buf, 1);
|
||||
u8 version = buf[0];
|
||||
// count
|
||||
is.read(buf, 2);
|
||||
u16 count = readU16((u8*)buf);
|
||||
for(u16 i=0; i<count; i++)
|
||||
{
|
||||
StaticObject s_obj;
|
||||
s_obj.deSerialize(is, version);
|
||||
m_stored.push_back(s_obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "irrlichttypes_bloated.h"
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include "util/serialize.h"
|
||||
#include "debug.h"
|
||||
|
||||
struct StaticObject
|
||||
{
|
||||
@@ -43,33 +43,8 @@ struct StaticObject
|
||||
{
|
||||
}
|
||||
|
||||
void serialize(std::ostream &os)
|
||||
{
|
||||
char buf[12];
|
||||
// type
|
||||
buf[0] = type;
|
||||
os.write(buf, 1);
|
||||
// pos
|
||||
writeV3S32((u8*)buf, v3s32(pos.X*1000,pos.Y*1000,pos.Z*1000));
|
||||
os.write(buf, 12);
|
||||
// data
|
||||
os<<serializeString(data);
|
||||
}
|
||||
void deSerialize(std::istream &is, u8 version)
|
||||
{
|
||||
char buf[12];
|
||||
// type
|
||||
is.read(buf, 1);
|
||||
type = buf[0];
|
||||
// pos
|
||||
is.read(buf, 12);
|
||||
v3s32 intp = readV3S32((u8*)buf);
|
||||
pos.X = (f32)intp.X/1000;
|
||||
pos.Y = (f32)intp.Y/1000;
|
||||
pos.Z = (f32)intp.Z/1000;
|
||||
// data
|
||||
data = deSerializeString(is);
|
||||
}
|
||||
void serialize(std::ostream &os);
|
||||
void deSerialize(std::istream &is, u8 version);
|
||||
};
|
||||
|
||||
class StaticObjectList
|
||||
@@ -110,47 +85,8 @@ class StaticObjectList
|
||||
m_active.remove(id);
|
||||
}
|
||||
|
||||
void serialize(std::ostream &os)
|
||||
{
|
||||
char buf[12];
|
||||
// version
|
||||
buf[0] = 0;
|
||||
os.write(buf, 1);
|
||||
// count
|
||||
u16 count = m_stored.size() + m_active.size();
|
||||
writeU16((u8*)buf, count);
|
||||
os.write(buf, 2);
|
||||
for(core::list<StaticObject>::Iterator
|
||||
i = m_stored.begin();
|
||||
i != m_stored.end(); i++)
|
||||
{
|
||||
StaticObject &s_obj = *i;
|
||||
s_obj.serialize(os);
|
||||
}
|
||||
for(core::map<u16, StaticObject>::Iterator
|
||||
i = m_active.getIterator();
|
||||
i.atEnd()==false; i++)
|
||||
{
|
||||
StaticObject s_obj = i.getNode()->getValue();
|
||||
s_obj.serialize(os);
|
||||
}
|
||||
}
|
||||
void deSerialize(std::istream &is)
|
||||
{
|
||||
char buf[12];
|
||||
// version
|
||||
is.read(buf, 1);
|
||||
u8 version = buf[0];
|
||||
// count
|
||||
is.read(buf, 2);
|
||||
u16 count = readU16((u8*)buf);
|
||||
for(u16 i=0; i<count; i++)
|
||||
{
|
||||
StaticObject s_obj;
|
||||
s_obj.deSerialize(is, version);
|
||||
m_stored.push_back(s_obj);
|
||||
}
|
||||
}
|
||||
void serialize(std::ostream &os);
|
||||
void deSerialize(std::istream &is);
|
||||
|
||||
/*
|
||||
NOTE: When an object is transformed to active, it is removed
|
||||
|
||||
22
src/test.cpp
@@ -41,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "util/numeric.h"
|
||||
#include "util/serialize.h"
|
||||
#include "noise.h" // PseudoRandom used for random data for compression
|
||||
#include "clientserver.h" // LATEST_PROTOCOL_VERSION
|
||||
|
||||
/*
|
||||
Asserts that the exception occurs
|
||||
@@ -314,6 +315,26 @@ struct TestSerialization: public TestBase
|
||||
}
|
||||
};
|
||||
|
||||
struct TestNodedefSerialization: public TestBase
|
||||
{
|
||||
void Run()
|
||||
{
|
||||
ContentFeatures f;
|
||||
f.name = "default:stone";
|
||||
for(int i = 0; i < 6; i++)
|
||||
f.tiledef[i].name = "default_stone.png";
|
||||
f.is_ground_content = true;
|
||||
std::ostringstream os(std::ios::binary);
|
||||
f.serialize(os, LATEST_PROTOCOL_VERSION);
|
||||
verbosestream<<"Test ContentFeatures size: "<<os.str().size()<<std::endl;
|
||||
std::istringstream is(os.str(), std::ios::binary);
|
||||
ContentFeatures f2;
|
||||
f2.deSerialize(is);
|
||||
UASSERT(f.walkable == f2.walkable);
|
||||
UASSERT(f.node_box.type == f2.node_box.type);
|
||||
}
|
||||
};
|
||||
|
||||
struct TestCompress: public TestBase
|
||||
{
|
||||
void Run()
|
||||
@@ -1736,6 +1757,7 @@ void run_tests()
|
||||
TEST(TestSettings);
|
||||
TEST(TestCompress);
|
||||
TEST(TestSerialization);
|
||||
TEST(TestNodedefSerialization);
|
||||
TESTPARAMS(TestMapNode, ndef);
|
||||
TESTPARAMS(TestVoxelManipulator, ndef);
|
||||
TESTPARAMS(TestVoxelAlgorithms, ndef);
|
||||
|
||||
16
src/tile.cpp
@@ -372,6 +372,18 @@ class TextureSource : public IWritableTextureSource
|
||||
// Update new texture pointer and texture coordinates to an
|
||||
// AtlasPointer based on it's texture id
|
||||
void updateAP(AtlasPointer &ap);
|
||||
|
||||
bool isKnownSourceImage(const std::string &name)
|
||||
{
|
||||
bool is_known = false;
|
||||
bool cache_found = m_source_image_existence.get(name, &is_known);
|
||||
if(cache_found)
|
||||
return is_known;
|
||||
// Not found in cache; find out if a local file exists
|
||||
is_known = (getTexturePath(name) != "");
|
||||
m_source_image_existence.set(name, is_known);
|
||||
return is_known;
|
||||
}
|
||||
|
||||
// Processes queued texture requests from other threads.
|
||||
// Shall be called from the main thread.
|
||||
@@ -400,6 +412,9 @@ class TextureSource : public IWritableTextureSource
|
||||
// This should be only accessed from the main thread
|
||||
SourceImageCache m_sourcecache;
|
||||
|
||||
// Thread-safe cache of what source images are known (true = known)
|
||||
MutexedMap<std::string, bool> m_source_image_existence;
|
||||
|
||||
// A texture id is index in this array.
|
||||
// The first position contains a NULL texture.
|
||||
core::array<SourceAtlasPointer> m_atlaspointer_cache;
|
||||
@@ -781,6 +796,7 @@ void TextureSource::insertSourceImage(const std::string &name, video::IImage *im
|
||||
assert(get_current_thread_id() == m_main_thread);
|
||||
|
||||
m_sourcecache.insert(name, img, true, m_device->getVideoDriver());
|
||||
m_source_image_existence.set(name, true);
|
||||
}
|
||||
|
||||
void TextureSource::rebuildImagesAndTextures()
|
||||
|
||||
50
src/tile.h
@@ -131,6 +131,7 @@ class ITextureSource
|
||||
virtual IrrlichtDevice* getDevice()
|
||||
{return NULL;}
|
||||
virtual void updateAP(AtlasPointer &ap){};
|
||||
virtual bool isKnownSourceImage(const std::string &name)=0;
|
||||
};
|
||||
|
||||
class IWritableTextureSource : public ITextureSource
|
||||
@@ -149,6 +150,7 @@ class IWritableTextureSource : public ITextureSource
|
||||
virtual IrrlichtDevice* getDevice()
|
||||
{return NULL;}
|
||||
virtual void updateAP(AtlasPointer &ap){};
|
||||
virtual bool isKnownSourceImage(const std::string &name)=0;
|
||||
|
||||
virtual void processQueue()=0;
|
||||
virtual void insertSourceImage(const std::string &name, video::IImage *img)=0;
|
||||
@@ -159,10 +161,9 @@ class IWritableTextureSource : public ITextureSource
|
||||
IWritableTextureSource* createTextureSource(IrrlichtDevice *device);
|
||||
|
||||
enum MaterialType{
|
||||
MATERIAL_ALPHA_NONE,
|
||||
MATERIAL_ALPHA_VERTEX,
|
||||
MATERIAL_ALPHA_SIMPLE, // >127 = opaque
|
||||
MATERIAL_ALPHA_BLEND,
|
||||
TILE_MATERIAL_BASIC,
|
||||
TILE_MATERIAL_LIQUID_TRANSPARENT,
|
||||
TILE_MATERIAL_LIQUID_OPAQUE,
|
||||
};
|
||||
|
||||
// Material flags
|
||||
@@ -176,6 +177,8 @@ enum MaterialType{
|
||||
// Animation made up by splitting the texture to vertical frames, as
|
||||
// defined by extra parameters
|
||||
#define MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES 0x08
|
||||
// Whether liquid shader should be used
|
||||
#define MATERIAL_FLAG_
|
||||
|
||||
/*
|
||||
This fully defines the looks of a tile.
|
||||
@@ -186,9 +189,7 @@ struct TileSpec
|
||||
TileSpec():
|
||||
texture(0),
|
||||
alpha(255),
|
||||
//material_type(MATERIAL_ALPHA_NONE),
|
||||
// Use this so that leaves don't need a separate material
|
||||
material_type(MATERIAL_ALPHA_SIMPLE),
|
||||
material_type(TILE_MATERIAL_BASIC),
|
||||
material_flags(
|
||||
//0 // <- DEBUG, Use the one below
|
||||
MATERIAL_FLAG_BACKFACE_CULLING
|
||||
@@ -216,15 +217,34 @@ struct TileSpec
|
||||
// Sets everything else except the texture in the material
|
||||
void applyMaterialOptions(video::SMaterial &material) const
|
||||
{
|
||||
if(material_type == MATERIAL_ALPHA_NONE)
|
||||
material.MaterialType = video::EMT_SOLID;
|
||||
else if(material_type == MATERIAL_ALPHA_VERTEX)
|
||||
material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
|
||||
else if(material_type == MATERIAL_ALPHA_SIMPLE)
|
||||
switch(material_type){
|
||||
case TILE_MATERIAL_BASIC:
|
||||
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
else if(material_type == MATERIAL_ALPHA_BLEND)
|
||||
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
|
||||
break;
|
||||
case TILE_MATERIAL_LIQUID_TRANSPARENT:
|
||||
material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
|
||||
break;
|
||||
case TILE_MATERIAL_LIQUID_OPAQUE:
|
||||
material.MaterialType = video::EMT_SOLID;
|
||||
break;
|
||||
}
|
||||
material.BackfaceCulling = (material_flags & MATERIAL_FLAG_BACKFACE_CULLING) ? true : false;
|
||||
}
|
||||
void applyMaterialOptionsWithShaders(video::SMaterial &material,
|
||||
const video::E_MATERIAL_TYPE &basic,
|
||||
const video::E_MATERIAL_TYPE &liquid) const
|
||||
{
|
||||
switch(material_type){
|
||||
case TILE_MATERIAL_BASIC:
|
||||
material.MaterialType = basic;
|
||||
break;
|
||||
case TILE_MATERIAL_LIQUID_TRANSPARENT:
|
||||
material.MaterialType = liquid;
|
||||
break;
|
||||
case TILE_MATERIAL_LIQUID_OPAQUE:
|
||||
material.MaterialType = liquid;
|
||||
break;
|
||||
}
|
||||
material.BackfaceCulling = (material_flags & MATERIAL_FLAG_BACKFACE_CULLING) ? true : false;
|
||||
}
|
||||
|
||||
|
||||
@@ -107,6 +107,17 @@ class MutexedMap
|
||||
return true;
|
||||
}
|
||||
|
||||
core::list<Value> getValues()
|
||||
{
|
||||
core::list<Value> result;
|
||||
for(typename core::map<Key, Value>::Iterator
|
||||
i = m_values.getIterator();
|
||||
i.atEnd() == false; i++){
|
||||
result.push_back(i.getNode()->getValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
core::map<Key, Value> m_values;
|
||||
JMutex m_mutex;
|
||||
|
||||
@@ -222,7 +222,7 @@ class SharedBuffer
|
||||
/*
|
||||
Copies whole buffer
|
||||
*/
|
||||
SharedBuffer(T *t, unsigned int size)
|
||||
SharedBuffer(const T *t, unsigned int size)
|
||||
{
|
||||
m_size = size;
|
||||
if(m_size != 0)
|
||||
|
||||
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#define UTIL_SERIALIZE_HEADER
|
||||
|
||||
#include "../irrlichttypes.h"
|
||||
#include "../irrlichttypes_bloated.h"
|
||||
#include "../irr_v2d.h"
|
||||
#include "../irr_v3d.h"
|
||||
#include <iostream>
|
||||
@@ -59,7 +60,7 @@ inline void writeU8(u8 *data, u8 i)
|
||||
data[0] = ((i>> 0)&0xff);
|
||||
}
|
||||
|
||||
inline u64 readU64(u8 *data)
|
||||
inline u64 readU64(const u8 *data)
|
||||
{
|
||||
return ((u64)data[0]<<56) | ((u64)data[1]<<48)
|
||||
| ((u64)data[2]<<40) | ((u64)data[3]<<32)
|
||||
@@ -67,17 +68,17 @@ inline u64 readU64(u8 *data)
|
||||
| ((u64)data[6]<<8) | ((u64)data[7]<<0);
|
||||
}
|
||||
|
||||
inline u32 readU32(u8 *data)
|
||||
inline u32 readU32(const u8 *data)
|
||||
{
|
||||
return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);
|
||||
}
|
||||
|
||||
inline u16 readU16(u8 *data)
|
||||
inline u16 readU16(const u8 *data)
|
||||
{
|
||||
return (data[0]<<8) | (data[1]<<0);
|
||||
}
|
||||
|
||||
inline u8 readU8(u8 *data)
|
||||
inline u8 readU8(const u8 *data)
|
||||
{
|
||||
return (data[0]<<0);
|
||||
}
|
||||
@@ -85,28 +86,28 @@ inline u8 readU8(u8 *data)
|
||||
inline void writeS32(u8 *data, s32 i){
|
||||
writeU32(data, (u32)i);
|
||||
}
|
||||
inline s32 readS32(u8 *data){
|
||||
inline s32 readS32(const u8 *data){
|
||||
return (s32)readU32(data);
|
||||
}
|
||||
|
||||
inline void writeS16(u8 *data, s16 i){
|
||||
writeU16(data, (u16)i);
|
||||
}
|
||||
inline s16 readS16(u8 *data){
|
||||
inline s16 readS16(const u8 *data){
|
||||
return (s16)readU16(data);
|
||||
}
|
||||
|
||||
inline void writeS8(u8 *data, s8 i){
|
||||
writeU8(data, (u8)i);
|
||||
}
|
||||
inline s8 readS8(u8 *data){
|
||||
inline s8 readS8(const u8 *data){
|
||||
return (s8)readU8(data);
|
||||
}
|
||||
|
||||
inline void writeF1000(u8 *data, f32 i){
|
||||
writeS32(data, i*1000);
|
||||
}
|
||||
inline f32 readF1000(u8 *data){
|
||||
inline f32 readF1000(const u8 *data){
|
||||
return (f32)readS32(data)/1000.;
|
||||
}
|
||||
|
||||
@@ -116,7 +117,7 @@ inline void writeV3S32(u8 *data, v3s32 p)
|
||||
writeS32(&data[4], p.Y);
|
||||
writeS32(&data[8], p.Z);
|
||||
}
|
||||
inline v3s32 readV3S32(u8 *data)
|
||||
inline v3s32 readV3S32(const u8 *data)
|
||||
{
|
||||
v3s32 p;
|
||||
p.X = readS32(&data[0]);
|
||||
@@ -131,7 +132,7 @@ inline void writeV3F1000(u8 *data, v3f p)
|
||||
writeF1000(&data[4], p.Y);
|
||||
writeF1000(&data[8], p.Z);
|
||||
}
|
||||
inline v3f readV3F1000(u8 *data)
|
||||
inline v3f readV3F1000(const u8 *data)
|
||||
{
|
||||
v3f p;
|
||||
p.X = (float)readF1000(&data[0]);
|
||||
@@ -145,7 +146,7 @@ inline void writeV2F1000(u8 *data, v2f p)
|
||||
writeF1000(&data[0], p.X);
|
||||
writeF1000(&data[4], p.Y);
|
||||
}
|
||||
inline v2f readV2F1000(u8 *data)
|
||||
inline v2f readV2F1000(const u8 *data)
|
||||
{
|
||||
v2f p;
|
||||
p.X = (float)readF1000(&data[0]);
|
||||
@@ -159,7 +160,7 @@ inline void writeV2S16(u8 *data, v2s16 p)
|
||||
writeS16(&data[2], p.Y);
|
||||
}
|
||||
|
||||
inline v2s16 readV2S16(u8 *data)
|
||||
inline v2s16 readV2S16(const u8 *data)
|
||||
{
|
||||
v2s16 p;
|
||||
p.X = readS16(&data[0]);
|
||||
@@ -173,7 +174,7 @@ inline void writeV2S32(u8 *data, v2s32 p)
|
||||
writeS32(&data[2], p.Y);
|
||||
}
|
||||
|
||||
inline v2s32 readV2S32(u8 *data)
|
||||
inline v2s32 readV2S32(const u8 *data)
|
||||
{
|
||||
v2s32 p;
|
||||
p.X = readS32(&data[0]);
|
||||
@@ -188,7 +189,7 @@ inline void writeV3S16(u8 *data, v3s16 p)
|
||||
writeS16(&data[4], p.Z);
|
||||
}
|
||||
|
||||
inline v3s16 readV3S16(u8 *data)
|
||||
inline v3s16 readV3S16(const u8 *data)
|
||||
{
|
||||
v3s16 p;
|
||||
p.X = readS16(&data[0]);
|
||||
@@ -197,6 +198,24 @@ inline v3s16 readV3S16(u8 *data)
|
||||
return p;
|
||||
}
|
||||
|
||||
inline void writeARGB8(u8 *data, video::SColor p)
|
||||
{
|
||||
writeU8(&data[0], p.getAlpha());
|
||||
writeU8(&data[1], p.getRed());
|
||||
writeU8(&data[2], p.getGreen());
|
||||
writeU8(&data[3], p.getBlue());
|
||||
}
|
||||
|
||||
inline video::SColor readARGB8(const u8 *data)
|
||||
{
|
||||
video::SColor p;
|
||||
p.setAlpha(readU8(&data[0]));
|
||||
p.setRed(readU8(&data[1]));
|
||||
p.setGreen(readU8(&data[2]));
|
||||
p.setBlue(readU8(&data[3]));
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
The above stuff directly interfaced to iostream
|
||||
*/
|
||||
@@ -344,6 +363,20 @@ inline v3s16 readV3S16(std::istream &is)
|
||||
return readV3S16((u8*)buf);
|
||||
}
|
||||
|
||||
inline void writeARGB8(std::ostream &os, video::SColor p)
|
||||
{
|
||||
char buf[4] = {0};
|
||||
writeARGB8((u8*)buf, p);
|
||||
os.write(buf, 4);
|
||||
}
|
||||
|
||||
inline video::SColor readARGB8(std::istream &is)
|
||||
{
|
||||
char buf[4] = {0};
|
||||
is.read(buf, 4);
|
||||
return readARGB8((u8*)buf);
|
||||
}
|
||||
|
||||
/*
|
||||
More serialization stuff
|
||||
*/
|
||||
|
||||