Merge remote-tracking branch 'upstream/master'

This commit is contained in:
ExMatics HydrogenC
2023-11-29 09:57:54 +08:00
39 changed files with 374 additions and 162 deletions

View File

@@ -25,6 +25,16 @@ namespace FlaxEditor.Content
/// </summary>
protected ContentFolder _folder;
/// <summary>
/// Whether this node can be deleted.
/// </summary>
public virtual bool CanDelete => true;
/// <summary>
/// Whether this node can be duplicated.
/// </summary>
public virtual bool CanDuplicate => true;
/// <summary>
/// Gets the content folder item.
/// </summary>
@@ -302,7 +312,7 @@ namespace FlaxEditor.Content
StartRenaming();
return true;
case KeyboardKeys.Delete:
if (Folder.Exists)
if (Folder.Exists && CanDelete)
Editor.Instance.Windows.ContentWin.Delete(Folder);
return true;
}
@@ -311,7 +321,7 @@ namespace FlaxEditor.Content
switch (key)
{
case KeyboardKeys.D:
if (Folder.Exists)
if (Folder.Exists && CanDuplicate)
Editor.Instance.Windows.ContentWin.Duplicate(Folder);
return true;
}

View File

@@ -12,6 +12,12 @@ namespace FlaxEditor.Content
{
private FileSystemWatcher _watcher;
/// <inheritdoc />
public override bool CanDelete => false;
/// <inheritdoc />
public override bool CanDuplicate => false;
/// <summary>
/// Initializes a new instance of the <see cref="MainContentTreeNode"/> class.
/// </summary>

View File

@@ -114,18 +114,32 @@ namespace FlaxEditor.Windows
}
}
cm.AddButton("Delete", () => Delete(item));
if (isFolder && folder.Node is MainContentTreeNode)
{
cm.AddSeparator();
}
else
{
cm.AddButton("Delete", () => Delete(item));
cm.AddSeparator();
cm.AddSeparator();
cm.AddButton("Duplicate", _view.Duplicate);
cm.AddButton("Duplicate", _view.Duplicate);
cm.AddButton("Copy", _view.Copy);
cm.AddButton("Copy", _view.Copy);
}
b = cm.AddButton("Paste", _view.Paste);
b.Enabled = _view.CanPaste();
cm.AddButton("Rename", () => Rename(item));
if (isFolder && folder.Node is MainContentTreeNode)
{
// Do nothing
}
else
{
cm.AddButton("Rename", () => Rename(item));
}
// Custom options
ContextMenuShow?.Invoke(cm, item);

View File

@@ -25,6 +25,19 @@ private:
int32 _capacity;
AllocationData _allocation;
FORCE_INLINE static void MoveToEmpty(AllocationData& to, AllocationData& from, int32 fromCount, int32 fromCapacity)
{
if IF_CONSTEXPR (AllocationType::HasSwap)
to.Swap(from);
else
{
to.Allocate(fromCapacity);
Memory::MoveItems(to.Get(), from.Get(), fromCount);
Memory::DestructItems(from.Get(), fromCount);
from.Free();
}
}
public:
/// <summary>
/// Initializes a new instance of the <see cref="Array"/> class.
@@ -134,7 +147,7 @@ public:
_capacity = other._capacity;
other._count = 0;
other._capacity = 0;
_allocation.Swap(other._allocation);
MoveToEmpty(_allocation, other._allocation, _count, _capacity);
}
/// <summary>
@@ -191,7 +204,7 @@ public:
_capacity = other._capacity;
other._count = 0;
other._capacity = 0;
_allocation.Swap(other._allocation);
MoveToEmpty(_allocation, other._allocation, _count, _capacity);
}
return *this;
}
@@ -713,9 +726,18 @@ public:
/// <param name="other">The other collection.</param>
void Swap(Array& other)
{
::Swap(_count, other._count);
::Swap(_capacity, other._capacity);
_allocation.Swap(other._allocation);
if IF_CONSTEXPR (AllocationType::HasSwap)
{
_allocation.Swap(other._allocation);
::Swap(_count, other._count);
::Swap(_capacity, other._capacity);
}
else
{
Array tmp = MoveTemp(other);
other = *this;
*this = MoveTemp(tmp);
}
}
/// <summary>
@@ -726,9 +748,7 @@ public:
T* data = _allocation.Get();
const int32 count = _count / 2;
for (int32 i = 0; i < count; i++)
{
::Swap(data[i], data[_count - i - 1]);
}
}
public:

View File

@@ -110,6 +110,33 @@ private:
int32 _size = 0;
AllocationData _allocation;
FORCE_INLINE static void MoveToEmpty(AllocationData& to, AllocationData& from, int32 fromSize)
{
if IF_CONSTEXPR (AllocationType::HasSwap)
to.Swap(from);
else
{
to.Allocate(fromSize);
Bucket* toData = to.Get();
Bucket* fromData = from.Get();
for (int32 i = 0; i < fromSize; i++)
{
Bucket& fromBucket = fromData[i];
if (fromBucket.IsOccupied())
{
Bucket& toBucket = toData[i];
Memory::MoveItems(&toBucket.Key, &fromBucket.Key, 1);
Memory::MoveItems(&toBucket.Value, &fromBucket.Value, 1);
toBucket._state = Bucket::Occupied;
Memory::DestructItem(&fromBucket.Key);
Memory::DestructItem(&fromBucket.Value);
fromBucket._state = Bucket::Empty;
}
}
from.Free();
}
}
public:
/// <summary>
/// Initializes a new instance of the <see cref="Dictionary"/> class.
@@ -139,7 +166,7 @@ public:
other._elementsCount = 0;
other._deletedCount = 0;
other._size = 0;
_allocation.Swap(other._allocation);
MoveToEmpty(_allocation, other._allocation, _size);
}
/// <summary>
@@ -180,7 +207,7 @@ public:
other._elementsCount = 0;
other._deletedCount = 0;
other._size = 0;
_allocation.Swap(other._allocation);
MoveToEmpty(_allocation, other._allocation, _size);
}
return *this;
}
@@ -510,7 +537,7 @@ public:
return;
ASSERT(capacity >= 0);
AllocationData oldAllocation;
oldAllocation.Swap(_allocation);
MoveToEmpty(oldAllocation, _allocation, _size);
const int32 oldSize = _size;
const int32 oldElementsCount = _elementsCount;
_deletedCount = _elementsCount = 0;
@@ -580,10 +607,19 @@ public:
/// <param name="other">The other collection.</param>
void Swap(Dictionary& other)
{
::Swap(_elementsCount, other._elementsCount);
::Swap(_deletedCount, other._deletedCount);
::Swap(_size, other._size);
_allocation.Swap(other._allocation);
if IF_CONSTEXPR (AllocationType::HasSwap)
{
::Swap(_elementsCount, other._elementsCount);
::Swap(_deletedCount, other._deletedCount);
::Swap(_size, other._size);
_allocation.Swap(other._allocation);
}
else
{
Dictionary tmp = MoveTemp(other);
other = *this;
*this = MoveTemp(tmp);
}
}
public:
@@ -930,7 +966,7 @@ private:
{
// Rebuild entire table completely
AllocationData oldAllocation;
oldAllocation.Swap(_allocation);
MoveToEmpty(oldAllocation, _allocation, _size);
_allocation.Allocate(_size);
Bucket* data = _allocation.Get();
for (int32 i = 0; i < _size; i++)

View File

@@ -93,6 +93,31 @@ private:
int32 _size = 0;
AllocationData _allocation;
FORCE_INLINE static void MoveToEmpty(AllocationData& to, AllocationData& from, int32 fromSize)
{
if IF_CONSTEXPR (AllocationType::HasSwap)
to.Swap(from);
else
{
to.Allocate(fromSize);
Bucket* toData = to.Get();
Bucket* fromData = from.Get();
for (int32 i = 0; i < fromSize; i++)
{
Bucket& fromBucket = fromData[i];
if (fromBucket.IsOccupied())
{
Bucket& toBucket = toData[i];
Memory::MoveItems(&toBucket.Item, &fromBucket.Item, 1);
toBucket._state = Bucket::Occupied;
Memory::DestructItem(&fromBucket.Item);
fromBucket._state = Bucket::Empty;
}
}
from.Free();
}
}
public:
/// <summary>
/// Initializes a new instance of the <see cref="HashSet"/> class.
@@ -122,7 +147,7 @@ public:
other._elementsCount = 0;
other._deletedCount = 0;
other._size = 0;
_allocation.Swap(other._allocation);
MoveToEmpty(_allocation, other._allocation, _size);
}
/// <summary>
@@ -163,7 +188,7 @@ public:
other._elementsCount = 0;
other._deletedCount = 0;
other._size = 0;
_allocation.Swap(other._allocation);
MoveToEmpty(_allocation, other._allocation, _size);
}
return *this;
}
@@ -389,7 +414,7 @@ public:
return;
ASSERT(capacity >= 0);
AllocationData oldAllocation;
oldAllocation.Swap(_allocation);
MoveToEmpty(oldAllocation, _allocation, _size);
const int32 oldSize = _size;
const int32 oldElementsCount = _elementsCount;
_deletedCount = _elementsCount = 0;
@@ -458,10 +483,19 @@ public:
/// <param name="other">The other collection.</param>
void Swap(HashSet& other)
{
::Swap(_elementsCount, other._elementsCount);
::Swap(_deletedCount, other._deletedCount);
::Swap(_size, other._size);
_allocation.Swap(other._allocation);
if IF_CONSTEXPR (AllocationType::HasSwap)
{
::Swap(_elementsCount, other._elementsCount);
::Swap(_deletedCount, other._deletedCount);
::Swap(_size, other._size);
_allocation.Swap(other._allocation);
}
else
{
HashSet tmp = MoveTemp(other);
other = *this;
*this = MoveTemp(tmp);
}
}
public:
@@ -726,7 +760,7 @@ private:
{
// Rebuild entire table completely
AllocationData oldAllocation;
oldAllocation.Swap(_allocation);
MoveToEmpty(oldAllocation, _allocation, _size);
_allocation.Allocate(_size);
Bucket* data = _allocation.Get();
for (int32 i = 0; i < _size; i++)

View File

@@ -93,3 +93,10 @@
#endif
#define PACK_STRUCT(__Declaration__) PACK_BEGIN() __Declaration__ PACK_END()
// C++ 17
#if __cplusplus >= 201703L
#define IF_CONSTEXPR constexpr
#else
#define IF_CONSTEXPR
#endif

View File

@@ -12,6 +12,8 @@ template<int Capacity>
class FixedAllocation
{
public:
enum { HasSwap = false };
template<typename T>
class Data
{
@@ -61,12 +63,9 @@ public:
{
}
FORCE_INLINE void Swap(Data& other)
void Swap(Data& other)
{
byte tmp[Capacity * sizeof(T)];
Platform::MemoryCopy(tmp, _data, Capacity * sizeof(T));
Platform::MemoryCopy(_data, other._data, Capacity * sizeof(T));
Platform::MemoryCopy(other._data, tmp, Capacity * sizeof(T));
// Not supported
}
};
};
@@ -77,6 +76,8 @@ public:
class HeapAllocation
{
public:
enum { HasSwap = true };
template<typename T>
class Data
{
@@ -179,6 +180,8 @@ template<int Capacity, typename OtherAllocator = HeapAllocation>
class InlinedAllocation
{
public:
enum { HasSwap = false };
template<typename T>
class Data
{
@@ -267,14 +270,9 @@ public:
}
}
FORCE_INLINE void Swap(Data& other)
void Swap(Data& other)
{
byte tmp[Capacity * sizeof(T)];
Platform::MemoryCopy(tmp, _data, Capacity * sizeof(T));
Platform::MemoryCopy(_data, other._data, Capacity * sizeof(T));
Platform::MemoryCopy(other._data, tmp, Capacity * sizeof(T));
::Swap(_useOther, other._useOther);
_other.Swap(other._other);
// Not supported
}
};
};

View File

@@ -522,7 +522,13 @@ void EngineImpl::InitLog()
LOG(Info, "Compiled for Dev Environment");
#endif
LOG(Info, "Version " FLAXENGINE_VERSION_TEXT);
LOG(Info, "Compiled: {0} {1}", TEXT(__DATE__), TEXT(__TIME__));
const Char* cpp = TEXT("?");
if (__cplusplus == 202101L) cpp = TEXT("C++23");
else if (__cplusplus == 202002L) cpp = TEXT("C++20");
else if (__cplusplus == 201703L) cpp = TEXT("C++17");
else if (__cplusplus == 201402L) cpp = TEXT("C++14");
else if (__cplusplus == 201103L) cpp = TEXT("C++11");
LOG(Info, "Compiled: {0} {1} {2}", TEXT(__DATE__), TEXT(__TIME__), cpp);
#ifdef _MSC_VER
const String mcsVer = StringUtils::ToString(_MSC_FULL_VER);
LOG(Info, "Compiled with Visual C++ {0}.{1}.{2}.{3:0^2d}", mcsVer.Substring(0, 2), mcsVer.Substring(2, 2), mcsVer.Substring(4, 5), _MSC_BUILD);

View File

@@ -1271,6 +1271,9 @@ namespace FlaxEngine.Interop
case Type _ when type == typeof(IntPtr):
monoType = MTypes.Ptr;
break;
case Type _ when type.IsPointer:
monoType = MTypes.Ptr;
break;
case Type _ when type.IsEnum:
monoType = MTypes.Enum;
break;

View File

@@ -1112,11 +1112,9 @@ namespace FlaxEngine.Interop
internal static void ToManagedPointer(ref IntPtr managedValue, IntPtr nativePtr, bool byRef)
{
Type type = typeof(T);
byRef |= type.IsByRef; // Is this needed?
if (type.IsByRef)
Assert.IsTrue(type.GetElementType().IsValueType);
managedValue = byRef ? nativePtr : Unsafe.Read<IntPtr>(nativePtr.ToPointer());
if (byRef)
nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
managedValue = nativePtr;
}
internal static void ToManagedHandle(ref ManagedHandle managedValue, IntPtr nativePtr, bool byRef)
@@ -1135,7 +1133,7 @@ namespace FlaxEngine.Interop
marshallers[i](fields[i], offsets[i], ref managedValue, fieldPtr, out int fieldSize);
fieldPtr += fieldSize;
}
Assert.IsTrue((fieldPtr - nativePtr) <= Unsafe.SizeOf<T>());
//Assert.IsTrue((fieldPtr - nativePtr) <= GetTypeSize(typeof(T)));
}
internal static void ToManaged(ref T managedValue, IntPtr nativePtr, bool byRef)
@@ -1182,7 +1180,7 @@ namespace FlaxEngine.Interop
marshallers[i](fields[i], offsets[i], ref managedValue, nativePtr, out int fieldSize);
nativePtr += fieldSize;
}
Assert.IsTrue((nativePtr - fieldPtr) <= Unsafe.SizeOf<T>());
//Assert.IsTrue((nativePtr - fieldPtr) <= GetTypeSize(typeof(T)));
}
internal static void ToNative(ref T managedValue, IntPtr nativePtr)
@@ -1580,7 +1578,7 @@ namespace FlaxEngine.Interop
private static IntPtr PinValue<T>(T value) where T : struct
{
// Store the converted value in unmanaged memory so it will not be relocated by the garbage collector.
int size = Unsafe.SizeOf<T>();
int size = GetTypeSize(typeof(T));
uint index = Interlocked.Increment(ref pinnedAllocationsPointer) % (uint)pinnedAllocations.Length;
ref (IntPtr ptr, int size) alloc = ref pinnedAllocations[index];
if (alloc.size < size)

View File

@@ -63,7 +63,6 @@ StreamingTexture::~StreamingTexture()
{
UnloadTexture();
SAFE_DELETE(_texture);
ASSERT(_streamingTasks.Count() == 0);
}
Float2 StreamingTexture::Size() const
@@ -134,11 +133,9 @@ bool StreamingTexture::Create(const TextureHeader& header)
void StreamingTexture::UnloadTexture()
{
ScopeLock lock(_owner->GetOwnerLocker());
// Release
CancelStreamingTasks();
_texture->ReleaseGPU();
_header.MipLevels = 0;
ASSERT(_streamingTasks.Count() == 0);
}

View File

@@ -162,7 +162,7 @@ void ENetDriver::Disconnect(const NetworkConnection& connection)
}
}
bool ENetDriver::PopEvent(NetworkEvent* eventPtr)
bool ENetDriver::PopEvent(NetworkEvent& eventPtr)
{
ASSERT(_host);
ENetEvent event;
@@ -173,30 +173,30 @@ bool ENetDriver::PopEvent(NetworkEvent* eventPtr)
{
// Copy sender data
const uint32 connectionId = enet_peer_get_id(event.peer);
eventPtr->Sender.ConnectionId = connectionId;
eventPtr.Sender.ConnectionId = connectionId;
switch (event.type)
{
case ENET_EVENT_TYPE_CONNECT:
eventPtr->EventType = NetworkEventType::Connected;
eventPtr.EventType = NetworkEventType::Connected;
if (IsServer())
_peerMap.Add(connectionId, event.peer);
break;
case ENET_EVENT_TYPE_DISCONNECT:
eventPtr->EventType = NetworkEventType::Disconnected;
eventPtr.EventType = NetworkEventType::Disconnected;
if (IsServer())
_peerMap.Remove(connectionId);
break;
case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT:
eventPtr->EventType = NetworkEventType::Timeout;
eventPtr.EventType = NetworkEventType::Timeout;
if (IsServer())
_peerMap.Remove(connectionId);
break;
case ENET_EVENT_TYPE_RECEIVE:
eventPtr->EventType = NetworkEventType::Message;
eventPtr->Message = _networkHost->CreateMessage();
eventPtr->Message.Length = event.packet->dataLength;
Platform::MemoryCopy(eventPtr->Message.Buffer, event.packet->data, event.packet->dataLength);
eventPtr.EventType = NetworkEventType::Message;
eventPtr.Message = _networkHost->CreateMessage();
eventPtr.Message.Length = event.packet->dataLength;
Platform::MemoryCopy(eventPtr.Message.Buffer, event.packet->data, event.packet->dataLength);
break;
default:
break;

View File

@@ -29,7 +29,7 @@ public:
bool Connect() override;
void Disconnect() override;
void Disconnect(const NetworkConnection& connection) override;
bool PopEvent(NetworkEvent* eventPtr) override;
bool PopEvent(NetworkEvent& eventPtr) override;
void SendMessage(NetworkChannelType channelType, const NetworkMessage& message) override;
void SendMessage(NetworkChannelType channelType, const NetworkMessage& message, NetworkConnection target) override;
void SendMessage(NetworkChannelType channelType, const NetworkMessage& message, const Array<NetworkConnection, HeapAllocation>& targets) override;

View File

@@ -92,7 +92,7 @@ void NetworkLagDriver::Disconnect(const NetworkConnection& connection)
_driver->Disconnect(connection);
}
bool NetworkLagDriver::PopEvent(NetworkEvent* eventPtr)
bool NetworkLagDriver::PopEvent(NetworkEvent& eventPtr)
{
if (!_driver)
return false;
@@ -104,7 +104,7 @@ bool NetworkLagDriver::PopEvent(NetworkEvent* eventPtr)
if (e.Lag > 0.0)
continue;
*eventPtr = e.Event;
eventPtr = e.Event;
_events.RemoveAtKeepOrder(i);
return true;
}
@@ -117,7 +117,7 @@ bool NetworkLagDriver::PopEvent(NetworkEvent* eventPtr)
auto& e = _events.AddOne();
e.Lag = (double)Lag;
e.Event = *eventPtr;
e.Event = eventPtr;
}
return false;
}

View File

@@ -68,7 +68,7 @@ public:
bool Connect() override;
void Disconnect() override;
void Disconnect(const NetworkConnection& connection) override;
bool PopEvent(NetworkEvent* eventPtr) override;
bool PopEvent(NetworkEvent& eventPtr) override;
void SendMessage(NetworkChannelType channelType, const NetworkMessage& message) override;
void SendMessage(NetworkChannelType channelType, const NetworkMessage& message, NetworkConnection target) override;
void SendMessage(NetworkChannelType channelType, const NetworkMessage& message, const Array<NetworkConnection, HeapAllocation>& targets) override;

View File

@@ -71,7 +71,7 @@ public:
/// </summary>
/// <param name="eventPtr">The pointer to event structure.</param>
/// <returns>True when succeeded and the event can be processed.</returns>
API_FUNCTION() virtual bool PopEvent(NetworkEvent* eventPtr) = 0;
API_FUNCTION() virtual bool PopEvent(API_PARAM(Out) NetworkEvent& eventPtr) = 0;
/// <summary>
/// Sends given message over specified channel to the server.

View File

@@ -10,13 +10,19 @@
API_STRUCT(Namespace="FlaxEngine.Networking") struct FLAXENGINE_API NetworkConnection
{
DECLARE_SCRIPTING_TYPE_MINIMAL(NetworkConnection);
public:
/// <summary>
/// The identifier of the connection.
/// </summary>
/// <remarks>Used by network driver implementations.</remarks>
API_FIELD()
uint32 ConnectionId;
API_FIELD() uint32 ConnectionId;
};
template<>
struct TIsPODType<NetworkConnection>
{
enum { Value = true };
};
inline bool operator==(const NetworkConnection& a, const NetworkConnection& b)

View File

@@ -43,24 +43,28 @@ API_ENUM(Namespace="FlaxEngine.Networking") enum class NetworkEventType
API_STRUCT(Namespace="FlaxEngine.Networking") struct FLAXENGINE_API NetworkEvent
{
DECLARE_SCRIPTING_TYPE_MINIMAL(NetworkEvent);
public:
/// <summary>
/// The type of the received event.
/// </summary>
API_FIELD();
NetworkEventType EventType;
API_FIELD() NetworkEventType EventType;
/// <summary>
/// The message when this event is an "message" event - not valid in any other cases.
/// If this is an message-event, make sure to return the message using RecycleMessage function of the peer after processing it!
/// </summary>
API_FIELD();
NetworkMessage Message;
API_FIELD() NetworkMessage Message;
/// <summary>
/// The connected of the client that has sent message, connected, disconnected or got a timeout.
/// </summary>
/// <remarks>Only valid when event has been received on server-peer.</remarks>
API_FIELD();
NetworkConnection Sender;
API_FIELD() NetworkConnection Sender;
};
template<>
struct TIsPODType<NetworkEvent>
{
enum { Value = true };
};

View File

@@ -382,7 +382,8 @@ void NetworkManagerService::Update()
// Process network messages
NetworkEvent event;
while (peer->PopEvent(event))
bool eventIsValid = true;
while (peer->PopEvent(event) && eventIsValid)
{
switch (event.EventType)
{
@@ -472,6 +473,9 @@ void NetworkManagerService::Update()
}
peer->RecycleMessage(event.Message);
break;
default:
eventIsValid = false;
break;
}
}

View File

@@ -134,7 +134,7 @@ void NetworkPeer::Disconnect(const NetworkConnection& connection)
bool NetworkPeer::PopEvent(NetworkEvent& eventRef)
{
PROFILE_CPU();
return NetworkDriver->PopEvent(&eventRef);
return NetworkDriver->PopEvent(eventRef);
}
NetworkMessage NetworkPeer::CreateMessage()

View File

@@ -37,30 +37,26 @@ public:
/// Once this is called, this peer becomes a server.
/// </summary>
/// <returns>True when succeeded.</returns>
API_FUNCTION()
bool Listen();
API_FUNCTION() bool Listen();
/// <summary>
/// Starts connection handshake with the end point specified in the <seealso cref="NetworkConfig"/> structure.
/// Once this is called, this peer becomes a client.
/// </summary>
/// <returns>True when succeeded.</returns>
API_FUNCTION()
bool Connect();
API_FUNCTION() bool Connect();
/// <summary>
/// Disconnects from the server.
/// </summary>
/// <remarks>Can be used only by the client!</remarks>
API_FUNCTION()
void Disconnect();
API_FUNCTION() void Disconnect();
/// <summary>
/// Disconnects given connection from the server.
/// </summary>
/// <remarks>Can be used only by the server!</remarks>
API_FUNCTION()
void Disconnect(const NetworkConnection& connection);
API_FUNCTION() void Disconnect(const NetworkConnection& connection);
/// <summary>
/// Tries to pop an network event from the queue.
@@ -68,8 +64,7 @@ public:
/// <param name="eventRef">The reference to event structure.</param>
/// <returns>True when succeeded and the event can be processed.</returns>
/// <remarks>If this returns message event, make sure to recycle the message using <see cref="RecycleMessage"/> function after processing it!</remarks>
API_FUNCTION()
bool PopEvent(API_PARAM(out) NetworkEvent& eventRef);
API_FUNCTION() bool PopEvent(API_PARAM(Out) NetworkEvent& eventRef);
/// <summary>
/// Acquires new message from the pool.
@@ -77,29 +72,25 @@ public:
/// </summary>
/// <returns>The acquired message.</returns>
/// <remarks>Make sure to recycle the message to this peer once it is no longer needed!</remarks>
API_FUNCTION()
NetworkMessage CreateMessage();
API_FUNCTION() NetworkMessage CreateMessage();
/// <summary>
/// Returns given message to the pool.
/// </summary>
/// <remarks>Make sure that this message belongs to the peer and has not been recycled already (debug build checks for this)!</remarks>
API_FUNCTION()
void RecycleMessage(const NetworkMessage& message);
API_FUNCTION() void RecycleMessage(const NetworkMessage& message);
/// <summary>
/// Acquires new message from the pool and setups it for sending.
/// </summary>
/// <returns>The acquired message.</returns>
API_FUNCTION()
NetworkMessage BeginSendMessage();
API_FUNCTION() NetworkMessage BeginSendMessage();
/// <summary>
/// Aborts given message send. This effectively deinitializes the message and returns it to the pool.
/// </summary>
/// <param name="message">The message.</param>
API_FUNCTION()
void AbortSendMessage(const NetworkMessage& message);
API_FUNCTION() void AbortSendMessage(const NetworkMessage& message);
/// <summary>
/// Sends given message over specified channel to the server.
@@ -111,8 +102,7 @@ public:
/// Do not recycle the message after calling this.
/// This function automatically recycles the message.
/// </remarks>
API_FUNCTION()
bool EndSendMessage(NetworkChannelType channelType, const NetworkMessage& message);
API_FUNCTION() bool EndSendMessage(NetworkChannelType channelType, const NetworkMessage& message);
/// <summary>
/// Sends given message over specified channel to the given client connection (target).
@@ -125,8 +115,7 @@ public:
/// Do not recycle the message after calling this.
/// This function automatically recycles the message.
/// </remarks>
API_FUNCTION()
bool EndSendMessage(NetworkChannelType channelType, const NetworkMessage& message, const NetworkConnection& target);
API_FUNCTION() bool EndSendMessage(NetworkChannelType channelType, const NetworkMessage& message, const NetworkConnection& target);
/// <summary>
/// Sends given message over specified channel to the given client connection (target).
@@ -139,8 +128,7 @@ public:
/// Do not recycle the message after calling this.
/// This function automatically recycles the message.
/// </remarks>
API_FUNCTION()
bool EndSendMessage(NetworkChannelType channelType, const NetworkMessage& message, const Array<NetworkConnection, HeapAllocation>& targets);
API_FUNCTION() bool EndSendMessage(NetworkChannelType channelType, const NetworkMessage& message, const Array<NetworkConnection, HeapAllocation>& targets);
/// <summary>
/// Creates new peer using given configuration.
@@ -148,15 +136,13 @@ public:
/// <param name="config">The configuration to create and setup new peer.</param>
/// <returns>The peer.</returns>
/// <remarks>Peer should be destroyed using <see cref="ShutdownPeer"/> once it is no longer in use. Returns null if failed to create a peer (eg. config is invalid).</remarks>
API_FUNCTION()
static NetworkPeer* CreatePeer(const NetworkConfig& config);
API_FUNCTION() static NetworkPeer* CreatePeer(const NetworkConfig& config);
/// <summary>
/// Shutdowns and destroys given peer.
/// </summary>
/// <param name="peer">The peer to destroy.</param>
API_FUNCTION()
static void ShutdownPeer(NetworkPeer* peer);
API_FUNCTION() static void ShutdownPeer(NetworkPeer* peer);
public:
bool IsValid() const

View File

@@ -11,6 +11,8 @@ public:
static FLAXENGINE_API void* Allocate(uintptr size);
static FLAXENGINE_API void Free(void* ptr, uintptr size);
enum { HasSwap = true };
template<typename T>
class Data
{

View File

@@ -18,7 +18,7 @@ private:
#elif USE_NETCORE
void* _handle;
StringAnsi _name;
StringAnsi _namespace_;
StringAnsi _namespace;
uint32 _types = 0;
mutable uint32 _size = 0;
#endif

View File

@@ -1208,6 +1208,10 @@ void* MUtils::VariantToManagedArgPtr(Variant& value, MType* type, bool& failed)
object = nullptr;
return object;
}
case MTypes::Ptr:
if (value.Type.Type == VariantType::Null)
return nullptr;
return (void*)value;
default:
break;
}

View File

@@ -118,7 +118,7 @@ struct MConverter<String>
{
MString** dataPtr = MCore::Array::GetAddress<MString*>(data);
for (int32 i = 0; i < result.Length(); i++)
MUtils::ToString(dataPtr[i], result[i]);
MUtils::ToString(dataPtr[i], result.Get()[i]);
}
};
@@ -151,7 +151,7 @@ struct MConverter<StringAnsi>
{
MString** dataPtr = MCore::Array::GetAddress<MString*>(data);
for (int32 i = 0; i < result.Length(); i++)
MUtils::ToString(dataPtr[i], result[i]);
MUtils::ToString(dataPtr[i], result.Get()[i]);
}
};
@@ -184,7 +184,7 @@ struct MConverter<StringView>
{
MString** dataPtr = MCore::Array::GetAddress<MString*>(data);
for (int32 i = 0; i < result.Length(); i++)
MUtils::ToString(dataPtr[i], result[i]);
MUtils::ToString(dataPtr[i], result.Get()[i]);
}
};
@@ -217,7 +217,7 @@ struct MConverter<Variant>
{
MObject** dataPtr = MCore::Array::GetAddress<MObject*>(data);
for (int32 i = 0; i < result.Length(); i++)
result[i] = MUtils::UnboxVariant(dataPtr[i]);
result.Get()[i] = MUtils::UnboxVariant(dataPtr[i]);
}
};
@@ -250,7 +250,7 @@ struct MConverter<T*, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Va
{
MObject** dataPtr = MCore::Array::GetAddress<MObject*>(data);
for (int32 i = 0; i < result.Length(); i++)
result[i] = (T*)ScriptingObject::ToNative(dataPtr[i]);
result.Get()[i] = (T*)ScriptingObject::ToNative(dataPtr[i]);
}
};
@@ -307,7 +307,7 @@ struct MConverter<ScriptingObjectReference<T>>
{
MObject** dataPtr = MCore::Array::GetAddress<MObject*>(data);
for (int32 i = 0; i < result.Length(); i++)
result[i] = (T*)ScriptingObject::ToNative(dataPtr[i]);
result.Get()[i] = (T*)ScriptingObject::ToNative(dataPtr[i]);
}
};
@@ -343,7 +343,7 @@ struct MConverter<AssetReference<T>>
{
MObject** dataPtr = MCore::Array::GetAddress<MObject*>(data);
for (int32 i = 0; i < result.Length(); i++)
result[i] = (T*)ScriptingObject::ToNative(dataPtr[i]);
result.Get()[i] = (T*)ScriptingObject::ToNative(dataPtr[i]);
}
};

View File

@@ -836,7 +836,7 @@ bool MAssembly::UnloadImage(bool isReloading)
MClass::MClass(const MAssembly* parentAssembly, void* handle, const char* name, const char* fullname, const char* namespace_, MTypeAttributes attributes)
: _handle(handle)
, _name(name)
, _namespace_(namespace_)
, _namespace(namespace_)
, _assembly(parentAssembly)
, _fullname(fullname)
, _hasCachedProperties(false)
@@ -915,7 +915,7 @@ StringAnsiView MClass::GetName() const
StringAnsiView MClass::GetNamespace() const
{
return _namespace_;
return _namespace;
}
MType* MClass::GetType() const

View File

@@ -20,10 +20,7 @@ public class Scripting : EngineModule
void AddFrameworkDefines(string template, int major, int latestMinor)
{
for (int minor = latestMinor; minor >= 0; minor--)
{
options.ScriptingAPI.Defines.Add(string.Format(template, major, minor));
options.ScriptingAPI.Defines.Add(string.Format($"{template}_OR_GREATER", major, minor));
}
}
// .NET
@@ -31,14 +28,15 @@ public class Scripting : EngineModule
options.ScriptingAPI.Defines.Add("USE_NETCORE");
// .NET SDK
AddFrameworkDefines("NET{0}_{1}", 7, 0); // "NET7_0" and "NET7_0_OR_GREATER"
AddFrameworkDefines("NET{0}_{1}", 6, 0);
AddFrameworkDefines("NET{0}_{1}", 5, 0);
var dotnetSdk = DotNetSdk.Instance;
options.ScriptingAPI.Defines.Add("NET");
AddFrameworkDefines("NETCOREAPP{0}_{1}", 3, 1); // "NETCOREAPP3_1" and "NETCOREAPP3_1_OR_GREATER"
AddFrameworkDefines("NETCOREAPP{0}_{1}", 2, 2);
AddFrameworkDefines("NETCOREAPP{0}_{1}", 1, 1);
AddFrameworkDefines("NET{0}_{1}", dotnetSdk.Version.Major, 0); // "NET7_0"
for (int i = 5; i <= dotnetSdk.Version.Major; i++)
AddFrameworkDefines("NET{0}_{1}_OR_GREATER", dotnetSdk.Version.Major, 0); // "NET7_0_OR_GREATER"
options.ScriptingAPI.Defines.Add("NETCOREAPP");
AddFrameworkDefines("NETCOREAPP{0}_{1}_OR_GREATER", 3, 1); // "NETCOREAPP3_1_OR_GREATER"
AddFrameworkDefines("NETCOREAPP{0}_{1}_OR_GREATER", 2, 2);
AddFrameworkDefines("NETCOREAPP{0}_{1}_OR_GREATER", 1, 1);
if (options.Target is EngineTarget engineTarget && engineTarget.UseSeparateMainExecutable(options))
{

View File

@@ -441,6 +441,23 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value)
break;
}
}
// Channel masking
switch (box->ID)
{
case 2:
value = value.GetX();
break;
case 3:
value = value.GetY();
break;
case 4:
value = value.GetZ();
break;
case 5:
value = value.GetW();
break;
}
break;
}
// Scene Color

View File

@@ -271,6 +271,48 @@ ShaderGraphValue ShaderGraphValue::InitForOne(VariantType::Types type)
return ShaderGraphValue(type, String(v));
}
ShaderGraphValue ShaderGraphValue::GetY() const
{
switch (Type)
{
case VariantType::Float2:
case VariantType::Float3:
case VariantType::Float4:
case VariantType::Double2:
case VariantType::Double3:
case VariantType::Double4:
return ShaderGraphValue(VariantType::Types::Float, Value + _subs[1]);
default:
return Zero;
}
}
ShaderGraphValue ShaderGraphValue::GetZ() const
{
switch (Type)
{
case VariantType::Float3:
case VariantType::Float4:
case VariantType::Double3:
case VariantType::Double4:
return ShaderGraphValue(VariantType::Types::Float, Value + _subs[2]);
default:
return Zero;
}
}
ShaderGraphValue ShaderGraphValue::GetW() const
{
switch (Type)
{
case VariantType::Float4:
case VariantType::Double4:
return ShaderGraphValue(VariantType::Types::Float, Value + _subs[3]);
default:
return One;
}
}
ShaderGraphValue ShaderGraphValue::Cast(const ShaderGraphValue& v, VariantType::Types to)
{
// If they are the same types or input value is empty, then just return value

View File

@@ -318,28 +318,19 @@ public:
/// Gets the Y component of the value. Valid only for vector types.
/// </summary>
/// <returns>The Y component.</returns>
ShaderGraphValue GetY() const
{
return ShaderGraphValue(VariantType::Types::Float, Value + _subs[1]);
}
ShaderGraphValue GetY() const;
/// <summary>
/// Gets the Z component of the value. Valid only for vector types.
/// </summary>
/// <returns>The Z component.</returns>
ShaderGraphValue GetZ() const
{
return ShaderGraphValue(VariantType::Types::Float, Value + _subs[2]);
}
ShaderGraphValue GetZ() const;
/// <summary>
/// Gets the W component of the value. Valid only for vector types.
/// </summary>
/// <returns>The W component.</returns>
ShaderGraphValue GetW() const
{
return ShaderGraphValue(VariantType::Types::Float, Value + _subs[3]);
}
ShaderGraphValue GetW() const;
public:
/// <summary>

View File

@@ -1532,9 +1532,7 @@ namespace Flax.Build.Bindings
if (paramIsRef && !parameterInfo.Type.IsConst)
{
// Unbox from MObject*
parameterInfo.Type.IsRef = false;
contents.Append($" {parameterInfo.Name} = MUtils::Unbox<{parameterInfo.Type}>(*(MObject**)params[{i}]);").AppendLine();
parameterInfo.Type.IsRef = true;
contents.Append($" {parameterInfo.Name} = MUtils::Unbox<{parameterInfo.Type.ToString(false)}>(*(MObject**)params[{i}]);").AppendLine();
}
}
}
@@ -1559,8 +1557,7 @@ namespace Flax.Build.Bindings
for (var i = 0; i < functionInfo.Parameters.Count; i++)
{
var parameterInfo = functionInfo.Parameters[i];
var paramIsRef = parameterInfo.IsRef || parameterInfo.IsOut;
if (paramIsRef && !parameterInfo.Type.IsConst)
if ((parameterInfo.IsRef || parameterInfo.IsOut) && !parameterInfo.Type.IsConst)
{
// Direct value convert
var managedToNative = GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, classInfo, out var managedType, out var apiType, null, out _);
@@ -2007,8 +2004,7 @@ namespace Flax.Build.Bindings
for (var i = 0; i < paramsCount; i++)
{
var paramType = eventInfo.Type.GenericArgs[i];
var paramIsRef = paramType.IsRef && !paramType.IsConst;
if (paramIsRef)
if (paramType.IsRef && !paramType.IsConst)
{
// Convert value back from managed to native (could be modified there)
paramType.IsRef = false;
@@ -2569,6 +2565,18 @@ namespace Flax.Build.Bindings
contents.AppendLine(" {");
contents.AppendLine(" Variant __result;");
contents.AppendLine($" typeHandle.Module->InvokeMethod(method, Object, Span<Variant>(parameters, {functionInfo.Parameters.Count}), __result);");
// Convert parameter values back from scripting to native (could be modified there)
for (var i = 0; i < functionInfo.Parameters.Count; i++)
{
var parameterInfo = functionInfo.Parameters[i];
var paramIsRef = parameterInfo.IsRef || parameterInfo.IsOut;
if (paramIsRef && !parameterInfo.Type.IsConst)
{
contents.AppendLine($" {parameterInfo.Name} = {GenerateCppWrapperVariantToNative(buildData, parameterInfo.Type, interfaceInfo, $"parameters[{i}]")};");
}
}
if (functionInfo.ReturnType.IsVoid)
contents.AppendLine(" return;");
else
@@ -2767,11 +2775,12 @@ namespace Flax.Build.Bindings
// Variant converting helper methods
foreach (var typeInfo in CppVariantToTypes)
{
var name = typeInfo.ToString(false);
header.AppendLine();
header.AppendLine("namespace {");
header.Append($"{typeInfo} VariantTo{GenerateCppWrapperNativeToVariantMethodName(typeInfo)}(const Variant& v)").AppendLine();
header.Append($"{name} VariantTo{GenerateCppWrapperNativeToVariantMethodName(typeInfo)}(const Variant& v)").AppendLine();
header.Append('{').AppendLine();
header.Append($" {typeInfo} result;").AppendLine();
header.Append($" {name} result;").AppendLine();
if (typeInfo.Type == "Array" && typeInfo.GenericArgs != null)
{
header.Append(" const auto* array = reinterpret_cast<const Array<Variant, HeapAllocation>*>(v.AsData);").AppendLine();

View File

@@ -180,7 +180,7 @@ namespace Flax.Build.Bindings
return sb.ToString();
}
public override string ToString()
public string ToString(bool canRef = true)
{
var sb = new StringBuilder(64);
if (IsConst)
@@ -199,13 +199,18 @@ namespace Flax.Build.Bindings
}
if (IsPtr)
sb.Append('*');
if (IsRef)
if (IsRef && canRef)
sb.Append('&');
if (IsMoveRef)
if (IsMoveRef && canRef)
sb.Append('&');
return sb.ToString();
}
public override string ToString()
{
return ToString(true);
}
public static bool Equals(List<TypeInfo> a, List<TypeInfo> b)
{
if (a == null && b == null)

View File

@@ -247,7 +247,7 @@ namespace Flax.Build
args.Add("/fullpaths");
args.Add("/filealign:512");
#if USE_NETCORE
args.Add("/langversion:11.0");
args.Add($"/langversion:{dotnetSdk.CSharpLanguageVersion}");
args.Add(string.Format("/nullable:{0}", buildOptions.ScriptingAPI.CSharpNullableReferences.ToString().ToLowerInvariant()));
if (buildOptions.ScriptingAPI.CSharpNullableReferences == CSharpNullableReferences.Disable)
args.Add("-nowarn:8632"); // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

View File

@@ -161,6 +161,18 @@ namespace Flax.Build
/// </summary>
public readonly string RuntimeVersionName;
/// <summary>
/// Maximum supported C#-language version for the SDK.
/// </summary>
public string CSharpLanguageVersion => Version.Major switch
{
8 => "12.0",
7 => "11.0",
6 => "10.0",
5 => "9.0",
_ => "7.3",
};
/// <summary>
/// Initializes a new instance of the <see cref="DotNetSdk"/> class.
/// </summary>

View File

@@ -21,6 +21,7 @@
<ErrorReport>none</ErrorReport>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn>1701;1702;8981</NoWarn>
<RollForward>LatestMajor</RollForward>
</PropertyGroup>
<ItemGroup>

View File

@@ -453,6 +453,7 @@ namespace Flax.Build.Platforms
commonArgs.Add("/std:c++latest");
break;
}
commonArgs.Add("/Zc:__cplusplus");
// Generate Intrinsic Functions
if (compileEnvironment.IntrinsicFunctions)

View File

@@ -28,6 +28,7 @@ namespace Flax.Build.Projects.VisualStudio
/// <inheritdoc />
public override void GenerateProject(Project project, string solutionPath)
{
var dotnetSdk = DotNetSdk.Instance;
var csProjectFileContent = new StringBuilder();
var vsProject = (VisualStudioProject)project;
@@ -73,8 +74,8 @@ namespace Flax.Build.Projects.VisualStudio
csProjectFileContent.AppendLine(string.Format(" <Platforms>{0}</Platforms>", string.Join(";", allPlatforms)));
// Provide default platform and configuration
csProjectFileContent.AppendLine(string.Format(" <Configuration Condition=\" '$(Configuration)' == '' \">{0}</Configuration>", defaultConfiguration.Text));
csProjectFileContent.AppendLine(string.Format(" <Platform Condition=\" '$(Platform)' == '' \">{0}</Platform>", defaultConfiguration.ArchitectureName));
csProjectFileContent.AppendLine(string.Format(" <Configuration>{0}</Configuration>", defaultConfiguration.Text));
csProjectFileContent.AppendLine(string.Format(" <Platform>{0}</Platform>", defaultConfiguration.ArchitectureName));
switch (project.OutputType ?? defaultTarget.OutputType)
{
@@ -96,7 +97,7 @@ namespace Flax.Build.Projects.VisualStudio
var cacheProjectsPath = Utilities.MakePathRelativeTo(Path.Combine(Globals.Root, "Cache", "Projects"), projectDirectory);
var flaxBuildTargetsPath = !string.IsNullOrEmpty(cacheProjectsPath) ? Path.Combine(cacheProjectsPath, flaxBuildTargetsFilename) : flaxBuildTargetsFilename;
csProjectFileContent.AppendLine(" <TargetFramework>net7.0</TargetFramework>");
csProjectFileContent.AppendLine($" <TargetFramework>net{dotnetSdk.Version.Major}.{dotnetSdk.Version.Minor}</TargetFramework>");
csProjectFileContent.AppendLine(" <ImplicitUsings>disable</ImplicitUsings>");
csProjectFileContent.AppendLine(string.Format(" <Nullable>{0}</Nullable>", baseConfiguration.TargetBuildOptions.ScriptingAPI.CSharpNullableReferences.ToString().ToLowerInvariant()));
csProjectFileContent.AppendLine(" <IsPackable>false</IsPackable>");
@@ -108,7 +109,7 @@ namespace Flax.Build.Projects.VisualStudio
csProjectFileContent.AppendLine(" <ProduceReferenceAssembly>false</ProduceReferenceAssembly>");
csProjectFileContent.AppendLine(string.Format(" <RootNamespace>{0}</RootNamespace>", project.BaseName));
csProjectFileContent.AppendLine(string.Format(" <AssemblyName>{0}.CSharp</AssemblyName>", project.BaseName));
csProjectFileContent.AppendLine(" <LangVersion>11.0</LangVersion>");
csProjectFileContent.AppendLine($" <LangVersion>{dotnetSdk.CSharpLanguageVersion}</LangVersion>");
csProjectFileContent.AppendLine(" <FileAlignment>512</FileAlignment>");
//csProjectFileContent.AppendLine(" <CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>"); // TODO: use it to reduce burden of framework libs

View File

@@ -34,7 +34,7 @@
<Expand>
<Item Name="[Size]" ExcludeView="simple">_count</Item>
<Item Name="[Capacity]" ExcludeView="simple">_capacity</Item>
<ArrayItems Condition="_count &lt;= _capacity">
<ArrayItems Condition="_count &lt;= _capacity">
<Size>_count</Size>
<ValuePointer>_allocation._data</ValuePointer>
</ArrayItems>
@@ -153,22 +153,22 @@
</ArrayItems>
</Expand>
</Type>
<!-- Vector2/Float2/Double2/Int2 -->
<Type Name="Vector2Base&lt;*&gt;">
<DisplayString>{{ X={X}, Y={Y} }}</DisplayString>
</Type>
<!-- Vector3/Float3/Double3/Int3 -->
<Type Name="Vector3Base&lt;*&gt;">
<DisplayString>{{ X={X}, Y={Y}, Z={Z} }}</DisplayString>
</Type>
<!-- Vector4/Float4/Double4/Int4 -->
<Type Name="Vector4Base&lt;*&gt;">
<DisplayString>{{ X={X}, Y={Y}, Z={Z}, W={W} }}</DisplayString>
</Type>
<!-- Quaternion -->
<Type Name="Quaternion">
<DisplayString>{{ X={X}, Y={Y}, Z={Z}, W={W} }}</DisplayString>
@@ -231,7 +231,7 @@
<DisplayString>{{ Length={_length} }}</DisplayString>
<Expand>
<Item Name="[Length]" ExcludeView="simple">_length</Item>
<ArrayItems Condition="_data != nullptr">
<ArrayItems Condition="_data != nullptr">
<Size>_length</Size>
<ValuePointer>_data</ValuePointer>
</ArrayItems>