Deleting/Disconnecting a SceneTreeTimer - godot

I'm trying to disconnect a SceneTreeTimer to avoid a function being called on timeout
like this:
extends Node2D
onready var something = $Node2D
var timer
func abort():
timer.disconnect("timeout",something,"queue_free")
timer.emit_signal("timeout")
print("timer=>",timer)
func _ready():
timer=get_tree().create_timer(3)
timer.connect("timeout",something,"queue_free")
...
abort()
And while it does stop the timer from invoking the function
I'm still seeing the timer after aborting it, Output:
timer=>[SceneTreeTimer:1276]
Shouldn't it be something like this since it's time has elapsed?
timer=>[Deleted Object]

SceneTreeTimer unlike Node is a Reference.
If you have a look at the good old class diagram. You are going to see that some classes extend Node others Reference (including Resource) and other extend Object directly.
The classes that extend Reference are reference counted, they won't be deleted as long as you hold (a not WeakRef) reference to them.
While the classes that extend Node use explicit memory management, so they are deleted by calling free or queue_free on them.
Thus, drop the reference once you are no longer using the SceneTreeTimer:
func abort():
timer.disconnect("timeout",something,"queue_free")
timer.emit_signal("timeout")
timer = null
print("timer=>",timer) # null, duh
Godot will still emit the "timeout" signal, and when it does it releases its internal reference. We find this in "scene_tree.cpp" (source):
if (time_left < 0) {
E->get()->emit_signal("timeout");
timers.erase(E);
}
We can also experiment using a WeakRef to get a result similar to the one you expect. However, remember that since Godot is holding a reference internally the timer won't be deleted before its normal timeout.
extends Node2D
onready var something = $Node2D
var timer_ref:WeakRef
func abort():
var timer := timer_ref.get_ref() as SceneTreeTimer
timer.disconnect("timeout",something,"queue_free")
timer.emit_signal("timeout")
func _ready():
var timer := get_tree().create_timer(3)
# warning-ignore:return_value_discarded
timer.connect("timeout",something,"queue_free")
timer_ref = weakref(timer)
abort()
func _process(_delta: float) -> void:
print("timer=>", timer_ref.get_ref())
You should see it change from
timer=>[SceneTreeTimer:1234]
To
timer=>null
After 3 seconds, since that is the argument we gave to create_timer.
Trivia: Here you will get some number where I put "1234", that number is the instance id of the object. You can get it with get_instance_id and you can get the instance from the id with instance_from_id. We saw an example of instance_from_id in FauxBody2D.
You might also find it convenient to create an Autoload where you create, stop, and even pause your timers while keeping a API similar to create_timer, for example see Godot 4.0. how stop a auto call SceneTreeTimer?.
Addendum:
DON'T DO THIS
You might actually mess up with Godot. Since it is reference counted, and we can freely change the count, we can make it release the timer early:
var timer := timer_ref.get_ref() as SceneTreeTimer
timer.disconnect("timeout",something,"queue_free")
timer.emit_signal("timeout")
timer.unreference()
I tested this both on the debugger and on a release export, with Godot 3.5.1, and it didn't crash the game, not output any errors.
For clarity unreference is not the same as free, instead:
reference increases the count by one.
unreference decreases the count by one.
I'm calling unreference to cancel out the internal reference that Godot has.
We can confirm that the timer is being freed, either by using a weak reference or by looking at Godot's profiler. However, Godot has an internal list with references to the timers which are not being cleared properly.
I made this code to test out if the timer loop was being affected by the timers being released early by the above means.
extends Node2D
var can_fire := true
func _process(_delta: float) -> void:
var timer := get_tree().create_timer(60)
# warning-ignore:return_value_discarded
timer.unreference()
if can_fire:
can_fire = false
print("CREATED")
# warning-ignore:return_value_discarded
get_tree().create_timer(2).connect("timeout", self, "fire")
func fire() -> void:
print("FIRED")
can_fire = true
You might expect it to output FIRED each couple seconds. However, what I found out is that by using unreference on unrelated timers, we get the others to fire much faster.
My hypothesis is that Godot is keeping the dead reference in its internal list, then when another timer is allocated it takes the same memory. Then the timer counts faster because it appears multiple times in the list.
Removing unreference results in the expected behavior.

It does seem to exist still because calling "disconnect" function won't automatically free itself. Try doing timer.stop() instead.

Related

Invoke function on adding a keyframe in animation player

I have an animation player and I want to invoke a function anytime a keyframe gets added
like this:
extends AnimationPlayer
...
func key_added(track_indx,key_indx):
print("key added: ",key_indx," to track:",track_indx)
is something like this possible? is there any inbuilt function that I'm missing?
I did not have the time to fully experiment with it, but this should give you a direction you could look into.
first of you will need to alter the animation class to give you the needed event. To be able to use it in the editor keep in mind, that you need the tool flag:
extends Animation
tool
class_name ToolAnimation
signal key_added(track_idx, key_indx)
func track_insert_key ( track_idx : int, time : float, key, transition : float = 1) -> void:
.track_insert_key(track_idx, time, key, transition)
#need to find the key index of the key we added
var key_id = track_find_key ( track_idx, time, true )
emit_signal("key_added", track_idx, key_id)
All I do here is to overwrite the track_insert_key to search for the key Id after adding it and then emit a signal.
Now we need to tell our animation_player to add our newly created animations instead of normal animation classes so we change the script of the animation_player and override the add_animation function:
extends AnimationPlayer
tool
func add_animation(name : String, animation: Animation):
var tool_animation = ToolAnimation.new()
tool_animation.connect("key_added", self, "key_added")
.add_animation(name, tool_animation)
pass
func key_added(track_indx,key_indx):
print("key added: ",key_indx," to track:",track_indx)
Now everytime a key is added you should get into the key_added method.
This will only work for newly created animations, because existing ones will not have the toolanimation extensions. To add the feature to existing animations, you would need to deep copy them in your ready functions, for example.
Edit: As #cakelover pointed out in the comments: To alter existing animations, iterate over them and use their set_script() function.
Second thing I noticed, when trying it out was, that my key_added method was not called if a track is newly created and the first key is added simultaniously (basically pressing the key symbol on a property I did not track before). So thats something you should look into, if you also need the first key.

There is a problem in memory-management of object in lua programming

I'm making a shooting game with solar 2d, everything was working fine but after some time I feel that the games frame rate is dropping, but I did steps to delete my laser when the task finishes
local function fireLaser()
audio.play( fire sound )
newLaser = display.newImageRect( mainGroup, objectSheet, 5, 14, 40 )
physics.addBody( newLaser, "dynamic", { isSensor=true } )
newLaser.isBullet = true
newLaser.myName = "laser"
newLaser.x = ship.x
newLaser.y = ship.y
newLaser:toBack()
transition.to( newLaser, { y=400, time=500,
onComplete = function()display.remove( newLaser ) end
} )
end
I think what is happening, that onComplete calls the display.remove( newLaser ) after 600ms but the function again called but in less than 600ms , say 400ms, so display.remove( newLaser ) dump the first object which is called on first clicked and remove the second one or say latest one, but if the player continuously clicking the fire laser button, and each click has a difference of less than 600 ms, then nothing would be removed. Please Help me as soon as possible.
If you are only using newLaser inside of fireLaser you should define it as a local variable.
This will seem like a insignificant change, but when you do
onComplete = function() display.remove(newLaser) end
you are creating a enclosed function.
When a function is written enclosed in another function, it has full access to local variables from the enclosing function; this feature is called lexical scoping. Although that may sound obvious, it is not. Lexical scoping, plus first-class functions, is a powerful concept in a programming language, but few languages support that concept. - Programming in Lua: 6.1 – Closures
This does not work when newLaser is global because each call to fireLaser is acting on the same global variable of newLaser rather than a unique local variable.

How does the update diff work in AzerothCore?

The worldserver source code is full of Update methods that take as input a diff integer value:
How does it work?
And how is this linked to the "Update time diff" from the .server info command?
To fully understand how this works, it's necessary to have a look at the main World run process.
WorldRunnable::run()
File: src/server/worldserver/WorldThread/WorldRunnable.cpp
The method void WorldRunnable::run() is the "Main heartbeat for the World". This method runs the whole world process.
Inside it, there is a while loop that runs as long as the world is supposed to keep running:
void WorldRunnable::run()
{
uint32 realCurrTime = 0;
uint32 realPrevTime = getMSTime();
///- While we have not World::m_stopEvent, update the world
while (!World::IsStopped())
{
++World::m_worldLoopCounter;
realCurrTime = getMSTime();
uint32 diff = getMSTimeDiff(realPrevTime, realCurrTime);
sWorld->Update( diff );
realPrevTime = realCurrTime;
uint32 executionTimeDiff = getMSTimeDiff(realCurrTime, getMSTime());
devDiffTracker.Update(executionTimeDiff);
avgDiffTracker.Update(executionTimeDiff > WORLD_SLEEP_CONST ? executionTimeDiff : WORLD_SLEEP_CONST);
// ... some more code here
}
// at this point the world process is terminating
// ... some more code here
What this loop really does is basically:
1) calculate the elapsed time (in milliseconds) since the previous iteration, this will be the diff
2) call the sWorld->Update( diff ); function, that contains all the world process logic (see below) and passing the diff to it
3) calculate how much time it took to run sWorld->Update( diff ); and update the devDiffTracker and its average avgDiffTracker. These values will be displayed by the .server info command.
World::Update(uint32 diff)
File: src/server/game/World/World.cpp
The World::Update(uint32 diff) function gets constantly called by the main worldserver loop process and every time it takes in input the amount diff of elapsed time since the last call.
This function is responsible for constantly updating the world, this is where all the magic happens.
Timers
There are a set of timers (defined in World.h that are being updated within the World::Update function:
/// Timers for different object refresh rates
enum WorldTimers
{
WUPDATE_AUCTIONS,
WUPDATE_WEATHERS,
WUPDATE_UPTIME,
WUPDATE_CORPSES,
WUPDATE_EVENTS,
WUPDATE_CLEANDB,
WUPDATE_AUTOBROADCAST,
WUPDATE_MAILBOXQUEUE,
WUPDATE_PINGDB,
WUPDATE_5_SECS,
WUPDATE_COUNT
};
For example, WUPDATE_AUTOBROADCAST is responsible for the period global messages defined in the acore_auth.autobroadcast table.
Tasks
The World::Update function also takes care of many timed-tasks, for example:
/// Handle daily quests reset time
if (m_gameTime > m_NextDailyQuestReset)
ResetDailyQuests();
Calling Update(diff) functions of Managers
In AzerothCore there are singleton classes called Managers (Mgr) that handle specific parts of the game. For example BattlegroundMgr handles the Battlegrounds (BGs).
Those classes have their own Update(uint32 diff) functions and they are called by World::Update that passes down the diff to them, for example:
sBattlegroundMgr->Update(diff);
sOutdoorPvPMgr->Update(diff);
sBattlefieldMgr->Update(diff);
/// ... there are more!
OnWorldUpdate hook
Last but not least, it calls sScriptMgr->OnWorldUpdate(diff);.
This is part of the AzerothCore Module System, and defines a hook that can be used by third-part modules to attach custom logic to the World::Update function.

Godot: add_child() on an instanced node's children to recursively create objects

I'm creating a little program that creates image patterns like these using line segments that rotate around each other:
image from Engare Steam store page for reference
How do I tell Godot to create instances of the Polygon2D scene I'm using as line segments with origins on Position2D nodes that exist as children in the Polygon2D scene? Here is a sample of my code:
const SHAPE_MASTER = preload("res://SpinningBar.tscn")
...
func bar_Maker(bar_num, parent_node):
for i in range(bar_num):
var GrabbedInstance = SHAPE_MASTER.instance()
parent_node.add_child(GrabbedInstance)
bar_Maker(bar_num - 1, $Polygon2D/RotPoint)
...
func _physics_process(delta):
...
if Input.is_action_just_pressed("Switch Item"): # from an older version of the program, just bound to ctrl
bar_Maker(segment_count, BarParent)
bar_num is the number of bars to instance, set elsewhere (range 1-6).
parent_node in the main scene is just a Node2D called BarParent.
The SpinningBar.tscn I'm instancing as GrabbedInstance has a Position2D node called "RotPoint" at the opposite end of the segment from the object's origin. This is the point I would like successive segments to rotate around (and also put particle emitters here to trace lines, but that is a trivial issue once this first one is answered).
Running as-is and creating more than 1 line segment returns "Attempt to call function 'add_child' in base 'null instance' on a null instance." Clearly I am adding the second (and later) segments incorrectly, so I know it's related to how I'm performing recursion/selecting new parents for segments 1+ node deep.
Bang your head against the wall and you will find the answer:
func bar_Maker(bar_num, parent_node):
for i in range(bar_num):
var GrabbedInstance = SHAPE_MASTER.instance()
parent_node.add_child(GrabbedInstance)
var new_children = GrabbedInstance.get_children()
bar_Maker(bar_num - 1, new_children[0])
If someone is aware of a more elegant way to do this please inform me and future readers. o7

Cairo.Surface is leaking... How to debug it with Monodevelop?

I have many doubts related with Cairo and GTK# (that runs on .NET and Mono). I'm developing a GTK# application for MS Windows and Linux. I'm using GTK# 2.12 over .NET right now while I'm working on the application.
I've created a custom widget that uses Cairo.ImageSurface and Cairo.Context objects. As far as I know, I'm calling the Dispose method of every ImageSurface object and every Context object I create inside the widget code.
The widget responds to the "MouseOver" event, redrawing some parts of its DrawingArea.
The (first) problem:
almost every redrawing operation increases a little bit the amount of used memory. When the amount of used memory has increased 3 or 4 Kbytes the Monodevelop tracelog panel shows me the following message:
Cairo.Surface is leaking, programmer is missing a call to Dispose
Set MONO_CAIRO_DEBUG_DISPOSE to track allocation traces
The code that redraws a part of the widget is something like:
// SRGB is a custom struct, not from Gdk nor Cairo
void paintSingleBlock(SRGB color, int i)
{
using (Cairo.Context g = CairoHelper.Create (GdkWindow)) {
paintSingleBlock (g, color, i);
// We do this to avoid memory leaks. Cairo does not work well with the GC.
g.GetTarget().Dispose ();
g.Dispose ();
}
}
void paintSingleBlock(Cairo.Context g, SRGB color, int i)
{
var scale = Math.Pow (10.0, TimeScale);
g.Save();
g.Rectangle (x(i), y(i), w(i), h(i));
g.ClosePath ();
g.Restore ();
// We don't directly use stb.Color because in some cases we need more flexibility
g.SetSourceRGB (color.R, color.G, color.B);
g.LineWidth = 0;
g.Fill ();
}
The (second) problem: Ok, Monodevelop tells me that I should set MONO_CAIRO_DEBUG_DISPOSE to "track allocation traces" (In order to find the leak, I suppose)... but I don't know how to set this environment variable (I'm in Windows). I've tried using bash and executing something like:
MONO_CAIRO_DEBUG_DISPOSE=1 ./LightCreator.exe
But nothing appears in stderr nor stdout... (neither the messages that appear in the Monodevelop's applicationt trace panel). I also don't know how to get the debugging messages that see inside Monodevelop but without Monodevelop.
There's anyone with experience debugging GTK# or Cairo# memory leaks?
Thanks in advance.
Just wanted to throw my 2c here as I was fighting a similar leak problem in Cairo with surfaces. What I noticed is that if I create a Surface object the ReferenceCount property becomes 1 and if I attach this surface to a Context if becomes not 2 but 3. After disposing the Context the ReferenceCount comes back but to 2.
So I used some reflection to call the native methods in Cairo to decrease the ReferenceCount when I really want to Dispose a surface. I use this code:
public static void HardDisposeSurface (this Surface surface)
{
var handle = surface.Handle;
long refCount = surface.ReferenceCount;
surface.Dispose ();
refCount--;
if (refCount <= 0)
return;
var asm = typeof (Surface).Assembly;
var nativeMethods = asm.GetType ("Cairo.NativeMethods");
var surfaceDestroy = nativeMethods.GetMethod ("cairo_surface_destroy", BindingFlags.Static | BindingFlags.NonPublic);
for (long i = refCount; i > 0; i--)
surfaceDestroy.Invoke (null, new object [] { handle });
}
After using it I still have some leaks, but they seem to be related to other parts of Cairo and not with the surfaces.
I have found that a context created with CairoHelper.Create() will have a reference count of two.
A call to dispose reduces the reference count by one. Thus the context is never freed and keeps its target alive, too.
The native objects have manual reference counting, but the Gtk# wrappers want to keep a native object alive as long as there is a C# instance referencing it.
If a native object is created for a C# wrapper instance it does not need to increment the reference count because the wrapper instance 'owns' the native object and the reference count has the correct value of one. But if a wrapper instance is created for an already existing native object the reference count of the native object needs to be manually incremented to keep the object alive.
This is decided by a bool parameter when a wrapper instance is created.
Looking at the code for CairoHelper.Create() will show something like this
public static Cairo.Context Create(Gdk.Window window) {
IntPtr raw_ret = gdk_cairo_create(window == null ? IntPtr.Zero : window.Handle);
Cairo.Context ret = new Cairo.Context (raw_ret, false);
return ret;
}
Even though the native context was just created 'owned' will be false and the C# context will increment the reference count.
There is no fixed version right now, it can only be corrected by fixing the source and building Gtk# yourself.
CairoHelper is an auto-generated file, to change the parameter to true this attribute must be included in gdk/Gdk.metadata.
<attr path="/api/namespace/class[#cname='GdkCairo_']/method[#name='Create']/return-type" name="owned">true</attr>
Everything to build Gtk# can be found here.
https://github.com/mono/gtk-sharp

Resources