Defold 1.6.4 has been released

Defold 1.6.4

Summary

  • NEW: (#8364) Updated to Xcode 15.1, iOS 17.2 and macOS 14.2
  • NEW: (#8353) Added options to control how json data is encoded and decoded
  • NEW: (#8352) Generate a node id when cloning a gui node
  • NEW: (#8336) Added engine loader fallback when WebAssembly streaming fails
  • NEW: (#8255) Custom vertex format support for Models
  • NEW: (#8296) Remove glfw from the engine builds
  • NEW: (#8300) Dynamic resizing of collision shapes
  • NEW: (#8330) Load images in runtime as buffers
  • NEW: (#8419) Add new default filtering keyword for material samplers (Engine support)
  • NEW: (#8421) Remove material count limit for models
  • NEW: (#8428) Added options in sound.stop(url, [options]) where it’s possible to specify what exactly voice should be stopped
  • NEW: (#8416) New API functions: sys.load_buffer and sys.load_buffer_async
  • NEW: (#8429) Added physics.set_listener(fn) to set a function as the physics world listener
  • NEW: (#8258) Added sprite multitexture support
  • NEW: (#8456) New function physics.update_mass(url, mass)
  • NEW: (#8318) Select the default build server based on channel
  • NEW: (#8375) Slightly improve editor memory usage for large projects
  • NEW: (#8434) Add editor.create_directory() and code completion to editor scripts
  • NEW: (#8439) Add physics.JOINT_TYPE_WHEEL for 2d physics
  • FIX: (#8310) Update node transform if adjust mode changed using gui.set_adjust_mode()
  • FIX: (#8338) Fix for outputting the correct skinned tangents
  • FIX: (#8344) Buffered render buffers support
  • FIX: (#8357) Add missing functions to null physics libraries
  • FIX: (#8358) Set data correctly when recreating dynamic texture in gui
  • FIX: (#8293) Compute shader support, part deux
  • FIX: (#8367) Fix ogg-validate invocation for sounds from mounted extensions
  • FIX: (#8369) Add hot reload functionality for label component.
  • FIX: (#8450) If the hash string is unknown, show its value instead.
  • FIX: (#8452) Remove redunant malloc in font_map
  • FIX: (#8461) Fixed how mass is calculated for physics collision objects with more than one shape.
  • FIX: (#8418) Don’t request LSP completions for dependencies

Engine

NEW: (#8364) Updated to Xcode 15.1, iOS 17.2 and macOS 14.2

NEW: (#8353) Added options to control how json data is encoded and decoded
It is now possible to configure the behaviour when encoding and decoding JSON data.

When encoding to JSON it is possible to control wether an empty Lua table should encode as a JSON object or array. The default behaviour when encoding an empty Lua table is to encode to a JSON object.

When decoding from JSON it is now possible to control wether a JSON null value should decode to json-null or nil. The default behaviour when decoding a JSON null value is to decode to nil.

local t = {}
json.encode(t, { encode_empty_table_as_object = true }) -- {}
json.encode(t, { encode_empty_table_as_object = false }) -- []
json.encode(t) -- {}


local s = "[ 1, 2, null, 3 ]"
json.decode(s, { decode_null_as_userdata = true}) -- { 1, 2, json.null, 4 }
json.decode(s, { decode_null_as_userdata = false}) -- { 1, 2, nil, 4 }
json.decode(s) -- { 1, 2, nil, 4 }

NEW: (#8352) Generate a node id when cloning a gui node
Cloned gui nodes are now automatically assigned a node id instead of an empty hash.

NEW: (#8336) Added engine loader fallback when WebAssembly streaming fails
The engine loader will now use XMLHttpRequest as a fallback when WebAssembly compilation and instantiation from a streamed source fails.

NEW: (#8255) Custom vertex format support for Models
We have added initial support for custom vertex formats for models.

NEW: (#8296) Remove glfw from the engine builds
GLFW is no longer being built as part of our main engine build. Instead, the current GLFW version (modified 2.7) is now begin built and distributed as an external package. We have also removed GLFW from our SDK, which means that some extensions might potentially break. This is considered a bugfix instead of a breaking change, since the headers should never have been part of the SDK from the first place.

This is the second part of our ongoing task (#7970) of migrating the current GLFW version to the latest stable official release, as well as separating all non-desktop platforms our of the GLFW infrastructure.

NEW: (#8300) Dynamic resizing of collision shapes
Added script functions to get and set collision shape sizes in runtime. The new functions are:

physics.get_shape(url, shape_name)
physics.set_shape(url, shape_name, table)

For example, to update the box shape my_box for a collision object located at /go#collisionobject:

local box = physics.get_shape("/go#collisionobject", "my_box")
box.dimensions = box.dimensions + vmath.vector3(5,10,15)
physics.set_shape("/go#collisionobject", "my_box", box)

NEW: (#8330) Load images in runtime as buffers
The image script module now has a new function to return a buffer object. The new function is called image.load_buffer and can be used to dynamically create texture resources in runtime:

local img = image.load_buffer(compressed_data)
-- img.buffer now contains an actual buffer object that can be passed into resource.create_texture
local tparams = {
	width  = img.width,
	height = img.height,
	type   = resource.TEXTURE_TYPE_2D,
	format = resource.TEXTURE_FORMAT_RGBA
}
local my_texture_id = resource.create_texture("/my_custom_texture.texturec", tparams, img.buffer)

NEW: (#8419) Add new default filtering keyword for material samplers (Engine support)
This PR adds new filtering keyword for material samplers called:

FILTER_MODE_MIN_DEFAULT
FILTER_MODE_MAG_DEFAULT

When using these settings on a sampler in the material, the engine will pick the global min and mag settings that is specified in the game.project -> graphics setting. This can be useful for having a global base filtering method, while still being able to specialise settings per sampler if needed.

NEW: (#8421) Remove material count limit for models
We have removed the limit for how many materials a model component can reference.

NEW: (#8428) Added options in sound.stop(url, [options]) where it’s possible to specify what exactly voice should be stopped
Now it’s possible to stop one particular voice of the sound component:

     sound.stop("#sound")
     local id = sound.play("#sound")
     sound.stop("#sound", {play_id = id}) -- stop only one voice

NEW: (#8416) New API functions: sys.load_buffer and sys.load_buffer_async
Two new script functions has been added:

function async_callback(self, request_id, status, buf)
    -- do something with data here
end

local buf = sys.load_buffer(path)
local request_id = sys.load_buffer_async(path, callback)

These functions can be used to read data into a buffer object from either via the resource system, or direct file locations if the resource could not be found on any of the mounted resource locations. Meaning, the path supplied is not necessary a custom resource location, it can be any file on disk.

NEW: (#8429) Added physics.set_listener(fn) to set a function as the physics world listener
Now, it is possible to set a function that will receive all physics interaction events in one place. If a function is set, physics messages will no longer be sent.

physics.set_listener(function(self, event, data)
  if event == hash("contact_point_event") then
    pprint(data)
    -- {
    -- 	applied_impulse = 310.00769042969,
    -- 	distance = 0.0714111328125,
    -- 	a = {
    -- 		position = vmath.vector3(446, 371, 0),
    -- 		relative_velocity = vmath.vector3(1.1722083854693e-06, -20.667181015015, -0),
    -- 		mass = 0,
    -- 		group = hash: [default],
    -- 		id = hash: [/flat],
    -- 		normal = vmath.vector3(-0, -1, -0)
    -- 	},
    -- 	b = {
    -- 		position = vmath.vector3(185, 657.92858886719, 0),
    -- 		relative_velocity = vmath.vector3(-1.1722083854693e-06, 20.667181015015, 0),
    -- 		mass = 10,
    -- 		group = hash: [default],
    -- 		id = hash: [/go2],
    -- 		normal = vmath.vector3(0, 1, 0)
    -- 	}
    -- }
  elseif event == hash("collision_event") then
    pprint(data)
    -- {
    -- 	a = {
    -- 			group = hash: [default],
    -- 			position = vmath.vector3(183, 666, 0),
    -- 			id = hash: [/go1]
    -- 		},
    -- 	b = {
    -- 			group = hash: [default],
    -- 			position = vmath.vector3(185, 704.05865478516, 0),
    -- 			id = hash: [/go2]
    -- 		}
    -- }
  elseif event ==  hash("trigger_event") then
    pprint(data)
    -- {
    -- 	enter = true,
    -- 	b = {
    -- 		group = hash: [default],
    -- 		id = hash: [/go2]
    -- 	},
    -- 	a = {
    -- 		group = hash: [default],
    -- 		id = hash: [/go1]
    -- 	}
    -- },
  elseif event ==  hash("ray_cast_response") then
    pprint(data)
    --{
    -- 	group = hash: [default],
    -- 	request_id = 0,
    -- 	position = vmath.vector3(249.92222595215, 249.92222595215, 0),
    -- 	fraction = 0.68759721517563,
    -- 	normal = vmath.vector3(0, 1, 0),
    -- 	id = hash: [/go]
    -- }
  elseif event ==  hash("ray_cast_missed") then
    pprint(data)
    -- {
    --  request_id = 0
    --},
  end
end)

NEW: (#8456) New function physics.update_mass(url, mass)
Added new function physics.update_mass(url, mass) which updates the mass of a dynamic 2D collision object in the physics world.

The function recalculates the density of each shape based on the total area of all shapes and the specified mass, then updates the mass of the body accordingly.

NEW: (#8258) Added sprite multitexture support
With the latest version, we now have support for multiple atlases in the sprite component.

To use it, you need a material and shader that has multiple samplers available.
The sprite will then display property fields where you can select an atlas for each sampler.

The animations shown are selected from the first sampler’s atlas.
The sprite will use this animation’s fps setting and frame names.

You will also need to match animations between atlases. If the default animation is “jump”, then it will automatically choose the “jump” animation from the other atlases as well.
It is also required that frames within the animations matches.
In a scenario where A.atlas has animation jump:

jump
    frame1.png
    frame2.png

Then B.atlas needs this animation as well:

jump
    frame_normal_1.png
    frame_normal_1.png

In this case, the frame names don’t match, and you’ll need to use the rename_patterns field to alter the frame names.
It is a comma separated list of patterns:

rename_patterns: _normal_=

In this example, it replaces the string “normal” with the string “”, resulting in the final animation/frame names for B.atlas:

jump
    frame1.png
    frame1.png

The documentation has been updated: Showing 2D images

NEW: (#8439) Add physics.JOINT_TYPE_WHEEL for 2d physics
Added physics.JOINT_TYPE_WHEEL for 2d physics

FIX: (#8310) Update node transform if adjust mode changed using gui.set_adjust_mode()
Fix bug when adjust mode applied to a node only after window resize.

FIX: (#8338) Fix for outputting the correct skinned tangents
Due to a typo, the skinned tangents weren’t calculated correctly.

FIX: (#8344) Buffered render buffers support
Fixed an issue for certain graphics adapter where vertex and index buffers are overwritten during the same frame.

FIX: (#8357) Add missing functions to null physics libraries

FIX: (#8358) Set data correctly when recreating dynamic texture in gui
Bugfix for when recreating a deleted texture within the same frame in GUI:

gui.new_texture(tex_id, img.width, img.height, img.type, img.buffer)
gui.delete_texture(tex_id)
gui.new_texture(tex_id, img.width, img.height, img.type, img.buffer)
gui.set_texture(node, tex_id)

FIX: (#8293) Compute shader support, part deux
This is the second part of the compute shader support, this PR includes engine resources for the compute program and shaders needed to build the compute program. At this point we cannot still reference the compute programs anywhere in the engine (which is the next step - to formalize a user-facing API around this work).

FIX: (#8367) Fix ogg-validate invocation for sounds from mounted extensions
Copy ogg resource to temp file to deal with resources from mount points (e.g. extensions).
Ogg validation runs on temp ogg file now.
Temp files created into Bob root folder which removed at the end of the build.

FIX: (#8369) Add hot reload functionality for label component.
Add hot reload functionality for label component.
Reread properties from reloaded label resource and mark component to be rehashed.

FIX: (#8450) If the hash string is unknown, show its value instead.
Instead of showing just <unknown> when the corresponding string value is unknown, print its numeric value. For example:

<unknown:2256903789829718645>

FIX: (#8452) Remove redunant malloc in font_map

FIX: (#8461) Fixed how mass is calculated for physics collision objects with more than one shape.
Fixed a bug where the mass specified in the Collision Object component was applied to each shape, resulting in the object’s total mass becoming Collision Object mass x Shapes count.

With this fix, the mass will remain as specified in the Collision Object, and the density will be recalculated depending on it to be equal for each shape.

Editor

NEW: (#8318) Select the default build server based on channel
If the “Build Server” preference was never modified or is set to an empty string, the editor will pick either https://build-stage.defold.com or https://build.defold.com depending on the editor channel.

NEW: (#8375) Slightly improve editor memory usage for large projects
Slightly improve editor memory usage in projects with a large number of node endpoints. This typically corresponds to the number of files in the project, but varies significantly by file type.

Improves #8261

NEW: (#8434) Add editor.create_directory() and code completion to editor scripts
This changeset adds a new function to editor scripts that allows the user to create a new directory. The function expects a resource path, i.e. a /-prefixed path from the root of the project, for example:

editor.create_directory("/assets/generated")
local file = io.open("assets/generated/build.json")
file:write(...)
file:flush()
file:close()

Additionally, the editor now provides code completions for functions in the editor module.

FIX: (#8418) Don’t request LSP completions for dependencies

25 Likes

I can’t wait to try the resizing of collision objects.

This update looks exciting too me. Thank you.

1 Like

:astonished: wow I don’t have to uninstall and install the new version… The editor will automatically check for updates! :heart_eyes: :heartbeat:

Thanks you! :relaxed:

4 Likes

It’s a huge release - thank you!

Excited about it! We’re making a combat heavy game in the Gamedev Camp I am eager to check if this is useful in action!

I wanted to ask about details of memory here. The lifetime of the loaded image is as defined by the scope of the Lua variable? Or until resource.release()? Or different?

1 Like

It’s not a buffer resource, just a buffer object, so it will be equivalent to a buffer.create(). When it goes out of lua scope (i.e garbage collected), it will be removed.

5 Likes

As always, thank you for your hard work!

I’m interested in figuring it out and seeing an example of how to use the new functionality:

I see that documentation is in process, but I wonder if spine objects will be able to use this functionality also?

3 Likes

Since the beta, we’ve updated the documentation. (And I’ve fixed the release notes with the same link)

We haven’t really considered spine objetcs (yet). Are there such examples available online of such a setup?

3 Likes

maybe I don’t understand how multi textures work, for me it’s the ability to use 2 different atlases for a sprite, correct me if this is wrong :slight_smile:

but I was wondering if this could solve the Batching draw calls of GO sprites with GO spine.

1 Like

You are correct.

I haven’t encountered this scenario for a spine scene (yet), so I’d be happy to take a look at some example of it. And as always, feel free to add a feature request on Github!

The other topic you linked to highlights a bigger drawback of our current design, that we can’t batch between different collections and/or component types. We have plans for solving this, but no ETA, and it’s likely some time in the future.

4 Likes

Been getting this error occassionally since updating to 1.6.4.

Seems the message “sound_done” can’t be received because the object that played the sound no longer exists…?

ERROR:GAMEOBJECT: Instance '/instance12' could not be found when dispatching message 'sound_done' sent from main:/sound#exp-small

2 Likes

Updated to 1.6.4. Extension-rive is not building :frowning:

lld-link: error: undefined symbol: void __cdecl dmGraphics::EnableVertexDeclaration(void *, struct dmGraphics::VertexDeclaration *, unsigned __int64, unsigned __int64)
>>> referenced by /tmp/job14116362361621283313/upload/include/private/renderer_private.h:817
>>>               rivedefold.lib(renderer_private.cpp_0.o):(private: virtual void __cdecl dmRive::DefoldPLSRenderContext::flush(struct rive::pls::PLSRenderContext::FlushDescriptor const &))
>>> referenced by /tmp/job14116362361621283313/upload/include/private/renderer_private.h:862
>>>               rivedefold.lib(renderer_private.cpp_0.o):(private: virtual void __cdecl dmRive::DefoldPLSRenderContext::flush(struct rive::pls::PLSRenderContext::FlushDescriptor const &))
>>> referenced by /tmp/job14116362361621283313/upload/include/private/renderer_private.h:1008
>>>               rivedefold.lib(renderer_private.cpp_0.o):(private: virtual void __cdecl dmRive::DefoldPLSRenderContext::flush(struct rive::pls::PLSRenderContext::FlushDescriptor const &))
>>> referenced 1 more times
	clang++: error: linker command failed with exit code 1 (use -v to see invocation)
	com.defold.extender.ExtenderException: java.io.IOException: lld-link: error: undefined symbol: void __cdecl dmGraphics::EnableVertexDeclaration(void *, struct dmGraphics::VertexDeclaration *, unsigned __int64, unsigned __int64)
>>> referenced by /tmp/job14116362361621283313/upload/include/private/renderer_private.h:817
>>>               rivedefold.lib(renderer_private.cpp_0.o):(private: virtual void __cdecl dmRive::DefoldPLSRenderContext::flush(struct rive::pls::PLSRenderContext::FlushDescriptor const &))
>>> referenced by /tmp/job14116362361621283313/upload/include/private/renderer_private.h:862
>>>               rivedefold.lib(renderer_private.cpp_0.o):(private: virtual void __cdecl dmRive::DefoldPLSRenderContext::flush(struct rive::pls::PLSRenderContext::FlushDescriptor const &))
>>> referenced by /tmp/job14116362361621283313/upload/include/private/renderer_private.h:1008
>>>               rivedefold.lib(renderer_private.cpp_0.o):(private: virtual void __cdecl dmRive::DefoldPLSRenderContext::flush(struct rive::pls::PLSRenderContext::FlushDescriptor const &))
>>> referenced 1 more times
	Line 2: In file included from build/defold-rive/rive_ddf.cpp:2:
In file included from /var/extender/sdk/4689e4033ebfc982176b92545900302d0fcb03b3/defoldsdk//include/ddf/ddf_math.h:26:
In file included from /var/extender/sdk/4689e4033ebfc982176b92545900302d0fcb03b3/defoldsdk//sdk/include/dmsdk/dlib/vmath.h:18:
In file included from /var/extender/sdk/4689e4033ebfc982176b92545900302d0fcb03b3/defoldsdk//sdk/include/dmsdk/vectormath/cpp/vectormath_aos.h:40:
private field 'd' is not used [-Wunused-private-field]
   63 |     float d;
      |           ^
	Line 2: private field 'd' is not used [-Wunused-private-field]
  607 |     float d;
      |           ^
3 Likes

It seems we havent updated the extension. @jhonny.goransson is this something you can look at?

2 Likes

We’ve just released a hot-fix 553487eb9c84a23b6ddd2afcba0ff6085784a5fa which fixes a case when an atlas image was both rotated and also trimmed. (thanks @Qwarr who reported the issue)

1 Like

Thanks! Looks like there was another issue still there though.

2024-02-13 08_22_10-Big Klondike - Classic Solitaire

Seems sprites that are rotated that have trim mode enabled are getting the wrong parts trimmed?
Turning sprite trim mode to off does “fix” the issue.

I updated my example repo to demonstrate the issue: GitHub - Qwarr/AtlasRotation

1 Like

There’s also a sample project here: GitHub - defold/sample-normal-maps-2d with demo: Normal Maps 2D 1.0

3 Likes

this is really the update of all time

4 Likes

A new PR has been submitted, and should land within a few hours.

yes, I have encountered the same errors in my projects.

ERROR:GAMEOBJECT: Instance '/instance2' could not be found when dispatching message 'sound_done' sent from example1:/sounds#fireball_burst_a

It seems that playing a sound and deleting an object at once without waiting for a message causes an error. Such constructions can be for example in bullet collision handlers, when a “bang” sound is emitted and the bullet is deleted at once.

sound.play("/sounds#bang")
go.delete()
5 Likes

I’ve rectified this issue by moving all sound generation into a dedicated sound manager game object which is never deleted.

2 Likes