I don't know why the viewports are deleted with deleteLater(), but it leads
to an OpenGL context getting deselected behind our back, and so we don't know
when is a good time to re-select it. This leads to termination of the engine
when selecting File->Close (Ctrl+W) in the editor, because the graphics
re-initialization fails with no GL context active.
Instead, just delete the viewport widget immediately, which works fine at
least on Linux. This is also recommended by the Qt documentation at
http://doc.qt.io/qt-5/qopenglwidget.html.
When removing a viewport, then also remove it from the internal list of
viewports. Otherwise, we might attempt to delete it again later. Fixes
crash on editor shutdown on Linux.
This fixes a crash on Linux when exiting the editor. It was caused by
C4Console::~C4Console being called by the C++ runtime after after main()
returned. The C4Console destructor then goes and deletes all the Qt
resources (QApplication and friends), and that caused a segfault, maybe
because some of the static Qt structures have already been deallocated.
Fix this by making the destruction of the Qt components deterministic. Add
a function "DeleteConsoleWindow" which deletes all the Qt components, and
call this function in C4Console::Clear.
If a local variable in a definition was set to a proplist inside the
Definition() callback, and that proplist contained cyclic references
then those references were leaked. Typically cyclic references for
script-created proplists are broken in
C4PropListScript::ClearScriptPropLists, however definition proplists
are changed to be static proplists in
C4PropList::FreezeAndMakeStaticRecursively.
To fix this, each script host maintains a list of proplists made static
by FreezeAndMakeStaticRecursively, and explicitly deletes all of these
proplists on Clear().
This leak also leads to an assertion failure inside
C4PropListScript::ClearScriptPropLists in debug mode, and can also be
observed by C4PropList::PropLists not being empty after game clear.
The definition in Objects.ocd/Helpers.ocd/UserAction.ocd constructs
cyclic proplists in its Definition() call. A simpler, more minimal way
to provoke the leak is the following (it provokes the leak but not the
assertion failure):
local bla;
func Definition(def)
{
bla = {};
bla.test = { Name="Test222" , Options = { Name="Test333" } };
bla.test.Options.Link = { Name="Test444", Blub=bla.test };
}
Use RegexSearch() instead, which is 100 times faster for large strings
(see benchmark results below).
Example benchmark:
global func TestFindSubstring(int iterations)
{
var result;
for (var i = 0; i < iterations; i++)
{
result = FindSubstring(hamlet, "and");
}
return result;
}
global func TestRegexSearch(int iterations)
{
var result;
for (var i = 0; i < iterations; i++)
{
result = RegexSearch(hamlet, "and");
}
return result;
}
global func RunBenchmark(int iterations)
{
StartScriptProfiler();
Log("FindSubstring: %d iterations", iterations);
var substr = TestFindSubstring(iterations);
Log("RegexSearch: %d iterations", iterations);
var regex = TestRegexSearch(iterations);
StopScriptProfiler();
if (!DeepEqual(regex, substr))
Log("Results differ: %v vs %v", substr, regex);
}
Results:
FindSubstring: 100 iterations
RegexSearch: 100 iterations
Profiler statistics:
==============================
48903ms Global.FindSubstring
48903ms Global.TestFindSubstring
47979ms Global.TakeString
00504ms Global.TestRegexSearch
00016ms Global.PushBack
==============================
As carrier-grade NATs are becoming common, many players cannot host
Clonk games at all. The simple STUN-like netpuncher from Clonk Rage
which was removed three years ago is already effective against some
DS-Lite NATs.
With some extensions, we should be able to make it work with more
restrictive NATs as well.
This reverts commit 72002cc366.