_elements;
+ std::unordered_map _elementMap;
+ };
}
#endif // hifi_render_Stage_h
diff --git a/libraries/render/src/render/StageSetup.h b/libraries/render/src/render/StageSetup.h
new file mode 100644
index 0000000000..5691bca207
--- /dev/null
+++ b/libraries/render/src/render/StageSetup.h
@@ -0,0 +1,35 @@
+//
+// StageSetup.h
+// render/src/render
+//
+// Created by HifiExperiments on 10/16/24
+// Copyright 2024 Overte e.V.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_render_StageSetup_h
+#define hifi_render_StageSetup_h
+
+#include "Engine.h"
+
+namespace render {
+
+ template
+ class StageSetup {
+ public:
+ StageSetup() {}
+
+ void run(const RenderContextPointer& renderContext) {
+ if (renderContext->_scene) {
+ auto stage = renderContext->_scene->getStage(T::getName());
+ if (!stage) {
+ renderContext->_scene->resetStage(T::getName(), std::make_shared());
+ }
+ }
+ }
+ };
+}
+
+#endif // hifi_render_StageSetup_h
diff --git a/libraries/render/src/render/TransitionStage.cpp b/libraries/render/src/render/TransitionStage.cpp
index 9ddc72f4db..72637cc3d9 100644
--- a/libraries/render/src/render/TransitionStage.cpp
+++ b/libraries/render/src/render/TransitionStage.cpp
@@ -1,43 +1,25 @@
-#include "TransitionStage.h"
+//
+// TransitionStage.cpp
+//
+// Created by Olivier Prat on 07/07/2017.
+// Copyright 2017 High Fidelity, Inc.
+// Copyright 2024 Overte e.V.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
-#include
+#include "TransitionStage.h"
using namespace render;
-std::string TransitionStage::_name("Transition");
-const TransitionStage::Index TransitionStage::INVALID_INDEX{ indexed_container::INVALID_INDEX };
+template <>
+std::string TypedStage::_name { "TRANSITION_STAGE" };
TransitionStage::Index TransitionStage::addTransition(ItemID itemId, Transition::Type type, ItemID boundId) {
Transition transition;
- Index id;
-
transition.eventType = type;
transition.itemId = itemId;
transition.boundItemId = boundId;
- id = _transitions.newElement(transition);
- _activeTransitionIds.push_back(id);
-
- return id;
+ return addElement(transition);
}
-
-void TransitionStage::removeTransition(Index index) {
- TransitionIdList::iterator idIterator = std::find(_activeTransitionIds.begin(), _activeTransitionIds.end(), index);
- if (idIterator != _activeTransitionIds.end()) {
- _activeTransitionIds.erase(idIterator);
- }
- if (!_transitions.isElementFreed(index)) {
- _transitions.freeElement(index);
- }
-}
-
-TransitionStageSetup::TransitionStageSetup() {
-}
-
-void TransitionStageSetup::run(const RenderContextPointer& renderContext) {
- auto stage = renderContext->_scene->getStage(TransitionStage::getName());
- if (!stage) {
- stage = std::make_shared();
- renderContext->_scene->resetStage(TransitionStage::getName(), stage);
- }
-}
-
diff --git a/libraries/render/src/render/TransitionStage.h b/libraries/render/src/render/TransitionStage.h
index abfdca9a06..11256fb346 100644
--- a/libraries/render/src/render/TransitionStage.h
+++ b/libraries/render/src/render/TransitionStage.h
@@ -1,8 +1,9 @@
//
// TransitionStage.h
-
+//
// Created by Olivier Prat on 07/07/2017.
// Copyright 2017 High Fidelity, Inc.
+// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@@ -12,55 +13,22 @@
#define hifi_render_TransitionStage_h
#include "Stage.h"
-#include "IndexedContainer.h"
-#include "Engine.h"
+#include "StageSetup.h"
#include "Transition.h"
namespace render {
// Transition stage to set up Transition-related effects
- class TransitionStage : public render::Stage {
+ class TransitionStage : public TypedStage {
public:
-
- static const std::string& getName() { return _name; }
-
- using Index = indexed_container::Index;
- static const Index INVALID_INDEX;
- using TransitionIdList = indexed_container::Indices;
-
- static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; }
-
- bool isTransitionUsed(Index index) const { return _transitions.checkIndex(index) && !_transitions.isElementFreed(index); }
-
- const Transition& getTransition(Index TransitionId) const { return _transitions.get(TransitionId); }
-
- Transition& editTransition(Index TransitionId) { return _transitions.edit(TransitionId); }
-
+ bool isTransitionUsed(Index index) const { return _elements.checkIndex(index) && !_elements.isElementFreed(index); }
Index addTransition(ItemID itemId, Transition::Type type, ItemID boundId);
- void removeTransition(Index index);
-
- TransitionIdList::iterator begin() { return _activeTransitionIds.begin(); }
- TransitionIdList::iterator end() { return _activeTransitionIds.end(); }
-
- private:
-
- using Transitions = indexed_container::IndexedVector;
-
- static std::string _name;
-
- Transitions _transitions;
- TransitionIdList _activeTransitionIds;
};
using TransitionStagePointer = std::shared_ptr;
- class TransitionStageSetup {
+ class TransitionStageSetup : public StageSetup {
public:
- using JobModel = render::Job::Model;
-
- TransitionStageSetup();
- void run(const RenderContextPointer& renderContext);
-
- protected:
+ using JobModel = Job::Model;
};
}
diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp
index 23122cc302..58fee1f06d 100644
--- a/libraries/script-engine/src/ScriptManager.cpp
+++ b/libraries/script-engine/src/ScriptManager.cpp
@@ -381,6 +381,7 @@ ScriptManager::~ScriptManager() {
if (_type == ScriptManager::Type::ENTITY_CLIENT) {
printf("ScriptManager::~ScriptManager");
}
+ _isDeleted = true;
}
void ScriptManager::disconnectNonEssentialSignals() {
@@ -426,7 +427,10 @@ void ScriptManager::runInThread() {
void ScriptManager::executeOnScriptThread(std::function function, const Qt::ConnectionType& type ) {
if (QThread::currentThread() != thread()) {
- QMetaObject::invokeMethod(this, "executeOnScriptThread", type, Q_ARG(std::function, function));
+ // Lambda is necessary there to keep shared_ptr counter above zero
+ QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{
+ manager->executeOnScriptThread(function, type);
+ });
return;
}
@@ -858,10 +862,10 @@ void ScriptManager::removeEventHandler(const EntityItemID& entityID, const QStri
qCDebug(scriptengine) << "*** WARNING *** ScriptManager::removeEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
"entityID:" << entityID << " eventName:" << eventName;
#endif
- QMetaObject::invokeMethod(this, "removeEventHandler",
- Q_ARG(const EntityItemID&, entityID),
- Q_ARG(const QString&, eventName),
- Q_ARG(const ScriptValue&, handler));
+ // Lambda is necessary there to keep shared_ptr counter above zero
+ QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{
+ manager->removeEventHandler(entityID, eventName, handler);
+ });
return;
}
#ifdef THREAD_DEBUGGING
@@ -905,10 +909,10 @@ void ScriptManager::addEventHandler(const EntityItemID& entityID, const QString&
"entityID:" << entityID << " eventName:" << eventName;
#endif
- QMetaObject::invokeMethod(this, "addEventHandler",
- Q_ARG(const EntityItemID&, entityID),
- Q_ARG(const QString&, eventName),
- Q_ARG(const ScriptValue&, handler));
+ // Lambda is necessary there to keep shared_ptr counter above zero
+ QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{
+ manager->addEventHandler(entityID, eventName, handler);
+ });
return;
}
#ifdef THREAD_DEBUGGING
@@ -1167,7 +1171,10 @@ void ScriptManager::stop(bool marshal) {
_isStopping = true; // this can be done on any thread
if (marshal) {
- QMetaObject::invokeMethod(this, "stop");
+ // Lambda is necessary there to keep shared_ptr counter above zero if this gets called from different thread
+ QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{
+ manager->stop(false);
+ });
return;
}
@@ -2011,11 +2018,10 @@ bool ScriptManager::hasEntityScriptDetails(const EntityItemID& entityID) const {
void ScriptManager::loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload) {
if (QThread::currentThread() != thread()) {
- QMetaObject::invokeMethod(this, "loadEntityScript",
- Q_ARG(const EntityItemID&, entityID),
- Q_ARG(const QString&, entityScript),
- Q_ARG(bool, forceRedownload)
- );
+ // Lambda is necessary there to keep shared_ptr counter above zero
+ QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{
+ manager->loadEntityScript(entityID, entityScript, forceRedownload);
+ });
return;
}
PROFILE_RANGE(script, __FUNCTION__);
@@ -2092,13 +2098,10 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c
<< contents << "isURL:" << isURL << "success:" << success;
#endif
- QMetaObject::invokeMethod(this, "entityScriptContentAvailable",
- Q_ARG(const EntityItemID&, entityID),
- Q_ARG(const QString&, scriptOrURL),
- Q_ARG(const QString&, contents),
- Q_ARG(bool, isURL),
- Q_ARG(bool, success),
- Q_ARG(const QString&, status));
+ // Lambda is necessary there to keep shared_ptr counter above zero
+ QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{
+ manager->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success, status);
+ });
return;
}
@@ -2442,9 +2445,10 @@ void ScriptManager::unloadEntityScript(const EntityItemID& entityID, bool should
"entityID:" << entityID;
#endif
- QMetaObject::invokeMethod(this, "unloadEntityScript",
- Q_ARG(const EntityItemID&, entityID),
- Q_ARG(bool, shouldRemoveFromMap));
+ // Lambda is necessary there to keep shared_ptr counter above zero
+ QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{
+ manager->unloadEntityScript(entityID, shouldRemoveFromMap);
+ });
return;
}
#ifdef THREAD_DEBUGGING
@@ -2494,9 +2498,10 @@ void ScriptManager::unloadAllEntityScripts(bool blockingCall) {
#ifdef THREAD_DEBUGGING
qCDebug(scriptengine) << "*** WARNING *** ScriptManager::unloadAllEntityScripts() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]";
#endif
-
- QMetaObject::invokeMethod(this, "unloadAllEntityScripts",
- blockingCall ? Qt::BlockingQueuedConnection : Qt::QueuedConnection);
+ // Lambda is necessary there to keep shared_ptr counter above zero
+ QMetaObject::invokeMethod(this, [=, manager = shared_from_this()] {
+ manager->unloadAllEntityScripts(blockingCall);
+ }, blockingCall ? Qt::BlockingQueuedConnection : Qt::QueuedConnection);
return;
}
#ifdef THREAD_DEBUGGING
@@ -2589,12 +2594,10 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q
qCDebug(scriptengine) << "*** WARNING *** ScriptManager::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
"entityID:" << entityID << "methodName:" << methodName;
#endif
-
- QMetaObject::invokeMethod(this, "callEntityScriptMethod",
- Q_ARG(const EntityItemID&, entityID),
- Q_ARG(const QString&, methodName),
- Q_ARG(const QStringList&, params),
- Q_ARG(const QUuid&, remoteCallerID));
+ // Lambda is necessary there to keep shared_ptr counter above zero
+ QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{
+ manager->callEntityScriptMethod(entityID, methodName, params, remoteCallerID);
+ });
return;
}
#ifdef THREAD_DEBUGGING
@@ -2659,10 +2662,10 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q
"entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent";
#endif
- QMetaObject::invokeMethod(this, "callEntityScriptMethod",
- Q_ARG(const EntityItemID&, entityID),
- Q_ARG(const QString&, methodName),
- Q_ARG(const PointerEvent&, event));
+ // Lambda is necessary there to keep shared_ptr counter above zero
+ QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{
+ manager->callEntityScriptMethod(entityID, methodName, event);
+ });
return;
}
#ifdef THREAD_DEBUGGING
@@ -2698,11 +2701,10 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q
"entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision";
#endif
- QMetaObject::invokeMethod(this, "callEntityScriptMethod",
- Q_ARG(const EntityItemID&, entityID),
- Q_ARG(const QString&, methodName),
- Q_ARG(const EntityItemID&, otherID),
- Q_ARG(const Collision&, collision));
+ // Lambda is necessary there to keep shared_ptr counter above zero
+ QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{
+ manager->callEntityScriptMethod(entityID, methodName, otherID, collision);
+ });
return;
}
#ifdef THREAD_DEBUGGING
diff --git a/libraries/script-engine/src/ScriptManager.h b/libraries/script-engine/src/ScriptManager.h
index 8197f26285..7185d3e615 100644
--- a/libraries/script-engine/src/ScriptManager.h
+++ b/libraries/script-engine/src/ScriptManager.h
@@ -280,9 +280,6 @@ public:
*/
class ScriptManager : public QObject, public EntitiesScriptEngineProvider, public std::enable_shared_from_this {
Q_OBJECT
- Q_PROPERTY(QString context READ getContext)
- Q_PROPERTY(QString type READ getTypeAsString)
- Q_PROPERTY(QString fileName MEMBER _fileNameString CONSTANT)
public:
static const QString SCRIPT_EXCEPTION_FORMAT;
static const QString SCRIPT_BACKTRACE_SEP;
@@ -381,8 +378,11 @@ public:
Q_ENUM(Type);
static int processLevelMaxRetries;
- ScriptManager(Context context, const QString& scriptContents = NO_SCRIPT, const QString& fileNameString = QString("about:ScriptEngine"));
- ~ScriptManager();
+private:
+ // Constructor is private so that only properly generated shared pointer can be used
+ explicit ScriptManager(Context context, const QString& scriptContents = NO_SCRIPT, const QString& fileNameString = QString("about:ScriptEngine"));
+public:
+ ~ScriptManager() override;
// static initialization support
typedef void (*ScriptManagerInitializer)(ScriptManager*);
@@ -390,7 +390,7 @@ public:
public:
ScriptManagerInitializer init;
StaticInitializerNode* prev;
- inline StaticInitializerNode(ScriptManagerInitializer&& pInit) : init(std::move(pInit)),prev(nullptr) { registerNewStaticInitializer(this); }
+ inline explicit StaticInitializerNode(ScriptManagerInitializer&& pInit) : init(std::move(pInit)),prev(nullptr) { registerNewStaticInitializer(this); }
};
static void registerNewStaticInitializer(StaticInitializerNode* dest);
@@ -398,7 +398,7 @@ public:
public:
ScriptManagerInitializer init;
StaticTypesInitializerNode* prev;
- inline StaticTypesInitializerNode(ScriptManagerInitializer&& pInit) : init(std::move(pInit)),prev(nullptr) { registerNewStaticTypesInitializer(this); }
+ inline explicit StaticTypesInitializerNode(ScriptManagerInitializer&& pInit) : init(std::move(pInit)),prev(nullptr) { registerNewStaticTypesInitializer(this); }
};
static void registerNewStaticTypesInitializer(StaticTypesInitializerNode* dest);
@@ -1668,6 +1668,7 @@ protected:
friend ScriptManagerPointer newScriptManager(Context context, const QString& scriptContents, const QString& fileNameString);
friend class ScriptManagerScriptingInterface;
+ std::atomic _isDeleted {false}; // This is used for debugging use-after-delete. It happens quite often, so I'm keeping it here for now.
};
/**
diff --git a/libraries/script-engine/src/ScriptManagerScriptingInterface.h b/libraries/script-engine/src/ScriptManagerScriptingInterface.h
index 9fc23de283..0a2ccb66e3 100644
--- a/libraries/script-engine/src/ScriptManagerScriptingInterface.h
+++ b/libraries/script-engine/src/ScriptManagerScriptingInterface.h
@@ -58,6 +58,9 @@ public:
class ScriptManagerScriptingInterface : public QObject {
Q_OBJECT
+ Q_PROPERTY(QString context READ getContext)
+ Q_PROPERTY(QString type READ getTypeAsString)
+ Q_PROPERTY(QString fileName READ getAbsoluteFilename CONSTANT)
public:
ScriptManagerScriptingInterface(ScriptManager *parent);
@@ -96,6 +99,26 @@ public:
*/
Q_INVOKABLE QString getContext() const { return _manager->getContext(); }
+ /*@jsdoc
+ * Gets the type of script that is running: Interface, avatar, client entity, server entity, or assignment client.
+ * @function Script.getTypeAsString
+ * @returns {string} The type of script that is running:
+ *
+ * "client"
: An Interface script.
+ * "entity_client"
: A client entity script.
+ * "avatar"
: An avatar script.
+ * "entity_server"
: A server entity script.
+ * "agent"
: An assignment client script.
+ *
+ */
+ Q_INVOKABLE QString getTypeAsString() const { return _manager->getTypeAsString(); }
+
+ /*@jsdoc
+ * Gets the filename of the script file.
+ * @function Script.getAbsoluteFilename
+ * @returns {string} The filename of the script file.
+ */
+ Q_INVOKABLE QString getAbsoluteFilename() const { return _manager->getAbsoluteFilename(); }
/*@jsdoc
* Checks whether the script is running as an Interface or avatar script.
diff --git a/libraries/script-engine/src/v8/ScriptEngineDebugFlags.h b/libraries/script-engine/src/v8/ScriptEngineDebugFlags.h
new file mode 100644
index 0000000000..bdecb3f6a2
--- /dev/null
+++ b/libraries/script-engine/src/v8/ScriptEngineDebugFlags.h
@@ -0,0 +1,18 @@
+//
+// ScriptEngineDebugFlags.h
+// libraries/script-engine/src/v8/ScriptEngineDebugFlags.h
+//
+// Created by dr Karol Suprynowicz on 2024/11/14.
+// Copyright 2024 Overte e.V.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#ifndef overte_ScriptEngineDebugFlags_h
+#define overte_ScriptEngineDebugFlags_h
+
+#define OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD
+
+#endif
diff --git a/libraries/script-engine/src/v8/ScriptEngineV8.cpp b/libraries/script-engine/src/v8/ScriptEngineV8.cpp
index 5a9dead93f..5e233d3a90 100644
--- a/libraries/script-engine/src/v8/ScriptEngineV8.cpp
+++ b/libraries/script-engine/src/v8/ScriptEngineV8.cpp
@@ -258,6 +258,13 @@ ScriptEngineV8::ScriptEngineV8(ScriptManager *manager) : ScriptEngine(manager),
}
ScriptEngineV8::~ScriptEngineV8() {
+ // Process remaining events to avoid problems with `deleteLater` calling destructor of script proxies after script engine has been deleted:
+ {
+ QEventLoop loop;
+ loop.processEvents();
+ }
+ // This is necessary for script engines that don't run in ScriptManager::run(), for example entity scripts:
+ disconnectSignalProxies();
deleteUnusedValueWrappers();
#ifdef OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD
_wasDestroyed = true;
@@ -272,14 +279,14 @@ void ScriptEngineV8::perManagerLoopIterationCleanup() {
void ScriptEngineV8::disconnectSignalProxies() {
_signalProxySetLock.lockForRead();
while (!_signalProxySet.empty()) {
+ auto proxy = *_signalProxySet.begin();
_signalProxySetLock.unlock();
- delete *_signalProxySet.begin();
+ delete proxy;
_signalProxySetLock.lockForRead();
}
_signalProxySetLock.unlock();
}
-
void ScriptEngineV8::deleteUnusedValueWrappers() {
while (!_scriptValueWrappersToDelete.empty()) {
auto wrapper = _scriptValueWrappersToDelete.dequeue();
diff --git a/libraries/script-engine/src/v8/ScriptEngineV8.h b/libraries/script-engine/src/v8/ScriptEngineV8.h
index 02352c9ed7..dd2edca41b 100644
--- a/libraries/script-engine/src/v8/ScriptEngineV8.h
+++ b/libraries/script-engine/src/v8/ScriptEngineV8.h
@@ -35,6 +35,7 @@
#include "libplatform/libplatform.h"
#include "v8.h"
+#include "ScriptEngineDebugFlags.h"
#include "../ScriptEngine.h"
#include "../ScriptManager.h"
#include "../ScriptException.h"
@@ -58,8 +59,6 @@ using ScriptContextV8Pointer = std::shared_ptr;
const double GARBAGE_COLLECTION_TIME_LIMIT_S = 1.0;
-#define OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD
-
Q_DECLARE_METATYPE(ScriptEngine::FunctionSignature)
/// [V8] Implements ScriptEngine for V8 and translates calls for QScriptEngine
diff --git a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp
index 7c3fd07e9b..eeae1e2e94 100644
--- a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp
+++ b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp
@@ -1217,7 +1217,9 @@ ScriptSignalV8Proxy::~ScriptSignalV8Proxy() {
_objectLifetime.Reset();
_v8Context.Reset();
#ifdef OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD
+ Q_ASSERT(!_wasDeleted);
Q_ASSERT(!_engine->_wasDestroyed);
+ _wasDeleted = true;
#endif
_engine->_signalProxySetLock.lockForWrite();
_engine->_signalProxySet.remove(this);
diff --git a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.h b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.h
index 9e3445ca98..14b8f1900e 100644
--- a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.h
+++ b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.h
@@ -23,6 +23,7 @@
#include
#include
+#include "ScriptEngineDebugFlags.h"
#include "../ScriptEngine.h"
#include "../Scriptable.h"
#include "ScriptEngineV8.h"
@@ -295,6 +296,9 @@ private: // storage
// Call counter for debugging purposes. It can be used to determine which signals are overwhelming script engine.
int _callCounter{0};
float _totalCallTime_s{ 0.0 };
+#ifdef OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD
+ std::atomic _wasDeleted{false};
+#endif
Q_DISABLE_COPY(ScriptSignalV8Proxy)
};
diff --git a/scripts/communityScripts/armored-chat/armored_chat.js b/scripts/communityScripts/armored-chat/armored_chat.js
index fe66da7a54..779dc3ff54 100644
--- a/scripts/communityScripts/armored-chat/armored_chat.js
+++ b/scripts/communityScripts/armored-chat/armored_chat.js
@@ -14,6 +14,7 @@
var settings = {
external_window: false,
maximum_messages: 200,
+ join_notification: true
};
// Global vars
@@ -97,24 +98,31 @@
if (channel !== "chat") return;
message = JSON.parse(message);
+ // Get the message data
+ const currentTimestamp = _getTimestamp();
+ const timeArray = _formatTimestamp(currentTimestamp);
+
if (!message.channel) message.channel = "domain"; // We don't know where to put this message. Assume it is a domain wide message.
if (message.forApp) return; // Floofchat
// Floofchat compatibility hook
message = floofChatCompatibilityConversion(message);
- message.channel = message.channel.toLowerCase(); // Make sure the "local", "domain", etc. is formatted consistently
+ message.channel = message.channel.toLowerCase();
- if (!channels.includes(message.channel)) return; // Check the channel
- if (
- message.channel == "local" &&
- Vec3.distance(MyAvatar.position, message.position) >
- maxLocalDistance
- )
- return; // If message is local, and if player is too far away from location, don't do anything
+ // Check the channel. If the channel is not one we have, do nothing.
+ if (!channels.includes(message.channel)) return;
+
+ // If message is local, and if player is too far away from location, do nothing.
+ if (message.channel == "local" && isTooFar(message.position)) return;
+
+ // Format the timestamp
+ message.timeString = timeArray[0];
+ message.dateString = timeArray[1];
// Update qml view of to new message
_emitEvent({ type: "show_message", ...message });
+ // Show new message on screen
Messages.sendLocalMessage(
"Floof-Notif",
JSON.stringify({
@@ -125,20 +133,25 @@
// Save message to history
let savedMessage = message;
+
+ // Remove unnecessary data.
delete savedMessage.position;
- savedMessage.timeString = new Date().toLocaleTimeString(undefined, {
- hour12: false,
- });
- savedMessage.dateString = new Date().toLocaleDateString(undefined, {
- year: "numeric",
- month: "long",
- day: "numeric",
- });
+ delete savedMessage.timeString;
+ delete savedMessage.dateString;
+ delete savedMessage.action;
+
+ savedMessage.timestamp = currentTimestamp;
+
messageHistory.push(savedMessage);
while (messageHistory.length > settings.maximum_messages) {
messageHistory.shift();
}
Settings.setValue("ArmoredChat-Messages", messageHistory);
+
+ // Check to see if the message is close enough to the user
+ function isTooFar(messagePosition) {
+ return Vec3.distance(MyAvatar.position, messagePosition) > maxLocalDistance;
+ }
}
function fromQML(event) {
switch (event.type) {
@@ -146,25 +159,25 @@
_sendMessage(event.message, event.channel);
break;
case "setting_change":
+ // Set the setting value, and save the config
settings[event.setting] = event.value; // Update local settings
_saveSettings(); // Save local settings
+ // Extra actions to preform.
switch (event.setting) {
case "external_window":
chatOverlayWindow.presentationMode = event.value
? Desktop.PresentationMode.NATIVE
: Desktop.PresentationMode.VIRTUAL;
break;
- case "maximum_messages":
- // Do nothing
- break;
}
break;
case "action":
switch (event.action) {
case "erase_history":
- Settings.setValue("ArmoredChat-Messages", []);
+ Settings.setValue("ArmoredChat-Messages", null);
+ messageHistory = [];
_emitEvent({
type: "clear_messages",
});
@@ -213,9 +226,7 @@
// Get the display name of the user
let displayName = "";
- displayName =
- AvatarManager.getPalData([sessionId])?.data[0]
- ?.sessionDisplayName || null;
+ displayName = AvatarManager.getPalData([sessionId])?.data[0]?.sessionDisplayName || null;
if (displayName == null) {
for (let i = 0; i < palData.length; i++) {
if (palData[i].sessionUUID == sessionId) {
@@ -226,8 +237,22 @@
// Format the packet
let message = {};
+ const timeArray = _formatTimestamp(_getTimestamp());
+ message.timeString = timeArray[0];
+ message.dateString = timeArray[1];
message.message = `${displayName} ${type}`;
+ // Show new message on screen
+ if (settings.join_notification){
+ Messages.sendLocalMessage(
+ "Floof-Notif",
+ JSON.stringify({
+ sender: displayName,
+ text: type,
+ })
+ );
+ }
+
_emitEvent({ type: "notification", ...message });
}, 1500);
}
@@ -237,7 +262,9 @@
if (messageHistory) {
// Load message history
messageHistory.forEach((message) => {
- delete message.action;
+ const timeArray = _formatTimestamp(_getTimestamp());
+ message.timeString = timeArray[0];
+ message.dateString = timeArray[1];
_emitEvent({ type: "show_message", ...message });
});
}
@@ -249,6 +276,24 @@
console.log("Saving config");
Settings.setValue("ArmoredChat-Config", settings);
}
+ function _getTimestamp(){
+ return Date.now();
+ }
+ function _formatTimestamp(timestamp){
+ let timeArray = [];
+
+ timeArray.push(new Date().toLocaleTimeString(undefined, {
+ hour12: false,
+ }));
+
+ timeArray.push(new Date(timestamp).toLocaleDateString(undefined, {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ }));
+
+ return timeArray;
+ }
/**
* Emit a packet to the HTML front end. Easy communication!
diff --git a/scripts/communityScripts/armored-chat/armored_chat.qml b/scripts/communityScripts/armored-chat/armored_chat.qml
index d1e46f57a6..07eb75c626 100644
--- a/scripts/communityScripts/armored-chat/armored_chat.qml
+++ b/scripts/communityScripts/armored-chat/armored_chat.qml
@@ -1,5 +1,5 @@
import QtQuick 2.7
-import QtQuick.Controls 2.0
+import QtQuick.Controls 2.15
import QtQuick.Layouts 1.3
import controlsUit 1.0 as HifiControlsUit
@@ -30,7 +30,7 @@ Rectangle {
running: false
repeat: false
onTriggered: {
- scrollToBottom();
+ scrollToBottom(true);
}
}
@@ -145,49 +145,60 @@ Rectangle {
anchors.top: navigation_bar.bottom
visible: ["local", "domain"].includes(pageVal) ? true : false
-
// Chat Message History
- ListView {
+ Flickable {
width: parent.width
height: parent.height - 40
+ contentWidth: parent.width
+ contentHeight: listview.height
clip: true
- interactive: true
- spacing: 5
- id: listview
+ id: messageViewFlickable
- delegate: Loader {
- property int delegateIndex: index
- property string delegateText: model.text
- property string delegateUsername: model.username
- property string delegateDate: model.date
- width: listview.width
+ ColumnLayout {
+ id: listview
+ Layout.fillWidth: true
- sourceComponent: {
- if (model.type === "chat") {
- return template_chat_message;
- } else if (model.type === "notification") {
- return template_notification;
+ Repeater {
+ model: getChannel(pageVal)
+ delegate: Loader {
+ property int delegateIndex: model.index
+ property string delegateText: model.text
+ property string delegateUsername: model.username
+ property string delegateDate: model.date
+
+ sourceComponent: {
+ if (model.type === "chat") {
+ return template_chat_message;
+ } else if (model.type === "notification") {
+ return template_notification;
+ }
+ }
+
}
}
}
- ScrollBar.vertical: ScrollBar {
- id: chat_scrollbar
- height: 100
- size: 0.05
+ ScrollBar.vertical: ScrollBar {
+ size: 100
+ minimumSize: 0.1
}
- model: getChannel(pageVal)
-
+ rebound: Transition {
+ NumberAnimation {
+ properties: "x,y"
+ duration: 1
+ }
+ }
}
+
ListModel {
id: local
}
ListModel {
id: domain
- }
+ }
// Chat Entry
Rectangle {
@@ -205,6 +216,8 @@ Rectangle {
height: parent.height
placeholderText: pageVal.charAt(0).toUpperCase() + pageVal.slice(1) + " chat message..."
clip: false
+ font.italic: text == ""
+
Keys.onPressed: {
if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && !(event.modifiers & Qt.ShiftModifier)) {
event.accepted = true;
@@ -335,6 +348,31 @@ Rectangle {
}
}
}
+
+
+ // Join notification
+ Rectangle {
+ width: parent.width
+ height: 40
+ color: "transparent"
+
+ Text{
+ text: "Join notification"
+ color: "white"
+ font.pointSize: 12
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ CheckBox{
+ id: s_join_notification
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+
+ onCheckedChanged: {
+ toScript({type: 'setting_change', setting: 'join_notification', value: checked})
+ }
+ }
+ }
}
}
@@ -344,7 +382,7 @@ Rectangle {
Component {
id: template_chat_message
- Rectangle{
+ Rectangle {
property int index: delegateIndex
property string texttest: delegateText
property string username: delegateUsername
@@ -352,6 +390,8 @@ Rectangle {
height: Math.max(65, children[1].height + 30)
color: index % 2 === 0 ? "transparent" : Qt.rgba(0.15,0.15,0.15,1)
+ width: listview.parent.parent.width
+ Layout.fillWidth: true
Item {
width: parent.width - 10
@@ -370,7 +410,7 @@ Rectangle {
}
}
- TextEdit{
+ TextEdit {
anchors.top: parent.children[0].bottom
x: 5
text: texttest
@@ -451,16 +491,25 @@ Rectangle {
}
-
-
property var channels: {
"local": local,
"domain": domain,
}
- function scrollToBottom() {
- if (listview.count == 0) return;
- listview.positionViewAtEnd();
+ function scrollToBottom(bypassDistanceCheck = false, extraMoveDistance = 0) {
+ const totalHeight = listview.height; // Total height of the content
+ const currentPosition = messageViewFlickable.contentY; // Current position of the view
+ const windowHeight = listview.parent.parent.height; // Total height of the window
+ const bottomPosition = currentPosition + windowHeight;
+
+ // Check if the view is within 300 units from the bottom
+ const closeEnoughToBottom = totalHeight - bottomPosition <= 300;
+ if (!bypassDistanceCheck && !closeEnoughToBottom) return;
+ if (totalHeight < windowHeight) return; // No reason to scroll, we don't have an overflow.
+ if (bottomPosition == totalHeight) return; // At the bottom, do nothing.
+
+ messageViewFlickable.contentY = listview.height - listview.parent.parent.height;
+ messageViewFlickable.returnToBounds();
}
@@ -469,13 +518,13 @@ Rectangle {
// Format content
message = formatContent(message);
-
message = embedImages(message);
if (type === "notification"){
channel.append({ text: message, date: date, type: "notification" });
last_message_user = "";
- scrollToBottom();
+ scrollToBottom(null, 30);
+
last_message_time = new Date();
return;
}
@@ -487,22 +536,18 @@ Rectangle {
var last_item_index = channel.count - 1;
var last_item = channel.get(last_item_index);
- // FIXME: When adding a new message this would check to see if we could append the incoming message
- // to the bottom of the last message. This current implimentation causes issues with scrollToBottom()
- // Specifically, scrolling to the bottom does not like image embeds.
- // This needs to be reworked entirely before it can be reimplimented
- // if (last_message_user === username && elapsed_minutes < 1 && last_item){
- // message = "
" + message
- // last_item.text = last_item.text += "\n" + message;
- // scrollToBottom()
- // last_message_time = new Date();
- // return;
- // }
+ if (last_message_user === username && elapsed_minutes < 1 && last_item){
+ message = "
" + message
+ last_item.text = last_item.text += "\n" + message;
+ load_scroll_timer.running = true;
+ last_message_time = new Date();
+ return;
+ }
last_message_user = username;
last_message_time = new Date();
channel.append({ text: message, username: username, date: date, type: type });
- scrollToBottom();
+ load_scroll_timer.running = true;
}
function getChannel(id) {
@@ -542,15 +587,13 @@ Rectangle {
// Messages from script
function fromScript(message) {
- let time = new Date().toLocaleTimeString(undefined, { hour12: false });
- let date = new Date().toLocaleDateString(undefined, { year: "numeric", month: "long", day: "numeric", });
switch (message.type){
case "show_message":
- addMessage(message.displayName, message.message, `[ ${message.timeString || time} - ${message.dateString || date} ]`, message.channel, "chat");
+ addMessage(message.displayName, message.message, `[ ${message.timeString} - ${message.dateString} ]`, message.channel, "chat");
break;
case "notification":
- addMessage("SYSTEM", message.message, `[ ${time} - ${date} ]`, "domain", "notification");
+ addMessage("SYSTEM", message.message, `[ ${message.timeString} - ${message.dateString} ]`, "domain", "notification");
break;
case "clear_messages":
local.clear();
@@ -559,6 +602,7 @@ Rectangle {
case "initial_settings":
if (message.settings.external_window) s_external_window.checked = true;
if (message.settings.maximum_messages) s_maximum_messages.value = message.settings.maximum_messages;
+ if (message.settings.join_notification) s_join_notification.checked = true;
break;
}
}
diff --git a/scripts/communityScripts/armored-chat/armored_chat_quick_message.qml b/scripts/communityScripts/armored-chat/armored_chat_quick_message.qml
index ae110db379..b14fd0a811 100644
--- a/scripts/communityScripts/armored-chat/armored_chat_quick_message.qml
+++ b/scripts/communityScripts/armored-chat/armored_chat_quick_message.qml
@@ -1,7 +1,7 @@
import QtQuick 2.5
import QtQuick.Controls 1.4
-Rectangle {
+Item {
id: root
property var window
@@ -21,15 +21,22 @@ Rectangle {
z: 99
visible: false
- TextArea {
- id: textArea
- x: 0
+ Rectangle {
width: parent.width
height: parent.height
- text:""
- textColor: "#ffffff"
+ color: Qt.rgba(0.95,0.95,0.95,1)
+ }
+
+ TextInput {
+ id: textArea
+ x: 5
+ width: parent.width
+ height: parent.height
+ text: ""
+ color: "#000"
clip: false
font.pointSize: 18
+ verticalAlignment: Text.AlignVCenter
Keys.onReturnPressed: { _onEnterPressed(); }
Keys.onEnterPressed: { _onEnterPressed(); }
@@ -52,33 +59,36 @@ Rectangle {
text: "Local message..."
font.pointSize: 16
color: "gray"
- x: 0
+ x: 5
width: parent.width
anchors.verticalCenter: parent.verticalCenter
visible: textArea.text == ""
+ font.italic: true
}
- Button {
+ Rectangle {
id: button
x: parent.width - width
y: 0
width: 64
height: parent.height
clip: false
- visible: true
-
+ color: "#262626"
+
Image {
id: image
width: 30
height: 30
fillMode: Image.PreserveAspectFit
- visible: true
anchors.centerIn: parent
source: "./img/ui/send_white.png"
}
- onClicked: {
- _onEnterPressed();
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ _onEnterPressed();
+ }
}
}
diff --git a/scripts/communityScripts/notificationCore/notificationCore.js b/scripts/communityScripts/notificationCore/notificationCore.js
index f7ab6e73cd..a085e3b15b 100644
--- a/scripts/communityScripts/notificationCore/notificationCore.js
+++ b/scripts/communityScripts/notificationCore/notificationCore.js
@@ -22,7 +22,12 @@ var DEFAULT_OFFSET = 10;
var FLOOF_NOTIFICATION_CHANNEL = "Floof-Notif";
var MAIN_CHAT_APP_CHANNEL = "Chat";
var ARROW_REGEX = /\ ")
color: "#ffffff"
font.pixelSize: 12
}
+ Button {
+ id: pasteBtn
+ text: "Paste"
+ font.pixelSize: 11
+ height: 16
+ width: 40
+ radius: 4
+ anchors.top: text1.top
+ anchors.left: text1.right
+ anchors.bottom: text1.bottom
+ onClicked: {
+ soundURL.paste()
+ }
+ }
+
TextInput {
id: soundURL
height: 20
text: qsTr("")
color: "white"
- anchors.top: text1.bottom
+ anchors.top: pasteBtn.bottom
anchors.topMargin: 5
anchors.left: parent.left
anchors.leftMargin: 0
diff --git a/scripts/system/graphicsSettings.js b/scripts/system/graphicsSettings.js
index df556a91b1..748eafca24 100644
--- a/scripts/system/graphicsSettings.js
+++ b/scripts/system/graphicsSettings.js
@@ -1,15 +1,20 @@
//
// graphicsSettings.js
//
-// Created by Kalila L. on 8/5/2020
+// Created by Kalila L. on August 5th, 2020
// Copyright 2020 Vircadia contributors.
+// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function() { // BEGIN LOCAL_SCOPE
-
+ var channelComm = "Overte-ShowGraphicsIconChanged";
+ var appStatus = false;
+ var GRAPHICS_HIDE_AND_SHOW_SETTING_KEY = "showGraphicsIcon";
+ var GRAPHICS_HIDE_AND_SHOW_DEFAULT_VALUE = true;
+
var AppUi = Script.require('appUi');
// cellphone-cog MDI
@@ -49,22 +54,49 @@
}
function startup() {
- ui = new AppUi({
- buttonName: BUTTON_NAME,
- sortOrder: 8,
- normalButton: getIcon(),
- activeButton: getIcon().replace('white', 'black'),
- home: GRAPHICS_QML_SOURCE
- });
+ if (!appStatus) {
+ ui = new AppUi({
+ buttonName: BUTTON_NAME,
+ sortOrder: 8,
+ normalButton: getIcon(),
+ activeButton: getIcon().replace('white', 'black'),
+ home: GRAPHICS_QML_SOURCE
+ });
+ }
+ appStatus = true;
}
function shutdown() {
+ if (appStatus) {
+ ui.onScriptEnding();
+ appStatus = false;
+ }
+ }
+
+ function cleanup() {
+ Messages.messageReceived.disconnect(onMessageReceived);
+ Messages.unsubscribe(channelComm);
+ }
+
+ function onMessageReceived(channel, message, sender, localOnly) {
+ if (channel === channelComm && localOnly) {
+ if (Settings.getValue(GRAPHICS_HIDE_AND_SHOW_SETTING_KEY, GRAPHICS_HIDE_AND_SHOW_DEFAULT_VALUE)) {
+ startup();
+ } else {
+ shutdown();
+ }
+ }
}
//
// Run the functions.
//
- startup();
- Script.scriptEnding.connect(shutdown);
+ if (Settings.getValue(GRAPHICS_HIDE_AND_SHOW_SETTING_KEY, GRAPHICS_HIDE_AND_SHOW_DEFAULT_VALUE)) {
+ startup();
+ }
+ Messages.subscribe(channelComm);
+ Messages.messageReceived.connect(onMessageReceived);
+
+ Script.scriptEnding.connect(cleanup);
}()); // END LOCAL_SCOPE
diff --git a/server-console/src/main.js b/server-console/src/main.js
index 496ee099dc..3f5783e21f 100644
--- a/server-console/src/main.js
+++ b/server-console/src/main.js
@@ -56,7 +56,7 @@ const menuNotificationIcon = path.join(__dirname, '../resources/tray-menu-notifi
const DELETE_LOG_FILES_OLDER_THAN_X_SECONDS = 60 * 60 * 24 * 7; // 7 Days
const LOG_FILE_REGEX = /(domain-server|ac-monitor|ac)-.*-std(out|err).txt/;
-const HOME_CONTENT_URL = "http://cdn-1.vircadia.com/us-e-1/DomainContent/Sandbox/Rearranged_Basic_Sandbox.tar.gz";
+const HOME_CONTENT_URL = "https://content.overte.org/DomainContent/Sandbox/Rearranged_Basic_Sandbox.tar.gz";
const buildInfo = GetBuildInfo();
diff --git a/tools/ci-scripts/linux-ci/Dockerfile_build_ubuntu-20.04 b/tools/ci-scripts/linux-ci/Dockerfile_build_ubuntu-20.04
index 12a56ced03..eb26d1b426 100644
--- a/tools/ci-scripts/linux-ci/Dockerfile_build_ubuntu-20.04
+++ b/tools/ci-scripts/linux-ci/Dockerfile_build_ubuntu-20.04
@@ -1,8 +1,8 @@
-# Copyright 2022-2023 Overte e.V.
+# Copyright 2022-2024 Overte e.V.
# SPDX-License-Identifier: Apache-2.0
# Docker file for building Overte
-# Example build: docker build -t overte/overte-full-build:0.1.1-ubuntu-20.04 -f Dockerfile_build_ubuntu-20.04 .
+# Example build: docker build -t overte/overte-full-build:0.1.2-ubuntu-20.04 -f Dockerfile_build_ubuntu-20.04 .
FROM ubuntu:20.04
LABEL maintainer="Julian Groß (julian.gro@overte.org)"
LABEL description="Development image for full Overte builds"
@@ -18,6 +18,8 @@ RUN apt-get update && apt-get -y install tzdata
RUN apt-get -y install curl ninja-build git cmake g++ libssl-dev python3-distutils python3-distro mesa-common-dev libgl1-mesa-dev libsystemd-dev
# Install server-console build dependencies
RUN apt-get -y install npm
+# Install Interface dependencies
+RUN apt-get -y install pkg-config libxext-dev libdouble-conversion-dev libpcre2-16-0 libpulse0 libharfbuzz-dev libnss3 libnspr4 libxdamage1 libasound2 vulkan-validationlayers libvulkan-dev libvulkan1
# Install tools for package creation
RUN apt-get -y install sudo chrpath binutils dh-make
diff --git a/tools/ci-scripts/linux-ci/Dockerfile_build_ubuntu-22.04 b/tools/ci-scripts/linux-ci/Dockerfile_build_ubuntu-22.04
index a80207471e..a4da419e87 100644
--- a/tools/ci-scripts/linux-ci/Dockerfile_build_ubuntu-22.04
+++ b/tools/ci-scripts/linux-ci/Dockerfile_build_ubuntu-22.04
@@ -1,8 +1,8 @@
-# Copyright 2022-2023 Overte e.V.
+# Copyright 2022-2024 Overte e.V.
# SPDX-License-Identifier: Apache-2.0
# Docker file for building Overte
-# Example build: docker build -t overte/overte-full-build:0.1.1-ubuntu-22.04 -f Dockerfile_build_ubuntu-22.04 .
+# Example build: docker build -t overte/overte-full-build:0.1.2-ubuntu-22.04 -f Dockerfile_build_ubuntu-22.04 .
FROM ubuntu:22.04
LABEL maintainer="Julian Groß (julian.gro@overte.org)"
LABEL description="Development image for full Overte builds"
@@ -19,7 +19,7 @@ RUN apt-get -y install curl ninja-build git cmake g++ libssl-dev libqt5websocket
# Install Overte tools build dependencies
RUN apt-get -y install libqt5webchannel5-dev qtwebengine5-dev libqt5xmlpatterns5-dev
# Install Overte Interface build dependencies
-RUN apt-get -y install libqt5svg5-dev qttools5-dev
+RUN apt-get -y install libqt5svg5-dev qttools5-dev vulkan-validationlayers libvulkan-dev libvulkan1 libqt5x11extras5-dev qtbase5-private-dev
# Install server-console build dependencies
RUN apt-get -y install npm
diff --git a/tools/ci-scripts/rpm_package/Dockerfile_build_fedora-39 b/tools/ci-scripts/rpm_package/Dockerfile_build_fedora-39
deleted file mode 100644
index ef5ef24819..0000000000
--- a/tools/ci-scripts/rpm_package/Dockerfile_build_fedora-39
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2022-2024 Overte e.V.
-# SPDX-License-Identifier: Apache-2.0
-
-# Docker file for building Overte Server
-# Example build: docker build -t overte/overte-server-build:0.1.4-fedora-39 -f Dockerfile_build_fedora-39 .
-FROM fedora:39
-LABEL maintainer="Julian Groß (julian.gro@overte.org)"
-LABEL description="Development image for Overte Domain server and assignment clients."
-
-# Install Overte domain-server and assignment-client build dependencies
-RUN dnf -y install curl ninja-build git cmake gcc gcc-c++ openssl-devel qt5-qtwebsockets-devel qt5-qtmultimedia-devel unzip libXext-devel qt5-qtwebchannel-devel qt5-qtwebengine-devel qt5-qtxmlpatterns-devel systemd-devel python3.11
-
-# Install additional build tools
-RUN dnf -y install zip unzip
-
-# Install tools for package creation
-RUN dnf -y install chrpath rpmdevtools
-
-# Install tools needed for our Github Actions Workflow
-Run dnf -y install python3-boto3 python3-pygithub
diff --git a/tools/jsdoc/plugins/hifi.js b/tools/jsdoc/plugins/hifi.js
index 7a789e39ee..595d0bc9c4 100644
--- a/tools/jsdoc/plugins/hifi.js
+++ b/tools/jsdoc/plugins/hifi.js
@@ -71,7 +71,7 @@ exports.handlers = {
];
// only files with this extension will be searched for jsdoc comments.
- var exts = ['.h', '.cpp'];
+ var exts = ['.h', '.h.in', '.cpp', '.cpp.in'];
var fs = require('fs');
dirList.forEach(function (dir) {
@@ -123,9 +123,9 @@ exports.handlers = {
// Append an Available In: sentence at the beginning of the namespace description.
if (rows.length > 0) {
var availableIn = "Supported Script Types: " + rows.join(" • ") + "
";
-
+
e.doclet.description = availableIn + (e.doclet.description ? e.doclet.description : "");
- }
+ }
}
if (e.doclet.kind === "function" && e.doclet.returns && e.doclet.returns[0].type
diff --git a/tools/qt-builder/Dockerfile_Ubuntu_20.04_Qt5 b/tools/qt-builder/Dockerfile_Ubuntu_20.04_Qt5
index 8c7e32f360..5639d662b6 100644
--- a/tools/qt-builder/Dockerfile_Ubuntu_20.04_Qt5
+++ b/tools/qt-builder/Dockerfile_Ubuntu_20.04_Qt5
@@ -4,11 +4,11 @@
# - Check which commit you are building https://invent.kde.org/qt/qt/qt5/-/tree/kde/5.15
# - Adjust this file to include the commit hash you are building, the date, the number of threads you want to use (-j10), the platform, and the Qt and QtWebEngine versions.
# Keep in mind that building Qt requires a lot of memory. You should have over 1.2GiB of system memory available per thread.
-# - Run the build process with something like `PROGRESS_NO_TRUNC=1 DOCKER_BUILDKIT=1 BUILDKIT_STEP_LOG_MAX_SIZE=-1 docker build --progress plain -t overte-qt5:5.15.14-2024.06.17-kde_570f5b2105df1ea052bec0d6dbf8a00137274371 -f Dockerfile_Ubuntu_20.04_Qt5 .`
+# - Run the build process with something like `PROGRESS_NO_TRUNC=1 DOCKER_BUILDKIT=1 BUILDKIT_STEP_LOG_MAX_SIZE=-1 docker build --progress plain -t overte-qt5:5.15.16-2024.12.14-kde_32be154325bfba3ad2ba8bf75dad702f3588e8d3 -f Dockerfile_Ubuntu_20.04_Qt5 .`
# Buildkit is used to cache intermittent steps in case you need to modify something afterwards.
# - Once the build has completed, create a container from the image and export the created Qt package.
-# `docker create --name extract overte-qt5:5.15.14-2024.06.17-kde_570f5b2105df1ea052bec0d6dbf8a00137274371`
-# `docker cp extract:qt5-install-5.15.14-2024.06.17-kde_570f5b2105df1ea052bec0d6dbf8a00137274371-ubuntu-20.04-amd64.tar.xz /path/on/host`
+# `docker create --name extract overte-qt5:5.15.16-2024.12.14-kde_32be154325bfba3ad2ba8bf75dad702f3588e8d3`
+# `docker cp extract:qt5-install-5.15.16-2024.12.14-kde_32be154325bfba3ad2ba8bf75dad702f3588e8d3-ubuntu-20.04-amd64.tar.xz /path/on/host`
# `docker rm extract`
FROM ubuntu:20.04
@@ -47,7 +47,7 @@ RUN apt-get -y install git python gperf flex bison pkg-config mesa-utils libgl1-
RUN mkdir qt5-install && mkdir qt5-build
WORKDIR qt5-build
-RUN ../qt5/configure -force-debug-info -release -opensource -confirm-license -platform linux-g++ -recheck-all -nomake tests -nomake examples -skip qttranslations -skip qtserialport -skip qt3d -skip qtlocation -skip qtwayland -skip qtsensors -skip qtgamepad -skip qtcharts -skip qtx11extras -skip qtmacextras -skip qtvirtualkeyboard -skip qtpurchasing -skip qtdatavis3d -skip qtlottie -skip qtquick3d -skip qtpim -skip qtdocgallery -no-warnings-are-errors -no-pch -no-icu -prefix ../qt5-install
+RUN ../qt5/configure -force-debug-info -release -opensource -confirm-license -platform linux-g++ -recheck-all -nomake tests -nomake examples -skip qttranslations -skip qtserialport -skip qt3d -skip qtlocation -skip qtwayland -skip qtsensors -skip qtgamepad -skip qtcharts -skip qtmacextras -skip qtvirtualkeyboard -skip qtpurchasing -skip qtdatavis3d -skip qtlottie -skip qtquick3d -skip qtpim -skip qtdocgallery -no-warnings-are-errors -no-pch -no-icu -prefix ../qt5-install
RUN NINJAFLAGS='-j6' make -j6
@@ -58,12 +58,12 @@ WORKDIR ../../qt5-install
RUN find . -name \*.prl -exec sed -i -e '/^QMAKE_PRL_BUILD_DIR/d' {} \;
# Overwrite QtWebengine version to work around version conflicts
-RUN find . -name \Qt5WebEngine*Config.cmake -exec sed -i '' -e 's/5\.15\.17/5\.15\.14/g' {} \;
-RUN cp lib/libQt5WebEngine.so.5.15.17 lib/libQt5WebEngine.so.5.15.14
-RUN cp lib/libQt5WebEngineCore.so.5.15.17 lib/libQt5WebEngineCore.so.5.15.14
-RUN cp lib/libQt5WebEngineWidgets.so.5.15.17 lib/libQt5WebEngineWidgets.so.5.15.14
-RUN cp lib/libQt5Pdf.so.5.15.17 lib/libQt5Pdf.so.5.15.14
-RUN cp lib/libQt5PdfWidgets.so.5.15.17 lib/libQt5PdfWidgets.so.5.15.14
+RUN find . -name \Qt5WebEngine*Config.cmake -exec sed -i '' -e 's/5\.15\.19/5\.15\.16/g' {} \;
+RUN cp lib/libQt5WebEngine.so.5.15.19 lib/libQt5WebEngine.so.5.15.16
+RUN cp lib/libQt5WebEngineCore.so.5.15.19 lib/libQt5WebEngineCore.so.5.15.16
+RUN cp lib/libQt5WebEngineWidgets.so.5.15.19 lib/libQt5WebEngineWidgets.so.5.15.16
+RUN cp lib/libQt5Pdf.so.5.15.19 lib/libQt5Pdf.so.5.15.16
+RUN cp lib/libQt5PdfWidgets.so.5.15.19 lib/libQt5PdfWidgets.so.5.15.16
COPY ./qt.conf ./bin/
@@ -71,4 +71,4 @@ COPY ./qt.conf ./bin/
RUN cp ../qt5-build/config.summary ./
WORKDIR ..
-RUN XZ_OPT='-T0' tar -Jcvf qt5-install-5.15.14-2024.06.17-kde_570f5b2105df1ea052bec0d6dbf8a00137274371-ubuntu-20.04-amd64.tar.xz qt5-install
+RUN XZ_OPT='-T0' tar -Jcvf qt5-install-5.15.16-2024.12.14-kde_32be154325bfba3ad2ba8bf75dad702f3588e8d3-ubuntu-20.04-amd64.tar.xz qt5-install