diff --git a/builtin/chatcommands.lua b/builtin/chatcommands.lua index 03c278d4..f8df83d8 100644 --- a/builtin/chatcommands.lua +++ b/builtin/chatcommands.lua @@ -261,9 +261,12 @@ minetest.register_chatcommand("teleport", { } for _, d in ipairs(tries) do local p = {x = pos.x+d.x, y = pos.y+d.y, z = pos.z+d.z} - local n = minetest.get_node(p) - if not minetest.registered_nodes[n.name].walkable then - return p, true + local n = minetest.get_node_or_nil(p) + if n and n.name then + local def = minetest.registered_nodes[n.name] + if def and not def.walkable then + return p, true + end end end return pos, false diff --git a/builtin/item.lua b/builtin/item.lua index de546c2e..002c14f5 100644 --- a/builtin/item.lua +++ b/builtin/item.lua @@ -367,7 +367,7 @@ function minetest.node_punch(pos, node, puncher, pointed_thing) -- Copy pos and node because callback can modify them local pos_copy = vector.new(pos) local node_copy = {name=node.name, param1=node.param1, param2=node.param2} - local pointed_thing_copy = copy_pointed_thing(pointed_thing) + local pointed_thing_copy = pointed_thing and copy_pointed_thing(pointed_thing) or nil callback(pos_copy, node_copy, puncher, pointed_thing_copy) end end diff --git a/builtin/item_entity.lua b/builtin/item_entity.lua index 95affe3d..0dcc2dc2 100644 --- a/builtin/item_entity.lua +++ b/builtin/item_entity.lua @@ -116,6 +116,7 @@ minetest.register_entity("__builtin:item", { return end end + self.itemstring = '' self.object:remove() end, }) diff --git a/builtin/mainmenu.lua b/builtin/mainmenu.lua index f2649443..4cd1503d 100644 --- a/builtin/mainmenu.lua +++ b/builtin/mainmenu.lua @@ -176,7 +176,7 @@ function update_menu() -- handle errors if gamedata.errormessage ~= nil then - formspec = "size[12,5.2]" .. + formspec = "size[12,5.2,true]" .. "textarea[1,2;10,2;;ERROR: " .. engine.formspec_escape(gamedata.errormessage) .. ";]".. @@ -365,7 +365,7 @@ end function tabbuilder.gettab() local tsize = tabbuilder.tabsizes[tabbuilder.current_tab] or {width=12, height=5.2} - local retval = "size[" .. tsize.width .. "," .. tsize.height .. "]" + local retval = "size[" .. tsize.width .. "," .. tsize.height .. ",true]" if tabbuilder.show_buttons then retval = retval .. tabbuilder.tab_header() @@ -714,15 +714,15 @@ function tabbuilder.handle_settings_buttons(fields) if fields["cb_particles"] then engine.setting_set("enable_particles", fields["cb_particles"]) end - if fields["cb_finite_liquid"] then - engine.setting_set("liquid_finite", fields["cb_finite_liquid"]) - end if fields["cb_bumpmapping"] then engine.setting_set("enable_bumpmapping", fields["cb_bumpmapping"]) end if fields["cb_parallax"] then engine.setting_set("enable_parallax_occlusion", fields["cb_parallax"]) end + if fields["cb_generate_normalmaps"] then + engine.setting_set("generate_normalmaps", fields["cb_generate_normalmaps"]) + end if fields["cb_waving_water"] then engine.setting_set("enable_waving_water", fields["cb_waving_water"]) end @@ -994,9 +994,6 @@ function tabbuilder.tab_settings() .. dump(engine.setting_getbool("preload_item_visuals")) .. "]".. "checkbox[1,2.5;cb_particles;".. fgettext("Enable Particles") .. ";" .. dump(engine.setting_getbool("enable_particles")) .. "]".. - "checkbox[1,3.0;cb_finite_liquid;".. fgettext("Finite Liquid") .. ";" - .. dump(engine.setting_getbool("liquid_finite")) .. "]".. - "checkbox[4.5,0;cb_mipmapping;".. fgettext("Mip-Mapping") .. ";" .. dump(engine.setting_getbool("mip_map")) .. "]".. "checkbox[4.5,0.5;cb_anisotrophic;".. fgettext("Anisotropic Filtering") .. ";" @@ -1010,27 +1007,30 @@ function tabbuilder.tab_settings() .. dump(engine.setting_getbool("enable_shaders")) .. "]".. "button[1,4.5;2.25,0.5;btn_change_keys;".. fgettext("Change keys") .. "]" -if engine.setting_getbool("enable_shaders") then - tab_string = tab_string .. + if engine.setting_getbool("enable_shaders") then + tab_string = tab_string .. "checkbox[8,0.5;cb_bumpmapping;".. fgettext("Bumpmapping") .. ";" .. dump(engine.setting_getbool("enable_bumpmapping")) .. "]".. "checkbox[8,1.0;cb_parallax;".. fgettext("Parallax Occlusion") .. ";" .. dump(engine.setting_getbool("enable_parallax_occlusion")) .. "]".. - "checkbox[8,1.5;cb_waving_water;".. fgettext("Waving Water") .. ";" + "checkbox[8,1.5;cb_generate_normalmaps;".. fgettext("Generate Normalmaps") .. ";" + .. dump(engine.setting_getbool("generate_normalmaps")) .. "]".. + "checkbox[8,2.0;cb_waving_water;".. fgettext("Waving Water") .. ";" .. dump(engine.setting_getbool("enable_waving_water")) .. "]".. - "checkbox[8,2.0;cb_waving_leaves;".. fgettext("Waving Leaves") .. ";" + "checkbox[8,2.5;cb_waving_leaves;".. fgettext("Waving Leaves") .. ";" .. dump(engine.setting_getbool("enable_waving_leaves")) .. "]".. - "checkbox[8,2.5;cb_waving_plants;".. fgettext("Waving Plants") .. ";" + "checkbox[8,3.0;cb_waving_plants;".. fgettext("Waving Plants") .. ";" .. dump(engine.setting_getbool("enable_waving_plants")) .. "]" -else - tab_string = tab_string .. + else + tab_string = tab_string .. "textlist[8.33,0.7;4,1;;#888888" .. fgettext("Bumpmapping") .. ";0;true]" .. "textlist[8.33,1.2;4,1;;#888888" .. fgettext("Parallax Occlusion") .. ";0;true]" .. - "textlist[8.33,1.7;4,1;;#888888" .. fgettext("Waving Water") .. ";0;true]" .. - "textlist[8.33,2.2;4,1;;#888888" .. fgettext("Waving Leaves") .. ";0;true]" .. - "textlist[8.33,2.7;4,1;;#888888" .. fgettext("Waving Plants") .. ";0;true]" + "textlist[8.33,1.7;4,1;;#888888" .. fgettext("Generate Normalmaps") .. ";0;true]" .. + "textlist[8.33,2.2;4,1;;#888888" .. fgettext("Waving Water") .. ";0;true]" .. + "textlist[8.33,2.7;4,1;;#888888" .. fgettext("Waving Leaves") .. ";0;true]" .. + "textlist[8.33,3.2;4,1;;#888888" .. fgettext("Waving Plants") .. ";0;true]" end -return tab_string + return tab_string end -------------------------------------------------------------------------------- diff --git a/builtin/misc.lua b/builtin/misc.lua index 1d5e146c..f91f5e09 100644 --- a/builtin/misc.lua +++ b/builtin/misc.lua @@ -21,6 +21,8 @@ minetest.register_globalstep(function(dtime) end) function minetest.after(time, func, ...) + assert(tonumber(time) and type(func) == "function", + "Invalid minetest.after invocation") table.insert(minetest.timers_to_add, {time=time, func=func, args={...}}) end diff --git a/builtin/modmgr.lua b/builtin/modmgr.lua index 11434ab3..eeb65add 100644 --- a/builtin/modmgr.lua +++ b/builtin/modmgr.lua @@ -422,7 +422,7 @@ function modmgr.dialog_configure_world() local mod = filterlist.get_list(modmgr.modlist)[modmgr.world_config_selected_mod] local retval = - "size[11,6.5]" .. + "size[11,6.5,true]" .. "label[0.5,-0.25;" .. fgettext("World:") .. "]" .. "label[1.75,-0.25;" .. worldspec.name .. "]" diff --git a/builtin/modstore.lua b/builtin/modstore.lua index 43d8d7e2..ef7fd016 100644 --- a/builtin/modstore.lua +++ b/builtin/modstore.lua @@ -98,7 +98,7 @@ end -- @function [parent=#modstore] getsuccessfuldialog function modstore.getsuccessfuldialog() local retval = "" - retval = retval .. "size[6,2]" + retval = retval .. "size[6,2,true]" if modstore.lastmodentry ~= nil then retval = retval .. "label[0,0.25;" .. fgettext("Successfully installed:") .. "]" retval = retval .. "label[3,0.25;" .. modstore.lastmodentry.moddetails.title .. "]" @@ -152,7 +152,7 @@ end -------------------------------------------------------------------------------- -- @function [parent=#modstore] tabheader function modstore.tabheader(tabname) - local retval = "size[12,10.25]" + local retval = "size[12,10.25,true]" retval = retval .. "tabheader[-0.3,-0.99;modstore_tab;" .. "Unsorted,Search;" .. modstore.nametoindex(tabname) .. ";true;false]" .. diff --git a/client/shaders/alpha_shader/opengl_fragment.glsl b/client/shaders/alpha_shader/opengl_fragment.glsl index 6ed00be2..4359a8c8 100644 --- a/client/shaders/alpha_shader/opengl_fragment.glsl +++ b/client/shaders/alpha_shader/opengl_fragment.glsl @@ -1,71 +1,110 @@ -uniform sampler2D baseTexture; -uniform sampler2D normalTexture; -uniform sampler2D useNormalmap; - -uniform vec4 skyBgColor; -uniform float fogDistance; -uniform vec3 eyePosition; - -varying vec3 vPosition; -varying vec3 eyeVec; - -#ifdef ENABLE_PARALLAX_OCCLUSION -varying vec3 tsEyeVec; -#endif - -const float e = 2.718281828459; - -void main (void) -{ - vec3 color; - vec2 uv = gl_TexCoord[0].st; - -#ifdef USE_NORMALMAPS - float use_normalmap = texture2D(useNormalmap,vec2(1.0,1.0)).r; -#endif - -#ifdef ENABLE_PARALLAX_OCCLUSION - float height; - vec2 tsEye = vec2(tsEyeVec.x,-tsEyeVec.y); - - if (use_normalmap > 0.0) { - float map_height = texture2D(normalTexture, uv).a; - if (map_height < 1.0){ - float height = PARALLAX_OCCLUSION_SCALE * map_height - PARALLAX_OCCLUSION_BIAS; - uv = uv + height * tsEye; - } - } -#endif - -#ifdef ENABLE_BUMPMAPPING - if (use_normalmap > 0.0) { - vec3 base = texture2D(baseTexture, uv).rgb; - vec3 vVec = normalize(eyeVec); - vec3 bump = normalize(texture2D(normalTexture, uv).xyz * 2.0 - 1.0); - vec3 R = reflect(-vVec, bump); - vec3 lVec = normalize(vVec); - float diffuse = max(dot(lVec, bump), 0.0); - float specular = pow(clamp(dot(R, lVec), 0.0, 1.0),1.0); - color = mix (base,diffuse*base,1.0) + 0.1 * specular * diffuse; - } else { - color = texture2D(baseTexture, uv).rgb; - } -#else - color = texture2D(baseTexture, uv).rgb; -#endif - - float alpha = texture2D(baseTexture, uv).a; - vec4 col = vec4(color.r, color.g, color.b, alpha); - col *= gl_Color; - col = col * col; // SRGB -> Linear - col *= 1.8; - col.r = 1.0 - exp(1.0 - col.r) / e; - col.g = 1.0 - exp(1.0 - col.g) / e; - col.b = 1.0 - exp(1.0 - col.b) / e; - 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, alpha); -} +uniform sampler2D baseTexture; +uniform sampler2D normalTexture; +uniform sampler2D useNormalmap; + +uniform vec4 skyBgColor; +uniform float fogDistance; +uniform vec3 eyePosition; + +varying vec3 vPosition; +varying vec3 worldPosition; + +varying vec3 eyeVec; +varying vec3 tsEyeVec; +varying vec3 lightVec; +varying vec3 tsLightVec; + +bool normalTexturePresent = false; + +const float e = 2.718281828459; + +float intensity (vec3 color){ + return (color.r + color.g + color.b) / 3.0; +} + +float get_rgb_height (vec2 uv){ + return intensity(texture2D(baseTexture,uv).rgb); +} + +vec4 get_normal_map(vec2 uv){ + vec4 bump = texture2D(normalTexture, uv).rgba; + bump.xyz = normalize(bump.xyz * 2.0 -1.0); + bump.y = -bump.y; + return bump; +} + +void main (void) +{ + vec3 color; + vec4 bump; + vec2 uv = gl_TexCoord[0].st; + bool use_normalmap = false; + +#ifdef USE_NORMALMAPS + if (texture2D(useNormalmap,vec2(1.0,1.0)).r > 0.0){ + normalTexturePresent = true; + } +#endif + +#ifdef ENABLE_PARALLAX_OCCLUSION + if (normalTexturePresent){ + vec3 tsEye = normalize(tsEyeVec); + float height = PARALLAX_OCCLUSION_SCALE * texture2D(normalTexture, uv).a - PARALLAX_OCCLUSION_BIAS; + uv = uv + texture2D(normalTexture, uv).z * height * vec2(tsEye.x,-tsEye.y); + } +#endif + +#ifdef USE_NORMALMAPS + if (normalTexturePresent){ + bump = get_normal_map(uv); + use_normalmap = true; + } +#endif + +#ifdef GENERATE_NORMALMAPS + if (use_normalmap == false){ + float tl = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y+SAMPLE_STEP)); + float t = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y-SAMPLE_STEP)); + float tr = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y+SAMPLE_STEP)); + float r = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y)); + float br = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y-SAMPLE_STEP)); + float b = get_rgb_height (vec2(uv.x,uv.y-SAMPLE_STEP)); + float bl = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y-SAMPLE_STEP)); + float l = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y)); + float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl); + float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr); + bump = vec4 (normalize(vec3 (dX, -dY, NORMALMAPS_STRENGTH)),1.0); + use_normalmap = true; + } +#endif + +vec4 base = texture2D(baseTexture, uv).rgba; + +#ifdef ENABLE_BUMPMAPPING + if (use_normalmap){ + vec3 L = normalize(lightVec); + vec3 E = normalize(eyeVec); + float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0),0.5); + float diffuse = dot(E,bump.xyz); + color = 0.05*base.rgb + diffuse*base.rgb + 0.2*specular*base.rgb; + } else { + color = base.rgb; + } +#else + color = base.rgb; +#endif + + vec4 col = vec4(color.rgb, base.a); + col = col * col; // SRGB -> Linear + col *= 1.8; + col.r = 1.0 - exp(1.0 - col.r) / e; + col.g = 1.0 - exp(1.0 - col.g) / e; + col.b = 1.0 - exp(1.0 - col.b) / e; + col = sqrt(col); // Linear -> SRGB + col *= gl_Color; + 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.rgb, base.a); +} diff --git a/client/shaders/alpha_shader/opengl_vertex.glsl b/client/shaders/alpha_shader/opengl_vertex.glsl index e359955d..356ba2eb 100644 --- a/client/shaders/alpha_shader/opengl_vertex.glsl +++ b/client/shaders/alpha_shader/opengl_vertex.glsl @@ -1,27 +1,33 @@ uniform mat4 mWorldViewProj; uniform mat4 mInvWorld; uniform mat4 mTransWorld; +uniform mat4 mWorld; + uniform float dayNightRatio; uniform vec3 eyePosition; varying vec3 vPosition; -varying vec3 eyeVec; +varying vec3 worldPosition; + +varying vec3 eyeVec; +varying vec3 lightVec; -#ifdef ENABLE_PARALLAX_OCCLUSION varying vec3 tsEyeVec; -#endif +varying vec3 tsLightVec; + +const float BS = 10.0; void main(void) { + gl_TexCoord[0] = gl_MultiTexCoord0; gl_Position = mWorldViewProj * gl_Vertex; - vPosition = (mWorldViewProj * gl_Vertex).xyz; - eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz; + vPosition = gl_Position.xyz; + worldPosition = (mWorld * gl_Vertex).xyz; + vec3 sunPosition = vec3 (0.0, eyePosition.y * BS + 900.0, 0.0); -#ifdef ENABLE_PARALLAX_OCCLUSION - vec3 normal,tangent,binormal; + vec3 normal, tangent, binormal; normal = normalize(gl_NormalMatrix * gl_Normal); - if (gl_Normal.x > 0.5) { // 1.0, 0.0, 0.0 tangent = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, -1.0)); @@ -47,25 +53,20 @@ void main(void) tangent = normalize(gl_NormalMatrix * vec3(-1.0, 0.0, 0.0)); binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0)); } - mat3 tbnMatrix = mat3( tangent.x, binormal.x, normal.x, tangent.y, binormal.y, normal.y, tangent.z, binormal.z, normal.z); - tsEyeVec = normalize(eyeVec * tbnMatrix); -#endif + lightVec = sunPosition - worldPosition; + tsLightVec = lightVec * tbnMatrix; + eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz; + tsEyeVec = eyeVec * tbnMatrix; 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 * 2.5; // Make light sources brighter float b = rg; @@ -90,13 +91,8 @@ void main(void) 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; - } diff --git a/client/shaders/leaves_shader/opengl_fragment.glsl b/client/shaders/leaves_shader/opengl_fragment.glsl index 31981f9b..1db79807 100644 --- a/client/shaders/leaves_shader/opengl_fragment.glsl +++ b/client/shaders/leaves_shader/opengl_fragment.glsl @@ -1,54 +1,100 @@ -uniform sampler2D baseTexture; -uniform sampler2D normalTexture; -uniform sampler2D useNormalmap; - -uniform vec4 skyBgColor; -uniform float fogDistance; -uniform vec3 eyePosition; - -varying vec3 vPosition; -varying vec3 eyeVec; - -const float e = 2.718281828459; - -void main (void) -{ - vec3 color; - vec2 uv = gl_TexCoord[0].st; - -#ifdef USE_NORMALMAPS - float use_normalmap = texture2D(useNormalmap,vec2(1.0,1.0)).r; -#endif - -#ifdef ENABLE_BUMPMAPPING - if (use_normalmap > 0.0) { - vec3 base = texture2D(baseTexture, uv).rgb; - vec3 vVec = normalize(eyeVec); - vec3 bump = normalize(texture2D(normalTexture, uv).xyz * 2.0 - 1.0); - vec3 R = reflect(-vVec, bump); - vec3 lVec = normalize(vVec); - float diffuse = max(dot(lVec, bump), 0.0); - float specular = pow(clamp(dot(R, lVec), 0.0, 1.0),1.0); - color = mix (base,diffuse*base,1.0) + 0.1 * specular * diffuse; - } else { - color = texture2D(baseTexture, uv).rgb; - } -#else - color = texture2D(baseTexture, uv).rgb; -#endif - - float alpha = texture2D(baseTexture, uv).a; - vec4 col = vec4(color.r, color.g, color.b, alpha); - col *= gl_Color; - col = col * col; // SRGB -> Linear - col *= 1.8; - col.r = 1.0 - exp(1.0 - col.r) / e; - col.g = 1.0 - exp(1.0 - col.g) / e; - col.b = 1.0 - exp(1.0 - col.b) / e; - 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, alpha); -} +uniform sampler2D baseTexture; +uniform sampler2D normalTexture; +uniform sampler2D useNormalmap; + +uniform vec4 skyBgColor; +uniform float fogDistance; +uniform vec3 eyePosition; + +varying vec3 vPosition; +varying vec3 worldPosition; + +varying vec3 eyeVec; +varying vec3 lightVec; + +bool normalTexturePresent = false; + +const float e = 2.718281828459; + +float intensity (vec3 color){ + return (color.r + color.g + color.b) / 3.0; +} + +float get_rgb_height (vec2 uv){ + return intensity(texture2D(baseTexture,uv).rgb); +} + +vec4 get_normal_map(vec2 uv){ + vec4 bump = texture2D(normalTexture, uv).rgba; + bump.xyz = normalize(bump.xyz * 2.0 -1.0); + bump.y = -bump.y; + return bump; +} + +void main (void) +{ + vec3 color; + vec4 bump; + vec2 uv = gl_TexCoord[0].st; + bool use_normalmap = false; + +#ifdef USE_NORMALMAPS + if (texture2D(useNormalmap,vec2(1.0,1.0)).r > 0.0){ + normalTexturePresent = true; + } +#endif + +#ifdef USE_NORMALMAPS + if (normalTexturePresent){ + bump = get_normal_map(uv); + use_normalmap = true; + } +#endif + +#ifdef GENERATE_NORMALMAPS + if (use_normalmap == false){ + float tl = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y+SAMPLE_STEP)); + float t = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y-SAMPLE_STEP)); + float tr = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y+SAMPLE_STEP)); + float r = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y)); + float br = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y-SAMPLE_STEP)); + float b = get_rgb_height (vec2(uv.x,uv.y-SAMPLE_STEP)); + float bl = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y-SAMPLE_STEP)); + float l = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y)); + float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl); + float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr); + bump = vec4 (normalize(vec3 (dX, -dY, NORMALMAPS_STRENGTH)),1.0); + use_normalmap = true; + } +#endif + +vec4 base = texture2D(baseTexture, uv).rgba; + +#ifdef ENABLE_BUMPMAPPING + if (use_normalmap){ + vec3 L = normalize(lightVec); + vec3 E = normalize(eyeVec); + float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0),0.5); + float diffuse = dot(E,bump.xyz); + color = 0.05*base.rgb + diffuse*base.rgb + 0.2*specular*base.rgb; + } else { + color = base.rgb; + } +#else + color = base.rgb; +#endif + + vec4 col = vec4(color.rgb, base.a); + col = col * col; // SRGB -> Linear + col *= 1.8; + col.r = 1.0 - exp(1.0 - col.r) / e; + col.g = 1.0 - exp(1.0 - col.g) / e; + col.b = 1.0 - exp(1.0 - col.b) / e; + col = sqrt(col); // Linear -> SRGB + col *= gl_Color; + 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.rgb, base.a); +} diff --git a/client/shaders/leaves_shader/opengl_vertex.glsl b/client/shaders/leaves_shader/opengl_vertex.glsl index 3702b1b5..30ad00b8 100644 --- a/client/shaders/leaves_shader/opengl_vertex.glsl +++ b/client/shaders/leaves_shader/opengl_vertex.glsl @@ -1,13 +1,20 @@ uniform mat4 mWorldViewProj; uniform mat4 mInvWorld; uniform mat4 mTransWorld; +uniform mat4 mWorld; + uniform float dayNightRatio; uniform float animationTimer; uniform vec3 eyePosition; varying vec3 vPosition; +varying vec3 worldPosition; + varying vec3 eyeVec; +varying vec3 lightVec; + +const float BS = 10.0; #ifdef ENABLE_WAVING_LEAVES float smoothCurve( float x ) { @@ -27,7 +34,7 @@ void main(void) #ifdef ENABLE_WAVING_LEAVES vec4 pos = gl_Vertex; - vec4 pos2 = mTransWorld*gl_Vertex; + vec4 pos2 = mWorld*gl_Vertex; pos.x += (smoothTriangleWave(animationTimer*10.0 + pos2.x * 0.01 + pos2.z * 0.01) * 2.0 - 1.0) * 0.4; pos.y += (smoothTriangleWave(animationTimer*15.0 + pos2.x * -0.01 + pos2.z * -0.01) * 2.0 - 1.0) * 0.2; pos.z += (smoothTriangleWave(animationTimer*10.0 + pos2.x * -0.01 + pos2.z * -0.01) * 2.0 - 1.0) * 0.4; @@ -36,10 +43,13 @@ void main(void) gl_Position = mWorldViewProj * gl_Vertex; #endif - vPosition = (mWorldViewProj * gl_Vertex).xyz; + vPosition = gl_Position.xyz; + worldPosition = (mWorld * gl_Vertex).xyz; + vec3 sunPosition = vec3 (0.0, eyePosition.y * BS + 900.0, 0.0); + lightVec = sunPosition - worldPosition; eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz; - + vec4 color; //color = vec4(1.0, 1.0, 1.0, 1.0); @@ -75,13 +85,8 @@ void main(void) 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; - } diff --git a/client/shaders/liquids_shader/opengl_fragment.glsl b/client/shaders/liquids_shader/opengl_fragment.glsl index cab8d8e0..5bc932ad 100644 --- a/client/shaders/liquids_shader/opengl_fragment.glsl +++ b/client/shaders/liquids_shader/opengl_fragment.glsl @@ -1,54 +1,95 @@ -uniform sampler2D baseTexture; -uniform sampler2D normalTexture; -uniform sampler2D useNormalmap; - -uniform vec4 skyBgColor; -uniform float fogDistance; -uniform vec3 eyePosition; - -varying vec3 vPosition; -varying vec3 eyeVec; - -const float e = 2.718281828459; - -void main (void) -{ - vec3 color; - vec2 uv = gl_TexCoord[0].st; - -#ifdef USE_NORMALMAPS - float use_normalmap = texture2D(useNormalmap,vec2(1.0,1.0)).r; -#endif - -#ifdef ENABLE_BUMPMAPPING - if (use_normalmap > 0.0) { - vec3 base = texture2D(baseTexture, uv).rgb; - vec3 vVec = normalize(eyeVec); - vec3 bump = normalize(texture2D(normalTexture, uv).xyz * 2.0 - 1.0); - vec3 R = reflect(-vVec, bump); - vec3 lVec = normalize(vVec); - float diffuse = max(dot(vec3(-1.0, -0.4, 0.5), bump), 0.0); - float specular = pow(clamp(dot(R, lVec), 0.0, 1.0),1.0); - color = mix (base,diffuse*base,1.0) + 0.1 * specular * diffuse; - } else { - color = texture2D(baseTexture, uv).rgb; - } -#else - color = texture2D(baseTexture, uv).rgb; -#endif - - float alpha = gl_Color.a; - vec4 col = vec4(color.r, color.g, color.b, alpha); - col *= gl_Color; - col = col * col; // SRGB -> Linear - col *= 1.8; - col.r = 1.0 - exp(1.0 - col.r) / e; - col.g = 1.0 - exp(1.0 - col.g) / e; - col.b = 1.0 - exp(1.0 - col.b) / e; - col = sqrt(col); // Linear -> SRGB - if(fogDistance != 0.0){ - float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0)); - alpha = mix(alpha, 0.0, d); - } - gl_FragColor = vec4(col.r, col.g, col.b, alpha); -} +uniform sampler2D baseTexture; +uniform sampler2D normalTexture; +uniform sampler2D useNormalmap; + +uniform vec4 skyBgColor; +uniform float fogDistance; +uniform vec3 eyePosition; + +varying vec3 vPosition; +varying vec3 worldPosition; + +varying vec3 eyeVec; +varying vec3 tsEyeVec; +varying vec3 lightVec; +varying vec3 tsLightVec; + +const float e = 2.718281828459; + +float intensity (vec3 color){ + return (color.r + color.g + color.b) / 3.0; +} + +float get_rgb_height (vec2 uv){ + return intensity(texture2D(baseTexture,uv).rgb); +} + +vec4 get_normal_map(vec2 uv){ + vec4 bump = texture2D(normalTexture, uv).rgba; + bump.xyz = normalize(bump.xyz * 2.0 -1.0); + bump.y = -bump.y; + return bump; +} + +void main (void) +{ + vec3 color; + vec4 bump; + vec2 uv = gl_TexCoord[0].st; + bool use_normalmap = false; + +#ifdef USE_NORMALMAPS + if (texture2D(useNormalmap,vec2(1.0,1.0)).r > 0.0){ + bump = get_normal_map(uv); + use_normalmap = true; + } +#endif + +#ifdef GENERATE_NORMALMAPS + if (use_normalmap == false){ + float tl = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y+SAMPLE_STEP)); + float t = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y-SAMPLE_STEP)); + float tr = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y+SAMPLE_STEP)); + float r = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y)); + float br = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y-SAMPLE_STEP)); + float b = get_rgb_height (vec2(uv.x,uv.y-SAMPLE_STEP)); + float bl = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y-SAMPLE_STEP)); + float l = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y)); + float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl); + float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr); + bump = vec4 (normalize(vec3 (dX, -dY, NORMALMAPS_STRENGTH)),1.0); + use_normalmap = true; + } +#endif + +vec4 base = texture2D(baseTexture, uv).rgba; + +#ifdef ENABLE_BUMPMAPPING + if (use_normalmap){ + vec3 L = normalize(lightVec); + vec3 E = normalize(eyeVec); + float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0),0.5); + float diffuse = dot(E,bump.xyz); + color = 0.05*base.rgb + diffuse*base.rgb + 0.2*specular*base.rgb; + } else { + color = base.rgb; + } +#else + color = base.rgb; +#endif + + float alpha = gl_Color.a; + vec4 col = vec4(color.rgb, alpha); + col = col * col; // SRGB -> Linear + col *= 1.8; + col.r = 1.0 - exp(1.0 - col.r) / e; + col.g = 1.0 - exp(1.0 - col.g) / e; + col.b = 1.0 - exp(1.0 - col.b) / e; + col = sqrt(col); // Linear -> SRGB + col *= gl_Color; + if(fogDistance != 0.0){ + float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0)); + alpha = mix(alpha, 0.0, d); + } + gl_FragColor = vec4(col.rgb, alpha); +} diff --git a/client/shaders/liquids_shader/opengl_vertex.glsl b/client/shaders/liquids_shader/opengl_vertex.glsl index e8f18582..9d64ce4e 100644 --- a/client/shaders/liquids_shader/opengl_vertex.glsl +++ b/client/shaders/liquids_shader/opengl_vertex.glsl @@ -1,40 +1,84 @@ uniform mat4 mWorldViewProj; uniform mat4 mInvWorld; uniform mat4 mTransWorld; +uniform mat4 mWorld; + uniform float dayNightRatio; uniform float animationTimer; uniform vec3 eyePosition; varying vec3 vPosition; +varying vec3 worldPosition; + varying vec3 eyeVec; +varying vec3 lightVec; + +varying vec3 tsEyeVec; +varying vec3 tsLightVec; + +const float BS = 10.0; void main(void) { + gl_TexCoord[0] = gl_MultiTexCoord0; + #ifdef ENABLE_WAVING_WATER vec4 pos2 = gl_Vertex; pos2.y -= 2.0; pos2.y -= sin (pos2.z/WATER_WAVE_LENGTH + animationTimer * WATER_WAVE_SPEED * WATER_WAVE_LENGTH) * WATER_WAVE_HEIGHT + sin ((pos2.z/WATER_WAVE_LENGTH + animationTimer * WATER_WAVE_SPEED * WATER_WAVE_LENGTH) / 7.0) * WATER_WAVE_HEIGHT; gl_Position = mWorldViewProj * pos2; + vPosition = gl_Position.xyz; #else gl_Position = mWorldViewProj * gl_Vertex; + vPosition = gl_Position.xyz; #endif + worldPosition = (mWorld * gl_Vertex).xyz; + vec3 sunPosition = vec3 (0.0, eyePosition.y * BS + 900.0, 0.0); + + vec3 normal, tangent, binormal; + normal = normalize(gl_NormalMatrix * gl_Normal); + if (gl_Normal.x > 0.5) { + // 1.0, 0.0, 0.0 + tangent = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, -1.0)); + binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0)); + } else if (gl_Normal.x < -0.5) { + // -1.0, 0.0, 0.0 + tangent = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, 1.0)); + binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0)); + } else if (gl_Normal.y > 0.5) { + // 0.0, 1.0, 0.0 + tangent = normalize(gl_NormalMatrix * vec3( 1.0, 0.0, 0.0)); + binormal = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, 1.0)); + } else if (gl_Normal.y < -0.5) { + // 0.0, -1.0, 0.0 + tangent = normalize(gl_NormalMatrix * vec3( 1.0, 0.0, 0.0)); + binormal = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, 1.0)); + } else if (gl_Normal.z > 0.5) { + // 0.0, 0.0, 1.0 + tangent = normalize(gl_NormalMatrix * vec3( 1.0, 0.0, 0.0)); + binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0)); + } else if (gl_Normal.z < -0.5) { + // 0.0, 0.0, -1.0 + tangent = normalize(gl_NormalMatrix * vec3(-1.0, 0.0, 0.0)); + binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0)); + } + mat3 tbnMatrix = mat3( tangent.x, binormal.x, normal.x, + tangent.y, binormal.y, normal.y, + tangent.z, binormal.z, normal.z); + + lightVec = sunPosition - worldPosition; + tsLightVec = lightVec * tbnMatrix; eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz; - vPosition = (mWorldViewProj * gl_Vertex).xyz; + tsEyeVec = eyeVec * tbnMatrix; 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 * 2.5; // Make light sources brighter float b = rg; @@ -54,10 +98,13 @@ void main(void) color.r = clamp(rg,0.0,1.0); color.g = clamp(rg,0.0,1.0); color.b = clamp(b,0.0,1.0); + + // Make sides and bottom darker than the top + color = color * color; // SRGB -> Linear + if(gl_Normal.y <= 0.5) + color *= 0.6; + color = sqrt(color); // Linear -> SRGB color.a = gl_Color.a; gl_FrontColor = gl_BackColor = color; - - gl_TexCoord[0] = gl_MultiTexCoord0; - } diff --git a/client/shaders/plants_shader/opengl_fragment.glsl b/client/shaders/plants_shader/opengl_fragment.glsl index 31981f9b..817530a8 100644 --- a/client/shaders/plants_shader/opengl_fragment.glsl +++ b/client/shaders/plants_shader/opengl_fragment.glsl @@ -1,54 +1,94 @@ -uniform sampler2D baseTexture; -uniform sampler2D normalTexture; -uniform sampler2D useNormalmap; - -uniform vec4 skyBgColor; -uniform float fogDistance; -uniform vec3 eyePosition; - -varying vec3 vPosition; -varying vec3 eyeVec; - -const float e = 2.718281828459; - -void main (void) -{ - vec3 color; - vec2 uv = gl_TexCoord[0].st; - -#ifdef USE_NORMALMAPS - float use_normalmap = texture2D(useNormalmap,vec2(1.0,1.0)).r; -#endif - -#ifdef ENABLE_BUMPMAPPING - if (use_normalmap > 0.0) { - vec3 base = texture2D(baseTexture, uv).rgb; - vec3 vVec = normalize(eyeVec); - vec3 bump = normalize(texture2D(normalTexture, uv).xyz * 2.0 - 1.0); - vec3 R = reflect(-vVec, bump); - vec3 lVec = normalize(vVec); - float diffuse = max(dot(lVec, bump), 0.0); - float specular = pow(clamp(dot(R, lVec), 0.0, 1.0),1.0); - color = mix (base,diffuse*base,1.0) + 0.1 * specular * diffuse; - } else { - color = texture2D(baseTexture, uv).rgb; - } -#else - color = texture2D(baseTexture, uv).rgb; -#endif - - float alpha = texture2D(baseTexture, uv).a; - vec4 col = vec4(color.r, color.g, color.b, alpha); - col *= gl_Color; - col = col * col; // SRGB -> Linear - col *= 1.8; - col.r = 1.0 - exp(1.0 - col.r) / e; - col.g = 1.0 - exp(1.0 - col.g) / e; - col.b = 1.0 - exp(1.0 - col.b) / e; - 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, alpha); -} +uniform sampler2D baseTexture; +uniform sampler2D normalTexture; +uniform sampler2D useNormalmap; + +uniform vec4 skyBgColor; +uniform float fogDistance; +uniform vec3 eyePosition; + +varying vec3 vPosition; +varying vec3 worldPosition; + +varying vec3 eyeVec; +varying vec3 lightVec; + +bool normalTexturePresent = false; + +const float e = 2.718281828459; + +float intensity (vec3 color){ + return (color.r + color.g + color.b) / 3.0; +} + +float get_rgb_height (vec2 uv){ + return intensity(texture2D(baseTexture,uv).rgb); +} + +vec4 get_normal_map(vec2 uv){ + vec4 bump = texture2D(normalTexture, uv).rgba; + bump.xyz = normalize(bump.xyz * 2.0 -1.0); + bump.y = -bump.y; + return bump; +} + +void main (void) +{ + vec3 color; + vec4 bump; + vec2 uv = gl_TexCoord[0].st; + bool use_normalmap = false; + +#ifdef USE_NORMALMAPS + if (texture2D(useNormalmap,vec2(1.0,1.0)).r > 0.0){ + bump = get_normal_map(uv); + use_normalmap = true; + } +#endif + +#ifdef GENERATE_NORMALMAPS + if (use_normalmap == false){ + float tl = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y+SAMPLE_STEP)); + float t = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y-SAMPLE_STEP)); + float tr = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y+SAMPLE_STEP)); + float r = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y)); + float br = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y-SAMPLE_STEP)); + float b = get_rgb_height (vec2(uv.x,uv.y-SAMPLE_STEP)); + float bl = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y-SAMPLE_STEP)); + float l = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y)); + float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl); + float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr); + bump = vec4 (normalize(vec3 (dX, -dY, NORMALMAPS_STRENGTH)),1.0); + use_normalmap = true; + } +#endif + +vec4 base = texture2D(baseTexture, uv).rgba; + +#ifdef ENABLE_BUMPMAPPING + if (use_normalmap){ + vec3 L = normalize(lightVec); + vec3 E = normalize(eyeVec); + float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0),0.5); + float diffuse = dot(E,bump.xyz); + color = 0.05*base.rgb + diffuse*base.rgb + 0.2*specular*base.rgb; + } else { + color = base.rgb; + } +#else + color = base.rgb; +#endif + + vec4 col = vec4(color.rgb, base.a); + col = col * col; // SRGB -> Linear + col *= 1.8; + col.r = 1.0 - exp(1.0 - col.r) / e; + col.g = 1.0 - exp(1.0 - col.g) / e; + col.b = 1.0 - exp(1.0 - col.b) / e; + col = sqrt(col); // Linear -> SRGB + col *= gl_Color; + 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.rgb, base.a); +} diff --git a/client/shaders/plants_shader/opengl_vertex.glsl b/client/shaders/plants_shader/opengl_vertex.glsl index 7987fc16..a95c2024 100644 --- a/client/shaders/plants_shader/opengl_vertex.glsl +++ b/client/shaders/plants_shader/opengl_vertex.glsl @@ -1,13 +1,20 @@ uniform mat4 mWorldViewProj; uniform mat4 mInvWorld; uniform mat4 mTransWorld; +uniform mat4 mWorld; + uniform float dayNightRatio; uniform float animationTimer; uniform vec3 eyePosition; varying vec3 vPosition; +varying vec3 worldPosition; + varying vec3 eyeVec; +varying vec3 lightVec; + +const float BS = 10.0; #ifdef ENABLE_WAVING_PLANTS float smoothCurve( float x ) { @@ -23,12 +30,11 @@ float smoothTriangleWave( float x ) { void main(void) { - gl_TexCoord[0] = gl_MultiTexCoord0; #ifdef ENABLE_WAVING_PLANTS vec4 pos = gl_Vertex; - vec4 pos2 = mTransWorld * gl_Vertex; + vec4 pos2 = mWorld * gl_Vertex; if (gl_TexCoord[0].y < 0.05) { pos.x += (smoothTriangleWave(animationTimer * 20.0 + pos2.x * 0.1 + pos2.z * 0.1) * 2.0 - 1.0) * 0.8; pos.y -= (smoothTriangleWave(animationTimer * 10.0 + pos2.x * -0.5 + pos2.z * -0.5) * 2.0 - 1.0) * 0.4; @@ -38,9 +44,13 @@ void main(void) gl_Position = mWorldViewProj * gl_Vertex; #endif - vPosition = (mWorldViewProj * gl_Vertex).xyz; - eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz; + vPosition = gl_Position.xyz; + worldPosition = (mWorld * gl_Vertex).xyz; + vec3 sunPosition = vec3 (0.0, eyePosition.y * BS + 900.0, 0.0); + lightVec = sunPosition - worldPosition; + eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz; + vec4 color; //color = vec4(1.0, 1.0, 1.0, 1.0); @@ -76,11 +86,8 @@ void main(void) 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; - } diff --git a/client/shaders/solids_shader/opengl_fragment.glsl b/client/shaders/solids_shader/opengl_fragment.glsl index d81506a4..6370bf50 100644 --- a/client/shaders/solids_shader/opengl_fragment.glsl +++ b/client/shaders/solids_shader/opengl_fragment.glsl @@ -1,90 +1,110 @@ -uniform sampler2D baseTexture; -uniform sampler2D normalTexture; -uniform sampler2D useNormalmap; - -uniform vec4 skyBgColor; -uniform float fogDistance; -uniform vec3 eyePosition; - -varying vec3 vPosition; -varying vec3 eyeVec; - -#ifdef ENABLE_PARALLAX_OCCLUSION -varying vec3 tsEyeVec; -#endif - -const float e = 2.718281828459; - -void main (void) -{ - vec3 color; - vec2 uv = gl_TexCoord[0].st; - -#ifdef USE_NORMALMAPS - float use_normalmap = texture2D(useNormalmap,vec2(1.0,1.0)).r; -#endif - -#ifdef ENABLE_PARALLAX_OCCLUSION - float height; - vec2 tsEye = vec2(tsEyeVec.x,-tsEyeVec.y); - - if (use_normalmap > 0.0) { - float map_height = texture2D(normalTexture, uv).a; - if (map_height < 1.0){ - float height = PARALLAX_OCCLUSION_SCALE * map_height - PARALLAX_OCCLUSION_BIAS; - uv = uv + height * tsEye; - } - } -#endif - -/* Steep parallax code, for future use - if ((parallaxMappingMode == 2.0) && (use_normalmap > 0.0)) { - const float numSteps = 40.0; - float height = 1.0; - float step = 1.0 / numSteps; - vec4 NB = texture2D(normalTexture, uv); - vec2 delta = tsEye * parallaxMappingScale / numSteps; - for (float i = 0.0; i < numSteps; i++) { - if (NB.a < height) { - height -= step; - uv += delta; - NB = texture2D(normalTexture, uv); - } else { - break; - } - } - } -*/ - -#ifdef ENABLE_BUMPMAPPING - if (use_normalmap > 0.0) { - vec3 base = texture2D(baseTexture, uv).rgb; - vec3 vVec = normalize(eyeVec); - vec3 bump = normalize(texture2D(normalTexture, uv).xyz * 2.0 - 1.0); - vec3 R = reflect(-vVec, bump); - vec3 lVec = normalize(vVec); - float diffuse = max(dot(lVec, bump), 0.0); - float specular = pow(clamp(dot(R, lVec), 0.0, 1.0),1.0); - color = mix (base,diffuse*base,1.0) + 0.1 * specular * diffuse; - } else { - color = texture2D(baseTexture, uv).rgb; - } -#else - color = texture2D(baseTexture, uv).rgb; -#endif - - float alpha = texture2D(baseTexture, uv).a; - vec4 col = vec4(color.r, color.g, color.b, alpha); - col *= gl_Color; - col = col * col; // SRGB -> Linear - col *= 1.8; - col.r = 1.0 - exp(1.0 - col.r) / e; - col.g = 1.0 - exp(1.0 - col.g) / e; - col.b = 1.0 - exp(1.0 - col.b) / e; - 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, alpha); -} +uniform sampler2D baseTexture; +uniform sampler2D normalTexture; +uniform sampler2D useNormalmap; + +uniform vec4 skyBgColor; +uniform float fogDistance; +uniform vec3 eyePosition; + +varying vec3 vPosition; +varying vec3 worldPosition; + +varying vec3 eyeVec; +varying vec3 tsEyeVec; +varying vec3 lightVec; +varying vec3 tsLightVec; + +bool normalTexturePresent = false; + +const float e = 2.718281828459; + +float intensity (vec3 color){ + return (color.r + color.g + color.b) / 3.0; +} + +float get_rgb_height (vec2 uv){ + return intensity(texture2D(baseTexture,uv).rgb); +} + +vec4 get_normal_map(vec2 uv){ + vec4 bump = texture2D(normalTexture, uv).rgba; + bump.xyz = normalize(bump.xyz * 2.0 -1.0); + bump.y = -bump.y; + return bump; +} + +void main (void) +{ + vec3 color; + vec4 bump; + vec2 uv = gl_TexCoord[0].st; + bool use_normalmap = false; + +#ifdef USE_NORMALMAPS + if (texture2D(useNormalmap,vec2(1.0,1.0)).r > 0.0){ + normalTexturePresent = true; + } +#endif + +#ifdef ENABLE_PARALLAX_OCCLUSION + if (normalTexturePresent){ + vec3 tsEye = normalize(tsEyeVec); + float height = PARALLAX_OCCLUSION_SCALE * texture2D(normalTexture, uv).a - PARALLAX_OCCLUSION_BIAS; + uv = uv + texture2D(normalTexture, uv).z * height * vec2(tsEye.x,-tsEye.y); + } +#endif + +#ifdef USE_NORMALMAPS + if (normalTexturePresent){ + bump = get_normal_map(uv); + use_normalmap = true; + } +#endif + +#ifdef GENERATE_NORMALMAPS + if (use_normalmap == false){ + float tl = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y+SAMPLE_STEP)); + float t = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y-SAMPLE_STEP)); + float tr = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y+SAMPLE_STEP)); + float r = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y)); + float br = get_rgb_height (vec2(uv.x+SAMPLE_STEP,uv.y-SAMPLE_STEP)); + float b = get_rgb_height (vec2(uv.x,uv.y-SAMPLE_STEP)); + float bl = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y-SAMPLE_STEP)); + float l = get_rgb_height (vec2(uv.x-SAMPLE_STEP,uv.y)); + float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl); + float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr); + bump = vec4 (normalize(vec3 (dX, -dY, NORMALMAPS_STRENGTH)),1.0); + use_normalmap = true; + } +#endif + +vec4 base = texture2D(baseTexture, uv).rgba; + +#ifdef ENABLE_BUMPMAPPING + if (use_normalmap){ + vec3 L = normalize(lightVec); + vec3 E = normalize(eyeVec); + float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0),0.5); + float diffuse = dot(E,bump.xyz); + color = 0.05*base.rgb + diffuse*base.rgb + 0.2*specular*base.rgb; + } else { + color = base.rgb; + } +#else + color = base.rgb; +#endif + + vec4 col = vec4(color.rgb, base.a); + col = col * col; // SRGB -> Linear + col *= 1.8; + col.r = 1.0 - exp(1.0 - col.r) / e; + col.g = 1.0 - exp(1.0 - col.g) / e; + col.b = 1.0 - exp(1.0 - col.b) / e; + col = sqrt(col); // Linear -> SRGB + col *= gl_Color; + 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.rgb, base.a); +} diff --git a/client/shaders/solids_shader/opengl_vertex.glsl b/client/shaders/solids_shader/opengl_vertex.glsl index e359955d..356ba2eb 100644 --- a/client/shaders/solids_shader/opengl_vertex.glsl +++ b/client/shaders/solids_shader/opengl_vertex.glsl @@ -1,27 +1,33 @@ uniform mat4 mWorldViewProj; uniform mat4 mInvWorld; uniform mat4 mTransWorld; +uniform mat4 mWorld; + uniform float dayNightRatio; uniform vec3 eyePosition; varying vec3 vPosition; -varying vec3 eyeVec; +varying vec3 worldPosition; + +varying vec3 eyeVec; +varying vec3 lightVec; -#ifdef ENABLE_PARALLAX_OCCLUSION varying vec3 tsEyeVec; -#endif +varying vec3 tsLightVec; + +const float BS = 10.0; void main(void) { + gl_TexCoord[0] = gl_MultiTexCoord0; gl_Position = mWorldViewProj * gl_Vertex; - vPosition = (mWorldViewProj * gl_Vertex).xyz; - eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz; + vPosition = gl_Position.xyz; + worldPosition = (mWorld * gl_Vertex).xyz; + vec3 sunPosition = vec3 (0.0, eyePosition.y * BS + 900.0, 0.0); -#ifdef ENABLE_PARALLAX_OCCLUSION - vec3 normal,tangent,binormal; + vec3 normal, tangent, binormal; normal = normalize(gl_NormalMatrix * gl_Normal); - if (gl_Normal.x > 0.5) { // 1.0, 0.0, 0.0 tangent = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, -1.0)); @@ -47,25 +53,20 @@ void main(void) tangent = normalize(gl_NormalMatrix * vec3(-1.0, 0.0, 0.0)); binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0)); } - mat3 tbnMatrix = mat3( tangent.x, binormal.x, normal.x, tangent.y, binormal.y, normal.y, tangent.z, binormal.z, normal.z); - tsEyeVec = normalize(eyeVec * tbnMatrix); -#endif + lightVec = sunPosition - worldPosition; + tsLightVec = lightVec * tbnMatrix; + eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz; + tsEyeVec = eyeVec * tbnMatrix; 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 * 2.5; // Make light sources brighter float b = rg; @@ -90,13 +91,8 @@ void main(void) 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; - } diff --git a/doc/lua_api.txt b/doc/lua_api.txt index f5468494..b933caff 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -849,7 +849,7 @@ Example stuff: local meta = minetest.get_meta(pos) meta:set_string("formspec", - "invsize[8,9;]".. + "size[8,9]".. "list[context;main;0,0;8,4;]".. "list[current_player;main;0,5;8,4;]") meta:set_string("infotext", "Chest"); @@ -861,7 +861,7 @@ meta:from_table({ main = {[1] = "default:dirt", [2] = "", [3] = "", [4] = "", [5] = "", [6] = "", [7] = "", [8] = "", [9] = "", [10] = "", [11] = "", [12] = "", [13] = "", [14] = "default:cobble", [15] = "", [16] = "", [17] = "", [18] = "", [19] = "", [20] = "default:cobble", [21] = "", [22] = "", [23] = "", [24] = "", [25] = "", [26] = "", [27] = "", [28] = "", [29] = "", [30] = "", [31] = "", [32] = ""} }, fields = { - formspec = "invsize[8,9;]list[context;main;0,0;8,4;]list[current_player;main;0,5;8,4;]", + formspec = "size[8,9]list[context;main;0,0;8,4;]list[current_player;main;0,5;8,4;]", infotext = "Chest" } }) @@ -876,17 +876,17 @@ examples. Examples: - Chest: - invsize[8,9;] + size[8,9] list[context;main;0,0;8,4;] list[current_player;main;0,5;8,4;] - Furnace: - invsize[8,9;] + size[8,9] list[context;fuel;2,3;1,1;] list[context;src;2,1;1,1;] list[context;dst;5,1;2,2;] list[current_player;main;0,5;8,4;] - Minecraft-like player inventory - invsize[8,7.5;] + size[8,7.5] image[1,0.6;1,2;player.png] list[current_player;main;0,3.5;8,4;] list[current_player;craft;3,0;3,3;] @@ -894,8 +894,9 @@ Examples: Elements: -size[,] +size[,,] ^ Define the size of the menu in inventory slots +^ fixed_size true/false (optional) ^ deprecated: invsize[,;] list[;;,;,;] @@ -1199,6 +1200,29 @@ minetest.features minetest.has_feature(arg) -> bool, missing_features ^ arg: string or table in format {foo=true, bar=true} ^ missing_features: {foo=true, bar=true} +minetest.get_player_information(playername) +^ table containing information about player peer: +{ + address = "127.0.0.1", -- ip address of client + ip_version = 4, -- IPv4 / IPv6 + min_rtt = 0.01, -- minimum round trip time + max_rtt = 0.2, -- maximum round trip time + avg_rtt = 0.02, -- average round trip time + min_jitter = 0.01, -- minimum packet time jitter + max_jitter = 0.5, -- maximum packet time jitter + avg_jitter = 0.03, -- average packet time jitter + connection_uptime = 200, -- seconds since client connected + + -- following information is available on debug build only!!! + -- DO NOT USE IN MODS + --ser_vers = 26, -- serialization version used by client + --prot_vers = 23, -- protocol version used by client + --major = 0, -- major version number + --minor = 4, -- minor version number + --patch = 10, -- patch version number + --vers_string = "0.4.9-git", -- full version string + --state = "Active" -- current client state +} Logging: minetest.debug(line) @@ -1419,10 +1443,6 @@ minetest.set_node_level(pos, level) ^ set level of leveled node, default level = 1, if totallevel > maxlevel returns rest (total-max). minetest.add_node_level(pos, level) ^ increase level of leveled node by level, default level = 1, if totallevel > maxlevel returns rest (total-max). can be negative for decreasing -minetest.get_heat(pos) -^ heat at pos -minetest.get_humidity(pos) -^ humidity at pos Inventory: minetest.get_inventory(location) -> InvRef @@ -1850,6 +1870,15 @@ Player-only: (no-op for other objects) - override_day_night_ratio(ratio or nil) ^ 0...1: Overrides day-night ratio, controlling sunlight to a specific amount ^ nil: Disables override, defaulting to sunlight based on day-night cycle +- set_local_animation({x=0, y=79}, {x=168, y=187}, {x=189, y=198}, {x=200, y=219}, frame_speed=30): set animation for player model in third person view + ^ stand/idle animation key frames + ^ walk animation key frames + ^ dig animation key frames + ^ walk+dig animation key frames + ^ animation frame speed +- set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0}): defines offset value for camera per player + ^ in first person view + ^ in third person view (max. values {x=-10/10,y=-10,15,z=-5/5}) InvRef: Reference to an inventory methods: diff --git a/minetest.conf.example b/minetest.conf.example index 71a945b5..548adcce 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -93,24 +93,10 @@ #enable_fog = true # Enable a bit lower water surface; disable for speed (not quite optimized) #new_style_water = false -# Constant volume liquids -#liquid_finite = false # Max liquids processed per step #liquid_loop_max = 10000 # Update liquids every .. recommend for finite: 0.2 #liquid_update = 1.0 -# Relax flowing blocks to source if level near max and N nearby -# source blocks, more realistic, but not true constant. -# values: 0,1,2,3,4 : 0 - disable, 1 - most aggresive -# (for finite liquids) -#liquid_relax = 2 -# Optimization: faster cave flood (and not true constant) -# (for finite liquids) -#liquid_fast_flood = 1 -# Underground water and lava springs, its infnity sources if liquid_finite enabled -#underground_springs = 1 -# Enable weather (cold-hot, water freeze-melt). use only with liquid_finite=1 -#weather = false # Enable nice leaves; disable for speed #new_style_leaves = true # Enable smooth lighting with simple ambient occlusion; @@ -173,6 +159,14 @@ # Set to true to enable textures bumpmapping. Requires shaders enabled. #enable_bumpmapping = false # Set to true enables parallax occlusion mapping. Requires shaders enabled. +#generate_normalmaps = false +# Set to true enables on the fly normalmap generation (Emboss effect). +# Requires bumpmapping enabled. +#normalmaps_strength = 0.6 +# Strength of generated normalmaps +#normalmaps_smooth = 1 +# Defines sampling step of texture (0 - 2) +# Higher the value normal maps will be smoother #enable_parallax_occlusion = false # Scale of parallax occlusion effect #parallax_occlusion_scale = 0.08 @@ -353,6 +347,7 @@ # try reducing it, but don't reduce it to a number below double of targeted # client number #max_packets_per_iteration = 1024 + # # Physics stuff # @@ -430,6 +425,7 @@ #enable_ipv6 = true # Enable/disable running an IPv6 server. An IPv6 server may be restricted # to IPv6 clients, depending on system configuration. +# Ignored if bind_address is set. #ipv6_server = false #main_menu_script = diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 562306e1..6836ad6e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -291,6 +291,25 @@ if(ENABLE_LEVELDB) endif(LEVELDB_LIBRARY AND LEVELDB_INCLUDE_DIR) endif(ENABLE_LEVELDB) +set(USE_REDIS 0) + +OPTION(ENABLE_REDIS "Enable redis backend" 1) + +if(ENABLE_REDIS) + find_library(REDIS_LIBRARY hiredis) + find_path(REDIS_INCLUDE_DIR hiredis.h PATH_SUFFIXES hiredis) + message(STATUS "redis library: ${REDIS_LIBRARY}") + message(STATUS "redis headers: ${REDIS_INCLUDE_DIR}") + if(REDIS_LIBRARY AND REDIS_INCLUDE_DIR) + set(USE_REDIS 1) + message(STATUS "redis backend enabled") + include_directories(${REDIS_INCLUDE_DIR}) + else(REDIS_LIBRARY AND REDIS_INCLUDE_DIR) + set(USE_REDIS 0) + message(STATUS "redis not found!") + endif(REDIS_LIBRARY AND REDIS_INCLUDE_DIR) +endif(ENABLE_REDIS) + configure_file( "${PROJECT_SOURCE_DIR}/cmake_config.h.in" "${PROJECT_BINARY_DIR}/cmake_config.h" @@ -368,6 +387,7 @@ set(common_SRCS database-dummy.cpp database-leveldb.cpp database-sqlite3.cpp + database-redis.cpp player.cpp test.cpp sha1.cpp @@ -393,7 +413,7 @@ if(WIN32) set(CMAKE_RC_COMPILER "windres.exe") endif() ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/winresource_rc.o - COMMAND ${CMAKE_RC_COMPILER} -I${CMAKE_CURRENT_SOURCE_DIR} + COMMAND ${CMAKE_RC_COMPILER} -I${CMAKE_CURRENT_SOURCE_DIR} -I${CMAKE_CURRENT_BINARY_DIR} -i${WINRESOURCE_FILE} -o ${CMAKE_CURRENT_BINARY_DIR}/winresource_rc.o WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} @@ -424,11 +444,9 @@ set(minetest_SRCS chat.cpp hud.cpp guiKeyChangeMenu.cpp - guiMessageMenu.cpp guiTextInputMenu.cpp guiFormSpecMenu.cpp guiTable.cpp - guiPauseMenu.cpp guiPasswordChange.cpp guiVolumeChange.cpp guiDeathScreen.cpp @@ -535,6 +553,9 @@ if(BUILD_CLIENT) if (USE_LEVELDB) target_link_libraries(${PROJECT_NAME} ${LEVELDB_LIBRARY}) endif(USE_LEVELDB) + if (USE_REDIS) + target_link_libraries(${PROJECT_NAME} ${REDIS_LIBRARY}) + endif(USE_REDIS) endif(BUILD_CLIENT) if(BUILD_SERVER) @@ -552,6 +573,9 @@ if(BUILD_SERVER) if (USE_LEVELDB) target_link_libraries(${PROJECT_NAME}server ${LEVELDB_LIBRARY}) endif(USE_LEVELDB) + if (USE_REDIS) + target_link_libraries(${PROJECT_NAME}server ${REDIS_LIBRARY}) + endif(USE_REDIS) if(USE_CURL) target_link_libraries( ${PROJECT_NAME}server diff --git a/src/biome.cpp b/src/biome.cpp index dca900cb..e1dfc47a 100644 --- a/src/biome.cpp +++ b/src/biome.cpp @@ -203,54 +203,3 @@ u8 BiomeDefManager::getBiomeIdByName(const char *name) { return 0; } - - -///////////////////////////// Weather - - -s16 BiomeDefManager::calcBlockHeat(v3s16 p, u64 seed, float timeofday, float totaltime) { - //variant 1: full random - //f32 heat = NoisePerlin3D(np_heat, p.X, env->getGameTime()/100, p.Z, seed); - - //variant 2: season change based on default heat map - const f32 offset = 20; // = np_heat->offset - const f32 scale = 20; // = np_heat->scale - const f32 range = 20; - f32 heat = NoisePerlin2D(np_heat, p.X, p.Z, seed); // 0..50..100 - - heat -= np_heat->offset; // -50..0..+50 - - // normalizing - todo REMOVE after fixed NoiseParams nparams_biome_def_heat = {50, 50, -> 20, 50, - if (np_heat->scale) - heat /= np_heat->scale / scale; // -20..0..+20 - - f32 seasonv = totaltime; - seasonv /= 86400 * g_settings->getS16("year_days"); // season change speed - seasonv += (f32)p.X / 3000; // you can walk to area with other season - seasonv = sin(seasonv * M_PI); - heat += (range * (heat < 0 ? 2 : 0.5)) * seasonv; // -60..0..30 - - heat += offset; // -40..0..50 - heat += p.Y / -333; // upper=colder, lower=hotter, 3c per 1000 - - // daily change, hotter at sun +4, colder at night -4 - heat += 8 * (sin(cycle_shift(timeofday, -0.25) * M_PI) - 0.5); //-44..20..54 - - return heat; -} - - -s16 BiomeDefManager::calcBlockHumidity(v3s16 p, u64 seed, float timeofday, float totaltime) { - - f32 humidity = NoisePerlin2D(np_humidity, p.X, p.Z, seed); - - f32 seasonv = totaltime; - seasonv /= 86400 * 2; // bad weather change speed (2 days) - seasonv += (f32)p.Z / 300; - humidity += 30 * sin(seasonv * M_PI); - - humidity += -12 * (sin(cycle_shift(timeofday, -0.1) * M_PI) - 0.5); - humidity = rangelim(humidity, 0, 100); - - return humidity; -} diff --git a/src/camera.cpp b/src/camera.cpp index 783ae84c..b49e8e74 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -40,9 +40,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #define CAMERA_OFFSET_STEP 200 +#include "nodedef.h" + Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control, IGameDef *gamedef): - m_smgr(smgr), m_playernode(NULL), m_headnode(NULL), m_cameranode(NULL), @@ -248,7 +249,8 @@ void Camera::step(f32 dtime) } void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, - v2u32 screensize, f32 tool_reload_ratio) + v2u32 screensize, f32 tool_reload_ratio, + int current_camera_mode, ClientEnvironment &c_env) { // Get player position // Smooth the movement when walking up stairs @@ -276,7 +278,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, // Fall bobbing animation float fall_bobbing = 0; - if(player->camera_impact >= 1) + if(player->camera_impact >= 1 && current_camera_mode < CAMERA_MODE_THIRD) { if(m_view_bobbing_fall == -1) // Effect took place and has finished player->camera_impact = m_view_bobbing_fall = 0; @@ -293,8 +295,15 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, fall_bobbing *= g_settings->getFloat("fall_bobbing_amount"); } + // Calculate players eye offset for different camera modes + v3f PlayerEyeOffset = player->getEyeOffset(); + if (current_camera_mode == CAMERA_MODE_FIRST) + PlayerEyeOffset += player->eye_offset_first; + else + PlayerEyeOffset += player->eye_offset_third; + // Set head node transformation - m_headnode->setPosition(player->getEyeOffset()+v3f(0,cameratilt*-player->hurt_tilt_strength+fall_bobbing,0)); + m_headnode->setPosition(PlayerEyeOffset+v3f(0,cameratilt*-player->hurt_tilt_strength+fall_bobbing,0)); m_headnode->setRotation(v3f(player->getPitch(), 0, cameratilt*player->hurt_tilt_strength)); m_headnode->updateAbsolutePosition(); @@ -303,7 +312,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, v3f rel_cam_target = v3f(0,0,1); v3f rel_cam_up = v3f(0,1,0); - if (m_view_bobbing_anim != 0) + if (m_view_bobbing_anim != 0 && current_camera_mode < CAMERA_MODE_THIRD) { f32 bobfrac = my_modf(m_view_bobbing_anim * 2); f32 bobdir = (m_view_bobbing_anim < 0.5) ? 1.0 : -1.0; @@ -352,19 +361,60 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, v3f abs_cam_up; m_headnode->getAbsoluteTransformation().rotateVect(abs_cam_up, rel_cam_up); + // Seperate camera position for calculation + v3f my_cp = m_camera_position; + + // Reposition the camera for third person view + if (current_camera_mode > CAMERA_MODE_FIRST) { + + if (current_camera_mode == CAMERA_MODE_THIRD_FRONT) + m_camera_direction *= -1; + + my_cp.Y += 2; + + // Calculate new position + bool abort = false; + for (int i = BS; i <= BS*2; i++) { + my_cp.X = m_camera_position.X + m_camera_direction.X*-i; + my_cp.Z = m_camera_position.Z + m_camera_direction.Z*-i; + if (i > 12) + my_cp.Y = m_camera_position.Y + (m_camera_direction.Y*-i); + + // Prevent camera positioned inside nodes + INodeDefManager *nodemgr = m_gamedef->ndef(); + MapNode n = c_env.getClientMap().getNodeNoEx(floatToInt(my_cp, BS)); + const ContentFeatures& features = nodemgr->get(n); + if(features.walkable) { + my_cp.X += m_camera_direction.X*-1*-BS/2; + my_cp.Z += m_camera_direction.Z*-1*-BS/2; + my_cp.Y += m_camera_direction.Y*-1*-BS/2; + abort = true; + break; + } + } + + // If node blocks camera position don't move y to heigh + if (abort && my_cp.Y > player_position.Y+BS*2) + my_cp.Y = player_position.Y+BS*2; + } + // Update offset if too far away from the center of the map m_camera_offset.X += CAMERA_OFFSET_STEP* - (((s16)(m_camera_position.X/BS) - m_camera_offset.X)/CAMERA_OFFSET_STEP); + (((s16)(my_cp.X/BS) - m_camera_offset.X)/CAMERA_OFFSET_STEP); m_camera_offset.Y += CAMERA_OFFSET_STEP* - (((s16)(m_camera_position.Y/BS) - m_camera_offset.Y)/CAMERA_OFFSET_STEP); + (((s16)(my_cp.Y/BS) - m_camera_offset.Y)/CAMERA_OFFSET_STEP); m_camera_offset.Z += CAMERA_OFFSET_STEP* - (((s16)(m_camera_position.Z/BS) - m_camera_offset.Z)/CAMERA_OFFSET_STEP); + (((s16)(my_cp.Z/BS) - m_camera_offset.Z)/CAMERA_OFFSET_STEP); // Set camera node transformation - m_cameranode->setPosition(m_camera_position-intToFloat(m_camera_offset, BS)); + m_cameranode->setPosition(my_cp-intToFloat(m_camera_offset, BS)); m_cameranode->setUpVector(abs_cam_up); // *100.0 helps in large map coordinates - m_cameranode->setTarget(m_camera_position-intToFloat(m_camera_offset, BS) + 100 * m_camera_direction); + m_cameranode->setTarget(my_cp-intToFloat(m_camera_offset, BS) + 100 * m_camera_direction); + + // update the camera position in front-view mode to render blocks behind player + if (current_camera_mode == CAMERA_MODE_THIRD_FRONT) + m_camera_position = my_cp; // Get FOV setting f32 fov_degrees = g_settings->getFloat("fov"); diff --git a/src/camera.h b/src/camera.h index df40e3b9..d1c3b59d 100644 --- a/src/camera.h +++ b/src/camera.h @@ -27,10 +27,14 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/numeric.h" #include +#include "client.h" + class LocalPlayer; struct MapDrawControl; class IGameDef; +enum CameraModes {CAMERA_MODE_FIRST, CAMERA_MODE_THIRD, CAMERA_MODE_THIRD_FRONT}; + /* Client camera class, manages the player and camera scene nodes, the viewing distance and performs view bobbing etc. It also displays the wielded tool in front of the @@ -113,7 +117,8 @@ public: // Update the camera from the local player's position. // busytime is used to adjust the viewing range. void update(LocalPlayer* player, f32 frametime, f32 busytime, - v2u32 screensize, f32 tool_reload_ratio); + v2u32 screensize, f32 tool_reload_ratio, + int current_camera_mode, ClientEnvironment &c_env); // Render distance feedback loop void updateViewingRange(f32 frametime_in, f32 busytime_in); @@ -131,8 +136,7 @@ public: void drawWieldedTool(); private: - // Scene manager and nodes - scene::ISceneManager* m_smgr; + // Nodes scene::ISceneNode* m_playernode; scene::ISceneNode* m_headnode; scene::ICameraSceneNode* m_cameranode; diff --git a/src/cguittfont/irrUString.h b/src/cguittfont/irrUString.h index 21109ea4..132a35ee 100644 --- a/src/cguittfont/irrUString.h +++ b/src/cguittfont/irrUString.h @@ -3395,7 +3395,7 @@ inline ustring16 operator+(const ustring16& left, const short ri template inline ustring16 operator+(const short left, const ustring16& right) { - ustring16 ret(core::stringc(left)); + ustring16 ret((core::stringc(left))); ret += right; return ret; } @@ -3415,7 +3415,7 @@ inline ustring16 operator+(const ustring16& left, const unsigned template inline ustring16 operator+(const unsigned short left, const ustring16& right) { - ustring16 ret(core::stringc(left)); + ustring16 ret((core::stringc(left))); ret += right; return ret; } @@ -3435,7 +3435,7 @@ inline ustring16 operator+(const ustring16& left, const int righ template inline ustring16 operator+(const int left, const ustring16& right) { - ustring16 ret(core::stringc(left)); + ustring16 ret((core::stringc(left))); ret += right; return ret; } @@ -3455,7 +3455,7 @@ inline ustring16 operator+(const ustring16& left, const unsigned template inline ustring16 operator+(const unsigned int left, const ustring16& right) { - ustring16 ret(core::stringc(left)); + ustring16 ret((core::stringc(left))); ret += right; return ret; } @@ -3475,7 +3475,7 @@ inline ustring16 operator+(const ustring16& left, const long rig template inline ustring16 operator+(const long left, const ustring16& right) { - ustring16 ret(core::stringc(left)); + ustring16 ret((core::stringc(left))); ret += right; return ret; } @@ -3495,7 +3495,7 @@ inline ustring16 operator+(const ustring16& left, const unsigned template inline ustring16 operator+(const unsigned long left, const ustring16& right) { - ustring16 ret(core::stringc(left)); + ustring16 ret((core::stringc(left))); ret += right; return ret; } @@ -3515,7 +3515,7 @@ inline ustring16 operator+(const ustring16& left, const float ri template inline ustring16 operator+(const float left, const ustring16& right) { - ustring16 ret(core::stringc(left)); + ustring16 ret((core::stringc(left))); ret += right; return ret; } @@ -3535,7 +3535,7 @@ inline ustring16 operator+(const ustring16& left, const double r template inline ustring16 operator+(const double left, const ustring16& right) { - ustring16 ret(core::stringc(left)); + ustring16 ret((core::stringc(left))); ret += right; return ret; } diff --git a/src/client.cpp b/src/client.cpp index 4d6c0cb9..72964026 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -47,6 +47,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "serialization.h" #include "util/serialize.h" #include "config.h" +#include "cmake_config_githash.h" #include "util/directiontables.h" #include "util/pointedthing.h" #include "version.h" @@ -168,6 +169,8 @@ void * MeshUpdateThread::Thread() BEGIN_DEBUG_EXCEPTION_HANDLER + porting::setThreadName("MeshUpdateThread"); + while(!StopRequested()) { QueuedMeshUpdate *q = m_queue_in.pop(); @@ -252,7 +255,8 @@ Client::Client( 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_removed_sounds_check_timer(0), + m_state(LC_Created) { m_packetcounter_timer = 0.0; //m_delete_unused_sectors_timer = 0.0; @@ -325,17 +329,6 @@ void Client::connect(Address address) m_con.Connect(address); } -bool Client::connectedAndInitialized() -{ - if(m_con.Connected() == false) - return false; - - if(m_server_ser_ver == SER_FMT_VER_INVALID) - return false; - - return true; -} - void Client::step(float dtime) { DSTACK(__FUNCTION_NAME); @@ -372,9 +365,6 @@ void Client::step(float dtime) m_packetcounter.clear(); } } - - // Get connection status - bool connected = connectedAndInitialized(); #if 0 { @@ -467,7 +457,7 @@ void Client::step(float dtime) } #endif - if(connected == false) + if(m_state == LC_Created) { float &counter = m_connection_reinit_timer; counter -= dtime; @@ -632,7 +622,7 @@ void Client::step(float dtime) { counter = 0.0; // connectedAndInitialized() is true, peer exists. - float avg_rtt = m_con.GetPeerAvgRTT(PEER_ID_SERVER); + float avg_rtt = getRTT(); infostream<<"Client: avg_rtt="<= m_recommended_send_interval) + if((m_state == LC_Ready) && (counter >= m_recommended_send_interval)) { counter = 0.0; sendPlayerPos(); @@ -1051,6 +1041,8 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) // Send as reliable m_con.Send(PEER_ID_SERVER, 1, reply, true); + m_state = LC_Init; + return; } @@ -1222,7 +1214,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) m_time_of_day_set = true; u32 dr = m_env.getDayNightRatio(); - verbosestream<<"Client: time_of_day="< data, bool reliable) void Client::interact(u8 action, const PointedThing& pointed) { - if(connectedAndInitialized() == false){ + if(m_state != LC_Ready){ infostream<<"Client::interact() " "cancelled (not connected)" < data((u8*)s.c_str(), s.size()); + // Send as reliable + Send(0, data, true); +} + void Client::sendPlayerPos() { LocalPlayer *myplayer = m_env.getLocalPlayer(); @@ -2650,16 +2688,14 @@ void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font) infostream<<"- Starting mesh update thread"< &fields); void sendInventoryAction(InventoryAction *a); void sendChatMessage(const std::wstring &message); - void sendChangePassword(const std::wstring oldpassword, - const std::wstring newpassword); + void sendChangePassword(const std::wstring &oldpassword, + const std::wstring &newpassword); void sendDamage(u8 damage); void sendBreath(u16 breath); void sendRespawn(); + void sendReady(); ClientEnvironment& getEnv() { return m_env; } @@ -454,6 +454,8 @@ public: // Send a notification that no conventional media transfer is needed void received_media(); + LocalClientState getState() { return m_state; } + private: // Virtual methods from con::PeerHandler @@ -537,6 +539,9 @@ private: // Storage for mesh data for creating multiple instances of the same mesh std::map m_mesh_data; + + // own state + LocalClientState m_state; }; #endif // !CLIENT_HEADER diff --git a/src/clientiface.cpp b/src/clientiface.cpp index 06d87d2a..626e5da7 100644 --- a/src/clientiface.cpp +++ b/src/clientiface.cpp @@ -17,6 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include + #include "clientiface.h" #include "player.h" #include "settings.h" @@ -140,7 +142,8 @@ void RemoteClient::GetNextBlocks( */ s32 new_nearest_unsent_d = -1; - s16 d_max = g_settings->getS16("max_block_send_distance"); + const s16 full_d_max = g_settings->getS16("max_block_send_distance"); + s16 d_max = full_d_max; s16 d_max_gen = g_settings->getS16("max_block_generate_distance"); // Don't loop very much at a time @@ -214,7 +217,7 @@ void RemoteClient::GetNextBlocks( generate = false;*/ // Limit the send area vertically to 1/2 - if(abs(p.Y - center.Y) > d_max / 2) + if(abs(p.Y - center.Y) > full_d_max / 2) continue; } @@ -396,10 +399,11 @@ void RemoteClient::SetBlocksNotSent(std::map &blocks) void RemoteClient::notifyEvent(ClientStateEvent event) { + std::ostringstream myerror; switch (m_state) { case Invalid: - assert("State update for client in invalid state" != 0); + //intentionally do nothing break; case Created: @@ -419,7 +423,8 @@ void RemoteClient::notifyEvent(ClientStateEvent event) /* GotInit2 SetDefinitionsSent SetMediaSent */ default: - assert("Invalid client state transition!" == 0); + myerror << "Created: Invalid client state transition! " << event; + throw ClientStateError(myerror.str()); } break; @@ -445,7 +450,8 @@ void RemoteClient::notifyEvent(ClientStateEvent event) /* Init SetDefinitionsSent SetMediaSent */ default: - assert("Invalid client state transition!" == 0); + myerror << "InitSent: Invalid client state transition! " << event; + throw ClientStateError(myerror.str()); } break; @@ -466,14 +472,15 @@ void RemoteClient::notifyEvent(ClientStateEvent event) /* Init GotInit2 SetMediaSent */ default: - assert("Invalid client state transition!" == 0); + myerror << "InitDone: Invalid client state transition! " << event; + throw ClientStateError(myerror.str()); } break; case DefinitionsSent: switch(event) { - case SetMediaSent: + case SetClientReady: m_state = Active; break; @@ -487,7 +494,8 @@ void RemoteClient::notifyEvent(ClientStateEvent event) /* Init GotInit2 SetDefinitionsSent */ default: - assert("Invalid client state transition!" == 0); + myerror << "DefinitionsSent: Invalid client state transition! " << event; + throw ClientStateError(myerror.str()); } break; @@ -504,7 +512,8 @@ void RemoteClient::notifyEvent(ClientStateEvent event) /* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */ default: - assert("Invalid client state transition!" == 0); + myerror << "Active: Invalid client state transition! " << event; + throw ClientStateError(myerror.str()); break; } break; @@ -515,6 +524,11 @@ void RemoteClient::notifyEvent(ClientStateEvent event) } } +u32 RemoteClient::uptime() +{ + return getTime(PRECISION_SECONDS) - m_connection_time; +} + ClientInterface::ClientInterface(con::Connection* con) : m_con(con), @@ -748,7 +762,7 @@ void ClientInterface::event(u16 peer_id, ClientStateEvent event) n->second->notifyEvent(event); } - if ((event == SetMediaSent) || (event == Disconnect) || (event == SetDenied)) + if ((event == SetClientReady) || (event == Disconnect) || (event == SetDenied)) { UpdatePlayerList(); } @@ -762,9 +776,24 @@ u16 ClientInterface::getProtocolVersion(u16 peer_id) std::map::iterator n; n = m_clients.find(peer_id); - // No client to deliver event + // No client to get version if (n == m_clients.end()) return 0; return n->second->net_proto_version; } + +void ClientInterface::setClientVersion(u16 peer_id, u8 major, u8 minor, u8 patch, std::string full) +{ + JMutexAutoLock conlock(m_clients_mutex); + + // Error check + std::map::iterator n; + n = m_clients.find(peer_id); + + // No client to set versions + if (n == m_clients.end()) + return; + + n->second->setVersionInfo(major,minor,patch,full); +} diff --git a/src/clientiface.h b/src/clientiface.h index a2315b3b..752e2bb8 100644 --- a/src/clientiface.h +++ b/src/clientiface.h @@ -34,10 +34,115 @@ class MapBlock; class ServerEnvironment; class EmergeManager; +/* + * State Transitions + + Start + (peer connect) + | + v + /-----------------\ + | | + | Created | + | | + \-----------------/ + | + | ++-----------------------------+ invalid playername, password +|IN: | or denied by mod +| TOSERVER_INIT |------------------------------ ++-----------------------------+ | + | | + | Auth ok | + | | ++-----------------------------+ | +|OUT: | | +| TOCLIENT_INIT | | ++-----------------------------+ | + | | + v | + /-----------------\ | + | | | + | InitSent | | + | | | + \-----------------/ +------------------ + | | | ++-----------------------------+ +-----------------------------+ | +|IN: | |OUT: | | +| TOSERVER_INIT2 | | TOCLIENT_ACCESS_DENIED | | ++-----------------------------+ +-----------------------------+ | + | | | + v v | + /-----------------\ /-----------------\ | + | | | | | + | InitDone | | Denied | | + | | | | | + \-----------------/ \-----------------/ | + | | ++-----------------------------+ | +|OUT: | | +| TOCLIENT_MOVEMENT | | +| TOCLIENT_ITEMDEF | | +| TOCLIENT_NODEDEF | | +| TOCLIENT_ANNOUNCE_MEDIA | | +| TOCLIENT_DETACHED_INVENTORY | | +| TOCLIENT_TIME_OF_DAY | | ++-----------------------------+ | + | | + | | + | ----------------------------------- | + v | | | + /-----------------\ v | + | | +-----------------------------+ | + | DefinitionsSent | |IN: | | + | | | TOSERVER_REQUEST_MEDIA | | + \-----------------/ | TOSERVER_RECEIVED_MEDIA | | + | +-----------------------------+ | + | ^ | | + | ----------------------------------- | + | | ++-----------------------------+ | +|IN: | | +| TOSERVER_CLIENT_READY | | ++-----------------------------+ | + | async | + v mod action | ++-----------------------------+ (ban,kick) | +|OUT: | | +| TOCLIENT_MOVE_PLAYER | | +| TOCLIENT_PRIVILEGES | | +| TOCLIENT_INVENTORY_FORMSPEC | | +| UpdateCrafting | | +| TOCLIENT_INVENTORY | | +| TOCLIENT_HP (opt) | | +| TOCLIENT_BREATH | | +| TOCLIENT_DEATHSCREEN | | ++-----------------------------+ | + | | + v | + /-----------------\ | + | |------------------------------------------------------ + | Active | + | |---------------------------------- + \-----------------/ timeout | + | +-----------------------------+ + | |OUT: | + | | TOCLIENT_DISCONNECT | + | +-----------------------------+ + | | + | v ++-----------------------------+ /-----------------\ +|IN: | | | +| TOSERVER_DISCONNECT |------------------->| Disconnecting | ++-----------------------------+ | | + \-----------------/ +*/ namespace con { class Connection; } +#define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0])) + enum ClientState { Invalid, @@ -50,13 +155,24 @@ enum ClientState Active }; +static const char* statenames[] = { + "Invalid", + "Disconnecting", + "Denied", + "Created", + "InitSent", + "InitDone", + "DefinitionsSent", + "Active" +}; + enum ClientStateEvent { Init, GotInit2, SetDenied, SetDefinitionsSent, - SetMediaSent, + SetClientReady, Disconnect }; @@ -105,9 +221,13 @@ public: m_nearest_unsent_d(0), m_nearest_unsent_reset_timer(0.0), m_excess_gotblocks(0), - m_nothing_to_send_counter(0), m_nothing_to_send_pause_timer(0.0), - m_name("") + m_name(""), + m_version_major(0), + m_version_minor(0), + m_version_patch(0), + m_full_version("unknown"), + m_connection_time(getTime(PRECISION_SECONDS)) { } ~RemoteClient() @@ -178,6 +298,23 @@ public: void confirmSerializationVersion() { serialization_version = m_pending_serialization_version; } + /* get uptime */ + u32 uptime(); + + + /* set version information */ + void setVersionInfo(u8 major, u8 minor, u8 patch, std::string full) { + m_version_major = major; + m_version_minor = minor; + m_version_patch = patch; + m_full_version = full; + } + + /* read version information */ + u8 getMajor() { return m_version_major; } + u8 getMinor() { return m_version_minor; } + u8 getPatch() { return m_version_patch; } + std::string getVersion() { return m_full_version; } private: // Version is stored in here after INIT before INIT2 u8 m_pending_serialization_version; @@ -219,9 +356,26 @@ private: u32 m_excess_gotblocks; // CPU usage optimization - u32 m_nothing_to_send_counter; float m_nothing_to_send_pause_timer; + + /* + name of player using this client + */ std::string m_name; + + /* + client information + */ + u8 m_version_major; + u8 m_version_minor; + u8 m_version_patch; + + std::string m_full_version; + + /* + time this client was created + */ + const u32 m_connection_time; }; class ClientInterface { @@ -268,6 +422,9 @@ public: /* get protocol version of client */ u16 getProtocolVersion(u16 peer_id); + /* set client version */ + void setClientVersion(u16 peer_id, u8 major, u8 minor, u8 patch, std::string full); + /* event to update client state */ void event(u16 peer_id, ClientStateEvent event); @@ -275,6 +432,11 @@ public: void setEnv(ServerEnvironment* env) { assert(m_env == 0); m_env = env; } + static std::string state2Name(ClientState state) { + assert((int) state < ARRAYSIZE(statenames)); + return statenames[state]; + } + protected: //TODO find way to avoid this functions void Lock() diff --git a/src/clientmap.cpp b/src/clientmap.cpp index 20a59f26..0a5d00b9 100644 --- a/src/clientmap.cpp +++ b/src/clientmap.cpp @@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapblock.h" #include "profiler.h" #include "settings.h" +#include "camera.h" // CameraModes #include "util/mathconstants.h" #include @@ -866,13 +867,16 @@ void ClientMap::renderPostFx() v3f camera_position = m_camera_position; m_camera_mutex.Unlock(); + LocalPlayer *player = m_client->getEnv().getLocalPlayer(); + MapNode n = getNodeNoEx(floatToInt(camera_position, BS)); // - If the player is in a solid node, make everything black. // - If the player is in liquid, draw a semi-transparent overlay. + // - Do not if player is in third person mode const ContentFeatures& features = nodemgr->get(n); video::SColor post_effect_color = features.post_effect_color; - if(features.solidness == 2 && !(g_settings->getBool("noclip") && m_gamedef->checkLocalPrivilege("noclip"))) + if(features.solidness == 2 && !(g_settings->getBool("noclip") && m_gamedef->checkLocalPrivilege("noclip")) && player->camera_mode == CAMERA_MODE_FIRST) { post_effect_color = video::SColor(255, 0, 0, 0); } diff --git a/src/clientobject.h b/src/clientobject.h index 613c635a..233617b5 100644 --- a/src/clientobject.h +++ b/src/clientobject.h @@ -55,7 +55,7 @@ public: virtual void updateLight(u8 light_at_pos){} virtual v3s16 getLightPosition(){return v3s16(0,0,0);} virtual core::aabbox3d* getSelectionBox(){return NULL;} - virtual core::aabbox3d* getCollisionBox(){return NULL;} + virtual bool getCollisionBox(aabb3f *toset){return false;} virtual bool collideWithObjects(){return false;} virtual v3f getPosition(){return v3f(0,0,0);} virtual scene::IMeshSceneNode *getMeshSceneNode(){return NULL;} diff --git a/src/clientserver.h b/src/clientserver.h index d1e250ea..1f2e19e4 100644 --- a/src/clientserver.h +++ b/src/clientserver.h @@ -100,9 +100,13 @@ with this program; if not, write to the Free Software Foundation, Inc., version, heat and humidity transfer in MapBock automatic_face_movement_dir and automatic_face_movement_dir_offset added to object properties + PROTOCOL_VERSION 22: + add swap_node + PROTOCOL_VERSION 23: + TOSERVER_CLIENT_READY */ -#define LATEST_PROTOCOL_VERSION 22 +#define LATEST_PROTOCOL_VERSION 23 // Server's supported network protocol range #define SERVER_PROTOCOL_VERSION_MIN 13 @@ -129,7 +133,7 @@ enum ToClientCommand [0] u16 TOSERVER_INIT [2] u8 deployed version - [3] v3s16 player's position + v3f(0,BS/2,0) floatToInt'd + [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) @@ -526,6 +530,23 @@ enum ToClientCommand u8 do_override (boolean) u16 day-night ratio 0...65535 */ + + TOCLIENT_LOCAL_PLAYER_ANIMATIONS = 0x51, + /* + u16 command + v2s32 stand/idle + v2s32 walk + v2s32 dig + v2s32 walk+dig + f1000 frame_speed + */ + + TOCLIENT_EYE_OFFSET = 0x52, + /* + u16 command + v3f1000 first + v3f1000 third + */ }; enum ToServerCommand @@ -755,6 +776,16 @@ enum ToServerCommand u16 command u16 breath */ + + TOSERVER_CLIENT_READY = 0x43, + /* + u8 major + u8 minor + u8 patch + u8 reserved + u16 len + u8[len] full_version_string + */ }; #endif diff --git a/src/clouds.h b/src/clouds.h index d718e56b..a6883a44 100644 --- a/src/clouds.h +++ b/src/clouds.h @@ -76,7 +76,6 @@ private: video::SMaterial m_material; core::aabbox3d m_box; float m_cloud_y; - float m_brightness; video::SColorf m_color; u32 m_seed; v2f m_camera_pos; diff --git a/src/cmake_config.h.in b/src/cmake_config.h.in index 17d3c224..906b3e47 100644 --- a/src/cmake_config.h.in +++ b/src/cmake_config.h.in @@ -14,6 +14,7 @@ #define CMAKE_STATIC_SHAREDIR "@SHAREDIR@" #define CMAKE_USE_LEVELDB @USE_LEVELDB@ #define CMAKE_USE_LUAJIT @USE_LUAJIT@ +#define CMAKE_USE_REDIS @USE_REDIS@ #define CMAKE_VERSION_MAJOR @VERSION_MAJOR@ #define CMAKE_VERSION_MINOR @VERSION_MINOR@ #define CMAKE_VERSION_PATCH @VERSION_PATCH@ diff --git a/src/config.h b/src/config.h index 55bbb5be..8a9d7d63 100644 --- a/src/config.h +++ b/src/config.h @@ -9,12 +9,28 @@ #define PROJECT_NAME "Minetest" #define RUN_IN_PLACE 0 #define USE_GETTEXT 0 -#define USE_SOUND 0 -#define USE_CURL 0 +#ifndef USE_SOUND + #define USE_SOUND 0 +#endif + +#ifndef USE_CURL + #define USE_CURL 0 +#endif + #define USE_FREETYPE 0 #define STATIC_SHAREDIR "" -#define USE_LEVELDB 0 -#define USE_LUAJIT 0 + +#ifndef USE_LEVELDB + #define USE_LEVELDB 0 +#endif + +#ifndef USE_LUAJIT + #define USE_LUAJIT 0 +#endif + +#ifndef USE_REDIS + #define USE_REDIS 0 +#endif #ifdef USE_CMAKE_CONFIG_H #include "cmake_config.h" @@ -36,6 +52,8 @@ #define USE_LEVELDB CMAKE_USE_LEVELDB #undef USE_LUAJIT #define USE_LUAJIT CMAKE_USE_LUAJIT + #undef USE_REDIS + #define USE_REDIS CMAKE_USE_REDIS #undef VERSION_MAJOR #define VERSION_MAJOR CMAKE_VERSION_MAJOR #undef VERSION_MINOR diff --git a/src/connection.cpp b/src/connection.cpp index f8c68ed2..32634ac8 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -212,7 +212,7 @@ SharedBuffer makeReliablePacket( ReliablePacketBuffer */ -ReliablePacketBuffer::ReliablePacketBuffer(): m_list_size(0),writeptr(0) {} +ReliablePacketBuffer::ReliablePacketBuffer(): m_list_size(0) {} void ReliablePacketBuffer::print() { @@ -1170,7 +1170,7 @@ void UDPPeer::RunCommandQueues( channels[i].queued_commands.push_front(c); } } - catch (ItemNotFoundException e) { + catch (ItemNotFoundException &e) { // intentionally empty } } @@ -1227,6 +1227,8 @@ void * ConnectionSendThread::Thread() PROFILE(std::stringstream ThreadIdentifier); PROFILE(ThreadIdentifier << "ConnectionSend: [" << m_connection->getDesc() << "]"); + porting::setThreadName("ConnectionSend"); + /* if stop is requested don't stop immediately but try to send all */ /* packets first */ while(!StopRequested() || packetsQueued()) { @@ -1939,8 +1941,7 @@ void ConnectionSendThread::sendAsPacket(u16 peer_id, u8 channelnum, ConnectionReceiveThread::ConnectionReceiveThread(Connection* parent, unsigned int max_packet_size) : - m_connection(parent), - m_max_packet_size(max_packet_size) + m_connection(parent) { } @@ -1955,6 +1956,8 @@ void * ConnectionReceiveThread::Thread() PROFILE(std::stringstream ThreadIdentifier); PROFILE(ThreadIdentifier << "ConnectionReceive: [" << m_connection->getDesc() << "]"); + porting::setThreadName("ConnectionReceive"); + #ifdef DEBUG_CONNECTION_KBPS u32 curtime = porting::getTimeMs(); u32 lasttime = curtime; @@ -2067,7 +2070,7 @@ void ConnectionReceiveThread::receive() m_connection->putEvent(e); } } - catch(ProcessedSilentlyException e) { + catch(ProcessedSilentlyException &e) { /* try reading again */ } } @@ -2875,11 +2878,11 @@ Address Connection::GetPeerAddress(u16 peer_id) return peer_address; } -float Connection::GetPeerAvgRTT(u16 peer_id) +float Connection::getPeerStat(u16 peer_id, rtt_stat_type type) { PeerHelper peer = getPeerNoEx(peer_id); if (!peer) return -1; - return peer->getStat(AVG_RTT); + return peer->getStat(type); } u16 Connection::createPeer(Address& sender, MTProtocols protocol, int fd) diff --git a/src/connection.h b/src/connection.h index 9d646f49..43fd2fb8 100644 --- a/src/connection.h +++ b/src/connection.h @@ -339,13 +339,11 @@ private: RPBSearchResult findPacket(u16 seqnum); std::list m_list; - u16 m_list_size; + u32 m_list_size; u16 m_oldest_non_answered_ack; JMutex m_list_mutex; - - unsigned int writeptr; }; /* @@ -975,7 +973,6 @@ private: Connection* m_connection; - unsigned int m_max_packet_size; }; class Connection @@ -1004,7 +1001,7 @@ public: void Send(u16 peer_id, u8 channelnum, SharedBuffer data, bool reliable); u16 GetPeerID(){ return m_peer_id; } Address GetPeerAddress(u16 peer_id); - float GetPeerAvgRTT(u16 peer_id); + float getPeerStat(u16 peer_id, rtt_stat_type type); const u32 GetProtocolID() const { return m_protocol_id; }; const std::string getDesc(); void DisconnectPeer(u16 peer_id); diff --git a/src/constants.h b/src/constants.h index 17f5d389..8c478ac6 100644 --- a/src/constants.h +++ b/src/constants.h @@ -89,11 +89,5 @@ with this program; if not, write to the Free Software Foundation, Inc., // Maximum hit points of a player #define PLAYER_MAX_HP 20 -/* - Environmental condition constants -*/ -#define HEAT_UNDEFINED (-0x7fff-1) -#define HUMIDITY_UNDEFINED (-0x7fff-1) - #endif diff --git a/src/content_abm.cpp b/src/content_abm.cpp index 9289035b..1ee41b2e 100644 --- a/src/content_abm.cpp +++ b/src/content_abm.cpp @@ -32,216 +32,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" -class LiquidFlowABM : public ActiveBlockModifier { - private: - std::set contents; - - public: - LiquidFlowABM(ServerEnvironment *env, INodeDefManager *nodemgr) { - std::set liquids; - nodemgr->getIds("group:liquid", liquids); - for(std::set::const_iterator k = liquids.begin(); k != liquids.end(); k++) - contents.insert(nodemgr->get(*k).liquid_alternative_flowing); - } - virtual std::set getTriggerContents() { - return contents; - } - virtual float getTriggerInterval() - { return 10.0; } - virtual u32 getTriggerChance() - { return 10; } - virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) { - ServerMap *map = &env->getServerMap(); - if (map->transforming_liquid_size() > 500) - return; - map->transforming_liquid_add(p); - } -}; - -class LiquidDropABM : public ActiveBlockModifier { - private: - std::set contents; - - public: - LiquidDropABM(ServerEnvironment *env, INodeDefManager *nodemgr) { - std::set liquids; - nodemgr->getIds("group:liquid", liquids); - for(std::set::const_iterator k = liquids.begin(); k != liquids.end(); k++) - contents.insert(nodemgr->get(*k).liquid_alternative_source); - } - virtual std::set getTriggerContents() - { return contents; } - virtual std::set getRequiredNeighbors() { - std::set neighbors; - neighbors.insert("air"); - return neighbors; - } - virtual float getTriggerInterval() - { return 20.0; } - virtual u32 getTriggerChance() - { return 10; } - virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) { - ServerMap *map = &env->getServerMap(); - if (map->transforming_liquid_size() > 500) - return; - if ( map->getNodeNoEx(p - v3s16(0, 1, 0 )).getContent() != CONTENT_AIR // below - && map->getNodeNoEx(p - v3s16(1, 0, 0 )).getContent() != CONTENT_AIR // right - && map->getNodeNoEx(p - v3s16(-1, 0, 0 )).getContent() != CONTENT_AIR // left - && map->getNodeNoEx(p - v3s16(0, 0, 1 )).getContent() != CONTENT_AIR // back - && map->getNodeNoEx(p - v3s16(0, 0, -1)).getContent() != CONTENT_AIR // front - ) - return; - map->transforming_liquid_add(p); - } -}; - -class LiquidFreeze : public ActiveBlockModifier { - public: - LiquidFreeze(ServerEnvironment *env, INodeDefManager *nodemgr) { } - virtual std::set getTriggerContents() { - std::set s; - s.insert("group:freezes"); - return s; - } - virtual std::set getRequiredNeighbors() { - std::set s; - s.insert("air"); - s.insert("group:melts"); - return s; - } - virtual float getTriggerInterval() - { return 10.0; } - virtual u32 getTriggerChance() - { return 20; } - virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) { - ServerMap *map = &env->getServerMap(); - INodeDefManager *ndef = env->getGameDef()->ndef(); - - float heat = map->updateBlockHeat(env, p); - //heater = rare - content_t c = map->getNodeNoEx(p - v3s16(0, -1, 0 )).getContent(); // top - //more chance to freeze if air at top - if (heat <= -1 && (heat <= -50 || (myrand_range(-50, heat) <= (c == CONTENT_AIR ? -10 : -40)))) { - content_t c_self = n.getContent(); - // making freeze not annoying, do not freeze random blocks in center of ocean - // todo: any block not water (dont freeze _source near _flowing) - bool allow = heat < -40; - // todo: make for(...) - if (!allow) { - c = map->getNodeNoEx(p - v3s16(0, 1, 0 )).getContent(); // below - if (c == CONTENT_AIR || c == CONTENT_IGNORE) - return; // do not freeze when falling - if (c != c_self && c != CONTENT_IGNORE) allow = 1; - if (!allow) { - c = map->getNodeNoEx(p - v3s16(1, 0, 0 )).getContent(); // right - if (c != c_self && c != CONTENT_IGNORE) allow = 1; - if (!allow) { - c = map->getNodeNoEx(p - v3s16(-1, 0, 0 )).getContent(); // left - if (c != c_self && c != CONTENT_IGNORE) allow = 1; - if (!allow) { - c = map->getNodeNoEx(p - v3s16(0, 0, 1 )).getContent(); // back - if (c != c_self && c != CONTENT_IGNORE) allow = 1; - if (!allow) { - c = map->getNodeNoEx(p - v3s16(0, 0, -1)).getContent(); // front - if (c != c_self && c != CONTENT_IGNORE) allow = 1; - } - } - } - } - } - if (allow) { - n.freezeMelt(ndef); - map->addNodeWithEvent(p, n); - } - } - } -}; - -class LiquidMeltWeather : public ActiveBlockModifier { - public: - LiquidMeltWeather(ServerEnvironment *env, INodeDefManager *nodemgr) { } - virtual std::set getTriggerContents() { - std::set s; - s.insert("group:melts"); - return s; - } - virtual std::set getRequiredNeighbors() { - std::set s; - s.insert("air"); - s.insert("group:freezes"); - return s; - } - virtual float getTriggerInterval() - { return 10.0; } - virtual u32 getTriggerChance() - { return 20; } - virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) { - ServerMap *map = &env->getServerMap(); - INodeDefManager *ndef = env->getGameDef()->ndef(); - - float heat = map->updateBlockHeat(env, p); - content_t c = map->getNodeNoEx(p - v3s16(0, -1, 0 )).getContent(); // top - if (heat >= 1 && (heat >= 40 || ((myrand_range(heat, 40)) >= (c == CONTENT_AIR ? 10 : 20)))) { - n.freezeMelt(ndef); - map->addNodeWithEvent(p, n); - env->getScriptIface()->node_falling_update(p); - } - } -}; - -class LiquidMeltHot : public ActiveBlockModifier { - public: - LiquidMeltHot(ServerEnvironment *env, INodeDefManager *nodemgr) { } - virtual std::set getTriggerContents() { - std::set s; - s.insert("group:melts"); - return s; - } - virtual std::set getRequiredNeighbors() { - std::set s; - s.insert("group:igniter"); - s.insert("group:hot"); - return s; - } - virtual float getTriggerInterval() - { return 2.0; } - virtual u32 getTriggerChance() - { return 4; } - virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) { - ServerMap *map = &env->getServerMap(); - INodeDefManager *ndef = env->getGameDef()->ndef(); - n.freezeMelt(ndef); - map->addNodeWithEvent(p, n); - env->getScriptIface()->node_falling_update(p); - } -}; - -/* too buggy, later via liquid flow code -class LiquidMeltAround : public LiquidMeltHot { - public: - LiquidMeltAround(ServerEnvironment *env, INodeDefManager *nodemgr) - : LiquidMeltHot(env, nodemgr) { } - virtual std::set getRequiredNeighbors() { - std::set s; - s.insert("group:melt_around"); - return s; - } - virtual float getTriggerInterval() - { return 40.0; } - virtual u32 getTriggerChance() - { return 60; } -}; -*/ - void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef) { - if (g_settings->getBool("liquid_finite")) { - env->addActiveBlockModifier(new LiquidFlowABM(env, nodedef)); - env->addActiveBlockModifier(new LiquidDropABM(env, nodedef)); - env->addActiveBlockModifier(new LiquidMeltHot(env, nodedef)); - //env->addActiveBlockModifier(new LiquidMeltAround(env, nodedef)); - if (env->m_use_weather) { - env->addActiveBlockModifier(new LiquidFreeze(env, nodedef)); - env->addActiveBlockModifier(new LiquidMeltWeather(env, nodedef)); - } - } + } diff --git a/src/content_cao.cpp b/src/content_cao.cpp index 84ec3e14..10aa22e7 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -41,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/mathconstants.h" #include "map.h" #include "main.h" // g_settings +#include "camera.h" // CameraModes #include #include #include @@ -165,7 +166,7 @@ public: void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, IrrlichtDevice *irr); - void removeFromScene(); + void removeFromScene(bool permanent); void updateLight(u8 light_at_pos); v3s16 getLightPosition(); void updateNodePos(); @@ -235,7 +236,7 @@ void TestCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, updateNodePos(); } -void TestCAO::removeFromScene() +void TestCAO::removeFromScene(bool permanent) { if(m_node == NULL) return; @@ -309,7 +310,7 @@ public: void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, IrrlichtDevice *irr); - void removeFromScene(); + void removeFromScene(bool permanent); void updateLight(u8 light_at_pos); v3s16 getLightPosition(); void updateNodePos(); @@ -411,7 +412,7 @@ void ItemCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, updateTexture(); } -void ItemCAO::removeFromScene() +void ItemCAO::removeFromScene(bool permanent) { if(m_node == NULL) return; @@ -580,7 +581,7 @@ private: v2s16 m_tx_basepos; bool m_initial_tx_basepos_set; bool m_tx_select_horiz_by_yawpitch; - v2f m_animation_range; + v2s32 m_animation_range; int m_animation_speed; int m_animation_blend; std::map > m_bone_position; // stores position and rotation for each bone name @@ -623,7 +624,7 @@ public: 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_range(v2s32(0,0)), m_animation_speed(15), m_animation_blend(0), m_bone_position(std::map >()), @@ -647,7 +648,6 @@ public: bool getCollisionBox(aabb3f *toset) { if (m_prop.physical) { - aabb3f retval; //update collision box toset->MinEdge = m_prop.collisionbox.MinEdge * BS; toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS; @@ -858,7 +858,7 @@ public: m_visuals_expired = false; - if(!m_prop.is_visible || m_is_local_player) + if(!m_prop.is_visible) return; //video::IVideoDriver* driver = smgr->getVideoDriver(); @@ -1078,6 +1078,76 @@ public: void step(float dtime, ClientEnvironment *env) { + // Handel model of local player instantly to prevent lags + if(m_is_local_player) { + LocalPlayer *player = m_env->getLocalPlayer(); + + if (player->camera_mode > CAMERA_MODE_FIRST) { + int old_anim = player->last_animation; + float old_anim_speed = player->last_animation_speed; + m_is_visible = true; + m_position = player->getPosition() + v3f(0,BS,0); + m_velocity = v3f(0,0,0); + m_acceleration = v3f(0,0,0); + pos_translator.vect_show = m_position; + m_yaw = player->getYaw(); + PlayerControl controls = player->getPlayerControl(); + + bool walking = false; + if(controls.up || controls.down || controls.left || controls.right) + walking = true; + + f32 new_speed = player->local_animation_speed; + v2s32 new_anim = v2s32(0,0); + bool allow_update = false; + + if(!player->touching_ground && + g_settings->getBool("free_move") && + m_gamedef->checkLocalPrivilege("fly") && + g_settings->getBool("fast_move") && + m_gamedef->checkLocalPrivilege("fast")) + new_speed *= 1.5; + if(controls.sneak && walking) + new_speed /= 2; + + if(walking && (controls.LMB || controls.RMB)) { + new_anim = player->local_animations[3]; + player->last_animation = WD_ANIM; + } else if(walking) { + new_anim = player->local_animations[1]; + player->last_animation = WALK_ANIM; + } else if(controls.LMB || controls.RMB) { + new_anim = player->local_animations[2]; + player->last_animation = DIG_ANIM; + } + + if ((new_anim.X + new_anim.Y) > 0) { + allow_update = true; + m_animation_range = new_anim; + m_animation_speed = new_speed; + player->last_animation_speed = m_animation_speed; + } else { + player->last_animation = NO_ANIM; + } + // reset animation when no input detected + if (!walking && !controls.LMB && !controls.RMB) { + player->last_animation = NO_ANIM; + if (old_anim != NO_ANIM) { + m_animation_range = player->local_animations[0]; + updateAnimation(); + } + } + + // Update local player animations + if ((player->last_animation != old_anim || m_animation_speed != old_anim_speed) && + player->last_animation != NO_ANIM && allow_update) + updateAnimation(); + + } else { + m_is_visible = false; + } + } + if(m_visuals_expired && m_smgr && m_irr){ m_visuals_expired = false; @@ -1440,8 +1510,7 @@ public: { if(m_animated_meshnode == NULL) return; - - m_animated_meshnode->setFrameLoop((int)m_animation_range.X, (int)m_animation_range.Y); + m_animated_meshnode->setFrameLoop(m_animation_range.X, m_animation_range.Y); m_animated_meshnode->setAnimationSpeed(m_animation_speed); m_animated_meshnode->setTransitionTime(m_animation_blend); } @@ -1701,6 +1770,7 @@ public: bool sneak = !readU8(is); bool sneak_glitch = !readU8(is); + if(m_is_local_player) { LocalPlayer *player = m_env->getLocalPlayer(); @@ -1713,11 +1783,31 @@ public: } else if(cmd == GENERIC_CMD_SET_ANIMATION) { - m_animation_range = readV2F1000(is); - m_animation_speed = readF1000(is); - m_animation_blend = readF1000(is); - - updateAnimation(); + // TODO: change frames send as v2s32 value + v2f range = readV2F1000(is); + if (!m_is_local_player) { + m_animation_range = v2s32((s32)range.X, (s32)range.Y); + m_animation_speed = readF1000(is); + m_animation_blend = readF1000(is); + updateAnimation(); + } else { + LocalPlayer *player = m_env->getLocalPlayer(); + if(player->last_animation == NO_ANIM) { + m_animation_range = v2s32((s32)range.X, (s32)range.Y); + m_animation_speed = readF1000(is); + m_animation_blend = readF1000(is); + } + // update animation only if local animations present + // and received animation is not unknown + int frames = 0; + for (int i = 0;i<4;i++) { + frames += (int)player->local_animations[i].Y; + } + if(frames < 1) { + player->last_animation = NO_ANIM; + updateAnimation(); + } + } } else if(cmd == GENERIC_CMD_SET_BONE_POSITION) { diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp index cda1846a..3637094f 100644 --- a/src/content_mapblock.cpp +++ b/src/content_mapblock.cpp @@ -219,7 +219,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, if(ntop.getContent() == c_flowing || ntop.getContent() == c_source) top_is_same_liquid = true; - u16 l = getInteriorLight(n, 0, data); + u16 l = getInteriorLight(n, 0, nodedef); video::SColor c = MapBlock_LightColor(f.alpha, l, decode_light(f.light_source)); /* @@ -389,10 +389,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data, } // Use the light of the node on top if possible else if(nodedef->get(ntop).param_type == CPT_LIGHT) - l = getInteriorLight(ntop, 0, data); + l = getInteriorLight(ntop, 0, nodedef); // Otherwise use the light of this node (the liquid) else - l = getInteriorLight(n, 0, data); + l = getInteriorLight(n, 0, nodedef); video::SColor c = MapBlock_LightColor(f.alpha, l, decode_light(f.light_source)); u8 range = rangelim(nodedef->get(c_flowing).liquid_range, 1, 8); @@ -696,7 +696,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, { TileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data); - u16 l = getInteriorLight(n, 1, data); + u16 l = getInteriorLight(n, 1, nodedef); video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); for(u32 j=0; j<6; j++) @@ -758,7 +758,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, TileSpec tiles[2]; tiles[0] = getNodeTile(n, p, dirs[0], data); tiles[1] = getNodeTile(n, p, dirs[1], data); - u16 l = getInteriorLight(n, 1, data); + u16 l = getInteriorLight(n, 1, nodedef); video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); v3f pos = intToFloat(p, BS); static const float a=BS/2; @@ -876,7 +876,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, TileSpec tile_leaves = getNodeTile(n, p, v3s16(0,0,0), data); - u16 l = getInteriorLight(n, 1, data); + u16 l = getInteriorLight(n, 1, nodedef); video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); v3f pos = intToFloat(p, BS); @@ -909,7 +909,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING; tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY; - u16 l = getInteriorLight(n, 1, data); + u16 l = getInteriorLight(n, 1, nodedef); video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); float s = BS/2*f.visual_scale; @@ -950,7 +950,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING; tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY; - u16 l = getInteriorLight(n, 0, data); + u16 l = getInteriorLight(n, 0, nodedef); video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); float d = (float)BS/16; @@ -993,7 +993,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, TileSpec tile = getNodeTileN(n, p, 0, data); tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY; - u16 l = getInteriorLight(n, 1, data); + u16 l = getInteriorLight(n, 1, nodedef); video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); float s = BS/2*f.visual_scale; @@ -1045,7 +1045,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, texturestring_rot, &tile_rot.texture_id); - u16 l = getInteriorLight(n, 1, data); + u16 l = getInteriorLight(n, 1, nodedef); video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); const f32 post_rad=(f32)BS/8; @@ -1294,7 +1294,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING; tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY; - u16 l = getInteriorLight(n, 0, data); + u16 l = getInteriorLight(n, 0, nodedef); video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); float d = (float)BS/64; @@ -1333,7 +1333,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, }; TileSpec tiles[6]; - u16 l = getInteriorLight(n, 0, data); + u16 l = getInteriorLight(n, 0, nodedef); video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); v3f pos = intToFloat(p, BS); diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 52b74136..095c6b5b 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -191,7 +191,7 @@ public: } ItemSAO(ServerEnvironment *env, v3f pos, - const std::string itemstring): + const std::string &itemstring): ServerActiveObject(env, pos), m_itemstring(itemstring), m_itemstring_changed(false), @@ -350,7 +350,7 @@ private: ItemSAO proto_ItemSAO(NULL, v3f(0,0,0), ""); ServerActiveObject* createItemSAO(ServerEnvironment *env, v3f pos, - const std::string itemstring) + const std::string &itemstring) { return new ItemSAO(env, pos, itemstring); } diff --git a/src/content_sao.h b/src/content_sao.h index 1be620f2..63e8ef46 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "object_properties.h" ServerActiveObject* createItemSAO(ServerEnvironment *env, v3f pos, - const std::string itemstring); + const std::string &itemstring); /* LuaEntitySAO needs some internals exposed. @@ -37,7 +37,7 @@ class LuaEntitySAO : public ServerActiveObject { public: LuaEntitySAO(ServerEnvironment *env, v3f pos, - const std::string &name, const std::string &state); + const std::string &name, const std::string &state); ~LuaEntitySAO(); u8 getType() const { return ACTIVEOBJECT_TYPE_LUAENTITY; } diff --git a/src/convert_json.cpp b/src/convert_json.cpp index c8e57aaf..6f227e79 100644 --- a/src/convert_json.cpp +++ b/src/convert_json.cpp @@ -31,8 +31,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "httpfetch.h" #include "porting.h" -Json::Value fetchJsonValue(const std::string url, - struct curl_slist *chunk) { +Json::Value fetchJsonValue(const std::string &url, + struct curl_slist *chunk) { #if USE_CURL HTTPFetchRequest fetchrequest; diff --git a/src/convert_json.h b/src/convert_json.h index 3fa9903b..ea9bafb7 100644 --- a/src/convert_json.h +++ b/src/convert_json.h @@ -28,7 +28,7 @@ struct ModStoreModDetails; std::vector readModStoreList(Json::Value& modlist); ModStoreModDetails readModStoreModDetails(Json::Value& details); -Json::Value fetchJsonValue(const std::string url, - struct curl_slist *chunk); +Json::Value fetchJsonValue(const std::string &url, + struct curl_slist *chunk); #endif diff --git a/src/database-dummy.cpp b/src/database-dummy.cpp index acc19ca0..c4794d28 100644 --- a/src/database-dummy.cpp +++ b/src/database-dummy.cpp @@ -151,7 +151,7 @@ MapBlock* Database_Dummy::loadBlock(v3s16 blockpos) void Database_Dummy::listAllLoadableBlocks(std::list &dst) { - for(std::map::iterator x = m_database.begin(); x != m_database.end(); ++x) + for(std::map::iterator x = m_database.begin(); x != m_database.end(); ++x) { v3s16 p = getIntegerAsBlock(x->first); //dstream<<"block_i="< #include +#include "database.h" +#include "irrlichttypes.h" class ServerMap; @@ -39,6 +40,6 @@ public: ~Database_Dummy(); private: ServerMap *srvmap; - std::map m_database; + std::map m_database; }; #endif diff --git a/src/database-redis.cpp b/src/database-redis.cpp new file mode 100644 index 00000000..1d77608f --- /dev/null +++ b/src/database-redis.cpp @@ -0,0 +1,224 @@ +/* +Minetest +Copyright (C) 2014 celeron55, Perttu Ahola + +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 "config.h" + +#if USE_REDIS +/* + Redis databases +*/ + + +#include "database-redis.h" +#include + +#include "map.h" +#include "mapsector.h" +#include "mapblock.h" +#include "serialization.h" +#include "main.h" +#include "settings.h" +#include "log.h" + +Database_Redis::Database_Redis(ServerMap *map, std::string savedir) +{ + Settings conf; + conf.readConfigFile((std::string(savedir) + DIR_DELIM + "world.mt").c_str()); + std::string tmp; + try { + tmp = conf.get("redis_address"); + hash = conf.get("redis_hash"); + } catch(SettingNotFoundException e) { + throw SettingNotFoundException("Set redis_address and redis_hash in world.mt to use the redis backend"); + } + const char *addr = tmp.c_str(); + int port = conf.exists("redis_port") ? conf.getU16("redis_port") : 6379; + ctx = redisConnect(addr, port); + if(!ctx) + throw FileNotGoodException("Cannot allocate redis context"); + else if(ctx->err) { + std::string err = std::string("Connection error: ") + ctx->errstr; + redisFree(ctx); + throw FileNotGoodException(err); + } + srvmap = map; +} + +int Database_Redis::Initialized(void) +{ + return 1; +} + +void Database_Redis::beginSave() { + redisReply *reply; + reply = (redisReply*) redisCommand(ctx, "MULTI"); + if(!reply) + throw FileNotGoodException(std::string("redis command 'MULTI' failed: ") + ctx->errstr); + freeReplyObject(reply); +} + +void Database_Redis::endSave() { + redisReply *reply; + reply = (redisReply*) redisCommand(ctx, "EXEC"); + if(!reply) + throw FileNotGoodException(std::string("redis command 'EXEC' failed: ") + ctx->errstr); + freeReplyObject(reply); +} + +void Database_Redis::saveBlock(MapBlock *block) +{ + DSTACK(__FUNCTION_NAME); + /* + Dummy blocks are not written + */ + if(block->isDummy()) + { + return; + } + + // Format used for writing + u8 version = SER_FMT_VER_HIGHEST_WRITE; + // Get destination + v3s16 p3d = block->getPos(); + + /* + [0] u8 serialization version + [1] data + */ + + std::ostringstream o(std::ios_base::binary); + o.write((char*)&version, 1); + // Write basic data + block->serialize(o, version, true); + // Write block to database + std::string tmp1 = o.str(); + std::string tmp2 = i64tos(getBlockAsInteger(p3d)); + + redisReply *reply; + reply = (redisReply*) redisCommand(ctx, "HSET %s %s %b", hash.c_str(), tmp2.c_str(), tmp1.c_str(), tmp1.size()); + if(!reply) + throw FileNotGoodException(std::string("redis command 'HSET %s %s %b' failed: ") + ctx->errstr); + if(reply->type == REDIS_REPLY_ERROR) + throw FileNotGoodException("Failed to store block in Database"); + + // We just wrote it to the disk so clear modified flag + block->resetModified(); +} + +MapBlock* Database_Redis::loadBlock(v3s16 blockpos) +{ + v2s16 p2d(blockpos.X, blockpos.Z); + + std::string tmp = i64tos(getBlockAsInteger(blockpos)); + redisReply *reply; + reply = (redisReply*) redisCommand(ctx, "HGET %s %s", hash.c_str(), tmp.c_str()); + if(!reply) + throw FileNotGoodException(std::string("redis command 'HGET %s %s' failed: ") + ctx->errstr); + + if (reply->type == REDIS_REPLY_STRING && reply->len == 0) { + freeReplyObject(reply); + errorstream << "Blank block data in database (reply->len == 0) (" + << blockpos.X << "," << blockpos.Y << "," << blockpos.Z << ")" << std::endl; + + if (g_settings->getBool("ignore_world_load_errors")) { + errorstream << "Ignoring block load error. Duck and cover! " + << "(ignore_world_load_errors)" << std::endl; + } else { + throw SerializationError("Blank block data in database"); + } + return NULL; + } + + if (reply->type == REDIS_REPLY_STRING) { + /* + Make sure sector is loaded + */ + MapSector *sector = srvmap->createSector(p2d); + + try { + std::istringstream is(std::string(reply->str, reply->len), std::ios_base::binary); + freeReplyObject(reply); // std::string copies the memory so we can already do this here + u8 version = SER_FMT_VER_INVALID; + is.read((char *)&version, 1); + + if (is.fail()) + throw SerializationError("ServerMap::loadBlock(): Failed" + " to read MapBlock version"); + + MapBlock *block = NULL; + bool created_new = false; + block = sector->getBlockNoCreateNoEx(blockpos.Y); + if (block == NULL) + { + block = sector->createBlankBlockNoInsert(blockpos.Y); + created_new = true; + } + + // Read basic data + block->deSerialize(is, version, true); + + // If it's a new block, insert it to the map + if (created_new) + sector->insertBlock(block); + + // We just loaded it from, so it's up-to-date. + block->resetModified(); + } + catch (SerializationError &e) + { + errorstream << "Invalid block data in database" + << " (" << blockpos.X << "," << blockpos.Y << "," << blockpos.Z + << ") (SerializationError): " << e.what() << std::endl; + // TODO: Block should be marked as invalid in memory so that it is + // not touched but the game can run + + if (g_settings->getBool("ignore_world_load_errors")) { + errorstream << "Ignoring block load error. Duck and cover! " + << "(ignore_world_load_errors)" << std::endl; + } else { + throw SerializationError("Invalid block data in database"); + } + } + + return srvmap->getBlockNoCreateNoEx(blockpos); // should not be using this here + } + return NULL; +} + +void Database_Redis::listAllLoadableBlocks(std::list &dst) +{ + redisReply *reply; + reply = (redisReply*) redisCommand(ctx, "HKEYS %s", hash.c_str()); + if(!reply) + throw FileNotGoodException(std::string("redis command 'HKEYS %s' failed: ") + ctx->errstr); + if(reply->type != REDIS_REPLY_ARRAY) + throw FileNotGoodException("Failed to get keys from database"); + for(size_t i = 0; i < reply->elements; i++) + { + assert(reply->element[i]->type == REDIS_REPLY_STRING); + dst.push_back(getIntegerAsBlock(stoi64(reply->element[i]->str))); + } + freeReplyObject(reply); +} + +Database_Redis::~Database_Redis() +{ + redisFree(ctx); +} +#endif diff --git a/src/guiMessageMenu.h b/src/database-redis.h similarity index 53% rename from src/guiMessageMenu.h rename to src/database-redis.h index 8ec8e4a4..da76775d 100644 --- a/src/guiMessageMenu.h +++ b/src/database-redis.h @@ -1,6 +1,6 @@ /* Minetest -Copyright (C) 2013 celeron55, Perttu Ahola +Copyright (C) 2014 celeron55, Perttu Ahola 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 @@ -17,44 +17,34 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef GUIMESSAGEMENU_HEADER -#define GUIMESSAGEMENU_HEADER +#ifndef DATABASE_REDIS_HEADER +#define DATABASE_REDIS_HEADER -#include "irrlichttypes_extrabloated.h" -#include "modalMenu.h" +#include "config.h" + +#if USE_REDIS + +#include "database.h" +#include #include -class GUIMessageMenu : public GUIModalMenu +class ServerMap; + +class Database_Redis : public Database { public: - GUIMessageMenu(gui::IGUIEnvironment* env, - gui::IGUIElement* parent, s32 id, - IMenuManager *menumgr, - std::wstring message_text); - ~GUIMessageMenu(); - - void removeChildren(); - /* - Remove and re-add (or reposition) stuff - */ - void regenerateGui(v2u32 screensize); - - void drawMenu(); - - bool OnEvent(const SEvent& event); - - /* - true = ok'd - */ - bool getStatus() - { - return m_status; - } - + Database_Redis(ServerMap *map, std::string savedir); + virtual void beginSave(); + virtual void endSave(); + virtual void saveBlock(MapBlock *block); + virtual MapBlock* loadBlock(v3s16 blockpos); + virtual void listAllLoadableBlocks(std::list &dst); + virtual int Initialized(void); + ~Database_Redis(); private: - std::wstring m_message_text; - bool m_status; + ServerMap *srvmap; + redisContext *ctx; + std::string hash; }; - #endif - +#endif diff --git a/src/database.cpp b/src/database.cpp index b793cd2f..15579a7f 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -20,33 +20,29 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "database.h" #include "irrlichttypes.h" -static s32 unsignedToSigned(s32 i, s32 max_positive) +static inline s16 unsigned_to_signed(u16 i, u16 max_positive) { - if(i < max_positive) + if (i < max_positive) { return i; - else - return i - 2*max_positive; + } else { + return i - (max_positive * 2); + } } -// modulo of a negative number does not work consistently in C -static s64 pythonmodulo(s64 i, s64 mod) + +s64 Database::getBlockAsInteger(const v3s16 pos) const { - if(i >= 0) - return i % mod; - return mod - ((-i) % mod); + return (((u64) pos.Z) << 24) + + (((u64) pos.Y) << 12) + + ((u64) pos.X); } -long long Database::getBlockAsInteger(const v3s16 pos) { - return (unsigned long long)pos.Z*16777216 + - (unsigned long long)pos.Y*4096 + - (unsigned long long)pos.X; +v3s16 Database::getIntegerAsBlock(const s64 i) const +{ + v3s16 pos; + pos.Z = unsigned_to_signed((i >> 24) & 0xFFF, 0x1000 / 2); + pos.Y = unsigned_to_signed((i >> 12) & 0xFFF, 0x1000 / 2); + pos.X = unsigned_to_signed((i ) & 0xFFF, 0x1000 / 2); + return pos; } -v3s16 Database::getIntegerAsBlock(long long i) { - s32 x = unsignedToSigned(pythonmodulo(i, 4096), 2048); - i = (i - x) / 4096; - s32 y = unsignedToSigned(pythonmodulo(i, 4096), 2048); - i = (i - y) / 4096; - s32 z = unsignedToSigned(pythonmodulo(i, 4096), 2048); - return v3s16(x,y,z); -} diff --git a/src/database.h b/src/database.h index 79cabe6a..a8686137 100644 --- a/src/database.h +++ b/src/database.h @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include "irr_v3d.h" +#include "irrlichttypes.h" class MapBlock; @@ -33,8 +34,8 @@ public: virtual void saveBlock(MapBlock *block)=0; virtual MapBlock* loadBlock(v3s16 blockpos)=0; - long long getBlockAsInteger(const v3s16 pos); - v3s16 getIntegerAsBlock(long long i); + s64 getBlockAsInteger(const v3s16 pos) const; + v3s16 getIntegerAsBlock(const s64 i) const; virtual void listAllLoadableBlocks(std::list &dst)=0; virtual int Initialized(void)=0; virtual ~Database() {}; diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 6b291bd2..ff3bf5b8 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -53,6 +53,7 @@ void set_default_settings(Settings *settings) settings->setDefault("keymap_toggle_update_camera", "KEY_F4"); settings->setDefault("keymap_toggle_debug", "KEY_F5"); settings->setDefault("keymap_toggle_profiler", "KEY_F6"); + settings->setDefault("keymap_camera_mode", "KEY_F7"); settings->setDefault("keymap_increase_viewing_range_min", "+"); settings->setDefault("keymap_decrease_viewing_range_min", "-"); settings->setDefault("anaglyph", "false"); @@ -130,8 +131,11 @@ void set_default_settings(Settings *settings) settings->setDefault("preload_item_visuals", "true"); settings->setDefault("enable_bumpmapping", "false"); settings->setDefault("enable_parallax_occlusion", "false"); - settings->setDefault("parallax_occlusion_scale", "0.08"); - settings->setDefault("parallax_occlusion_bias", "0.04"); + settings->setDefault("generate_normalmaps", "false"); + settings->setDefault("normalmaps_strength", "0.6"); + settings->setDefault("normalmaps_smooth", "1"); + settings->setDefault("parallax_occlusion_scale", "0.06"); + settings->setDefault("parallax_occlusion_bias", "0.03"); settings->setDefault("enable_waving_water", "false"); settings->setDefault("water_wave_height", "1.0"); settings->setDefault("water_wave_length", "20.0"); @@ -240,13 +244,8 @@ void set_default_settings(Settings *settings) settings->setDefault("movement_gravity", "9.81"); //liquid stuff - settings->setDefault("liquid_finite", "false"); settings->setDefault("liquid_loop_max", "10000"); settings->setDefault("liquid_update", "1.0"); - settings->setDefault("liquid_relax", "2"); - settings->setDefault("liquid_fast_flood", "1"); - settings->setDefault("underground_springs", "1"); - settings->setDefault("weather", "false"); //mapgen stuff settings->setDefault("mg_name", "v6"); diff --git a/src/emerge.cpp b/src/emerge.cpp index 0e805c95..443d7038 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -465,13 +465,15 @@ void *EmergeThread::Thread() { v3s16 last_tried_pos(-32768,-32768,-32768); // For error output v3s16 p; - u8 flags; + u8 flags = 0; map = (ServerMap *)&(m_server->m_env->getMap()); emerge = m_server->m_emerge; mapgen = emerge->mapgen[id]; enable_mapgen_debug_info = emerge->mapgen_debug_info; + porting::setThreadName("EmergeThread"); + while (!StopRequested()) try { if (!popBlockEmerge(&p, &flags)) { diff --git a/src/environment.cpp b/src/environment.cpp index 0e7830a2..fa7ce2ae 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -85,19 +85,17 @@ void Environment::addPlayer(Player *player) void Environment::removePlayer(u16 peer_id) { DSTACK(__FUNCTION_NAME); -re_search: + for(std::list::iterator i = m_players.begin(); - i != m_players.end(); ++i) + i != m_players.end();) { Player *player = *i; - if(player->peer_id != peer_id) - continue; - - delete player; - m_players.erase(i); - // See if there is an another one - // (shouldn't be, but just to be sure) - goto re_search; + if(player->peer_id == peer_id) { + delete player; + i = m_players.erase(i); + } else { + ++i; + } } } @@ -316,7 +314,6 @@ ServerEnvironment::ServerEnvironment(ServerMap *map, m_map(map), m_script(scriptIface), m_gamedef(gamedef), - m_random_spawn_timer(3), m_send_recommended_timer(0), m_active_block_interval_overload_skip(0), m_game_time(0), @@ -324,7 +321,6 @@ ServerEnvironment::ServerEnvironment(ServerMap *map, m_recommended_send_interval(0.1), m_max_lag_estimate(0.1) { - m_use_weather = g_settings->getBool("weather"); } ServerEnvironment::~ServerEnvironment() @@ -712,6 +708,34 @@ public: } } } + // Find out how many objects the given block and its neighbours contain. + // Returns the number of objects in the block, and also in 'wider' the + // number of objects in the block and all its neighbours. The latter + // may an estimate if any neighbours are unloaded. + u32 countObjects(MapBlock *block, ServerMap * map, u32 &wider) + { + wider = 0; + u32 wider_unknown_count = 0; + for(s16 x=-1; x<=1; x++) + for(s16 y=-1; y<=1; y++) + for(s16 z=-1; z<=1; z++) + { + MapBlock *block2 = map->getBlockNoCreateNoEx( + block->getPos() + v3s16(x,y,z)); + if(block2==NULL){ + wider_unknown_count++; + continue; + } + wider += block2->m_static_objects.m_active.size() + + block2->m_static_objects.m_stored.size(); + } + // Extrapolate + u32 active_object_count = block->m_static_objects.m_active.size(); + u32 wider_known_count = 3*3*3 - wider_unknown_count; + wider += wider_unknown_count * wider / wider_known_count; + return active_object_count; + + } void apply(MapBlock *block) { if(m_aabms.empty()) @@ -719,6 +743,10 @@ public: ServerMap *map = &m_env->getServerMap(); + u32 active_object_count_wider; + u32 active_object_count = this->countObjects(block, map, active_object_count_wider); + m_env->m_added_objects = 0; + v3s16 p0; for(p0.X=0; p0.Xm_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){ - 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, active_object_count, active_object_count_wider); + + // Count surrounding objects again if the abms added any + if(m_env->m_added_objects > 0) { + active_object_count = countObjects(block, map, active_object_count_wider); + m_env->m_added_objects = 0; + } } } } @@ -1084,7 +1095,7 @@ void ServerEnvironment::step(float dtime) continue; // Move - player->move(dtime, *m_map, 100*BS); + player->move(dtime, this, 100*BS); } } @@ -1358,6 +1369,7 @@ u16 getFreeServerActiveObjectId( u16 ServerEnvironment::addActiveObject(ServerActiveObject *object) { assert(object); + m_added_objects++; u16 id = addActiveObjectRaw(object, true, 0); return id; } @@ -2381,7 +2393,7 @@ void ClientEnvironment::step(float dtime) if(player->isLocal() == false) { // Move - player->move(dtime, *m_map, 100*BS); + player->move(dtime, this, 100*BS); } diff --git a/src/environment.h b/src/environment.h index 8cc0bcd7..5062b9c3 100644 --- a/src/environment.h +++ b/src/environment.h @@ -105,6 +105,9 @@ public: m_day_night_ratio_override = value; } + // counter used internally when triggering ABMs + u32 m_added_objects; + protected: // peer_ids in here should be unique, except that there may be many 0s std::list m_players; @@ -118,6 +121,7 @@ protected: // Overriding the day-night ratio is useful for custom sky visuals bool m_enable_day_night_ratio_override; u32 m_day_night_ratio_override; + }; /* @@ -310,9 +314,6 @@ public: void reportMaxLagEstimate(float f) { m_max_lag_estimate = f; } float getMaxLagEstimate() { return m_max_lag_estimate; } - // is weather active in this environment? - bool m_use_weather; - std::set* getForceloadedBlocks() { return &m_active_blocks.m_forceloaded_list; }; private: @@ -370,7 +371,6 @@ private: // Outgoing network message buffer for active objects std::list m_active_object_messages; // Some timers - float m_random_spawn_timer; // used for experimental code float m_send_recommended_timer; IntervalLimiter m_object_management_interval; // List of active blocks diff --git a/src/exceptions.h b/src/exceptions.h index 6fb97f3e..6d6ad333 100644 --- a/src/exceptions.h +++ b/src/exceptions.h @@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., class BaseException : public std::exception { public: - BaseException(const std::string s) throw() + BaseException(const std::string &s) throw() { m_s = s; } @@ -42,78 +42,83 @@ protected: class AsyncQueuedException : public BaseException { public: - AsyncQueuedException(std::string s): BaseException(s) {} + AsyncQueuedException(const std::string &s): BaseException(s) {} }; class NotImplementedException : public BaseException { public: - NotImplementedException(std::string s): BaseException(s) {} + NotImplementedException(const std::string &s): BaseException(s) {} }; class AlreadyExistsException : public BaseException { public: - AlreadyExistsException(std::string s): BaseException(s) {} + AlreadyExistsException(const std::string &s): BaseException(s) {} }; class VersionMismatchException : public BaseException { public: - VersionMismatchException(std::string s): BaseException(s) {} + VersionMismatchException(const std::string &s): BaseException(s) {} }; class FileNotGoodException : public BaseException { public: - FileNotGoodException(std::string s): BaseException(s) {} + FileNotGoodException(const std::string &s): BaseException(s) {} }; class SerializationError : public BaseException { public: - SerializationError(std::string s): BaseException(s) {} + SerializationError(const std::string &s): BaseException(s) {} }; class LoadError : public BaseException { public: - LoadError(std::string s): BaseException(s) {} + LoadError(const std::string &s): BaseException(s) {} }; class ContainerFullException : public BaseException { public: - ContainerFullException(std::string s): BaseException(s) {} + ContainerFullException(const std::string &s): BaseException(s) {} }; class SettingNotFoundException : public BaseException { public: - SettingNotFoundException(std::string s): BaseException(s) {} + SettingNotFoundException(const std::string &s): BaseException(s) {} }; class InvalidFilenameException : public BaseException { public: - InvalidFilenameException(std::string s): BaseException(s) {} + InvalidFilenameException(const std::string &s): BaseException(s) {} }; class ProcessingLimitException : public BaseException { public: - ProcessingLimitException(std::string s): BaseException(s) {} + ProcessingLimitException(const std::string &s): BaseException(s) {} }; class CommandLineError : public BaseException { public: - CommandLineError(std::string s): BaseException(s) {} + CommandLineError(const std::string &s): BaseException(s) {} }; class ItemNotFoundException : public BaseException { public: - ItemNotFoundException(std::string s): BaseException(s) {} + ItemNotFoundException(const std::string &s): BaseException(s) {} }; class ServerError : public BaseException { public: - ServerError(std::string s): BaseException(s) {} + ServerError(const std::string &s): BaseException(s) {} }; // Only used on Windows (SEH) class FatalSystemException : public BaseException { public: - FatalSystemException(std::string s): BaseException(s) {} + FatalSystemException(const std::string &s): BaseException(s) {} +}; + +class ClientStateError : public BaseException { +public: + ClientStateError(std::string s): BaseException(s) {} }; /* @@ -126,7 +131,7 @@ public: InvalidPositionException(): BaseException("Somebody tried to get/set something in a nonexistent position.") {} - InvalidPositionException(std::string s): + InvalidPositionException(const std::string &s): BaseException(s) {} }; diff --git a/src/game.cpp b/src/game.cpp index 18e69c13..9f1609aa 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -28,7 +28,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "IMeshCache.h" #include "client.h" #include "server.h" -#include "guiPauseMenu.h" #include "guiPasswordChange.h" #include "guiVolumeChange.h" #include "guiFormSpecMenu.h" @@ -75,24 +74,6 @@ with this program; if not, write to the Free Software Foundation, Inc., Text input system */ -struct TextDestChat : public TextDest -{ - TextDestChat(Client *client) - { - m_client = client; - } - void gotText(std::wstring text) - { - m_client->typeChatMessage(text); - } - void gotText(std::map fields) - { - m_client->typeChatMessage(narrow_to_wide(fields["text"])); - } - - Client *m_client; -}; - struct TextDestNodeMetadata : public TextDest { TextDestNodeMetadata(v3s16 p, Client *client) @@ -136,12 +117,81 @@ struct TextDestPlayerInventory : public TextDest m_client->sendInventoryFields(m_formname, fields); } - void setFormName(std::string formname) { + Client *m_client; +}; + +struct LocalFormspecHandler : public TextDest +{ + LocalFormspecHandler(); + LocalFormspecHandler(std::string formname) { m_formname = formname; } + LocalFormspecHandler(std::string formname,Client *client) { + m_formname = formname; + m_client = client; + } + + void gotText(std::wstring message) { + errorstream << "LocalFormspecHandler::gotText old style message received" << std::endl; + } + + void gotText(std::map fields) + { + if (m_formname == "MT_PAUSE_MENU") { + if (fields.find("btn_sound") != fields.end()) { + g_gamecallback->changeVolume(); + return; + } + + if (fields.find("btn_exit_menu") != fields.end()) { + g_gamecallback->disconnect(); + return; + } + + if (fields.find("btn_exit_os") != fields.end()) { + g_gamecallback->exitToOS(); + return; + } + + if (fields.find("btn_change_password") != fields.end()) { + g_gamecallback->changePassword(); + return; + } + + if (fields.find("quit") != fields.end()) { + return; + } + + if (fields.find("btn_continue") != fields.end()) { + return; + } + } + if (m_formname == "MT_CHAT_MENU") { + if ((fields.find("btn_send") != fields.end()) || + (fields.find("quit") != fields.end())) { + if (fields.find("f_text") != fields.end()) { + if (m_client != 0) { + m_client->typeChatMessage(narrow_to_wide(fields["f_text"])); + } + else { + errorstream << "LocalFormspecHandler::gotText received chat message but m_client is NULL" << std::endl; + } + } + return; + } + } + + errorstream << "LocalFormspecHandler::gotText unhandled >" << m_formname << "< event" << std::endl; + int i = 0; + for (std::map::iterator iter = fields.begin(); + iter != fields.end(); iter++) { + errorstream << "\t"<< i << ": " << iter->first << "=" << iter->second << std::endl; + i++; + } + } + Client *m_client; - std::string m_formname; }; /* Respawn menu callback */ @@ -224,13 +274,9 @@ inline bool isPointableNode(const MapNode& n, Find what the player is pointing at */ PointedThing getPointedThing(Client *client, v3f player_position, - v3f camera_direction, v3f camera_position, - core::line3d shootline, f32 d, - bool liquids_pointable, - bool look_for_object, - v3s16 camera_offset, - std::vector &hilightboxes, - ClientActiveObject *&selected_object) + v3f camera_direction, v3f camera_position, core::line3d shootline, + f32 d, bool liquids_pointable, bool look_for_object, v3s16 camera_offset, + std::vector &hilightboxes, ClientActiveObject *&selected_object) { PointedThing result; @@ -379,9 +425,8 @@ PointedThing getPointedThing(Client *client, v3f player_position, Additionally, a progressbar can be drawn when percent is set between 0 and 100. */ /*gui::IGUIStaticText **/ -void draw_load_screen(const std::wstring &text, - IrrlichtDevice* device, gui::IGUIFont* font, - float dtime=0 ,int percent=0, bool clouds=true) +void draw_load_screen(const std::wstring &text, IrrlichtDevice* device, + gui::IGUIFont* font, float dtime=0 ,int percent=0, bool clouds=true) { video::IVideoDriver* driver = device->getVideoDriver(); v2u32 screensize = driver->getScreenSize(); @@ -430,8 +475,8 @@ void draw_load_screen(const std::wstring &text, /* Profiler display */ void update_profiler_gui(gui::IGUIStaticText *guitext_profiler, - gui::IGUIFont *font, u32 text_height, - u32 show_profiler, u32 show_profiler_max) + gui::IGUIFont *font, u32 text_height, u32 show_profiler, + u32 show_profiler_max) { if(show_profiler == 0) { @@ -818,14 +863,17 @@ public: services->setPixelShaderConstant("eyePosition", (irr::f32*)&eye_position, 3); services->setVertexShaderConstant("eyePosition", (irr::f32*)&eye_position, 3); - // Normal map texture layer + // Uniform sampler layers + int layer0 = 0; int layer1 = 1; int layer2 = 2; // before 1.8 there isn't a "integer interface", only float #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) + services->setPixelShaderConstant("baseTexture" , (irr::f32*)&layer0, 1); services->setPixelShaderConstant("normalTexture" , (irr::f32*)&layer1, 1); services->setPixelShaderConstant("useNormalmap" , (irr::f32*)&layer2, 1); #else + services->setPixelShaderConstant("baseTexture" , (irr::s32*)&layer0, 1); services->setPixelShaderConstant("normalTexture" , (irr::s32*)&layer1, 1); services->setPixelShaderConstant("useNormalmap" , (irr::s32*)&layer2, 1); #endif @@ -833,8 +881,7 @@ public: }; bool nodePlacementPrediction(Client &client, - const ItemDefinition &playeritem_def, - v3s16 nodepos, v3s16 neighbourpos) + const ItemDefinition &playeritem_def, v3s16 nodepos, v3s16 neighbourpos) { std::string prediction = playeritem_def.node_placement_prediction; INodeDefManager *nodedef = client.ndef(); @@ -930,26 +977,98 @@ bool nodePlacementPrediction(Client &client, return false; } +static void show_chat_menu(FormspecFormSource* current_formspec, + TextDest* current_textdest, IWritableTextureSource* tsrc, + IrrlichtDevice * device, Client* client, std::string text) +{ + std::string formspec = + "size[11,5.5,true]" + "field[3,2.35;6,0.5;f_text;;" + text + "]" + "button_exit[4,3;3,0.5;btn_send;" + wide_to_narrow(wstrgettext("Proceed")) + "]" + ; -void the_game( - bool &kill, - bool random_input, - InputHandler *input, - IrrlichtDevice *device, - gui::IGUIFont* font, - std::string map_dir, - std::string playername, - std::string password, - std::string address, // If "", local server is used - u16 port, - std::wstring &error_message, - ChatBackend &chat_backend, - const SubgameSpec &gamespec, // Used for local game, - bool simple_singleplayer_mode -) + /* Create menu */ + /* Note: FormspecFormSource and LocalFormspecHandler + * are deleted by guiFormSpecMenu */ + current_formspec = new FormspecFormSource(formspec,¤t_formspec); + current_textdest = new LocalFormspecHandler("MT_CHAT_MENU",client); + GUIFormSpecMenu *menu = + new GUIFormSpecMenu(device, guiroot, -1, + &g_menumgr, + NULL, NULL, tsrc); + menu->doPause = false; + menu->setFormSource(current_formspec); + menu->setTextDest(current_textdest); + menu->drop(); +} + +/******************************************************************************/ +static void show_pause_menu(FormspecFormSource* current_formspec, + TextDest* current_textdest, IWritableTextureSource* tsrc, + IrrlichtDevice * device, bool singleplayermode) +{ + + std::string control_text = wide_to_narrow(wstrgettext("Default Controls:\n" + "- WASD: move\n" + "- Space: jump/climb\n" + "- Shift: sneak/go down\n" + "- Q: drop item\n" + "- I: inventory\n" + "- Mouse: turn/look\n" + "- Mouse left: dig/punch\n" + "- Mouse right: place/use\n" + "- Mouse wheel: select item\n" + "- T: chat\n" + )); + + float ypos = singleplayermode ? 1.0 : 0.5; + std::ostringstream os; + + os << "size[11,5.5,true]" + << "button_exit[4," << (ypos++) << ";3,0.5;btn_continue;" + << wide_to_narrow(wstrgettext("Continue")) << "]"; + + if (!singleplayermode) { + os << "button_exit[4," << (ypos++) << ";3,0.5;btn_change_password;" + << wide_to_narrow(wstrgettext("Change Password")) << "]"; + } + + os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;" + << wide_to_narrow(wstrgettext("Sound Volume")) << "]"; + os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_menu;" + << wide_to_narrow(wstrgettext("Exit to Menu")) << "]"; + os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_os;" + << wide_to_narrow(wstrgettext("Exit to OS")) << "]" + << "textarea[7.5,0.25;3.75,6;;" << control_text << ";]" + << "textarea[0.4,0.25;3.5,6;;" << "Minetest\n" + << minetest_build_info << "\n" + << "path_user = " << wrap_rows(porting::path_user, 20) + << "\n;]"; + + /* Create menu */ + /* Note: FormspecFormSource and LocalFormspecHandler * + * are deleted by guiFormSpecMenu */ + current_formspec = new FormspecFormSource(os.str(),¤t_formspec); + current_textdest = new LocalFormspecHandler("MT_PAUSE_MENU"); + GUIFormSpecMenu *menu = + new GUIFormSpecMenu(device, guiroot, -1, &g_menumgr, NULL, NULL, tsrc); + menu->doPause = true; + menu->setFormSource(current_formspec); + menu->setTextDest(current_textdest); + menu->drop(); +} + +/******************************************************************************/ +void the_game(bool &kill, bool random_input, InputHandler *input, + IrrlichtDevice *device, gui::IGUIFont* font, std::string map_dir, + std::string playername, std::string password, + std::string address /* If "", local server is used */, + u16 port, std::wstring &error_message, ChatBackend &chat_backend, + const SubgameSpec &gamespec /* Used for local game */, + bool simple_singleplayer_mode) { FormspecFormSource* current_formspec = 0; - TextDestPlayerInventory* current_textdest = 0; + TextDest* current_textdest = 0; video::IVideoDriver* driver = device->getVideoDriver(); scene::ISceneManager* smgr = device->getSceneManager(); @@ -1028,27 +1147,34 @@ void the_game( draw_load_screen(text, device, font,0,25); delete[] text; infostream<<"Creating server"<get("bind_address"); Address bind_addr(0,0,0,0, port); - if (bind_str != "") - { - try { - bind_addr.Resolve(bind_str.c_str()); - address = bind_str; - } catch (ResolveError &e) { - infostream << "Resolving bind address \"" << bind_str - << "\" failed: " << e.what() - << " -- Listening on all addresses." << std::endl; - - if (g_settings->getBool("ipv6_server")) { - bind_addr.setAddress((IPv6AddressBytes*) NULL); - } - } + if (g_settings->getBool("ipv6_server")) { + bind_addr.setAddress((IPv6AddressBytes*) NULL); } + try { + bind_addr.Resolve(bind_str.c_str()); + address = bind_str; + } catch (ResolveError &e) { + infostream << "Resolving bind address \"" << bind_str + << "\" failed: " << e.what() + << " -- Listening on all addresses." << std::endl; + } + + if(bind_addr.isIPv6() && !g_settings->getBool("enable_ipv6")) { + error_message = L"Unable to listen on " + + narrow_to_wide(bind_addr.serializeString()) + + L" because IPv6 is disabled"; + errorstream<start(bind_addr); } @@ -1074,31 +1200,33 @@ void the_game( delete[] text; } Address connect_address(0,0,0,0, port); - try{ - if(address == "") - { + try { + connect_address.Resolve(address.c_str()); + if (connect_address.isZero()) { // i.e. INADDR_ANY, IN6ADDR_ANY //connect_address.Resolve("localhost"); - if(g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server")) - { + if (connect_address.isIPv6()) { IPv6AddressBytes addr_bytes; addr_bytes.bytes[15] = 1; connect_address.setAddress(&addr_bytes); - } - else - { + } else { connect_address.setAddress(127,0,0,1); } } - else - connect_address.Resolve(address.c_str()); } - catch(ResolveError &e) - { + catch(ResolveError &e) { error_message = L"Couldn't resolve address: " + narrow_to_wide(e.what()); errorstream<getBool("enable_ipv6")) { + error_message = L"Unable to connect to " + + narrow_to_wide(connect_address.serializeString()) + + L" because IPv6 is disabled"; + errorstream<step(dtime); // End condition - if(client.connectedAndInitialized()){ + if(client.getState() == LC_Init){ could_connect = true; break; } @@ -1254,7 +1382,7 @@ void the_game( errorstream<getBool("weather"); - core::stringw str = L"Minetest ["; str += driver->getName(); str += "]"; @@ -1781,6 +1909,7 @@ void the_game( PlayerInventoryFormSource *src = new PlayerInventoryFormSource(&client); assert(src); + menu->doPause = false; menu->setFormSpec(src->getForm(), inventoryloc); menu->setFormSource(src); menu->setTextDest(new TextDestPlayerInventory(&client)); @@ -1788,33 +1917,16 @@ void the_game( } else if(input->wasKeyDown(EscapeKey)) { - infostream<<"the_game: " - <<"Launching pause menu"<drop(); - - // Move mouse cursor on top of the disconnect button - if(simple_singleplayer_mode) - input->setMousePos(displaycenter.X, displaycenter.Y+0); - else - input->setMousePos(displaycenter.X, displaycenter.Y+25); + show_pause_menu(current_formspec, current_textdest, tsrc, device, + simple_singleplayer_mode); } else if(input->wasKeyDown(getKeySetting("keymap_chat"))) { - TextDest *dest = new TextDestChat(&client); - - (new GUITextInputMenu(guienv, guiroot, -1, - &g_menumgr, dest, - L""))->drop(); + show_chat_menu(current_formspec, current_textdest, tsrc, device, &client,""); } else if(input->wasKeyDown(getKeySetting("keymap_cmd"))) { - TextDest *dest = new TextDestChat(&client); - - (new GUITextInputMenu(guienv, guiroot, -1, - &g_menumgr, dest, - L"/"))->drop(); + show_chat_menu(current_formspec, current_textdest, tsrc, device, &client,"/"); } else if(input->wasKeyDown(getKeySetting("keymap_console"))) { @@ -2139,7 +2251,7 @@ void the_game( else{ s32 dx = input->getMousePos().X - displaycenter.X; s32 dy = input->getMousePos().Y - displaycenter.Y; - if(invert_mouse) + if(invert_mouse || player->camera_mode == CAMERA_MODE_THIRD_FRONT) dy = -dy; //infostream<<"window active, pos difference "<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; + player->keyPressed= + (((int)input->isKeyDown(getKeySetting("keymap_forward")) & 0x1) << 0) | + (((int)input->isKeyDown(getKeySetting("keymap_backward")) & 0x1) << 1) | + (((int)input->isKeyDown(getKeySetting("keymap_left")) & 0x1) << 2) | + (((int)input->isKeyDown(getKeySetting("keymap_right")) & 0x1) << 3) | + (((int)input->isKeyDown(getKeySetting("keymap_jump")) & 0x1) << 4) | + (((int)input->isKeyDown(getKeySetting("keymap_special1")) & 0x1) << 5) | + (((int)input->isKeyDown(getKeySetting("keymap_sneak")) & 0x1) << 6) | + (((int)input->getLeftState() & 0x1) << 7) | + (((int)input->getRightState() & 0x1) << 8); } /* @@ -2317,6 +2428,7 @@ void the_game( new GUIFormSpecMenu(device, guiroot, -1, &g_menumgr, &client, gamedef, tsrc); + menu->doPause = false; menu->setFormSource(current_formspec); menu->setTextDest(current_textdest); menu->drop(); @@ -2547,13 +2659,24 @@ void the_game( LocalPlayer* player = client.getEnv().getLocalPlayer(); float full_punch_interval = playeritem_toolcap.full_punch_interval; float tool_reload_ratio = time_from_last_punch / full_punch_interval; + + if(input->wasKeyDown(getKeySetting("keymap_camera_mode"))) { + + if (current_camera_mode == CAMERA_MODE_FIRST) + current_camera_mode = CAMERA_MODE_THIRD; + else if (current_camera_mode == CAMERA_MODE_THIRD) + current_camera_mode = CAMERA_MODE_THIRD_FRONT; + else + current_camera_mode = CAMERA_MODE_FIRST; + + } + player->camera_mode = current_camera_mode; tool_reload_ratio = MYMIN(tool_reload_ratio, 1.0); - camera.update(player, dtime, busytime, screensize, - tool_reload_ratio); + camera.update(player, dtime, busytime, screensize, tool_reload_ratio, + current_camera_mode, client.getEnv()); camera.step(dtime); v3f player_position = player->getPosition(); - v3s16 pos_i = floatToInt(player_position, BS); v3f camera_position = camera.getPosition(); v3f camera_direction = camera.getDirection(); f32 camera_fov = camera.getFovMax(); @@ -2573,7 +2696,7 @@ void the_game( } // Update sound listener - sound->updateListener(camera.getCameraNode()->getPosition(), + sound->updateListener(camera.getCameraNode()->getPosition()+intToFloat(camera_offset, BS), v3f(0,0,0), // velocity camera.getDirection(), camera.getCameraNode()->getUpVector()); @@ -2605,6 +2728,10 @@ void the_game( core::line3d shootline(camera_position, camera_position + camera_direction * BS * (d+1)); + // prevent player pointing anything in front-view + if (current_camera_mode == CAMERA_MODE_THIRD_FRONT) + shootline = core::line3d(0,0,0,0,0,0); + ClientActiveObject *selected_object = NULL; PointedThing pointed = getPointedThing( @@ -2871,6 +2998,7 @@ void the_game( new GUIFormSpecMenu(device, guiroot, -1, &g_menumgr, &client, gamedef, tsrc); + menu->doPause = false; menu->setFormSpec(meta->getString("formspec"), inventoryloc); menu->setFormSource(new NodeMetadataFormSource( @@ -2980,8 +3108,6 @@ void the_game( fog_range = 100000*BS; else { fog_range = draw_control.wanted_range*BS + 0.0*MAP_BLOCKSIZE*BS; - if(use_weather) - fog_range *= (1.5 - 1.4*(float)client.getEnv().getClientMap().getHumidity(pos_i)/100); fog_range = MYMIN(fog_range, (draw_control.farthest_drawn+20)*BS); fog_range *= 0.9; } @@ -3131,9 +3257,7 @@ void the_game( <<", "<<(player_position.Y/BS) <<", "<<(player_position.Z/BS) <<") (yaw="<<(wrapDegrees_0_360(camera_yaw)) - <<") (t="<setText(narrow_to_wide(os.str()).c_str()); guitext2->setVisible(true); @@ -3394,7 +3518,9 @@ void the_game( /* Wielded tool */ - if(show_hud && (player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE)) + if(show_hud && + (player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE) && + current_camera_mode < CAMERA_MODE_THIRD) { // Warning: This clears the Z buffer. camera.drawWieldedTool(); diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp index 628ea354..3f9d7f78 100644 --- a/src/guiFormSpecMenu.cpp +++ b/src/guiFormSpecMenu.cpp @@ -66,12 +66,9 @@ with this program; if not, write to the Free Software Foundation, Inc., */ GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev, - gui::IGUIElement* parent, s32 id, - IMenuManager *menumgr, - InventoryManager *invmgr, - IGameDef *gamedef, - ISimpleTextureSource *tsrc -): + gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, + InventoryManager *invmgr, IGameDef *gamedef, + ISimpleTextureSource *tsrc) : GUIModalMenu(dev->getGUIEnvironment(), parent, id, menumgr), m_device(dev), m_invmgr(invmgr), @@ -248,10 +245,11 @@ std::vector split(const std::string &s, char delim) { return tokens; } -void GUIFormSpecMenu::parseSize(parserData* data,std::string element) { +void GUIFormSpecMenu::parseSize(parserData* data,std::string element) +{ std::vector parts = split(element,','); - if (parts.size() == 2) { + if ((parts.size() == 2) || parts.size() == 3) { v2f invsize; if (parts[1].find(';') != std::string::npos) @@ -260,6 +258,13 @@ void GUIFormSpecMenu::parseSize(parserData* data,std::string element) { invsize.X = stof(parts[0]); invsize.Y = stof(parts[1]); + lockSize(false); + if (parts.size() == 3) { + if (parts[2] == "true") { + lockSize(true,v2u32(800,600)); + } + } + if (m_lock) { v2u32 current_screensize = m_device->getVideoDriver()->getScreenSize(); v2u32 delta = current_screensize - m_lockscreensize; @@ -305,8 +310,8 @@ void GUIFormSpecMenu::parseSize(parserData* data,std::string element) { errorstream<< "Invalid size element (" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseList(parserData* data,std::string element) { - +void GUIFormSpecMenu::parseList(parserData* data,std::string element) +{ if (m_gamedef == 0) { errorstream<<"WARNING: invalid use of 'list' with m_gamedef==0"< parts = split(element,';'); if ((parts.size() == 3) || (parts.size() == 4)) { @@ -408,7 +414,8 @@ void GUIFormSpecMenu::parseCheckbox(parserData* data,std::string element) { errorstream<< "Invalid checkbox element(" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseImage(parserData* data,std::string element) { +void GUIFormSpecMenu::parseImage(parserData* data,std::string element) +{ std::vector parts = split(element,';'); if (parts.size() == 3) { @@ -451,7 +458,8 @@ void GUIFormSpecMenu::parseImage(parserData* data,std::string element) { errorstream<< "Invalid image element(" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseItemImage(parserData* data,std::string element) { +void GUIFormSpecMenu::parseItemImage(parserData* data,std::string element) +{ std::vector parts = split(element,';'); if (parts.size() == 3) { @@ -478,7 +486,9 @@ void GUIFormSpecMenu::parseItemImage(parserData* data,std::string element) { errorstream<< "Invalid ItemImage element(" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseButton(parserData* data,std::string element,std::string type) { +void GUIFormSpecMenu::parseButton(parserData* data,std::string element, + std::string type) +{ std::vector parts = split(element,';'); if (parts.size() == 4) { @@ -530,7 +540,8 @@ void GUIFormSpecMenu::parseButton(parserData* data,std::string element,std::stri errorstream<< "Invalid button element(" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseBackground(parserData* data,std::string element) { +void GUIFormSpecMenu::parseBackground(parserData* data,std::string element) +{ std::vector parts = split(element,';'); if ((parts.size() == 3) || (parts.size() == 4)) { @@ -565,7 +576,8 @@ void GUIFormSpecMenu::parseBackground(parserData* data,std::string element) { errorstream<< "Invalid background element(" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseTableOptions(parserData* data,std::string element) { +void GUIFormSpecMenu::parseTableOptions(parserData* data,std::string element) +{ std::vector parts = split(element,';'); data->table_options.clear(); @@ -576,7 +588,8 @@ void GUIFormSpecMenu::parseTableOptions(parserData* data,std::string element) { } } -void GUIFormSpecMenu::parseTableColumns(parserData* data,std::string element) { +void GUIFormSpecMenu::parseTableColumns(parserData* data,std::string element) +{ std::vector parts = split(element,';'); data->table_columns.clear(); @@ -595,7 +608,8 @@ void GUIFormSpecMenu::parseTableColumns(parserData* data,std::string element) { } } -void GUIFormSpecMenu::parseTable(parserData* data,std::string element) { +void GUIFormSpecMenu::parseTable(parserData* data,std::string element) +{ std::vector parts = split(element,';'); if ((parts.size() == 4) || (parts.size() == 5)) { @@ -664,7 +678,8 @@ void GUIFormSpecMenu::parseTable(parserData* data,std::string element) { errorstream<< "Invalid table element(" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseTextList(parserData* data,std::string element) { +void GUIFormSpecMenu::parseTextList(parserData* data,std::string element) +{ std::vector parts = split(element,';'); if ((parts.size() == 4) || (parts.size() == 5) || (parts.size() == 6)) { @@ -737,7 +752,8 @@ void GUIFormSpecMenu::parseTextList(parserData* data,std::string element) { } -void GUIFormSpecMenu::parseDropDown(parserData* data,std::string element) { +void GUIFormSpecMenu::parseDropDown(parserData* data,std::string element) +{ std::vector parts = split(element,';'); if (parts.size() == 5) { @@ -790,7 +806,8 @@ void GUIFormSpecMenu::parseDropDown(parserData* data,std::string element) { << element << "'" << std::endl; } -void GUIFormSpecMenu::parsePwdField(parserData* data,std::string element) { +void GUIFormSpecMenu::parsePwdField(parserData* data,std::string element) +{ std::vector parts = split(element,';'); if (parts.size() == 4) { @@ -856,7 +873,9 @@ void GUIFormSpecMenu::parsePwdField(parserData* data,std::string element) { errorstream<< "Invalid pwdfield element(" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseSimpleField(parserData* data,std::vector &parts) { +void GUIFormSpecMenu::parseSimpleField(parserData* data, + std::vector &parts) +{ std::string name = parts[0]; std::string label = parts[1]; std::string default_val = parts[2]; @@ -935,7 +954,9 @@ void GUIFormSpecMenu::parseSimpleField(parserData* data,std::vector m_fields.push_back(spec); } -void GUIFormSpecMenu::parseTextArea(parserData* data,std::vector& parts,std::string type) { +void GUIFormSpecMenu::parseTextArea(parserData* data, + std::vector& parts,std::string type) +{ std::vector v_pos = split(parts[0],','); std::vector v_geom = split(parts[1],','); @@ -1026,7 +1047,9 @@ void GUIFormSpecMenu::parseTextArea(parserData* data,std::vector& p m_fields.push_back(spec); } -void GUIFormSpecMenu::parseField(parserData* data,std::string element,std::string type) { +void GUIFormSpecMenu::parseField(parserData* data,std::string element, + std::string type) +{ std::vector parts = split(element,';'); if (parts.size() == 3) { @@ -1041,7 +1064,8 @@ void GUIFormSpecMenu::parseField(parserData* data,std::string element,std::strin errorstream<< "Invalid field element(" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseLabel(parserData* data,std::string element) { +void GUIFormSpecMenu::parseLabel(parserData* data,std::string element) +{ std::vector parts = split(element,';'); if (parts.size() == 2) { @@ -1076,7 +1100,8 @@ void GUIFormSpecMenu::parseLabel(parserData* data,std::string element) { errorstream<< "Invalid label element(" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseVertLabel(parserData* data,std::string element) { +void GUIFormSpecMenu::parseVertLabel(parserData* data,std::string element) +{ std::vector parts = split(element,';'); if (parts.size() == 2) { @@ -1116,7 +1141,9 @@ void GUIFormSpecMenu::parseVertLabel(parserData* data,std::string element) { errorstream<< "Invalid vertlabel element(" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseImageButton(parserData* data,std::string element,std::string type) { +void GUIFormSpecMenu::parseImageButton(parserData* data,std::string element, + std::string type) +{ std::vector parts = split(element,';'); if ((parts.size() == 5) || (parts.size() == 7) || (parts.size() == 8)) { @@ -1202,7 +1229,8 @@ void GUIFormSpecMenu::parseImageButton(parserData* data,std::string element,std: errorstream<< "Invalid imagebutton element(" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseTabHeader(parserData* data,std::string element) { +void GUIFormSpecMenu::parseTabHeader(parserData* data,std::string element) +{ std::vector parts = split(element,';'); if ((parts.size() == 4) || (parts.size() == 6)) { @@ -1269,7 +1297,8 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data,std::string element) { errorstream<< "Invalid TabHeader element(" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element) { +void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element) +{ if (m_gamedef == 0) { errorstream<<"WARNING: invalid use of item_image_button with m_gamedef==0"< parts = split(element,';'); if (parts.size() == 3) { @@ -1368,7 +1398,8 @@ void GUIFormSpecMenu::parseBox(parserData* data,std::string element) { errorstream<< "Invalid Box element(" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseBackgroundColor(parserData* data,std::string element) { +void GUIFormSpecMenu::parseBackgroundColor(parserData* data,std::string element) +{ std::vector parts = split(element,';'); if ((parts.size() == 1) || (parts.size() == 2)) { @@ -1383,7 +1414,8 @@ void GUIFormSpecMenu::parseBackgroundColor(parserData* data,std::string element) errorstream<< "Invalid bgcolor element(" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseListColors(parserData* data,std::string element) { +void GUIFormSpecMenu::parseListColors(parserData* data,std::string element) +{ std::vector parts = split(element,';'); if ((parts.size() == 2) || (parts.size() == 3) || (parts.size() == 5)) { @@ -1408,8 +1440,8 @@ void GUIFormSpecMenu::parseListColors(parserData* data,std::string element) { errorstream<< "Invalid listcolors element(" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseElement(parserData* data,std::string element) { - +void GUIFormSpecMenu::parseElement(parserData* data,std::string element) +{ //some prechecks if (element == "") return; @@ -2132,16 +2164,22 @@ ItemStack GUIFormSpecMenu::verifySelectedItem() return ItemStack(); } -void GUIFormSpecMenu::acceptInput(bool quit=false) +void GUIFormSpecMenu::acceptInput(FormspecQuitMode quitmode=quit_mode_no) { if(m_text_dst) { std::map fields; - if (quit) { + if (quitmode == quit_mode_accept) { fields["quit"] = "true"; } + if (quitmode == quit_mode_cancel) { + fields["quit"] = "true"; + m_text_dst->gotText(fields); + return; + } + if (current_keys_pending.key_down) { fields["key_down"] = "true"; current_keys_pending.key_down = false; @@ -2281,10 +2319,11 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) if (event.KeyInput.PressedDown && (kp == EscapeKey || kp == getKeySetting("keymap_inventory"))) { - if (m_allowclose) { - acceptInput(true); + if (m_allowclose){ + doPause = false; + acceptInput(quit_mode_cancel); quitMenu(); - } else { + } else { m_text_dst->gotText(narrow_to_wide("MenuQuit")); } return true; @@ -2313,7 +2352,7 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) break; } if (current_keys_pending.key_enter && m_allowclose) { - acceptInput(true); + acceptInput(quit_mode_accept); quitMenu(); } else { @@ -2643,7 +2682,7 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) if (btn_id == 257) { if (m_allowclose) { - acceptInput(true); + acceptInput(quit_mode_accept); quitMenu(); } else { acceptInput(); @@ -2663,16 +2702,16 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) (s.fid == event.GUIEvent.Caller->getID())) { s.send = true; - acceptInput(); if(s.is_exit){ if (m_allowclose) { - acceptInput(true); + acceptInput(quit_mode_accept); quitMenu(); } else { m_text_dst->gotText(narrow_to_wide("ExitButton")); } return true; }else{ + acceptInput(); s.send = false; return true; } @@ -2685,7 +2724,7 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) { if (m_allowclose) { - acceptInput(true); + acceptInput(quit_mode_accept); quitMenu(); } else { @@ -2723,7 +2762,8 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) return Parent ? Parent->OnEvent(event) : false; } -bool GUIFormSpecMenu::parseColor(const std::string &value, video::SColor &color, bool quiet) +bool GUIFormSpecMenu::parseColor(const std::string &value, video::SColor &color, + bool quiet) { const char *hexpattern = NULL; if (value[0] == '#') { diff --git a/src/guiFormSpecMenu.h b/src/guiFormSpecMenu.h index 1946f88e..6f7de158 100644 --- a/src/guiFormSpecMenu.h +++ b/src/guiFormSpecMenu.h @@ -42,12 +42,22 @@ typedef enum { f_Unknown } FormspecFieldType; +typedef enum { + quit_mode_no, + quit_mode_accept, + quit_mode_cancel +} FormspecQuitMode; + struct TextDest { virtual ~TextDest() {}; // This is deprecated I guess? -celeron55 virtual void gotText(std::wstring text){} virtual void gotText(std::map fields) = 0; + virtual void setFormName(std::string formname) + { m_formname = formname;}; + + std::string m_formname; }; class IFormSource @@ -139,7 +149,8 @@ class GUIFormSpecMenu : public GUIModalMenu FieldSpec() { } - FieldSpec(const std::wstring name, const std::wstring label, const std::wstring fdeflt, int id): + FieldSpec(const std::wstring &name, const std::wstring &label, + const std::wstring &fdeflt, int id) : fname(name), flabel(label), fdefault(fdeflt), @@ -228,9 +239,11 @@ public: void updateSelectedItem(); ItemStack verifySelectedItem(); - void acceptInput(bool quit); + void acceptInput(FormspecQuitMode quitmode); bool preprocessEvent(const SEvent& event); bool OnEvent(const SEvent& event); + bool doPause; + bool pausesGame() { return doPause; } GUITable* getTable(std::wstring tablename); @@ -332,7 +345,8 @@ private: void parsePwdField(parserData* data,std::string element); void parseField(parserData* data,std::string element,std::string type); void parseSimpleField(parserData* data,std::vector &parts); - void parseTextArea(parserData* data,std::vector& parts,std::string type); + void parseTextArea(parserData* data,std::vector& parts, + std::string type); void parseLabel(parserData* data,std::string element); void parseVertLabel(parserData* data,std::string element); void parseImageButton(parserData* data,std::string element,std::string type); diff --git a/src/guiMessageMenu.cpp b/src/guiMessageMenu.cpp deleted file mode 100644 index dd9c0a26..00000000 --- a/src/guiMessageMenu.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* -Minetest -Copyright (C) 2013 celeron55, Perttu Ahola - -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 "guiMessageMenu.h" -#include "debug.h" -#include "serialization.h" -#include -#include -#include -#include -#include -#include - -#include "gettext.h" - -GUIMessageMenu::GUIMessageMenu(gui::IGUIEnvironment* env, - gui::IGUIElement* parent, s32 id, - IMenuManager *menumgr, - std::wstring message_text -): - GUIModalMenu(env, parent, id, menumgr), - m_message_text(message_text), - m_status(false) -{ -} - -GUIMessageMenu::~GUIMessageMenu() -{ - removeChildren(); -} - -void GUIMessageMenu::removeChildren() -{ - { - gui::IGUIElement *e = getElementFromId(256); - if(e != NULL) - e->remove(); - } - { - gui::IGUIElement *e = getElementFromId(257); - if(e != NULL) - e->remove(); - } -} - -void GUIMessageMenu::regenerateGui(v2u32 screensize) -{ - /* - Remove stuff - */ - removeChildren(); - - /* - Calculate new sizes and positions - */ - core::rect rect( - screensize.X/2 - 580/2, - screensize.Y/2 - 300/2, - screensize.X/2 + 580/2, - screensize.Y/2 + 300/2 - ); - - DesiredRect = rect; - recalculateAbsolutePosition(false); - - v2s32 size = rect.getSize(); - - gui::IGUISkin *skin = Environment->getSkin(); - gui::IGUIFont *font = skin->getFont(); - s32 msg_h = font->getDimension(m_message_text.c_str()).Height; - s32 msg_w = font->getDimension(m_message_text.c_str()).Width; - if(msg_h > 200) - msg_h = 200; - if(msg_w > 540) - msg_w = 540; - - /* - Add stuff - */ - { - core::rect rect(0, 0, msg_w, msg_h); - rect += v2s32(size.X/2-msg_w/2, size.Y/2-30/2 - msg_h/2); - Environment->addStaticText(m_message_text.c_str(), - rect, false, true, this, -1); - } - - int bw = 140; - { - core::rect rect(0, 0, bw, 30); - rect = rect + v2s32(size.X/2-bw/2, size.Y/2-30/2+5 + msg_h/2); - wchar_t* text = wgettext("Proceed"); - gui::IGUIElement *e = - Environment->addButton(rect, this, 257, - text); - Environment->setFocus(e); - delete[] text; - } -} - -void GUIMessageMenu::drawMenu() -{ - gui::IGUISkin* skin = Environment->getSkin(); - if (!skin) - return; - video::IVideoDriver* driver = Environment->getVideoDriver(); - - video::SColor bgcolor(140,0,0,0); - driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect); - - gui::IGUIElement::draw(); -} - -bool GUIMessageMenu::OnEvent(const SEvent& event) -{ - if(event.EventType==EET_KEY_INPUT_EVENT) - { - if(event.KeyInput.Key==KEY_ESCAPE && event.KeyInput.PressedDown) - { - m_status = true; - quitMenu(); - return true; - } - if(event.KeyInput.Key==KEY_RETURN && event.KeyInput.PressedDown) - { - m_status = true; - quitMenu(); - return true; - } - } - if(event.EventType==EET_GUI_EVENT) - { - if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST - && isVisible()) - { - if(!canTakeFocus(event.GUIEvent.Element)) - { - dstream<<"GUIMessageMenu: Not allowing focus change." - <getID()) - { - case 257: - m_status = true; - quitMenu(); - return true; - } - } - } - - return Parent ? Parent->OnEvent(event) : false; -} - diff --git a/src/guiPauseMenu.cpp b/src/guiPauseMenu.cpp deleted file mode 100644 index 4d5070c9..00000000 --- a/src/guiPauseMenu.cpp +++ /dev/null @@ -1,280 +0,0 @@ -/* -Minetest -Copyright (C) 2013 celeron55, Perttu Ahola - -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 "guiPauseMenu.h" -#include "debug.h" -#include "serialization.h" -#include "porting.h" -#include "config.h" -#include "version.h" -#include "main.h" -#include -#include -#include -#include -#include -#include "gettext.h" -#include "util/string.h" - -GUIPauseMenu::GUIPauseMenu(gui::IGUIEnvironment* env, - gui::IGUIElement* parent, s32 id, - IGameCallback *gamecallback, - IMenuManager *menumgr, - bool simple_singleplayer_mode): - GUIModalMenu(env, parent, id, menumgr), - m_gamecallback(gamecallback), - m_simple_singleplayer_mode(simple_singleplayer_mode) -{ -} - -GUIPauseMenu::~GUIPauseMenu() -{ - removeChildren(); -} - -void GUIPauseMenu::removeChildren() -{ - { - gui::IGUIElement *e = getElementFromId(256); - if(e != NULL) - e->remove(); - } - { - gui::IGUIElement *e = getElementFromId(257); - if(e != NULL) - e->remove(); - } - { - gui::IGUIElement *e = getElementFromId(258); - if(e != NULL) - e->remove(); - } - { - gui::IGUIElement *e = getElementFromId(259); - if(e != NULL) - e->remove(); - } - { - gui::IGUIElement *e = getElementFromId(260); - if(e != NULL) - e->remove(); - } - { - gui::IGUIElement *e = getElementFromId(261); - if(e != NULL) - e->remove(); - } - { - gui::IGUIElement *e = getElementFromId(262); - if(e != NULL) - e->remove(); - } -} - -void GUIPauseMenu::regenerateGui(v2u32 screensize) -{ - /* - Remove stuff - */ - removeChildren(); - - /* - Calculate new sizes and positions - */ - core::rect rect( - screensize.X/2 - 580/2, - screensize.Y/2 - 300/2, - screensize.X/2 + 580/2, - screensize.Y/2 + 300/2 - ); - - DesiredRect = rect; - recalculateAbsolutePosition(false); - - v2s32 size = rect.getSize(); - - /* - Add stuff - */ - const s32 btn_height = 30; - const s32 btn_gap = 20; - const s32 btn_num = m_simple_singleplayer_mode ? 4 : 5; - s32 btn_y = size.Y/2-((btn_num*btn_height+(btn_num-1)*btn_gap))/2; - { - core::rect rect(0, 0, 140, btn_height); - rect = rect + v2s32(size.X/2-140/2, btn_y); - wchar_t* text = wgettext("Continue"); - Environment->addButton(rect, this, 256, - text); - delete[] text; - } - btn_y += btn_height + btn_gap; - if(!m_simple_singleplayer_mode) - { - { - core::rect rect(0, 0, 140, btn_height); - rect = rect + v2s32(size.X/2-140/2, btn_y); - wchar_t* text = wgettext("Change Password"); - Environment->addButton(rect, this, 261, - text); - delete[] text; - } - btn_y += btn_height + btn_gap; - } - { - core::rect rect(0, 0, 140, btn_height); - rect = rect + v2s32(size.X/2-140/2, btn_y); - wchar_t* text = wgettext("Sound Volume"); - Environment->addButton(rect, this, 262, - text); - delete[] text; - } - btn_y += btn_height + btn_gap; - { - core::rect rect(0, 0, 140, btn_height); - rect = rect + v2s32(size.X/2-140/2, btn_y); - wchar_t* text = wgettext("Exit to Menu"); - Environment->addButton(rect, this, 260, - text); - delete[] text; - } - btn_y += btn_height + btn_gap; - { - core::rect rect(0, 0, 140, btn_height); - rect = rect + v2s32(size.X/2-140/2, btn_y); - wchar_t* text = wgettext("Exit to OS"); - Environment->addButton(rect, this, 257, - text); - delete[] text; - } - - { - core::rect rect(0, 0, 180, 240); - rect = rect + v2s32(size.X/2 + 90, size.Y/2-rect.getHeight()/2); - wchar_t* text = wgettext("Default Controls:\n" - "- WASD: move\n" - "- Space: jump/climb\n" - "- Shift: sneak/go down\n" - "- Q: drop item\n" - "- I: inventory\n" - "- Mouse: turn/look\n" - "- Mouse left: dig/punch\n" - "- Mouse right: place/use\n" - "- Mouse wheel: select item\n" - "- T: chat\n" - ); - Environment->addStaticText(text, rect, false, true, this, 258); - delete[] text; - - } - { - core::rect rect(0, 0, 180, 220); - rect = rect + v2s32(size.X/2 - 90 - rect.getWidth(), size.Y/2-rect.getHeight()/2); - - v2u32 max_texture_size; - { - video::IVideoDriver* driver = Environment->getVideoDriver(); - max_texture_size = driver->getMaxTextureSize(); - } - - std::ostringstream os; - os<<"Minetest\n"; - os<addStaticText(narrow_to_wide(os.str()).c_str(), rect, false, true, this, 259); - } -} - -void GUIPauseMenu::drawMenu() -{ - gui::IGUISkin* skin = Environment->getSkin(); - if (!skin) - return; - video::IVideoDriver* driver = Environment->getVideoDriver(); - - video::SColor bgcolor(140,0,0,0); - driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect); - - gui::IGUIElement::draw(); -} - -bool GUIPauseMenu::OnEvent(const SEvent& event) -{ - - if(event.EventType==EET_KEY_INPUT_EVENT) - { - if(event.KeyInput.PressedDown) - { - if(event.KeyInput.Key==KEY_ESCAPE) - { - quitMenu(); - return true; - } - else if(event.KeyInput.Key==KEY_RETURN) - { - quitMenu(); - return true; - } - } - } - if(event.EventType==EET_GUI_EVENT) - { - if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST - && isVisible()) - { - if(!canTakeFocus(event.GUIEvent.Element)) - { - dstream<<"GUIPauseMenu: Not allowing focus change." - <getID()) - { - case 256: // continue - quitMenu(); - // ALWAYS return immediately after quitMenu() - return true; - case 261: - m_gamecallback->changePassword(); - quitMenu(); - return true; - case 262: - m_gamecallback->changeVolume(); - quitMenu(); - return true; - case 260: // disconnect - m_gamecallback->disconnect(); - quitMenu(); - return true; - case 257: // exit - m_gamecallback->exitToOS(); - quitMenu(); - return true; - } - } - } - - return Parent ? Parent->OnEvent(event) : false; -} - diff --git a/src/guiPauseMenu.h b/src/guiPauseMenu.h deleted file mode 100644 index 2808c93b..00000000 --- a/src/guiPauseMenu.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -Minetest -Copyright (C) 2013 celeron55, Perttu Ahola - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2.1 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#ifndef GUIPAUSEMENU_HEADER -#define GUIPAUSEMENU_HEADER - -#include "irrlichttypes_extrabloated.h" -#include "modalMenu.h" - -class IGameCallback -{ -public: - virtual void exitToOS() = 0; - virtual void disconnect() = 0; - virtual void changePassword() = 0; - virtual void changeVolume() = 0; -}; - -class GUIPauseMenu : public GUIModalMenu -{ -public: - GUIPauseMenu(gui::IGUIEnvironment* env, - gui::IGUIElement* parent, s32 id, - IGameCallback *gamecallback, - IMenuManager *menumgr, - bool simple_singleplayer_mode); - ~GUIPauseMenu(); - - void removeChildren(); - /* - Remove and re-add (or reposition) stuff - */ - void regenerateGui(v2u32 screensize); - - void drawMenu(); - - bool OnEvent(const SEvent& event); - - bool pausesGame(){ return true; } - -private: - IGameCallback *m_gamecallback; - bool m_simple_singleplayer_mode; -}; - -#endif - diff --git a/src/guiVolumeChange.cpp b/src/guiVolumeChange.cpp index 5e7476bb..f31c650f 100644 --- a/src/guiVolumeChange.cpp +++ b/src/guiVolumeChange.cpp @@ -41,8 +41,7 @@ GUIVolumeChange::GUIVolumeChange(gui::IGUIEnvironment* env, IMenuManager *menumgr, Client* client ): - GUIModalMenu(env, parent, id, menumgr), - m_client(client) + GUIModalMenu(env, parent, id, menumgr) { } diff --git a/src/guiVolumeChange.h b/src/guiVolumeChange.h index 5258ee10..9f8199fa 100644 --- a/src/guiVolumeChange.h +++ b/src/guiVolumeChange.h @@ -44,11 +44,7 @@ public: bool OnEvent(const SEvent& event); - bool pausesGame(){ return true; } - -private: - Client* m_client; - + bool pausesGame() { return true; } }; #endif diff --git a/src/httpfetch.cpp b/src/httpfetch.cpp index 2eca363d..751a4471 100644 --- a/src/httpfetch.cpp +++ b/src/httpfetch.cpp @@ -566,6 +566,8 @@ protected: log_register_thread("CurlFetchThread"); DSTACK(__FUNCTION_NAME); + porting::setThreadName("CurlFetchThread"); + CurlHandlePool pool; m_multi = curl_multi_init(); diff --git a/src/hud.cpp b/src/hud.cpp index 80112a6e..75075564 100644 --- a/src/hud.cpp +++ b/src/hud.cpp @@ -143,7 +143,7 @@ void Hud::drawItem(v2s32 upperleftpos, s32 imgsize, s32 itemcount, steppos = v2s32(padding, -(padding + i * fullimglen)); break; default: - steppos = v2s32(padding + i * fullimglen, padding); + steppos = v2s32(padding + i * fullimglen, padding); } core::rect rect = imgrect + pos + steppos; @@ -334,7 +334,7 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, s steppos = v2s32(0, -1); break; default: - steppos = v2s32(1, 0); + steppos = v2s32(1, 0); } steppos.X *= srcd.Width; steppos.Y *= srcd.Height; @@ -363,7 +363,7 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, s void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem, s32 breath) { InventoryList *mainlist = inventory->getList("main"); if (mainlist == NULL) { - errorstream << "draw_hotbar(): mainlist == NULL" << std::endl; + //silently ignore this we may not be initialized completely return; } @@ -384,7 +384,8 @@ void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem, s void Hud::drawCrosshair() { - if (!(player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE)) + if (!(player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE) || + player->camera_mode == CAMERA_MODE_THIRD_FRONT) return; if (use_crosshair_image) { diff --git a/src/localplayer.cpp b/src/localplayer.cpp index a6f04849..e545dc42 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -43,6 +43,10 @@ LocalPlayer::LocalPlayer(IGameDef *gamedef): last_pitch(0), last_yaw(0), last_keyPressed(0), + camera_mode(0), + eye_offset_first(v3f(0,0,0)), + eye_offset_third(v3f(0,0,0)), + last_animation(NO_ANIM), hotbar_image(""), hotbar_selected_image(""), m_sneak_node(32767,32767,32767), @@ -61,7 +65,7 @@ LocalPlayer::~LocalPlayer() { } -void LocalPlayer::move(f32 dtime, ClientEnvironment *env, f32 pos_max_d, +void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d, std::list *collision_info) { Map *map = &env->getMap(); @@ -356,7 +360,7 @@ void LocalPlayer::move(f32 dtime, ClientEnvironment *env, f32 pos_max_d, m_can_jump = false; } -void LocalPlayer::move(f32 dtime, ClientEnvironment *env, f32 pos_max_d) +void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d) { move(dtime, env, pos_max_d, NULL); } diff --git a/src/localplayer.h b/src/localplayer.h index b6a3ed1f..38e7a4cd 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -23,10 +23,12 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "player.h" #include -class ClientEnvironment; +class Environment; class ClientActiveObject; +enum LocalPlayerAnimations {NO_ANIM, WALK_ANIM, DIG_ANIM, WD_ANIM}; // no local animation, walking, digging, both + class LocalPlayer : public Player { public: @@ -44,9 +46,9 @@ public: v3f overridePosition; - void move(f32 dtime, ClientEnvironment *env, f32 pos_max_d, + void move(f32 dtime, Environment *env, f32 pos_max_d); + void move(f32 dtime, Environment *env, f32 pos_max_d, std::list *collision_info); - void move(f32 dtime, ClientEnvironment *env, f32 pos_max_d); void applyControl(float dtime); @@ -60,6 +62,12 @@ public: unsigned int last_keyPressed; float camera_impact; + int camera_mode; + v3f eye_offset_first; + v3f eye_offset_third; + + int last_animation; + float last_animation_speed; std::string hotbar_image; std::string hotbar_selected_image; diff --git a/src/main.cpp b/src/main.cpp index 58312794..bb0c3a27 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -55,7 +55,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "constants.h" #include "porting.h" #include "gettime.h" -#include "guiMessageMenu.h" #include "filesys.h" #include "config.h" #include "version.h" @@ -85,6 +84,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifdef USE_LEVELDB #include "database-leveldb.h" #endif +#if USE_REDIS +#include "database-redis.h" +#endif /* Settings. @@ -361,7 +363,6 @@ public: s32 mouse_wheel; private: - IrrlichtDevice *m_device; // The current state of keys KeyList keyIsDown; @@ -1024,21 +1025,6 @@ int main(int argc, char *argv[]) if(port == 0) port = 30000; - // Bind address - std::string bind_str = g_settings->get("bind_address"); - Address bind_addr(0,0,0,0, port); - try { - bind_addr.Resolve(bind_str.c_str()); - } catch (ResolveError &e) { - infostream << "Resolving bind address \"" << bind_str - << "\" failed: " << e.what() - << " -- Listening on all addresses." << std::endl; - - if (g_settings->getBool("ipv6_server")) { - bind_addr.setAddress((IPv6AddressBytes*) NULL); - } - } - // World directory std::string commanded_world = ""; if(cmd_args.exists("world")) @@ -1224,8 +1210,29 @@ int main(int argc, char *argv[]) } verbosestream<<_("Using gameid")<<" ["<get("bind_address"); + Address bind_addr(0,0,0,0, port); + + if (g_settings->getBool("ipv6_server")) { + bind_addr.setAddress((IPv6AddressBytes*) NULL); + } + try { + bind_addr.Resolve(bind_str.c_str()); + } catch (ResolveError &e) { + infostream << "Resolving bind address \"" << bind_str + << "\" failed: " << e.what() + << " -- Listening on all addresses." << std::endl; + } + if(bind_addr.isIPv6() && !g_settings->getBool("enable_ipv6")) { + errorstream << "Unable to listen on " + << bind_addr.serializeString() + << L" because IPv6 is disabled" << std::endl; + return 1; + } + // Create server - Server server(world_path, gamespec, false); + Server server(world_path, gamespec, false, bind_addr.isIPv6()); // Database migration if (cmd_args.exists("migrate")) { @@ -1238,7 +1245,7 @@ int main(int argc, char *argv[]) } if (!world_mt.exists("backend")) { errorstream << "Please specify your current backend in world.mt file:" - << std::endl << " backend = {sqlite3|leveldb|dummy}" << std::endl; + << std::endl << " backend = {sqlite3|leveldb|redis|dummy}" << std::endl; return 1; } std::string backend = world_mt.get("backend"); @@ -1253,6 +1260,10 @@ int main(int argc, char *argv[]) else if (migrate_to == "leveldb") new_db = new Database_LevelDB(&(ServerMap&)server.getMap(), world_path); #endif + #if USE_REDIS + else if (migrate_to == "redis") + new_db = new Database_Redis(&(ServerMap&)server.getMap(), world_path); + #endif else { errorstream << "Migration to " << migrate_to << " is not supported" << std::endl; return 1; diff --git a/src/mainmenumanager.h b/src/mainmenumanager.h index ecfb89fd..78ae1fcf 100644 --- a/src/mainmenumanager.h +++ b/src/mainmenumanager.h @@ -25,9 +25,17 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "debug.h" // assert #include "modalMenu.h" -#include "guiPauseMenu.h" //For IGameCallback #include +class IGameCallback +{ +public: + virtual void exitToOS() = 0; + virtual void disconnect() = 0; + virtual void changePassword() = 0; + virtual void changeVolume() = 0; +}; + extern gui::IGUIEnvironment* guienv; extern gui::IGUIStaticText *guiroot; diff --git a/src/map.cpp b/src/map.cpp index 22ea41e0..86ad9ecb 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -46,6 +46,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #if USE_LEVELDB #include "database-leveldb.h" #endif +#if USE_REDIS +#include "database-redis.h" +#endif #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" @@ -1097,7 +1100,6 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, /* Add neighboring liquid nodes and the node itself if it is liquid (=water node was added) to transform queue. - note: todo: for liquid_finite enough to add only self node */ v3s16 dirs[7] = { v3s16(0,0,0), // self @@ -1289,7 +1291,6 @@ void Map::removeNodeAndUpdate(v3s16 p, /* Add neighboring liquid nodes and this node to transform queue. (it's vital for the node itself to get updated last.) - note: todo: for liquid_finite enough to add only self node */ v3s16 dirs[7] = { v3s16(0,0,1), // back @@ -1616,7 +1617,6 @@ struct NodeNeighbor { NeighborType t; v3s16 p; bool l; //can liquid - bool i; //infinity }; void Map::transforming_liquid_add(v3s16 p) { @@ -1627,383 +1627,8 @@ s32 Map::transforming_liquid_size() { return m_transforming_liquid.size(); } -const v3s16 g_7dirs[7] = -{ - // +right, +top, +back - v3s16( 0,-1, 0), // bottom - v3s16( 0, 0, 0), // self - v3s16( 0, 0, 1), // back - v3s16( 0, 0,-1), // front - v3s16( 1, 0, 0), // right - v3s16(-1, 0, 0), // left - v3s16( 0, 1, 0) // top -}; - -#define D_BOTTOM 0 -#define D_TOP 6 -#define D_SELF 1 - -void Map::transformLiquidsFinite(std::map & modified_blocks) -{ - INodeDefManager *nodemgr = m_gamedef->ndef(); - - DSTACK(__FUNCTION_NAME); - //TimeTaker timer("transformLiquids()"); - - u32 loopcount = 0; - u32 initial_size = m_transforming_liquid.size(); - - u8 relax = g_settings->getS16("liquid_relax"); - bool fast_flood = g_settings->getS16("liquid_fast_flood"); - int water_level = g_settings->getS16("water_level"); - - // list of nodes that due to viscosity have not reached their max level height - UniqueQueue must_reflow, must_reflow_second; - - // List of MapBlocks that will require a lighting update (due to lava) - std::map lighting_modified_blocks; - - u16 loop_max = g_settings->getU16("liquid_loop_max"); - - //if (m_transforming_liquid.size() > 0) errorstream << "Liquid queue size="< 0) - { - // This should be done here so that it is done when continue is used - if (loopcount >= initial_size || loopcount >= loop_max) - break; - loopcount++; - /* - Get a queued transforming liquid node - */ - v3s16 p0 = m_transforming_liquid.pop_front(); - u16 total_level = 0; - // surrounding flowing liquid nodes - NodeNeighbor neighbors[7]; - // current level of every block - s8 liquid_levels[7] = {-1, -1, -1, -1, -1, -1, -1}; - // target levels - s8 liquid_levels_want[7] = {-1, -1, -1, -1, -1, -1, -1}; - s8 can_liquid_same_level = 0; - content_t liquid_kind = CONTENT_IGNORE; - content_t liquid_kind_flowing = CONTENT_IGNORE; - /* - Collect information about the environment - */ - const v3s16 *dirs = g_7dirs; - for (u16 i = 0; i < 7; i++) { - NeighborType nt = NEIGHBOR_SAME_LEVEL; - switch (i) { - case D_TOP: - nt = NEIGHBOR_UPPER; - break; - case D_BOTTOM: - nt = NEIGHBOR_LOWER; - break; - } - v3s16 npos = p0 + dirs[i]; - - neighbors[i].n = getNodeNoEx(npos); - neighbors[i].t = nt; - neighbors[i].p = npos; - neighbors[i].l = 0; - neighbors[i].i = 0; - NodeNeighbor & nb = neighbors[i]; - - switch (nodemgr->get(nb.n.getContent()).liquid_type) { - case LIQUID_NONE: - if (nb.n.getContent() == CONTENT_AIR) { - liquid_levels[i] = 0; - nb.l = 1; - } - break; - case LIQUID_SOURCE: - // if this node is not (yet) of a liquid type, - // choose the first liquid type we encounter - if (liquid_kind_flowing == CONTENT_IGNORE) - liquid_kind_flowing = nodemgr->getId( - nodemgr->get(nb.n).liquid_alternative_flowing); - if (liquid_kind == CONTENT_IGNORE) - liquid_kind = nb.n.getContent(); - if (nb.n.getContent() == liquid_kind) { - liquid_levels[i] = nb.n.getLevel(nodemgr); //LIQUID_LEVEL_SOURCE; - nb.l = 1; - nb.i = (nb.n.param2 & LIQUID_INFINITY_MASK); - } - break; - case LIQUID_FLOWING: - // if this node is not (yet) of a liquid type, - // choose the first liquid type we encounter - if (liquid_kind_flowing == CONTENT_IGNORE) - liquid_kind_flowing = nb.n.getContent(); - if (liquid_kind == CONTENT_IGNORE) - liquid_kind = nodemgr->getId( - nodemgr->get(nb.n).liquid_alternative_source); - if (nb.n.getContent() == liquid_kind_flowing) { - liquid_levels[i] = nb.n.getLevel(nodemgr); //(nb.n.param2 & LIQUID_LEVEL_MASK); - nb.l = 1; - } - break; - } - - if (nb.l && nb.t == NEIGHBOR_SAME_LEVEL) - ++can_liquid_same_level; - if (liquid_levels[i] > 0) - total_level += liquid_levels[i]; - - /* - infostream << "get node i=" <<(int)i<<" " << PP(npos) << " c=" - << nb.n.getContent() <<" p0="<< (int)nb.n.param0 <<" p1=" - << (int)nb.n.param1 <<" p2="<< (int)nb.n.param2 << " lt=" - << nodemgr->get(nb.n.getContent()).liquid_type - //<< " lk=" << liquid_kind << " lkf=" << liquid_kind_flowing - << " l="<< nb.l << " inf="<< nb.i << " nlevel=" << (int)liquid_levels[i] - << " tlevel=" << (int)total_level << " cansame=" - << (int)can_liquid_same_level << std::endl; - */ - } - - if (liquid_kind == CONTENT_IGNORE || - !neighbors[D_SELF].l || - total_level <= 0) - continue; - - // fill bottom block - if (neighbors[D_BOTTOM].l) { - liquid_levels_want[D_BOTTOM] = total_level > LIQUID_LEVEL_SOURCE ? - LIQUID_LEVEL_SOURCE : total_level; - total_level -= liquid_levels_want[D_BOTTOM]; - } - - //relax up - if (relax && ((p0.Y == water_level) || (fast_flood && p0.Y <= water_level)) && liquid_levels[D_TOP] == 0 && - liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE && - total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level- - (can_liquid_same_level - relax) && - can_liquid_same_level >= relax + 1) { - total_level = LIQUID_LEVEL_SOURCE * can_liquid_same_level; - } - - // prevent lakes in air above unloaded blocks - if (liquid_levels[D_TOP] == 0 && (p0.Y > water_level) && neighbors[D_BOTTOM].n.getContent() == CONTENT_IGNORE && !(loopcount % 3)) { - --total_level; - } - - // calculate self level 5 blocks - u8 want_level = - total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level - ? LIQUID_LEVEL_SOURCE - : total_level / can_liquid_same_level; - total_level -= want_level * can_liquid_same_level; - - //relax down - if (relax && p0.Y == water_level + 1 && liquid_levels[D_TOP] == 0 && - liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE && want_level == 0 && - total_level <= (can_liquid_same_level - relax) && - can_liquid_same_level >= relax + 1) { - total_level = 0; - } - - for (u16 ii = D_SELF; ii < D_TOP; ++ii) { // fill only same level - if (!neighbors[ii].l) - continue; - liquid_levels_want[ii] = want_level; - if (liquid_levels_want[ii] < LIQUID_LEVEL_SOURCE && total_level > 0) { - if (loopcount % 3 || liquid_levels[ii] <= 0){ - if (liquid_levels[ii] > liquid_levels_want[ii]) { - ++liquid_levels_want[ii]; - --total_level; - } - } else if (neighbors[ii].l > 0){ - ++liquid_levels_want[ii]; - --total_level; - } - } - } - - for (u16 ii = 0; ii < 7; ++ii) { - if (total_level < 1) break; - if (liquid_levels_want[ii] >= 0 && - liquid_levels_want[ii] < LIQUID_LEVEL_SOURCE) { - ++liquid_levels_want[ii]; - --total_level; - } - } - - // fill top block if can - if (neighbors[D_TOP].l) { - liquid_levels_want[D_TOP] = total_level > LIQUID_LEVEL_SOURCE ? - LIQUID_LEVEL_SOURCE : total_level; - total_level -= liquid_levels_want[D_TOP]; - } - - for (u16 ii = 0; ii < 7; ii++) // infinity and cave flood optimization - if ( neighbors[ii].i || - (liquid_levels_want[ii] >= 0 && - (fast_flood && p0.Y < water_level && - (initial_size >= 1000 - && ii != D_TOP - && want_level >= LIQUID_LEVEL_SOURCE/4 - && can_liquid_same_level >= 5 - && liquid_levels[D_TOP] >= LIQUID_LEVEL_SOURCE)))) - liquid_levels_want[ii] = LIQUID_LEVEL_SOURCE; - - /* - if (total_level > 0) //|| flowed != volume) - infostream <<" AFTER level=" << (int)total_level - //<< " flowed="<ndef(); DSTACK(__FUNCTION_NAME); @@ -2382,26 +2007,6 @@ void Map::removeNodeTimer(v3s16 p) block->m_node_timers.remove(p_rel); } -s16 Map::getHeat(v3s16 p) -{ - MapBlock *block = getBlockNoCreateNoEx(getNodeBlockPos(p)); - if(block != NULL) { - return block->heat; - } - //errorstream << "No heat for " << p.X<<"," << p.Z << std::endl; - return 0; -} - -s16 Map::getHumidity(v3s16 p) -{ - MapBlock *block = getBlockNoCreateNoEx(getNodeBlockPos(p)); - if(block != NULL) { - return block->humidity; - } - //errorstream << "No humidity for " << p.X<<"," << p.Z << std::endl; - return 0; -} - /* ServerMap */ @@ -2434,6 +2039,10 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emer else if (backend == "leveldb") dbase = new Database_LevelDB(this, savedir); #endif + #if USE_REDIS + else if (backend == "redis") + dbase = new Database_Redis(this, savedir); + #endif else throw BaseException("Unknown map backend"); } @@ -2596,6 +2205,7 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos) // Sector metadata is loaded from disk if not already loaded. ServerMapSector *sector = createSector(sectorpos); assert(sector); + (void) sector; for(s16 y=blockpos_min.Y-extra_borders.Y; y<=blockpos_max.Y+extra_borders.Y; y++) @@ -2810,29 +2420,6 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data, <<","<getEnv(); - for(s16 x=blockpos_min.X-extra_borders.X; - x<=blockpos_max.X+extra_borders.X; x++) - for(s16 z=blockpos_min.Z-extra_borders.Z; - z<=blockpos_max.Z+extra_borders.Z; z++) - for(s16 y=blockpos_min.Y-extra_borders.Y; - y<=blockpos_max.Y+extra_borders.Y; y++) - { - v3s16 p(x, y, z); - MapBlock *block = getBlockNoCreateNoEx(p); - block->heat_last_update = 0; - block->humidity_last_update = 0; - if (senv->m_use_weather) { - updateBlockHeat(senv, p * MAP_BLOCKSIZE, block); - updateBlockHumidity(senv, p * MAP_BLOCKSIZE, block); - } else { - block->heat = HEAT_UNDEFINED; - block->humidity = HUMIDITY_UNDEFINED; - } - } #if 0 if(enable_mapgen_debug_info) @@ -3167,19 +2754,6 @@ MapBlock *ServerMap::getBlockOrEmerge(v3s16 p3d) } void ServerMap::prepareBlock(MapBlock *block) { - ServerEnvironment *senv = &((Server *)m_gamedef)->getEnv(); - - // Calculate weather conditions - block->heat_last_update = 0; - block->humidity_last_update = 0; - if (senv->m_use_weather) { - v3s16 p = block->getPos() * MAP_BLOCKSIZE; - updateBlockHeat(senv, p, block); - updateBlockHumidity(senv, p, block); - } else { - block->heat = HEAT_UNDEFINED; - block->humidity = HUMIDITY_UNDEFINED; - } } s16 ServerMap::findGroundLevel(v2s16 p2d) @@ -3261,12 +2835,13 @@ std::string ServerMap::getSectorDir(v2s16 pos, int layout) return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc; default: assert(false); + return ""; } } v2s16 ServerMap::getSectorPos(std::string dirname) { - unsigned int x, y; + unsigned int x = 0, y = 0; int r; std::string component; fs::RemoveLastPathComponent(dirname, &component, 1); @@ -3908,48 +3483,6 @@ void ServerMap::PrintInfo(std::ostream &out) out<<"ServerMap: "; } -s16 ServerMap::updateBlockHeat(ServerEnvironment *env, v3s16 p, MapBlock *block) -{ - u32 gametime = env->getGameTime(); - - if (block) { - if (gametime - block->heat_last_update < 10) - return block->heat; - } else { - block = getBlockNoCreateNoEx(getNodeBlockPos(p)); - } - - f32 heat = m_emerge->biomedef->calcBlockHeat(p, getSeed(), - env->getTimeOfDayF(), gametime * env->getTimeOfDaySpeed()); - - if(block) { - block->heat = heat; - block->heat_last_update = gametime; - } - return heat; -} - -s16 ServerMap::updateBlockHumidity(ServerEnvironment *env, v3s16 p, MapBlock *block) -{ - u32 gametime = env->getGameTime(); - - if (block) { - if (gametime - block->humidity_last_update < 10) - return block->humidity; - } else { - block = getBlockNoCreateNoEx(getNodeBlockPos(p)); - } - - f32 humidity = m_emerge->biomedef->calcBlockHumidity(p, getSeed(), - env->getTimeOfDayF(), gametime * env->getTimeOfDaySpeed()); - - if(block) { - block->humidity = humidity; - block->humidity_last_update = gametime; - } - return humidity; -} - /* MapVoxelManipulator */ diff --git a/src/map.h b/src/map.h index 191cf5f9..c2725d3d 100644 --- a/src/map.h +++ b/src/map.h @@ -304,7 +304,6 @@ public: virtual void PrintInfo(std::ostream &out); void transformLiquids(std::map & modified_blocks); - void transformLiquidsFinite(std::map & modified_blocks); /* Node metadata @@ -351,9 +350,6 @@ public: void transforming_liquid_add(v3s16 p); s32 transforming_liquid_size(); - virtual s16 getHeat(v3s16 p); - virtual s16 getHumidity(v3s16 p); - protected: friend class LuaVoxelManip; @@ -504,9 +500,6 @@ public: u64 getSeed(); s16 getWaterLevel(); - virtual s16 updateBlockHeat(ServerEnvironment *env, v3s16 p, MapBlock *block = NULL); - virtual s16 updateBlockHumidity(ServerEnvironment *env, v3s16 p, MapBlock *block = NULL); - private: // Emerge manager EmergeManager *m_emerge; diff --git a/src/mapblock.cpp b/src/mapblock.cpp index eafb956d..95e54fb3 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -43,10 +43,6 @@ with this program; if not, write to the Free Software Foundation, Inc., */ MapBlock::MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy): - heat(0), - humidity(0), - heat_last_update(0), - humidity_last_update(0), m_parent(parent), m_pos(pos), m_gamedef(gamedef), @@ -647,8 +643,8 @@ void MapBlock::serializeNetworkSpecific(std::ostream &os, u16 net_proto_version) if(net_proto_version >= 21){ int version = 1; writeU8(os, version); - writeF1000(os, heat); - writeF1000(os, humidity); + writeF1000(os, 0); // deprecated heat + writeF1000(os, 0); // deprecated humidity } } @@ -764,8 +760,8 @@ void MapBlock::deSerializeNetworkSpecific(std::istream &is) //if(version != 1) // throw SerializationError("unsupported MapBlock version"); if(version >= 1) { - heat = readF1000(is); - humidity = readF1000(is); + readF1000(is); // deprecated heat + readF1000(is); // deprecated humidity } } catch(SerializationError &e) diff --git a/src/mapblock.h b/src/mapblock.h index 501ab75d..3879c5b0 100644 --- a/src/mapblock.h +++ b/src/mapblock.h @@ -513,11 +513,6 @@ public: NodeMetadataList m_node_metadata; NodeTimerList m_node_timers; StaticObjectList m_static_objects; - - s16 heat; - s16 humidity; - u32 heat_last_update; - u32 humidity_last_update; private: /* diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp index ef05acbb..9f8dd221 100644 --- a/src/mapblock_mesh.cpp +++ b/src/mapblock_mesh.cpp @@ -150,9 +150,8 @@ void MeshMakeData::setSmoothLighting(bool smooth_lighting) Single light bank. */ static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment, - MeshMakeData *data) + INodeDefManager *ndef) { - INodeDefManager *ndef = data->m_gamedef->ndef(); u8 light = n.getLight(bank, ndef); while(increment > 0) @@ -173,10 +172,10 @@ static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment, Calculate non-smooth lighting at interior of node. Both light banks. */ -u16 getInteriorLight(MapNode n, s32 increment, MeshMakeData *data) +u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef) { - u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, data); - u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, data); + u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, ndef); + u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, ndef); return day | (night << 8); } @@ -185,10 +184,8 @@ u16 getInteriorLight(MapNode n, s32 increment, MeshMakeData *data) Single light bank. */ static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2, - v3s16 face_dir, MeshMakeData *data) + v3s16 face_dir, INodeDefManager *ndef) { - INodeDefManager *ndef = data->m_gamedef->ndef(); - u8 light; u8 l1 = n.getLight(bank, ndef); u8 l2 = n2.getLight(bank, ndef); @@ -227,10 +224,10 @@ static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2, Calculate non-smooth lighting at face of node. Both light banks. */ -u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, MeshMakeData *data) +u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef) { - u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, data); - u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, data); + u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, ndef); + u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, ndef); return day | (night << 8); } @@ -812,7 +809,7 @@ static void getTileInfo( if(data->m_smooth_lighting == false) { lights[0] = lights[1] = lights[2] = lights[3] = - getFaceLight(n0, n1, face_dir, data); + getFaceLight(n0, n1, face_dir, ndef); } else { @@ -1212,20 +1209,25 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset): ITextureSource *tsrc = data->m_gamedef->tsrc(); material.setTexture(2, tsrc->getTexture("disable_img.png")); if (enable_bumpmapping || enable_parallax_occlusion) { - std::string fname_base = tsrc->getTextureName(p.tile.texture_id); - std::string normal_ext = "_normal.png"; - size_t pos = fname_base.find("."); - std::string fname_normal = fname_base.substr(0, pos) + normal_ext; - - if (tsrc->isKnownSourceImage(fname_normal)) { - // look for image extension and replace it - size_t i = 0; - while ((i = fname_base.find(".", i)) != std::string::npos) { - fname_base.replace(i, 4, normal_ext); - i += normal_ext.length(); - } - material.setTexture(1, tsrc->getTexture(fname_base)); + if (tsrc->isKnownSourceImage("override_normal.png")){ + material.setTexture(1, tsrc->getTexture("override_normal.png")); material.setTexture(2, tsrc->getTexture("enable_img.png")); + } else { + std::string fname_base = tsrc->getTextureName(p.tile.texture_id); + std::string normal_ext = "_normal.png"; + size_t pos = fname_base.find("."); + std::string fname_normal = fname_base.substr(0, pos) + normal_ext; + + if (tsrc->isKnownSourceImage(fname_normal)) { + // look for image extension and replace it + size_t i = 0; + while ((i = fname_base.find(".", i)) != std::string::npos) { + fname_base.replace(i, 4, normal_ext); + i += normal_ext.length(); + } + material.setTexture(1, tsrc->getTexture(fname_base)); + material.setTexture(2, tsrc->getTexture("enable_img.png")); + } } } p.tile.applyMaterialOptionsWithShaders(material, @@ -1368,17 +1370,22 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat buf->getMaterial().setTexture(2, tsrc->getTexture("disable_img.png")); if (enable_shaders && (enable_bumpmapping || enable_parallax_occlusion)) { - std::string fname_base,fname_normal; - fname_base = tsrc->getTextureName(tile.texture_id); - unsigned pos; - pos = fname_base.find("."); - fname_normal = fname_base.substr (0, pos); - fname_normal += "_normal.png"; - if (tsrc->isKnownSourceImage(fname_normal)){ - os.str(""); - os<getMaterial().setTexture(1, tsrc->getTexture(os.str())); + if (tsrc->isKnownSourceImage("override_normal.png")){ + buf->getMaterial().setTexture(1, tsrc->getTexture("override_normal.png")); buf->getMaterial().setTexture(2, tsrc->getTexture("enable_img.png")); + } else { + std::string fname_base,fname_normal; + fname_base = tsrc->getTextureName(tile.texture_id); + unsigned pos; + pos = fname_base.find("."); + fname_normal = fname_base.substr (0, pos); + fname_normal += "_normal.png"; + if (tsrc->isKnownSourceImage(fname_normal)){ + os.str(""); + os<getMaterial().setTexture(1, tsrc->getTexture(os.str())); + buf->getMaterial().setTexture(2, tsrc->getTexture("enable_img.png")); + } } } } diff --git a/src/mapblock_mesh.h b/src/mapblock_mesh.h index 021309d9..7f523173 100644 --- a/src/mapblock_mesh.h +++ b/src/mapblock_mesh.h @@ -172,8 +172,8 @@ inline video::SColor MapBlock_LightColor(u8 alpha, u16 light, u8 light_source=0) } // Compute light at node -u16 getInteriorLight(MapNode n, s32 increment, MeshMakeData *data); -u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, MeshMakeData *data); +u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef); +u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef); u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data); // Retrieves the TileSpec of a face of a node diff --git a/src/mapgen.cpp b/src/mapgen.cpp index a7e9d2e0..1a31a8bc 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -977,10 +977,8 @@ void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax) { void Mapgen::updateLiquid(UniqueQueue *trans_liquid, v3s16 nmin, v3s16 nmax) { - bool isliquid, wasliquid, rare; + bool isliquid, wasliquid; v3s16 em = vm->m_area.getExtent(); - rare = g_settings->getBool("liquid_finite"); - int rarecnt = 0; for (s16 z = nmin.Z; z <= nmax.Z; z++) { for (s16 x = nmin.X; x <= nmax.X; x++) { @@ -990,8 +988,8 @@ void Mapgen::updateLiquid(UniqueQueue *trans_liquid, v3s16 nmin, v3s16 nm for (s16 y = nmax.Y; y >= nmin.Y; y--) { isliquid = ndef->get(vm->m_data[i]).isLiquid(); - // there was a change between liquid and nonliquid, add to queue. no need to add every with liquid_finite - if (isliquid != wasliquid && (!rare || !(rarecnt++ % 36))) + // there was a change between liquid and nonliquid, add to queue. + if (isliquid != wasliquid) trans_liquid->push_back(v3s16(x, y, z)); wasliquid = isliquid; diff --git a/src/mapgen.h b/src/mapgen.h index 9bc162fe..3c897e02 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -209,7 +209,7 @@ Ore *createOre(OreType type); enum DecorationType { - DECO_SIMPLE, + DECO_SIMPLE = 1, DECO_SCHEMATIC, DECO_LSYSTEM }; diff --git a/src/mapgen_indev.cpp b/src/mapgen_indev.cpp index ac5b4e81..f0154715 100644 --- a/src/mapgen_indev.cpp +++ b/src/mapgen_indev.cpp @@ -26,9 +26,9 @@ with this program; if not, write to the Free Software Foundation, Inc., /////////////////////////////////////////////////////////////////////////////// -void NoiseIndev::init(NoiseIndevParams *np, int seed, int sx, int sy, int sz) { - Noise::init((NoiseParams*)np, seed, sx, sy, sz); - this->npindev = np; +void NoiseIndev::init(NoiseParams *np, int seed, int sx, int sy, int sz) { + Noise::init(np, seed, sx, sy, sz); + this->npindev = (NoiseIndevParams*) np; } NoiseIndev::NoiseIndev(NoiseIndevParams *np, int seed, int sx, int sy) : Noise(np, seed, sx, sy) { diff --git a/src/mapgen_indev.h b/src/mapgen_indev.h index a5b0a667..d8be7dce 100644 --- a/src/mapgen_indev.h +++ b/src/mapgen_indev.h @@ -61,7 +61,7 @@ public: virtual ~NoiseIndev() {}; NoiseIndev(NoiseIndevParams *np, int seed, int sx, int sy); NoiseIndev(NoiseIndevParams *np, int seed, int sx, int sy, int sz); - void init(NoiseIndevParams *np, int seed, int sx, int sy, int sz); + void init(NoiseParams *np, int seed, int sx, int sy, int sz); void transformNoiseMapFarScale(float xx = 0, float yy = 0, float zz = 0); }; diff --git a/src/mods.h b/src/mods.h index dedcc989..f11401a1 100644 --- a/src/mods.h +++ b/src/mods.h @@ -66,7 +66,7 @@ struct ModSpec bool is_modpack; // if modpack: std::map modpack_content; - ModSpec(const std::string name_="", const std::string path_=""): + ModSpec(const std::string &name_="", const std::string &path_=""): name(name_), path(path_), depends(), diff --git a/src/player.h b/src/player.h index a1050d4c..4c5939d3 100644 --- a/src/player.h +++ b/src/player.h @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irrlichttypes_bloated.h" #include "inventory.h" #include "constants.h" // BS +#include #define PLAYERNAME_SIZE 20 @@ -88,6 +89,7 @@ class IGameDef; struct CollisionInfo; class PlayerSAO; struct HudElement; +class Environment; class Player { @@ -96,7 +98,10 @@ public: Player(IGameDef *gamedef); virtual ~Player() = 0; - virtual void move(f32 dtime, Map &map, f32 pos_max_d) + virtual void move(f32 dtime, Environment *env, f32 pos_max_d) + {} + virtual void move(f32 dtime, Environment *env, f32 pos_max_d, + std::list *collision_info) {} v3f getSpeed() @@ -269,6 +274,9 @@ public: bool physics_override_sneak; bool physics_override_sneak_glitch; + v2s32 local_animations[4]; + float local_animation_speed; + u16 hp; float hurt_tilt_timer; diff --git a/src/porting.cpp b/src/porting.cpp index b0a1843e..e7bef1d3 100644 --- a/src/porting.cpp +++ b/src/porting.cpp @@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc., See comments in porting.h */ +#include "porting.h" + #if defined(__APPLE__) #include #include "CoreFoundation/CoreFoundation.h" @@ -37,7 +39,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #endif -#include "porting.h" #include "config.h" #include "debug.h" #include "filesys.h" diff --git a/src/porting.h b/src/porting.h index c03ae40a..aaabce4e 100644 --- a/src/porting.h +++ b/src/porting.h @@ -24,6 +24,14 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifndef PORTING_HEADER #define PORTING_HEADER +#ifdef _WIN32 + #ifdef _WIN32_WINNT + #undef _WIN32_WINNT + #endif + #define _WIN32_WINNT 0x0501 // We need to do this before any other headers + // because those might include sdkddkver.h which defines _WIN32_WINNT if not already set +#endif + #include #include "irrlichttypes.h" // u32 #include "debug.h" @@ -42,9 +50,6 @@ with this program; if not, write to the Free Software Foundation, Inc., //#define ALIGNOF(type) offsetof (alignment_trick, member) #ifdef _WIN32 - #ifndef _WIN32_WINNT - #define _WIN32_WINNT 0x0501 - #endif #include #define sleep_ms(x) Sleep(x) @@ -266,6 +271,26 @@ inline u32 getTime(TimePrecision prec) return 0; } +#if (defined(linux) || defined(__linux)) + +#include + +inline void setThreadName(const char* name) { + prctl(PR_SET_NAME,name); +} +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +/* BSD doesn't seem to support thread names. If you know about a way + * to add this feature please create a pull request. + * "setproctitle" doesn't work for threadnames. + */ +inline void setThreadName(const char* name) {} +#elif defined(_WIN32) +// threadnames are not supported on windows +inline void setThreadName(const char* name) {} +#else +#warning "Unknown platform for setThreadName support, you wont have threadname support." +inline void setThreadName(const char* name) {} +#endif } // namespace porting diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 74e1b095..2898d28a 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -654,7 +654,7 @@ ItemStack read_item(lua_State* L, int index,Server* srv) } else { - throw LuaError(NULL, "Expecting itemstack, itemstring, table or nil"); + throw LuaError("Expecting itemstack, itemstring, table or nil"); } } @@ -840,23 +840,32 @@ void push_hit_params(lua_State *L,const HitParams ¶ms) } /******************************************************************************/ -u32 getflagsfield(lua_State *L, int table, const char *fieldname, - FlagDesc *flagdesc, u32 *flagmask) + +bool getflagsfield(lua_State *L, int table, const char *fieldname, + FlagDesc *flagdesc, u32 *flags, u32 *flagmask) { - u32 flags = 0; - lua_getfield(L, table, fieldname); - if (lua_isstring(L, -1)) { - std::string flagstr = lua_tostring(L, -1); - flags = readFlagString(flagstr, flagdesc, flagmask); - } else if (lua_istable(L, -1)) { - flags = read_flags_table(L, -1, flagdesc, flagmask); - } + bool success = read_flags(L, -1, flagdesc, flags, flagmask); lua_pop(L, 1); - return flags; + return success; +} + +bool read_flags(lua_State *L, int index, FlagDesc *flagdesc, + u32 *flags, u32 *flagmask) +{ + if (lua_isstring(L, index)) { + std::string flagstr = lua_tostring(L, index); + *flags = readFlagString(flagstr, flagdesc, flagmask); + } else if (lua_istable(L, index)) { + *flags = read_flags_table(L, index, flagdesc, flagmask); + } else { + return false; + } + + return true; } u32 read_flags_table(lua_State *L, int table, FlagDesc *flagdesc, u32 *flagmask) @@ -932,7 +941,7 @@ std::vector read_items(lua_State *L, int index, Server *srv) while (lua_next(L, index)) { s32 key = luaL_checkinteger(L, -2); if (key < 1) { - throw LuaError(NULL, "Invalid inventory list index"); + throw LuaError("Invalid inventory list index"); } if (items.size() < (u32) key) { items.resize(key); diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h index 9aed5ccf..f48c673b 100644 --- a/src/script/common/c_content.h +++ b/src/script/common/c_content.h @@ -119,9 +119,14 @@ int getenumfield (lua_State *L, const EnumString *spec, int default_); -u32 getflagsfield (lua_State *L, int table, +bool getflagsfield (lua_State *L, int table, const char *fieldname, - FlagDesc *flagdesc, u32 *flagmask); + FlagDesc *flagdesc, + u32 *flags, u32 *flagmask); + +bool read_flags (lua_State *L, int index, + FlagDesc *flagdesc, + u32 *flags, u32 *flagmask); u32 read_flags_table (lua_State *L, int table, FlagDesc *flagdesc, u32 *flagmask); diff --git a/src/script/common/c_converter.cpp b/src/script/common/c_converter.cpp index df86f2da..b2ef0573 100644 --- a/src/script/common/c_converter.cpp +++ b/src/script/common/c_converter.cpp @@ -59,6 +59,19 @@ v2s16 read_v2s16(lua_State *L, int index) return p; } +v2s32 read_v2s32(lua_State *L, int index) +{ + v2s32 p; + luaL_checktype(L, index, LUA_TTABLE); + lua_getfield(L, index, "x"); + p.X = lua_tonumber(L, -1); + lua_pop(L, 1); + lua_getfield(L, index, "y"); + p.Y = lua_tonumber(L, -1); + lua_pop(L, 1); + return p; +} + v2f read_v2f(lua_State *L, int index) { v2f p; diff --git a/src/script/common/c_converter.h b/src/script/common/c_converter.h index ab008312..0c051a80 100644 --- a/src/script/common/c_converter.h +++ b/src/script/common/c_converter.h @@ -75,6 +75,7 @@ v3s16 check_v3s16 (lua_State *L, int index); v3f read_v3f (lua_State *L, int index); v2f read_v2f (lua_State *L, int index); v2s16 read_v2s16 (lua_State *L, int index); +v2s32 read_v2s32 (lua_State *L, int index); video::SColor readARGB8 (lua_State *L, int index); aabb3f read_aabb3f (lua_State *L, int index, f32 scale); v3s16 read_v3s16 (lua_State *L, int index); diff --git a/src/script/common/c_internal.cpp b/src/script/common/c_internal.cpp index 90846676..4263dec9 100644 --- a/src/script/common/c_internal.cpp +++ b/src/script/common/c_internal.cpp @@ -71,7 +71,7 @@ void script_error(lua_State *L) { const char *s = lua_tostring(L, -1); std::string str(s ? s : ""); - throw LuaError(NULL, str); + throw LuaError(str); } // Push the list of callbacks (a lua table). diff --git a/src/script/common/c_types.cpp b/src/script/common/c_types.cpp index 6ffad1cb..e832ff2a 100644 --- a/src/script/common/c_types.cpp +++ b/src/script/common/c_types.cpp @@ -23,13 +23,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_internal.h" #include "itemdef.h" -LuaError::LuaError(lua_State *L, const std::string &s) : - ServerError(s) -{ - if (L) { - m_s += '\n' + script_get_backtrace(L); - } -} struct EnumString es_ItemType[] = { diff --git a/src/script/common/c_types.h b/src/script/common/c_types.h index 709d4f34..70647073 100644 --- a/src/script/common/c_types.h +++ b/src/script/common/c_types.h @@ -55,14 +55,7 @@ public: class LuaError : public ServerError { public: - LuaError(lua_State *L, const std::string &s); - - virtual ~LuaError() throw() - {} - virtual const char * what() const throw() - { - return m_s.c_str(); - } + LuaError(const std::string &s) : ServerError(s) {} }; diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index 89827174..932cc501 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -43,7 +43,7 @@ class ModNameStorer private: lua_State *L; public: - ModNameStorer(lua_State *L_, const std::string modname): + ModNameStorer(lua_State *L_, const std::string &modname): L(L_) { // Store current modname in registry @@ -151,13 +151,14 @@ void ScriptApiBase::realityCheck() if(top >= 30){ dstream<<"Stack is over 30:"< &result) @@ -108,7 +108,7 @@ void ScriptApiServer::createAuth(const std::string &playername, lua_getfield(L, -1, "create_auth"); lua_remove(L, -2); // Remove auth handler if(lua_type(L, -1) != LUA_TFUNCTION) - throw LuaError(NULL, "Authentication handler missing create_auth"); + throw LuaError("Authentication handler missing create_auth"); lua_pushstring(L, playername.c_str()); lua_pushstring(L, password.c_str()); if(lua_pcall(L, 2, 0, errorhandler)) @@ -128,7 +128,7 @@ bool ScriptApiServer::setPassword(const std::string &playername, lua_getfield(L, -1, "set_password"); lua_remove(L, -2); // Remove auth handler if(lua_type(L, -1) != LUA_TFUNCTION) - throw LuaError(NULL, "Authentication handler missing set_password"); + throw LuaError("Authentication handler missing set_password"); lua_pushstring(L, playername.c_str()); lua_pushstring(L, password.c_str()); if(lua_pcall(L, 2, 1, errorhandler)) diff --git a/src/script/lua_api/l_async_events.cpp b/src/script/lua_api/l_async_events.cpp index 2425f22b..f5c27a23 100644 --- a/src/script/lua_api/l_async_events.cpp +++ b/src/script/lua_api/l_async_events.cpp @@ -262,6 +262,9 @@ void* AsyncWorkerThread::worker_thread_main() { snprintf(number,sizeof(number),"%d",m_threadnum); log_register_thread(std::string("AsyncWorkerThread_") + number); + porting::setThreadName( + std::string(std::string("AsyncWorkTh_") + number).c_str()); + /** prepare job lua environment **/ lua_newtable(m_LuaStack); lua_setglobal(m_LuaStack, "engine"); diff --git a/src/script/lua_api/l_base.h b/src/script/lua_api/l_base.h index 694ce5a1..debbcd09 100644 --- a/src/script/lua_api/l_base.h +++ b/src/script/lua_api/l_base.h @@ -48,7 +48,7 @@ protected: ScriptApiBase *scriptIface = getScriptApiBase(L); T *scriptIfaceDowncast = dynamic_cast(scriptIface); if (!scriptIfaceDowncast) { - throw LuaError(NULL, "Requested unavailable ScriptApi - core engine bug!"); + throw LuaError("Requested unavailable ScriptApi - core engine bug!"); } return scriptIfaceDowncast; } diff --git a/src/script/lua_api/l_craft.cpp b/src/script/lua_api/l_craft.cpp index aaca84c5..8f8efbfb 100644 --- a/src/script/lua_api/l_craft.cpp +++ b/src/script/lua_api/l_craft.cpp @@ -150,16 +150,16 @@ int ModApiCraft::l_register_craft(lua_State *L) if(type == "shaped"){ std::string output = getstringfield_default(L, table, "output", ""); if(output == "") - throw LuaError(NULL, "Crafting definition is missing an output"); + throw LuaError("Crafting definition is missing an output"); int width = 0; std::vector recipe; lua_getfield(L, table, "recipe"); if(lua_isnil(L, -1)) - throw LuaError(NULL, "Crafting definition is missing a recipe" + throw LuaError("Crafting definition is missing a recipe" " (output=\"" + output + "\")"); if(!readCraftRecipeShaped(L, -1, width, recipe)) - throw LuaError(NULL, "Invalid crafting recipe" + throw LuaError("Invalid crafting recipe" " (output=\"" + output + "\")"); CraftReplacements replacements; @@ -167,7 +167,7 @@ int ModApiCraft::l_register_craft(lua_State *L) if(!lua_isnil(L, -1)) { if(!readCraftReplacements(L, -1, replacements)) - throw LuaError(NULL, "Invalid replacements" + throw LuaError("Invalid replacements" " (output=\"" + output + "\")"); } @@ -181,17 +181,17 @@ int ModApiCraft::l_register_craft(lua_State *L) else if(type == "shapeless"){ std::string output = getstringfield_default(L, table, "output", ""); if(output == "") - throw LuaError(NULL, "Crafting definition (shapeless)" + throw LuaError("Crafting definition (shapeless)" " is missing an output"); std::vector recipe; lua_getfield(L, table, "recipe"); if(lua_isnil(L, -1)) - throw LuaError(NULL, "Crafting definition (shapeless)" + throw LuaError("Crafting definition (shapeless)" " is missing a recipe" " (output=\"" + output + "\")"); if(!readCraftRecipeShapeless(L, -1, recipe)) - throw LuaError(NULL, "Invalid crafting recipe" + throw LuaError("Invalid crafting recipe" " (output=\"" + output + "\")"); CraftReplacements replacements; @@ -199,7 +199,7 @@ int ModApiCraft::l_register_craft(lua_State *L) if(!lua_isnil(L, -1)) { if(!readCraftReplacements(L, -1, replacements)) - throw LuaError(NULL, "Invalid replacements" + throw LuaError("Invalid replacements" " (output=\"" + output + "\")"); } @@ -224,12 +224,12 @@ int ModApiCraft::l_register_craft(lua_State *L) else if(type == "cooking"){ std::string output = getstringfield_default(L, table, "output", ""); if(output == "") - throw LuaError(NULL, "Crafting definition (cooking)" + throw LuaError("Crafting definition (cooking)" " is missing an output"); std::string recipe = getstringfield_default(L, table, "recipe", ""); if(recipe == "") - throw LuaError(NULL, "Crafting definition (cooking)" + throw LuaError("Crafting definition (cooking)" " is missing a recipe" " (output=\"" + output + "\")"); @@ -240,7 +240,7 @@ int ModApiCraft::l_register_craft(lua_State *L) if(!lua_isnil(L, -1)) { if(!readCraftReplacements(L, -1, replacements)) - throw LuaError(NULL, "Invalid replacements" + throw LuaError("Invalid replacements" " (cooking output=\"" + output + "\")"); } @@ -254,7 +254,7 @@ int ModApiCraft::l_register_craft(lua_State *L) else if(type == "fuel"){ std::string recipe = getstringfield_default(L, table, "recipe", ""); if(recipe == "") - throw LuaError(NULL, "Crafting definition (fuel)" + throw LuaError("Crafting definition (fuel)" " is missing a recipe"); float burntime = getfloatfield_default(L, table, "burntime", 1.0); @@ -264,7 +264,7 @@ int ModApiCraft::l_register_craft(lua_State *L) if(!lua_isnil(L, -1)) { if(!readCraftReplacements(L, -1, replacements)) - throw LuaError(NULL, "Invalid replacements" + throw LuaError("Invalid replacements" " (fuel recipe=\"" + recipe + "\")"); } @@ -274,7 +274,7 @@ int ModApiCraft::l_register_craft(lua_State *L) } else { - throw LuaError(NULL, "Unknown crafting definition type: \"" + type + "\""); + throw LuaError("Unknown crafting definition type: \"" + type + "\""); } lua_pop(L, 1); diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 6447866c..37fa167e 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -765,7 +765,6 @@ int ModApiEnvMod::l_spawn_tree(lua_State *L) return 1; } - // minetest.transforming_liquid_add(pos) int ModApiEnvMod::l_transforming_liquid_add(lua_State *L) { @@ -776,28 +775,6 @@ int ModApiEnvMod::l_transforming_liquid_add(lua_State *L) return 1; } -// minetest.get_heat(pos) -// pos = {x=num, y=num, z=num} -int ModApiEnvMod::l_get_heat(lua_State *L) -{ - GET_ENV_PTR; - - v3s16 pos = read_v3s16(L, 1); - lua_pushnumber(L, env->getServerMap().updateBlockHeat(env, pos)); - return 1; -} - -// minetest.get_humidity(pos) -// pos = {x=num, y=num, z=num} -int ModApiEnvMod::l_get_humidity(lua_State *L) -{ - GET_ENV_PTR; - - v3s16 pos = read_v3s16(L, 1); - lua_pushnumber(L, env->getServerMap().updateBlockHumidity(env, pos)); - return 1; -} - // minetest.forceload_block(blockpos) // blockpos = {x=num, y=num, z=num} int ModApiEnvMod::l_forceload_block(lua_State *L) @@ -855,8 +832,6 @@ void ModApiEnvMod::Initialize(lua_State *L, int top) API_FCT(find_path); API_FCT(line_of_sight); API_FCT(transforming_liquid_add); - API_FCT(get_heat); - API_FCT(get_humidity); API_FCT(forceload_block); API_FCT(forceload_free_block); } diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h index 7e1cabe3..8bf599b0 100644 --- a/src/script/lua_api/l_env.h +++ b/src/script/lua_api/l_env.h @@ -148,9 +148,6 @@ private: // minetest.transforming_liquid_add(pos) static int l_transforming_liquid_add(lua_State *L); - static int l_get_heat(lua_State *L); - static int l_get_humidity(lua_State *L); - // minetest.forceload_block(blockpos) // forceloads a block static int l_forceload_block(lua_State *L); diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp index 4b5c8979..094d0bb2 100644 --- a/src/script/lua_api/l_item.cpp +++ b/src/script/lua_api/l_item.cpp @@ -470,7 +470,7 @@ int ModApiItemMod::l_register_item_raw(lua_State *L) name = lua_tostring(L, -1); verbosestream<<"register_item_raw: "<set(f.name, f); if(id > MAX_REGISTERED_CONTENT){ - throw LuaError(NULL, "Number of registerable nodes (" + throw LuaError("Number of registerable nodes (" + itos(MAX_REGISTERED_CONTENT+1) + ") exceeded (" + name + ")"); } diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index 1a28c9ba..fbb70c38 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -387,11 +387,6 @@ int ModApiMainMenu::l_get_modstore_details(lua_State *L) /******************************************************************************/ int ModApiMainMenu::l_get_modstore_list(lua_State *L) { - std::string listtype = "local"; - - if (!lua_isnone(L,1)) { - listtype = luaL_checkstring(L,1); - } Json::Value mods; std::string url = ""; try{ @@ -990,6 +985,9 @@ int ModApiMainMenu::l_download_file(lua_State *L) lua_pushboolean(L,true); return 1; } + } else { + errorstream << "DOWNLOAD denied: " << absolute_destination + << " isn't a allowed path" << std::endl; } lua_pushboolean(L,false); return 1; diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index f357d3f4..9fbb46ee 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -189,9 +189,10 @@ int ModApiMapgen::l_set_mapgen_params(lua_State *L) return 0; EmergeManager *emerge = getServer(L)->getEmergeManager(); - ASSERT(emerge); + assert(emerge); std::string flagstr; + u32 flags = 0, flagmask = 0; lua_getfield(L, 1, "mgname"); if (lua_isstring(L, -1)) { @@ -216,13 +217,7 @@ int ModApiMapgen::l_set_mapgen_params(lua_State *L) "see lua_api.txt" << std::endl; } - lua_getfield(L, 1, "flags"); - if (lua_isstring(L, -1)) { - u32 flags, flagmask; - - flagstr = lua_tostring(L, -1); - flags = readFlagString(flagstr, flagdesc_mapgen, &flagmask); - + if (getflagsfield(L, 1, "flags", flagdesc_mapgen, &flags, &flagmask)) { emerge->params.flags &= ~flagmask; emerge->params.flags |= flags; } @@ -260,11 +255,13 @@ int ModApiMapgen::l_set_noiseparam_defaults(lua_State *L) // set_gen_notify(string) int ModApiMapgen::l_set_gen_notify(lua_State *L) { - if (lua_isstring(L, 1)) { + u32 flags = 0, flagmask = 0; + + if (read_flags(L, 1, flagdesc_gennotify, &flags, &flagmask)) { EmergeManager *emerge = getServer(L)->getEmergeManager(); - emerge->gennotify = readFlagString(lua_tostring(L, 1), - flagdesc_gennotify, NULL); + emerge->gennotify = flags; } + return 0; } @@ -327,8 +324,8 @@ int ModApiMapgen::l_register_decoration(lua_State *L) BiomeDefManager *bdef = emerge->biomedef; enum DecorationType decotype = (DecorationType)getenumfield(L, index, - "deco_type", es_DecorationType, -1); - if (decotype == -1) { + "deco_type", es_DecorationType, 0); + if (decotype == 0) { errorstream << "register_decoration: unrecognized " "decoration placement type"; return 0; @@ -407,8 +404,11 @@ int ModApiMapgen::l_register_decoration(lua_State *L) break; } case DECO_SCHEMATIC: { DecoSchematic *dschem = (DecoSchematic *)deco; - dschem->flags = getflagsfield(L, index, "flags", - flagdesc_deco_schematic, NULL); + + dschem->flags = 0; + getflagsfield(L, index, "flags", flagdesc_deco_schematic, + &dschem->flags, NULL); + dschem->rotation = (Rotation)getenumfield(L, index, "rotation", es_Rotation, ROTATE_0); @@ -482,8 +482,10 @@ int ModApiMapgen::l_register_ore(lua_State *L) ore->clust_size = getintfield_default(L, index, "clust_size", 0); ore->height_min = getintfield_default(L, index, "height_min", 0); ore->height_max = getintfield_default(L, index, "height_max", 0); - ore->flags = getflagsfield(L, index, "flags", flagdesc_ore, NULL); ore->nthresh = getfloatfield_default(L, index, "noise_threshhold", 0.); + ore->flags = 0; + getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL); + lua_getfield(L, index, "wherein"); if (lua_istable(L, -1)) { int i = lua_gettop(L); diff --git a/src/script/lua_api/l_noise.cpp b/src/script/lua_api/l_noise.cpp index 4ca9992a..263ecfd6 100644 --- a/src/script/lua_api/l_noise.cpp +++ b/src/script/lua_api/l_noise.cpp @@ -330,10 +330,10 @@ int LuaPseudoRandom::l_next(lua_State *L) max = luaL_checkinteger(L, 3); if(max < min){ errorstream<<"PseudoRandom.next(): max="< 32767/5) - throw LuaError(NULL, "PseudoRandom.next() max-min is not 32767" + throw LuaError("PseudoRandom.next() max-min is not 32767" " and is > 32768/5. This is disallowed due to" " the bad random distribution the" " implementation would otherwise make."); diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 059496c3..5e3ddd23 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -406,6 +406,61 @@ int ObjectRef::l_set_animation(lua_State *L) return 0; } +// set_local_animation(self, {stand/idle}, {walk}, {dig}, {walk+dig}, frame_speed) +int ObjectRef::l_set_local_animation(lua_State *L) +{ + //NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + Player *player = getplayer(ref); + if (player == NULL) + return 0; + // Do it + v2s32 frames[4]; + for (int i=0;i<4;i++) { + if(!lua_isnil(L, 2+1)) + frames[i] = read_v2s32(L, 2+i); + } + float frame_speed = 30; + if(!lua_isnil(L, 6)) + frame_speed = lua_tonumber(L, 6); + + if (!getServer(L)->setLocalPlayerAnimations(player, frames, frame_speed)) + return 0; + + lua_pushboolean(L, true); + return 0; +} + +// set_eye_offset(self, v3f first pv, v3f third pv) +int ObjectRef::l_set_eye_offset(lua_State *L) +{ + //NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + Player *player = getplayer(ref); + if (player == NULL) + return 0; + // Do it + v3f offset_first = v3f(0, 0, 0); + v3f offset_third = v3f(0, 0, 0); + + if(!lua_isnil(L, 2)) + offset_first = read_v3f(L, 2); + if(!lua_isnil(L, 3)) + offset_third = read_v3f(L, 3); + + // Prevent abuse of offset values (keep player always visible) + offset_third.X = rangelim(offset_third.X,-10,10); + offset_third.Z = rangelim(offset_third.Z,-5,5); + /* TODO: if possible: improve the camera colision detetion to allow Y <= -1.5) */ + offset_third.Y = rangelim(offset_third.Y,-10,15); //1.5*BS + + if (!getServer(L)->setPlayerEyeOffset(player, offset_first, offset_third)) + return 0; + + lua_pushboolean(L, true); + return 0; +} + // set_bone_position(self, std::string bone, v3f position, v3f rotation) int ObjectRef::l_set_bone_position(lua_State *L) { @@ -1120,7 +1175,7 @@ int ObjectRef::l_set_sky(lua_State *L) } if (type == "skybox" && params.size() != 6) - throw LuaError(L, "skybox expects 6 textures"); + throw LuaError("skybox expects 6 textures"); if (!getServer(L)->setSky(player, bgcolor, type, params)) return 0; @@ -1270,5 +1325,7 @@ const luaL_reg ObjectRef::methods[] = { luamethod(ObjectRef, hud_set_hotbar_selected_image), luamethod(ObjectRef, set_sky), luamethod(ObjectRef, override_day_night_ratio), + luamethod(ObjectRef, set_local_animation), + luamethod(ObjectRef, set_eye_offset), {0,0} }; diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h index 2c53d1a6..f6070585 100644 --- a/src/script/lua_api/l_object.h +++ b/src/script/lua_api/l_object.h @@ -231,6 +231,12 @@ private: // override_day_night_ratio(self, type, list) static int l_override_day_night_ratio(lua_State *L); + // set_local_animation(self, {stand/idle}, {walk}, {dig}, {walk+dig}, frame_speed) + static int l_set_local_animation(lua_State *L); + + // set_eye_offset(self, v3f first pv, v3f third pv) + static int l_set_eye_offset(lua_State *L); + public: ObjectRef(ServerActiveObject *object); diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index bbf5a707..531d044e 100644 --- a/src/script/lua_api/l_server.cpp +++ b/src/script/lua_api/l_server.cpp @@ -99,7 +99,7 @@ int ModApiServer::l_get_player_ip(lua_State *L) } try { - Address addr = getServer(L)->getPeerAddress(getEnv(L)->getPlayer(name)->peer_id); + Address addr = getServer(L)->getPeerAddress(player->peer_id); std::string ip_str = addr.serializeString(); lua_pushstring(L, ip_str.c_str()); return 1; @@ -112,6 +112,135 @@ int ModApiServer::l_get_player_ip(lua_State *L) } } +// get_player_information() +int ModApiServer::l_get_player_information(lua_State *L) +{ + + NO_MAP_LOCK_REQUIRED; + const char * name = luaL_checkstring(L, 1); + Player *player = getEnv(L)->getPlayer(name); + if(player == NULL) + { + lua_pushnil(L); // no such player + return 1; + } + + Address addr; + try + { + addr = getServer(L)->getPeerAddress(player->peer_id); + } + catch(con::PeerNotFoundException) // unlikely + { + dstream << __FUNCTION_NAME << ": peer was not found" << std::endl; + lua_pushnil(L); // error + return 1; + } + + float min_rtt,max_rtt,avg_rtt,min_jitter,max_jitter,avg_jitter; + ClientState state; + u32 uptime; + u16 prot_vers; + u8 ser_vers,major,minor,patch; + std::string vers_string; + +#define ERET(code) \ + if (!(code)) { \ + dstream << __FUNCTION_NAME << ": peer was not found" << std::endl; \ + lua_pushnil(L); /* error */ \ + return 1; \ + } + + ERET(getServer(L)->getClientConInfo(player->peer_id,con::MIN_RTT,&min_rtt)) + ERET(getServer(L)->getClientConInfo(player->peer_id,con::MAX_RTT,&max_rtt)) + ERET(getServer(L)->getClientConInfo(player->peer_id,con::AVG_RTT,&avg_rtt)) + ERET(getServer(L)->getClientConInfo(player->peer_id,con::MIN_JITTER,&min_jitter)) + ERET(getServer(L)->getClientConInfo(player->peer_id,con::MAX_JITTER,&max_jitter)) + ERET(getServer(L)->getClientConInfo(player->peer_id,con::AVG_JITTER,&avg_jitter)) + + ERET(getServer(L)->getClientInfo(player->peer_id, + &state, &uptime, &ser_vers, &prot_vers, + &major, &minor, &patch, &vers_string)) + + lua_newtable(L); + int table = lua_gettop(L); + + lua_pushstring(L,"address"); + lua_pushstring(L, addr.serializeString().c_str()); + lua_settable(L, table); + + lua_pushstring(L,"ip_version"); + if (addr.getFamily() == AF_INET) { + lua_pushnumber(L, 4); + } else if (addr.getFamily() == AF_INET6) { + lua_pushnumber(L, 6); + } else { + lua_pushnumber(L, 0); + } + lua_settable(L, table); + + lua_pushstring(L,"min_rtt"); + lua_pushnumber(L, min_rtt); + lua_settable(L, table); + + lua_pushstring(L,"max_rtt"); + lua_pushnumber(L, max_rtt); + lua_settable(L, table); + + lua_pushstring(L,"avg_rtt"); + lua_pushnumber(L, avg_rtt); + lua_settable(L, table); + + lua_pushstring(L,"min_jitter"); + lua_pushnumber(L, min_jitter); + lua_settable(L, table); + + lua_pushstring(L,"max_jitter"); + lua_pushnumber(L, max_jitter); + lua_settable(L, table); + + lua_pushstring(L,"avg_jitter"); + lua_pushnumber(L, avg_jitter); + lua_settable(L, table); + + lua_pushstring(L,"connection_uptime"); + lua_pushnumber(L, uptime); + lua_settable(L, table); + +#ifndef NDEBUG + lua_pushstring(L,"serialization_version"); + lua_pushnumber(L, ser_vers); + lua_settable(L, table); + + lua_pushstring(L,"protocol_version"); + lua_pushnumber(L, prot_vers); + lua_settable(L, table); + + lua_pushstring(L,"major"); + lua_pushnumber(L, major); + lua_settable(L, table); + + lua_pushstring(L,"minor"); + lua_pushnumber(L, minor); + lua_settable(L, table); + + lua_pushstring(L,"patch"); + lua_pushnumber(L, patch); + lua_settable(L, table); + + lua_pushstring(L,"version_string"); + lua_pushstring(L, vers_string.c_str()); + lua_settable(L, table); + + lua_pushstring(L,"state"); + lua_pushstring(L,ClientInterface::state2Name(state).c_str()); + lua_settable(L, table); +#endif + +#undef ERET + return 1; +} + // get_ban_list() int ModApiServer::l_get_ban_list(lua_State *L) { @@ -343,6 +472,7 @@ void ModApiServer::Initialize(lua_State *L, int top) API_FCT(sound_play); API_FCT(sound_stop); + API_FCT(get_player_information); API_FCT(get_player_privs); API_FCT(get_player_ip); API_FCT(get_ban_list); diff --git a/src/script/lua_api/l_server.h b/src/script/lua_api/l_server.h index 0d0aa45c..4101f285 100644 --- a/src/script/lua_api/l_server.h +++ b/src/script/lua_api/l_server.h @@ -67,6 +67,9 @@ private: // get_player_ip() static int l_get_player_ip(lua_State *L); + // get_player_information() + static int l_get_player_information(lua_State *L); + // get_ban_list() static int l_get_ban_list(lua_State *L); diff --git a/src/server.cpp b/src/server.cpp index 7eb78f3e..ebde0d9e 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -99,6 +99,8 @@ void * ServerThread::Thread() ThreadStarted(); + porting::setThreadName("ServerThread"); + while(!StopRequested()) { try{ @@ -164,7 +166,8 @@ v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const Server::Server( const std::string &path_world, const SubgameSpec &gamespec, - bool simple_singleplayer_mode + bool simple_singleplayer_mode, + bool ipv6 ): m_path_world(path_world), m_gamespec(gamespec), @@ -174,7 +177,7 @@ Server::Server( m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, - g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"), + ipv6, this), m_banmanager(NULL), m_rollback(NULL), @@ -1191,6 +1194,111 @@ void Server::Receive() m_env->removePlayer(peer_id);*/ } + catch(ClientStateError &e) + { + errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl; + DenyAccess(peer_id, L"Your client sent something server didn't expect." + L"Try reconnecting or updating your client"); + } +} + +PlayerSAO* Server::StageTwoClientInit(u16 peer_id) +{ + std::string playername = ""; + PlayerSAO *playersao = NULL; + m_clients.Lock(); + RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,InitDone); + if (client != NULL) { + playername = client->getName(); + playersao = emergePlayer(playername.c_str(), peer_id); + } + m_clients.Unlock(); + + RemotePlayer *player = + static_cast(m_env->getPlayer(playername.c_str())); + + // If failed, cancel + if((playersao == NULL) || (player == NULL)) + { + if(player && player->peer_id != 0){ + errorstream<<"Server: "<getBool("enable_damage")) + SendPlayerHP(peer_id); + + // Send Breath + SendPlayerBreath(peer_id); + + // Show death screen if necessary + if(player->hp == 0) + SendDeathscreen(peer_id, false, v3f(0,0,0)); + + // Note things in chat if not in simple singleplayer mode + if(!m_simple_singleplayer_mode) + { + // Send information about server to player in chat + SendChatMessage(peer_id, getStatusString()); + + // Send information about joining in chat + { + std::wstring name = L"unknown"; + Player *player = m_env->getPlayer(peer_id); + if(player != NULL) + name = narrow_to_wide(player->getName()); + + std::wstring message; + message += L"*** "; + message += name; + message += L" joined the game."; + SendChatMessage(PEER_ID_INEXISTENT,message); + } + } + + actionstream<getName() <<" joins game. " << std::endl; + /* + Print out action + */ + { + std::vector names = m_clients.getPlayerNames(); + + actionstream<getName() <<" joins game. List of players: "; + + for (std::vector::iterator i = names.begin(); + i != names.end(); i++) + { + actionstream << *i << " "; + } + + actionstream<getFloat("time_speed"); SendTimeOfDay(peer_id, time, time_speed); + ///// begin compatibility code + if (protocol_version <= 22) { + m_clients.event(peer_id, SetClientReady); + m_script->on_joinplayer(playersao); + } + ///// end compatibility code + // Warnings about protocol version can be issued here if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION) { @@ -1583,6 +1713,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } u8 peer_ser_ver = getClient(peer_id,InitDone)->serialization_version; + u16 peer_proto_ver = getClient(peer_id,InitDone)->net_proto_version; if(peer_ser_ver == SER_FMT_VER_INVALID) { @@ -1615,105 +1746,34 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) return; } else if(command == TOSERVER_RECEIVED_MEDIA) { - std::string playername = ""; - PlayerSAO *playersao = NULL; - m_clients.Lock(); - RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,DefinitionsSent); - if (client != NULL) { - playername = client->getName(); - playersao = emergePlayer(playername.c_str(), peer_id); - } - m_clients.Unlock(); + return; + } + else if(command == TOSERVER_CLIENT_READY) { + // clients <= protocol version 22 did not send ready message, + // they're already initialized + assert(peer_proto_ver > 22); - RemotePlayer *player = - static_cast(m_env->getPlayer(playername.c_str())); + PlayerSAO* playersao = StageTwoClientInit(peer_id); - // If failed, cancel - if((playersao == NULL) || (player == NULL)) - { - if(player && player->peer_id != 0){ - errorstream<<"Server: "<getBool("enable_damage")) - SendPlayerHP(peer_id); - - // Send Breath - SendPlayerBreath(peer_id); - - // Show death screen if necessary - if(player->hp == 0) - SendDeathscreen(peer_id, false, v3f(0,0,0)); - - // Note things in chat if not in simple singleplayer mode - if(!m_simple_singleplayer_mode) - { - // Send information about server to player in chat - SendChatMessage(peer_id, getStatusString()); - - // Send information about joining in chat - { - std::wstring name = L"unknown"; - Player *player = m_env->getPlayer(peer_id); - if(player != NULL) - name = narrow_to_wide(player->getName()); - - std::wstring message; - message += L"*** "; - message += name; - message += L" joined the game."; - SendChatMessage(PEER_ID_INEXISTENT,message); - } - } - - actionstream<getName()<<" ["< names = m_clients.getPlayerNames(); - - actionstream<getName()<<" ["<::iterator i = names.begin(); - i != names.end(); i++) - { - actionstream << *i << " "; - } - - actionstream<on_joinplayer(playersao); - return; + } else if(command == TOSERVER_GOTBLOCKS) { @@ -2809,6 +2869,46 @@ void Server::deletingPeer(con::Peer *peer, bool timeout) m_peer_change_queue.push_back(c); } +bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval) +{ + *retval = m_con.getPeerStat(peer_id,type); + if (*retval == -1) return false; + return true; +} + +bool Server::getClientInfo( + u16 peer_id, + ClientState* state, + u32* uptime, + u8* ser_vers, + u16* prot_vers, + u8* major, + u8* minor, + u8* patch, + std::string* vers_string + ) +{ + *state = m_clients.getClientState(peer_id); + m_clients.Lock(); + RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,Invalid); + + if (client == NULL) + return false; + + *uptime = client->uptime(); + *ser_vers = client->serialization_version; + *prot_vers = client->net_proto_version; + + *major = client->getMajor(); + *minor = client->getMinor(); + *patch = client->getPatch(); + *vers_string = client->getPatch(); + + m_clients.Unlock(); + + return true; +} + void Server::handlePeerChanges() { while(m_peer_change_queue.size() > 0) @@ -3046,8 +3146,8 @@ void Server::SendChatMessage(u16 peer_id, const std::wstring &message) } } -void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, - const std::string formname) +void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec, + const std::string &formname) { DSTACK(__FUNCTION_NAME); @@ -3384,6 +3484,38 @@ void Server::SendMovePlayer(u16 peer_id) m_clients.send(peer_id, 0, data, true); } +void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed) +{ + std::ostringstream os(std::ios_base::binary); + + writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS); + writeV2S32(os, animation_frames[0]); + writeV2S32(os, animation_frames[1]); + writeV2S32(os, animation_frames[2]); + writeV2S32(os, animation_frames[3]); + writeF1000(os, animation_speed); + + // Make data buffer + std::string s = os.str(); + SharedBuffer data((u8 *)s.c_str(), s.size()); + // Send as reliable + m_clients.send(peer_id, 0, data, true); +} + +void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third) +{ + std::ostringstream os(std::ios_base::binary); + + writeU16(os, TOCLIENT_EYE_OFFSET); + writeV3F1000(os, first); + writeV3F1000(os, third); + + // Make data buffer + std::string s = os.str(); + SharedBuffer data((u8 *)s.c_str(), s.size()); + // Send as reliable + m_clients.send(peer_id, 0, data, true); +} void Server::SendPlayerPrivileges(u16 peer_id) { Player *player = m_env->getPlayer(peer_id); @@ -3871,8 +4003,8 @@ struct SendableMediaAnnouncement std::string name; std::string sha1_digest; - SendableMediaAnnouncement(const std::string name_="", - const std::string sha1_digest_=""): + SendableMediaAnnouncement(const std::string &name_="", + const std::string &sha1_digest_=""): name(name_), sha1_digest(sha1_digest_) {} @@ -3933,8 +4065,8 @@ struct SendableMedia std::string path; std::string data; - SendableMedia(const std::string &name_="", const std::string path_="", - const std::string &data_=""): + SendableMedia(const std::string &name_="", const std::string &path_="", + const std::string &data_=""): name(name_), path(path_), data(data_) @@ -4385,7 +4517,7 @@ std::string Server::getBanDescription(const std::string &ip_or_name) return m_banmanager->getBanDescription(ip_or_name); } -void Server::notifyPlayer(const char *name, const std::wstring msg) +void Server::notifyPlayer(const char *name, const std::wstring &msg) { Player *player = m_env->getPlayer(name); if(!player) @@ -4478,6 +4610,24 @@ void Server::hudSetHotbarSelectedImage(Player *player, std::string name) { SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name); } +bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed) +{ + if (!player) + return false; + + SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed); + return true; +} + +bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third) +{ + if (!player) + return false; + + SendEyeOffset(player->peer_id, first, third); + return true; +} + bool Server::setSky(Player *player, const video::SColor &bgcolor, const std::string &type, const std::vector ¶ms) { @@ -4498,7 +4648,7 @@ bool Server::overrideDayNightRatio(Player *player, bool do_override, return true; } -void Server::notifyPlayers(const std::wstring msg) +void Server::notifyPlayers(const std::wstring &msg) { SendChatMessage(PEER_ID_INEXISTENT,msg); } diff --git a/src/server.h b/src/server.h index 7ad9bcaf..4cfc879c 100644 --- a/src/server.h +++ b/src/server.h @@ -122,8 +122,8 @@ struct MediaInfo std::string path; std::string sha1_digest; - MediaInfo(const std::string path_="", - const std::string sha1_digest_=""): + MediaInfo(const std::string &path_="", + const std::string &sha1_digest_=""): path(path_), sha1_digest(sha1_digest_) { @@ -174,7 +174,8 @@ public: Server( const std::string &path_world, const SubgameSpec &gamespec, - bool simple_singleplayer_mode + bool simple_singleplayer_mode, + bool ipv6 ); ~Server(); void start(Address bind_addr); @@ -185,6 +186,7 @@ public: // This is run by ServerThread and does the actual processing void AsyncRunStep(bool initial_step=false); void Receive(); + PlayerSAO* StageTwoClientInit(u16 peer_id); void ProcessData(u8 *data, u32 datasize, u16 peer_id); // Environment must be locked when called @@ -229,8 +231,8 @@ public: void unsetIpBanned(const std::string &ip_or_name); std::string getBanDescription(const std::string &ip_or_name); - void notifyPlayer(const char *name, const std::wstring msg); - void notifyPlayers(const std::wstring msg); + void notifyPlayer(const char *name, const std::wstring &msg); + void notifyPlayers(const std::wstring &msg); void spawnParticle(const char *playername, v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, @@ -320,6 +322,9 @@ public: inline Address getPeerAddress(u16 peer_id) { return m_con.GetPeerAddress(peer_id); } + bool setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed); + bool setPlayerEyeOffset(Player *player, v3f first, v3f third); + bool setSky(Player *player, const video::SColor &bgcolor, const std::string &type, const std::vector ¶ms); @@ -331,6 +336,10 @@ public: void deletingPeer(con::Peer *peer, bool timeout); void DenyAccess(u16 peer_id, const std::wstring &reason); + bool getClientConInfo(u16 peer_id, con::rtt_stat_type type,float* retval); + bool getClientInfo(u16 peer_id,ClientState* state, u32* uptime, + u8* ser_vers, u16* prot_vers, u8* major, u8* minor, u8* patch, + std::string* vers_string); private: @@ -355,9 +364,11 @@ private: void SendPlayerHP(u16 peer_id); void SendPlayerBreath(u16 peer_id); void SendMovePlayer(u16 peer_id); + void SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed); + void SendEyeOffset(u16 peer_id, v3f first, v3f third); void SendPlayerPrivileges(u16 peer_id); void SendPlayerInventoryFormspec(u16 peer_id); - void SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname); + void SendShowFormspecMessage(u16 peer_id, const std::string &formspec, const std::string &formname); void SendHUDAdd(u16 peer_id, u32 id, HudElement *form); void SendHUDRemove(u16 peer_id, u32 id); void SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value); diff --git a/src/serverlist.cpp b/src/serverlist.cpp index 64511b5b..10ec5771 100644 --- a/src/serverlist.cpp +++ b/src/serverlist.cpp @@ -218,7 +218,6 @@ void sendAnnounce(std::string action, const std::vector & clients_n server["dedicated"] = g_settings->get("server_dedicated"); server["privs"] = g_settings->get("default_privs"); server["rollback"] = g_settings->getBool("enable_rollback_recording"); - server["liquid_finite"] = g_settings->getBool("liquid_finite"); server["mapgen"] = g_settings->get("mg_name"); server["can_see_far_names"] = g_settings->getBool("unlimited_player_transfer_distance"); server["mods"] = Json::Value(Json::arrayValue); diff --git a/src/shader.cpp b/src/shader.cpp index d29c9d3a..4013add6 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -210,8 +210,7 @@ public: class MainShaderConstantSetter : public IShaderConstantSetter { public: - MainShaderConstantSetter(IrrlichtDevice *device): - m_device(device) + MainShaderConstantSetter(IrrlichtDevice *device) {} ~MainShaderConstantSetter() {} @@ -240,16 +239,21 @@ public: services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4); // set transposed world matrix - core::matrix4 world = driver->getTransform(video::ETS_WORLD); - world = world.getTransposed(); + core::matrix4 transWorld = driver->getTransform(video::ETS_WORLD); + transWorld = transWorld.getTransposed(); if(is_highlevel) - services->setVertexShaderConstant("mTransWorld", world.pointer(), 16); + services->setVertexShaderConstant("mTransWorld", transWorld.pointer(), 16); + else + services->setVertexShaderConstant(transWorld.pointer(), 8, 4); + + // set world matrix + core::matrix4 world = driver->getTransform(video::ETS_WORLD); + if(is_highlevel) + services->setVertexShaderConstant("mWorld", world.pointer(), 16); else services->setVertexShaderConstant(world.pointer(), 8, 4); - } -private: - IrrlichtDevice *m_device; + } }; /* @@ -673,7 +677,33 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device, // Create shaders header std::string shaders_header = "#version 120\n"; - + + if (g_settings->getBool("generate_normalmaps")){ + shaders_header += "#define GENERATE_NORMALMAPS\n"; + shaders_header += "#define NORMALMAPS_STRENGTH "; + shaders_header += ftos(g_settings->getFloat("normalmaps_strength")); + shaders_header += "\n"; + float sample_step; + int smooth = (int)g_settings->getFloat("normalmaps_smooth"); + switch (smooth){ + case 0: + sample_step = 0.0078125; // 1.0 / 128.0 + break; + case 1: + sample_step = 0.00390625; // 1.0 / 256.0 + break; + case 2: + sample_step = 0.001953125; // 1.0 / 512.0 + break; + default: + sample_step = 0.0078125; + break; + } + shaders_header += "#define SAMPLE_STEP "; + shaders_header += ftos(sample_step); + shaders_header += "\n"; + } + if (g_settings->getBool("enable_bumpmapping")) shaders_header += "#define ENABLE_BUMPMAPPING\n"; @@ -685,7 +715,7 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device, shaders_header += "#define PARALLAX_OCCLUSION_BIAS "; shaders_header += ftos(g_settings->getFloat("parallax_occlusion_bias")); shaders_header += "\n"; - } + } if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion")) shaders_header += "#define USE_NORMALMAPS\n"; diff --git a/src/sky.h b/src/sky.h index 06a99310..c906bd32 100644 --- a/src/sky.h +++ b/src/sky.h @@ -125,7 +125,6 @@ private: video::SColor m_skycolor; video::SColorf m_cloudcolor_f; v3f m_stars[SKY_STAR_COUNT]; - u16 m_star_indices[SKY_STAR_COUNT*4]; video::S3DVertex m_star_vertices[SKY_STAR_COUNT*4]; LocalPlayer* m_player; }; diff --git a/src/socket.cpp b/src/socket.cpp index 00856fb0..508d61a3 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -143,6 +143,15 @@ bool Address::operator!=(Address &address) void Address::Resolve(const char *name) { + if (!name || name[0] == 0) { + if (m_addr_family == AF_INET) { + setAddress((u32) 0); + } else if (m_addr_family == AF_INET6) { + setAddress((IPv6AddressBytes*) 0); + } + return; + } + struct addrinfo *resolved, hints; memset(&hints, 0, sizeof(hints)); @@ -193,7 +202,8 @@ std::string Address::serializeString() const #ifdef _WIN32 if(m_addr_family == AF_INET) { - u8 a, b, c, d, addr; + u8 a, b, c, d; + u32 addr; addr = ntohl(m_address.ipv4.sin_addr.s_addr); a = (addr & 0xFF000000) >> 24; b = (addr & 0x00FF0000) >> 16; @@ -251,6 +261,18 @@ bool Address::isIPv6() const return m_addr_family == AF_INET6; } +bool Address::isZero() const +{ + if (m_addr_family == AF_INET) { + return m_address.ipv4.sin_addr.s_addr == 0; + } else if (m_addr_family == AF_INET6) { + static const char zero[16] = {0}; + return memcmp(m_address.ipv6.sin6_addr.s6_addr, + zero, 16) == 0; + } + return false; +} + void Address::setAddress(u32 address) { m_addr_family = AF_INET; diff --git a/src/socket.h b/src/socket.h index 7d35a32d..92e0cbb1 100644 --- a/src/socket.h +++ b/src/socket.h @@ -88,6 +88,7 @@ public: Address(const IPv6AddressBytes * ipv6_bytes, u16 port); bool operator==(Address &address); bool operator!=(Address &address); + // Resolve() may throw ResolveError (address is unchanged in this case) void Resolve(const char *name); struct sockaddr_in getAddress() const; unsigned short getPort() const; @@ -97,6 +98,7 @@ public: struct sockaddr_in6 getAddress6() const; int getFamily() const; bool isIPv6() const; + bool isZero() const; void setPort(unsigned short port); void print(std::ostream *s) const; std::string serializeString() const; diff --git a/src/sound_openal.cpp b/src/sound_openal.cpp index 0cfbc279..d27526b5 100644 --- a/src/sound_openal.cpp +++ b/src/sound_openal.cpp @@ -391,7 +391,7 @@ public: } /* If buffer does not exist, consult the fetcher */ - SoundBuffer* getFetchBuffer(const std::string name) + SoundBuffer* getFetchBuffer(const std::string &name) { SoundBuffer *buf = getBuffer(name); if(buf) diff --git a/src/util/serialize.cpp b/src/util/serialize.cpp index 12638500..8779ee63 100644 --- a/src/util/serialize.cpp +++ b/src/util/serialize.cpp @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "porting.h" #include "util/string.h" #include "../exceptions.h" +#include "../irrlichttypes.h" #include #include @@ -384,23 +385,23 @@ fail: } -bool serializeStructToString(std::string *outstr, +// Casts *buf to a signed or unsigned fixed-width integer of 'w' width +#define SIGN_CAST(w, buf) (is_unsigned ? *((u##w *) buf) : *((s##w *) buf)) + +bool serializeStructToString(std::string *out, std::string format, void *value) { - char sbuf[2048]; - int sbuflen = sizeof(sbuf) - 1; - sbuf[sbuflen] = 0; + std::ostringstream os; std::string str; - int pos = 0; - size_t fpos; char *f; + size_t strpos; - char *bufpos = (char *)value; + char *bufpos = (char *) value; char *fmtpos, *fmt = &format[0]; while ((f = strtok_r(fmt, ",", &fmtpos))) { fmt = NULL; bool is_unsigned = false; - int width = 0, nprinted = 0; + int width = 0; char valtype = *f; width = (int)strtol(f + 1, &f, 10); @@ -414,79 +415,67 @@ bool serializeStructToString(std::string *outstr, case 'i': if (width == 16) { bufpos += PADDING(bufpos, u16); - nprinted = snprintf(sbuf + pos, sbuflen, - is_unsigned ? "%u, " : "%d, ", - *((u16 *)bufpos)); + os << SIGN_CAST(16, bufpos); bufpos += sizeof(u16); } else if (width == 32) { bufpos += PADDING(bufpos, u32); - nprinted = snprintf(sbuf + pos, sbuflen, - is_unsigned ? "%u, " : "%d, ", - *((u32 *)bufpos)); + os << SIGN_CAST(32, bufpos); bufpos += sizeof(u32); } else if (width == 64) { bufpos += PADDING(bufpos, u64); - nprinted = snprintf(sbuf + pos, sbuflen, - is_unsigned ? "%llu, " : "%lli, ", - (unsigned long long)*((u64 *)bufpos)); + os << SIGN_CAST(64, bufpos); bufpos += sizeof(u64); } break; case 'b': bufpos += PADDING(bufpos, bool); - nprinted = snprintf(sbuf + pos, sbuflen, "%s, ", - *((bool *)bufpos) ? "true" : "false"); + os << std::boolalpha << *((bool *) bufpos); bufpos += sizeof(bool); break; case 'f': bufpos += PADDING(bufpos, float); - nprinted = snprintf(sbuf + pos, sbuflen, "%f, ", - *((float *)bufpos)); + os << *((float *) bufpos); bufpos += sizeof(float); break; case 's': bufpos += PADDING(bufpos, std::string *); - str = **((std::string **)bufpos); + str = **((std::string **) bufpos); - fpos = 0; - while ((fpos = str.find('"', fpos)) != std::string::npos) { - str.insert(fpos, 1, '\\'); - fpos += 2; + strpos = 0; + while ((strpos = str.find('"', strpos)) != std::string::npos) { + str.insert(strpos, 1, '\\'); + strpos += 2; } - nprinted = snprintf(sbuf + pos, sbuflen, "\"%s\", ", - (*((std::string **)bufpos))->c_str()); + os << str; bufpos += sizeof(std::string *); break; case 'v': if (width == 2) { bufpos += PADDING(bufpos, v2f); - v2f *v = (v2f *)bufpos; - nprinted = snprintf(sbuf + pos, sbuflen, - "(%f, %f), ", v->X, v->Y); + v2f *v = (v2f *) bufpos; + os << '(' << v->X << ", " << v->Y << ')'; bufpos += sizeof(v2f); } else { bufpos += PADDING(bufpos, v3f); - v3f *v = (v3f *)bufpos; - nprinted = snprintf(sbuf + pos, sbuflen, - "(%f, %f, %f), ", v->X, v->Y, v->Z); + v3f *v = (v3f *) bufpos; + os << '(' << v->X << ", " << v->Y << ", " << v->Z << ')'; bufpos += sizeof(v3f); } break; default: return false; } - if (nprinted < 0) //error, buffer too small - return false; - pos += nprinted; - sbuflen -= nprinted; + os << ", "; } + *out = os.str(); - // this is to trim off the trailing comma - if (pos >= 2) - sbuf[pos - 2] = 0; - - *outstr = sbuf; + // Trim off the trailing comma and space + if (out->size() >= 2) { + out->resize(out->size() - 2); + } return true; } + +#undef SIGN_CAST diff --git a/src/util/serialize.h b/src/util/serialize.h index 4c883602..3f992528 100644 --- a/src/util/serialize.h +++ b/src/util/serialize.h @@ -166,14 +166,14 @@ inline v2s16 readV2S16(const u8 *data) inline void writeV2S32(u8 *data, v2s32 p) { writeS32(&data[0], p.X); - writeS32(&data[2], p.Y); + writeS32(&data[4], p.Y); } inline v2s32 readV2S32(const u8 *data) { v2s32 p; p.X = readS32(&data[0]); - p.Y = readS32(&data[2]); + p.Y = readS32(&data[4]); return p; } @@ -346,6 +346,19 @@ inline v2s16 readV2S16(std::istream &is) return readV2S16((u8*)buf); } +inline void writeV2S32(std::ostream &os, v2s32 p) +{ + char buf[8] = {0}; + writeV2S32((u8*)buf, p); + os.write(buf, 8); +} +inline v2s32 readV2S32(std::istream &is) +{ + char buf[8] = {0}; + is.read(buf, 8); + return readV2S32((u8*)buf); +} + inline void writeV3S16(std::ostream &os, v3s16 p) { char buf[6] = {0}; @@ -403,7 +416,7 @@ std::string deSerializeJsonString(std::istream &is); // Creates a string containing comma delimited values of a struct whose layout is // described by the parameter format -bool serializeStructToString(std::string *outstr, +bool serializeStructToString(std::string *out, std::string format, void *value); // Reads a comma delimited string of values into a struct whose layout is diff --git a/src/util/string.h b/src/util/string.h index 9bb89f14..bed66417 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -165,7 +165,7 @@ inline s32 mystoi(const std::string &s, s32 min, s32 max) inline s64 stoi64(const std::string &s) { std::stringstream tmp(s); - long long t; + s64 t; tmp >> t; return t; }