Merge branch 'FlaxEngine:master' into flax-msdf-font
This commit is contained in:
2
.github/ISSUE_TEMPLATE/1-bug.yaml
vendored
2
.github/ISSUE_TEMPLATE/1-bug.yaml
vendored
@@ -31,7 +31,7 @@ body:
|
||||
- '1.10'
|
||||
- '1.11'
|
||||
- master branch
|
||||
default: 2
|
||||
default: 3
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
Binary file not shown.
@@ -4,7 +4,7 @@
|
||||
"Major": 1,
|
||||
"Minor": 11,
|
||||
"Revision": 0,
|
||||
"Build": 6801
|
||||
"Build": 6803
|
||||
},
|
||||
"Company": "Flax",
|
||||
"Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.",
|
||||
|
||||
@@ -49,7 +49,7 @@ Follow the instructions below to compile and run the engine from source.
|
||||
* Fedora: `sudo dnf install dotnet-sdk-8.0`
|
||||
* Arch: `sudo pacman -S dotnet-sdk-8.0 dotnet-runtime-8.0 dotnet-targeting-pack-8.0 dotnet-host`
|
||||
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
|
||||
* Ubuntu: `sudo apt install vulkan-sdk`
|
||||
* Ubuntu: `sudo apt install vulkan-sdk` (deprecated, follow official docs)
|
||||
* Fedora: `sudo dnf install vulkan-headers vulkan-tools vulkan-validation-layers`
|
||||
* Arch: `sudo pacman -S vulkan-headers vulkan-tools vulkan-validation-layers`
|
||||
* Install Git with LFS
|
||||
@@ -60,7 +60,7 @@ Follow the instructions below to compile and run the engine from source.
|
||||
* Ubuntu: `sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev zlib1g-dev`
|
||||
* Fedora: `sudo dnf install libX11-devel libXcursor-devel libXinerama-devel ghc-zlib-devel`
|
||||
* Arch: `sudo pacman -S base-devel libx11 libxcursor libxinerama zlib`
|
||||
* Install Clang compiler (version 6 or later):
|
||||
* Install Clang compiler (version 14 or later):
|
||||
* Ubuntu: `sudo apt-get install clang lldb lld`
|
||||
* Fedora: `sudo dnf install clang llvm lldb lld`
|
||||
* Arch: `sudo pacman -S clang lldb lld`
|
||||
|
||||
@@ -130,6 +130,11 @@ namespace FlaxEditor.Content
|
||||
eyeAdaptation.Mode = EyeAdaptationMode.None;
|
||||
eyeAdaptation.OverrideFlags |= EyeAdaptationSettingsOverride.Mode;
|
||||
preview.PostFxVolume.EyeAdaptation = eyeAdaptation;
|
||||
|
||||
var antiAliasing = preview.PostFxVolume.AntiAliasing;
|
||||
antiAliasing.Mode = AntialiasingMode.FastApproximateAntialiasing;
|
||||
antiAliasing.OverrideFlags |= AntiAliasingSettingsOverride.Mode;
|
||||
preview.PostFxVolume.AntiAliasing = antiAliasing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -914,9 +914,11 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
// Remove drop down arrows and containment lines if no objects in the group
|
||||
if (group.Children.Count == 0)
|
||||
{
|
||||
group.Panel.Close();
|
||||
group.Panel.ArrowImageOpened = null;
|
||||
group.Panel.ArrowImageClosed = null;
|
||||
group.Panel.EnableContainmentLines = false;
|
||||
group.Panel.CanOpenClose = false;
|
||||
}
|
||||
|
||||
// Scripts arrange bar
|
||||
|
||||
@@ -1587,7 +1587,7 @@ namespace FlaxEditor
|
||||
if (dockedTo != null && dockedTo.SelectedTab != gameWin && dockedTo.SelectedTab != null)
|
||||
result = dockedTo.SelectedTab.Size;
|
||||
else
|
||||
result = gameWin.Viewport.Size;
|
||||
result = gameWin.Viewport.ContentSize;
|
||||
|
||||
result *= root.DpiScale;
|
||||
result = Float2.Round(result);
|
||||
|
||||
@@ -10,17 +10,117 @@ using FlaxEditor.Modules;
|
||||
using FlaxEditor.Options;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Json;
|
||||
|
||||
namespace FlaxEditor.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Render output control with content scaling support.
|
||||
/// </summary>
|
||||
public class ScaledRenderOutputControl : RenderOutputControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom scale.
|
||||
/// </summary>
|
||||
public float ContentScale = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Actual bounds size for content (incl. scale).
|
||||
/// </summary>
|
||||
public Float2 ContentSize => Size / ContentScale;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScaledRenderOutputControl(SceneRenderTask task)
|
||||
: base(task)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
DrawSelf();
|
||||
|
||||
// Draw children with scale
|
||||
var scaling = new Float3(ContentScale, ContentScale, 1);
|
||||
Matrix3x3.Scaling(ref scaling, out Matrix3x3 scale);
|
||||
Render2D.PushTransform(scale);
|
||||
if (ClipChildren)
|
||||
{
|
||||
GetDesireClientArea(out var clientArea);
|
||||
Render2D.PushClip(ref clientArea);
|
||||
DrawChildren();
|
||||
Render2D.PopClip();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawChildren();
|
||||
}
|
||||
|
||||
Render2D.PopTransform();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void GetDesireClientArea(out Rectangle rect)
|
||||
{
|
||||
// Scale the area for the client controls
|
||||
rect = new Rectangle(Float2.Zero, Size / ContentScale);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IntersectsContent(ref Float2 locationParent, out Float2 location)
|
||||
{
|
||||
// Skip local PointFromParent but use base code
|
||||
location = base.PointFromParent(ref locationParent);
|
||||
return ContainsPoint(ref location);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IntersectsChildContent(Control child, Float2 location, out Float2 childSpaceLocation)
|
||||
{
|
||||
location /= ContentScale;
|
||||
return base.IntersectsChildContent(child, location, out childSpaceLocation);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool ContainsPoint(ref Float2 location, bool precise = false)
|
||||
{
|
||||
if (precise) // Ignore as utility-only element
|
||||
return false;
|
||||
return base.ContainsPoint(ref location, precise);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool RayCast(ref Float2 location, out Control hit)
|
||||
{
|
||||
var p = location / ContentScale;
|
||||
if (RayCastChildren(ref p, out hit))
|
||||
return true;
|
||||
return base.RayCast(ref location, out hit);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Float2 PointToParent(ref Float2 location)
|
||||
{
|
||||
var result = base.PointToParent(ref location);
|
||||
result *= ContentScale;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Float2 PointFromParent(ref Float2 location)
|
||||
{
|
||||
var result = base.PointFromParent(ref location);
|
||||
result /= ContentScale;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides in-editor play mode simulation.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Windows.EditorWindow" />
|
||||
public class GameWindow : EditorWindow
|
||||
{
|
||||
private readonly RenderOutputControl _viewport;
|
||||
private readonly ScaledRenderOutputControl _viewport;
|
||||
private readonly GameRoot _guiRoot;
|
||||
private bool _showGUI = true, _editGUI = true;
|
||||
private bool _showDebugDraw = false;
|
||||
@@ -77,7 +177,7 @@ namespace FlaxEditor.Windows
|
||||
/// <summary>
|
||||
/// Gets the viewport.
|
||||
/// </summary>
|
||||
public RenderOutputControl Viewport => _viewport;
|
||||
public ScaledRenderOutputControl Viewport => _viewport;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether show game GUI in the view or keep it hidden.
|
||||
@@ -295,7 +395,7 @@ namespace FlaxEditor.Windows
|
||||
var task = MainRenderTask.Instance;
|
||||
|
||||
// Setup viewport
|
||||
_viewport = new RenderOutputControl(task)
|
||||
_viewport = new ScaledRenderOutputControl(task)
|
||||
{
|
||||
AnchorPreset = AnchorPresets.StretchAll,
|
||||
Offsets = Margin.Zero,
|
||||
@@ -396,11 +496,8 @@ namespace FlaxEditor.Windows
|
||||
{
|
||||
if (v == null)
|
||||
return;
|
||||
|
||||
if (v.Size.Y <= 0 || v.Size.X <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(v.Label, "Free Aspect", StringComparison.Ordinal) && v.Size == new Int2(1, 1))
|
||||
{
|
||||
@@ -448,15 +545,7 @@ namespace FlaxEditor.Windows
|
||||
|
||||
private void ResizeViewport()
|
||||
{
|
||||
if (!_freeAspect)
|
||||
{
|
||||
_windowAspectRatio = Width / Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
_windowAspectRatio = 1;
|
||||
}
|
||||
|
||||
_windowAspectRatio = _freeAspect ? 1 : Width / Height;
|
||||
var scaleWidth = _viewportAspectRatio / _windowAspectRatio;
|
||||
var scaleHeight = _windowAspectRatio / _viewportAspectRatio;
|
||||
|
||||
@@ -468,6 +557,24 @@ namespace FlaxEditor.Windows
|
||||
{
|
||||
_viewport.Bounds = new Rectangle(Width * (1 - scaleWidth) / 2, 0, Width * scaleWidth, Height);
|
||||
}
|
||||
|
||||
if (_viewport.KeepAspectRatio)
|
||||
{
|
||||
var resolution = _viewport.CustomResolution.HasValue ? (Float2)_viewport.CustomResolution.Value : Size;
|
||||
if (scaleHeight < 1)
|
||||
{
|
||||
_viewport.ContentScale = _viewport.Width / resolution.X;
|
||||
}
|
||||
else
|
||||
{
|
||||
_viewport.ContentScale = _viewport.Height / resolution.Y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_viewport.ContentScale = 1;
|
||||
}
|
||||
|
||||
_viewport.SyncBackbufferSize();
|
||||
PerformLayout();
|
||||
}
|
||||
@@ -907,6 +1014,7 @@ namespace FlaxEditor.Windows
|
||||
return child.OnNavigate(direction, Float2.Zero, this, visited);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -957,7 +1065,7 @@ namespace FlaxEditor.Windows
|
||||
else
|
||||
_defaultScaleActiveIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
if (_customScaleActiveIndex != -1)
|
||||
{
|
||||
var options = Editor.UI.CustomViewportScaleOptions;
|
||||
|
||||
@@ -425,6 +425,8 @@ namespace FlaxEngine.Interop
|
||||
var fieldOffsetPtr = (IntPtr*)field.FieldHandle.Value; // Pointer to MonoClassField
|
||||
fieldOffsetPtr += 3; // Skip three pointers (type, name, parent_and_flags)
|
||||
return *(int*)fieldOffsetPtr - IntPtr.Size * 2; // Load the value of a pointer (4 bytes, int32), then subtracting 16 bytes from it (2 pointers for vtable and threadsync)
|
||||
#else
|
||||
throw new NotImplementedException();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -491,7 +491,7 @@ void GPUContextDX12::flushUAVs()
|
||||
ASSERT(uaCount <= GPU_MAX_UA_BINDED);
|
||||
|
||||
// Fill table with source descriptors
|
||||
DxShaderHeader& header = _currentCompute ? ((GPUShaderProgramCSDX12*)_currentCompute)->Header : _currentState->Header;
|
||||
DxShaderHeader& header = _isCompute ? ((GPUShaderProgramCSDX12*)_currentCompute)->Header : _currentState->Header;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE srcDescriptorRangeStarts[GPU_MAX_UA_BINDED];
|
||||
for (uint32 i = 0; i < uaCount; i++)
|
||||
{
|
||||
|
||||
@@ -114,7 +114,7 @@ GPUContextVulkan::GPUContextVulkan(GPUDeviceVulkan* device, QueueVulkan* queue)
|
||||
#if GPU_ENABLE_TRACY
|
||||
#if VK_EXT_calibrated_timestamps && VK_EXT_host_query_reset && !PLATFORM_SWITCH
|
||||
// Use calibrated timestamps extension
|
||||
if (vkResetQueryPoolEXT && vkGetCalibratedTimestampsEXT)
|
||||
if (vkResetQueryPoolEXT && vkGetCalibratedTimestampsEXT && _device->PhysicalDeviceFeatures12.hostQueryReset)
|
||||
{
|
||||
_tracyContext = tracy::CreateVkContext(_device->Adapter->Gpu, _device->Device, vkResetQueryPoolEXT, vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, vkGetCalibratedTimestampsEXT);
|
||||
}
|
||||
|
||||
@@ -1568,7 +1568,15 @@ bool GPUDeviceVulkan::Init()
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queueCount, QueueFamilyProps.Get());
|
||||
|
||||
// Query device features
|
||||
RenderToolsVulkan::ZeroStruct(PhysicalDeviceFeatures12, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES);
|
||||
vkGetPhysicalDeviceFeatures(gpu, &PhysicalDeviceFeatures);
|
||||
if (vkGetPhysicalDeviceFeatures2)
|
||||
{
|
||||
VkPhysicalDeviceFeatures2 features2;
|
||||
RenderToolsVulkan::ZeroStruct(features2, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2);
|
||||
features2.pNext = &PhysicalDeviceFeatures12;
|
||||
vkGetPhysicalDeviceFeatures2(gpu, &features2);
|
||||
}
|
||||
|
||||
// Get extensions and layers
|
||||
Array<const char*> deviceExtensions;
|
||||
@@ -1671,6 +1679,16 @@ bool GPUDeviceVulkan::Init()
|
||||
VulkanPlatform::RestrictEnabledPhysicalDeviceFeatures(PhysicalDeviceFeatures, enabledFeatures);
|
||||
deviceInfo.pEnabledFeatures = &enabledFeatures;
|
||||
|
||||
#if GPU_ENABLE_TRACY && VK_EXT_calibrated_timestamps && VK_EXT_host_query_reset
|
||||
VkPhysicalDeviceHostQueryResetFeatures resetFeatures;
|
||||
if (PhysicalDeviceFeatures12.hostQueryReset)
|
||||
{
|
||||
RenderToolsVulkan::ZeroStruct(resetFeatures, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES);
|
||||
resetFeatures.hostQueryReset = VK_TRUE;
|
||||
deviceInfo.pNext = &resetFeatures;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create the device
|
||||
VALIDATE_VULKAN_RESULT(vkCreateDevice(gpu, &deviceInfo, nullptr, &Device));
|
||||
|
||||
|
||||
@@ -496,6 +496,7 @@ public:
|
||||
/// The physical device enabled features.
|
||||
/// </summary>
|
||||
VkPhysicalDeviceFeatures PhysicalDeviceFeatures;
|
||||
VkPhysicalDeviceVulkan12Features PhysicalDeviceFeatures12;
|
||||
|
||||
Array<BufferedQueryPoolVulkan*> TimestampQueryPools;
|
||||
Array<BufferedQueryPoolVulkan*> OcclusionQueryPools;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#endif
|
||||
|
||||
// Internal version number of networking implementation. Updated once engine changes serialization or connection rules.
|
||||
#define NETWORK_PROTOCOL_VERSION 4
|
||||
#define NETWORK_PROTOCOL_VERSION 5
|
||||
|
||||
// Enables encoding object ids and typenames via uint32 keys rather than full data send.
|
||||
#define USE_NETWORK_KEYS 1
|
||||
@@ -29,6 +29,7 @@ enum class NetworkMessageIDs : uint8
|
||||
ObjectDespawn,
|
||||
ObjectRole,
|
||||
ObjectRpc,
|
||||
ObjectRpcPart,
|
||||
|
||||
MAX,
|
||||
};
|
||||
@@ -48,6 +49,7 @@ public:
|
||||
static void OnNetworkMessageObjectDespawn(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
||||
static void OnNetworkMessageObjectRole(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
||||
static void OnNetworkMessageObjectRpc(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
||||
static void OnNetworkMessageObjectRpcPart(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
|
||||
|
||||
@@ -391,6 +391,7 @@ namespace
|
||||
NetworkInternal::OnNetworkMessageObjectDespawn,
|
||||
NetworkInternal::OnNetworkMessageObjectRole,
|
||||
NetworkInternal::OnNetworkMessageObjectRpc,
|
||||
NetworkInternal::OnNetworkMessageObjectRpcPart,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -55,14 +55,14 @@ PACK_STRUCT(struct NetworkMessageObjectReplicate
|
||||
uint32 OwnerFrame;
|
||||
});
|
||||
|
||||
PACK_STRUCT(struct NetworkMessageObjectReplicatePayload
|
||||
PACK_STRUCT(struct NetworkMessageObjectPartPayload
|
||||
{
|
||||
uint16 DataSize;
|
||||
uint16 PartsCount;
|
||||
uint16 PartSize;
|
||||
});
|
||||
|
||||
PACK_STRUCT(struct NetworkMessageObjectReplicatePart
|
||||
PACK_STRUCT(struct NetworkMessageObjectPart
|
||||
{
|
||||
NetworkMessageIDs ID = NetworkMessageIDs::ObjectReplicatePart;
|
||||
uint32 OwnerFrame;
|
||||
@@ -111,7 +111,7 @@ PACK_STRUCT(struct NetworkMessageObjectRole
|
||||
PACK_STRUCT(struct NetworkMessageObjectRpc
|
||||
{
|
||||
NetworkMessageIDs ID = NetworkMessageIDs::ObjectRpc;
|
||||
uint16 ArgsSize;
|
||||
uint32 OwnerFrame;
|
||||
});
|
||||
|
||||
struct NetworkReplicatedObject
|
||||
@@ -182,13 +182,14 @@ struct Serializer
|
||||
void* Tags[2];
|
||||
};
|
||||
|
||||
struct ReplicateItem
|
||||
struct PartsItem
|
||||
{
|
||||
ScriptingObjectReference<ScriptingObject> Object;
|
||||
Guid ObjectId;
|
||||
uint16 PartsLeft;
|
||||
uint32 OwnerFrame;
|
||||
uint32 OwnerClientId;
|
||||
const void* Tag;
|
||||
Array<byte> Data;
|
||||
};
|
||||
|
||||
@@ -220,7 +221,7 @@ struct DespawnItem
|
||||
DataContainer<uint32> Targets;
|
||||
};
|
||||
|
||||
struct RpcItem
|
||||
struct RpcSendItem
|
||||
{
|
||||
ScriptingObjectReference<ScriptingObject> Object;
|
||||
NetworkRpcName Name;
|
||||
@@ -233,11 +234,12 @@ namespace
|
||||
{
|
||||
CriticalSection ObjectsLock;
|
||||
HashSet<NetworkReplicatedObject> Objects;
|
||||
Array<ReplicateItem> ReplicationParts;
|
||||
Array<PartsItem> ReplicationParts;
|
||||
Array<PartsItem> RpcParts;
|
||||
Array<SpawnItemParts> SpawnParts;
|
||||
Array<SpawnItem> SpawnQueue;
|
||||
Array<DespawnItem> DespawnQueue;
|
||||
Array<RpcItem> RpcQueue;
|
||||
Array<RpcSendItem> RpcQueue;
|
||||
Dictionary<Guid, Guid> IdsRemappingTable;
|
||||
NetworkStream* CachedWriteStream = nullptr;
|
||||
NetworkStream* CachedReadStream = nullptr;
|
||||
@@ -251,6 +253,7 @@ namespace
|
||||
#endif
|
||||
Array<Guid> DespawnedObjects;
|
||||
uint32 SpawnId = 0;
|
||||
uint32 RpcId = 0;
|
||||
|
||||
#if USE_EDITOR
|
||||
void OnScriptsReloading()
|
||||
@@ -505,6 +508,76 @@ void SetupObjectSpawnMessageItem(SpawnItem* e, NetworkMessage& msg)
|
||||
msg.WriteStructure(msgDataItem);
|
||||
}
|
||||
|
||||
void SendInParts(NetworkPeer* peer, NetworkChannelType channel, const byte* data, const uint16 dataSize, NetworkMessage& msg, const NetworkRpcName& name, bool toServer, const Guid& objectId, uint32 ownerFrame, NetworkMessageIDs partId)
|
||||
{
|
||||
NetworkMessageObjectPartPayload msgDataPayload;
|
||||
msgDataPayload.DataSize = dataSize;
|
||||
const uint32 networkKeyIdWorstCaseSize = sizeof(uint32) + sizeof(Guid);
|
||||
const uint32 msgMaxData = peer->Config.MessageSize - msg.Position - sizeof(NetworkMessageObjectPartPayload);
|
||||
const uint32 partMaxData = peer->Config.MessageSize - sizeof(NetworkMessageObjectPart) - networkKeyIdWorstCaseSize;
|
||||
uint32 partsCount = 1;
|
||||
uint32 dataStart = 0;
|
||||
uint32 msgDataSize = dataSize;
|
||||
if (dataSize > msgMaxData)
|
||||
{
|
||||
// Send msgMaxData within first message
|
||||
msgDataSize = msgMaxData;
|
||||
dataStart += msgMaxData;
|
||||
|
||||
// Send rest of the data in separate parts
|
||||
partsCount += Math::DivideAndRoundUp(dataSize - dataStart, partMaxData);
|
||||
|
||||
// TODO: promote channel to Ordered when using parts?
|
||||
}
|
||||
else
|
||||
dataStart += dataSize;
|
||||
ASSERT(partsCount <= MAX_uint8);
|
||||
msgDataPayload.PartsCount = partsCount;
|
||||
msgDataPayload.PartSize = msgDataSize;
|
||||
msg.WriteStructure(msgDataPayload);
|
||||
msg.WriteBytes(data, msgDataSize);
|
||||
uint32 messageSize = msg.Length;
|
||||
if (toServer)
|
||||
peer->EndSendMessage(channel, msg);
|
||||
else
|
||||
peer->EndSendMessage(channel, msg, CachedTargets);
|
||||
|
||||
// Send all other parts
|
||||
for (uint32 partIndex = 1; partIndex < partsCount; partIndex++)
|
||||
{
|
||||
NetworkMessageObjectPart msgDataPart;
|
||||
msgDataPart.ID = partId;
|
||||
msgDataPart.OwnerFrame = ownerFrame;
|
||||
msgDataPart.DataSize = msgDataPayload.DataSize;
|
||||
msgDataPart.PartsCount = msgDataPayload.PartsCount;
|
||||
msgDataPart.PartStart = dataStart;
|
||||
msgDataPart.PartSize = Math::Min(dataSize - dataStart, partMaxData);
|
||||
msg = peer->BeginSendMessage();
|
||||
msg.WriteStructure(msgDataPart);
|
||||
msg.WriteNetworkId(objectId);
|
||||
msg.WriteBytes(data + msgDataPart.PartStart, msgDataPart.PartSize);
|
||||
messageSize += msg.Length;
|
||||
dataStart += msgDataPart.PartSize;
|
||||
if (toServer)
|
||||
peer->EndSendMessage(channel, msg);
|
||||
else
|
||||
peer->EndSendMessage(channel, msg, CachedTargets);
|
||||
}
|
||||
ASSERT_LOW_LAYER(dataStart == dataSize);
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
// Network stats recording
|
||||
if (NetworkInternal::EnableProfiling)
|
||||
{
|
||||
auto& profileEvent = NetworkInternal::ProfilerEvents[name];
|
||||
profileEvent.Count++;
|
||||
profileEvent.DataSize += dataSize;
|
||||
profileEvent.MessageSize += messageSize;
|
||||
profileEvent.Receivers += toServer ? 1 : CachedTargets.Count();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SendObjectSpawnMessage(const SpawnGroup& group, const Array<NetworkClient*>& clients)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
@@ -589,7 +662,7 @@ void SendObjectRoleMessage(const NetworkReplicatedObject& item, const NetworkCli
|
||||
msg.WriteNetworkId(objectId);
|
||||
if (NetworkManager::IsClient())
|
||||
{
|
||||
NetworkManager::Peer->EndSendMessage(NetworkChannelType::ReliableOrdered, msg);
|
||||
peer->EndSendMessage(NetworkChannelType::ReliableOrdered, msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -598,6 +671,160 @@ void SendObjectRoleMessage(const NetworkReplicatedObject& item, const NetworkCli
|
||||
}
|
||||
}
|
||||
|
||||
void SendDespawn(DespawnItem& e)
|
||||
{
|
||||
NETWORK_REPLICATOR_LOG(Info, "[NetworkReplicator] Despawn object ID={}", e.Id.ToString());
|
||||
NetworkMessageObjectDespawn msgData;
|
||||
Guid objectId = e.Id;
|
||||
{
|
||||
// Remap local client object ids into server ids
|
||||
IdsRemappingTable.KeyOf(objectId, &objectId);
|
||||
}
|
||||
auto peer = NetworkManager::Peer;
|
||||
NetworkMessage msg = peer->BeginSendMessage();
|
||||
msg.WriteStructure(msgData);
|
||||
msg.WriteNetworkId(objectId);
|
||||
BuildCachedTargets(NetworkManager::Clients, e.Targets);
|
||||
if (NetworkManager::IsClient())
|
||||
peer->EndSendMessage(NetworkChannelType::ReliableOrdered, msg);
|
||||
else
|
||||
peer->EndSendMessage(NetworkChannelType::ReliableOrdered, msg, CachedTargets);
|
||||
}
|
||||
|
||||
void SendReplication(ScriptingObject* obj, NetworkClientsMask targetClients)
|
||||
{
|
||||
auto it = Objects.Find(obj->GetID());
|
||||
if (it.IsEnd())
|
||||
return;
|
||||
auto& item = it->Item;
|
||||
const bool isClient = NetworkManager::IsClient();
|
||||
|
||||
// Skip serialization of objects that none will receive
|
||||
if (!isClient)
|
||||
{
|
||||
BuildCachedTargets(item, targetClients);
|
||||
if (CachedTargets.Count() == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.AsNetworkObject)
|
||||
item.AsNetworkObject->OnNetworkSerialize();
|
||||
|
||||
// Serialize object
|
||||
NetworkStream* stream = CachedWriteStream;
|
||||
stream->Initialize();
|
||||
const bool failed = NetworkReplicator::InvokeSerializer(obj->GetTypeHandle(), obj, stream, true);
|
||||
if (failed)
|
||||
{
|
||||
//NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Cannot serialize object {} of type {} (missing serialization logic)", item.ToString(), obj->GetType().ToString());
|
||||
return;
|
||||
}
|
||||
const uint32 size = stream->GetPosition();
|
||||
if (size > MAX_uint16)
|
||||
{
|
||||
LOG(Error, "Too much data for object {} replication ({} bytes provided while limit is {}).", item.ToString(), size, MAX_uint16);
|
||||
return;
|
||||
}
|
||||
|
||||
#if USE_NETWORK_REPLICATOR_CACHE
|
||||
// Process replication cache to skip sending object data if it didn't change
|
||||
if (item.RepCache.Data.Length() == size &&
|
||||
item.RepCache.Mask == targetClients &&
|
||||
Platform::MemoryCompare(item.RepCache.Data.Get(), stream->GetBuffer(), size) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
item.RepCache.Mask = targetClients;
|
||||
item.RepCache.Data.Copy(stream->GetBuffer(), size);
|
||||
#endif
|
||||
// TODO: use Unreliable for dynamic objects that are replicated every frame? (eg. player state)
|
||||
constexpr NetworkChannelType repChannel = NetworkChannelType::Reliable;
|
||||
|
||||
// Send object to clients
|
||||
NetworkMessageObjectReplicate msgData;
|
||||
msgData.OwnerFrame = NetworkManager::Frame;
|
||||
Guid objectId = item.ObjectId, parentId = item.ParentId;
|
||||
{
|
||||
// Remap local client object ids into server ids
|
||||
IdsRemappingTable.KeyOf(objectId, &objectId);
|
||||
IdsRemappingTable.KeyOf(parentId, &parentId);
|
||||
}
|
||||
NetworkPeer* peer = NetworkManager::Peer;
|
||||
NetworkMessage msg = peer->BeginSendMessage();
|
||||
msg.WriteStructure(msgData);
|
||||
msg.WriteNetworkId(objectId);
|
||||
msg.WriteNetworkId(parentId);
|
||||
msg.WriteNetworkName(obj->GetType().Fullname);
|
||||
const NetworkRpcName name(obj->GetTypeHandle(), StringAnsiView::Empty);
|
||||
SendInParts(peer, repChannel, stream->GetBuffer(), size, msg, name, isClient, objectId, msgData.OwnerFrame, NetworkMessageIDs::ObjectReplicatePart);
|
||||
}
|
||||
|
||||
void SendRpc(RpcSendItem& e)
|
||||
{
|
||||
ScriptingObject* obj = e.Object.Get();
|
||||
if (!obj)
|
||||
return;
|
||||
auto it = Objects.Find(obj->GetID());
|
||||
if (it == Objects.End())
|
||||
{
|
||||
#if !BUILD_RELEASE
|
||||
if (!DespawnedObjects.Contains(obj->GetID()))
|
||||
LOG(Error, "Cannot invoke RPC method '{0}.{1}' on object '{2}' that is not registered in networking (use 'NetworkReplicator.AddObject').", e.Name.First.ToString(), e.Name.Second.ToString(), obj->GetID());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
auto& item = it->Item;
|
||||
if (e.ArgsData.Length() > MAX_uint16)
|
||||
{
|
||||
LOG(Error, "Too much data for object RPC method '{}.{}' on object '{}' ({} bytes provided while limit is {}).", e.Name.First.ToString(), e.Name.Second.ToString(), obj->GetID(), e.ArgsData.Length(), MAX_uint16);
|
||||
return;
|
||||
}
|
||||
const NetworkManagerMode mode = NetworkManager::Mode;
|
||||
NetworkPeer* peer = NetworkManager::Peer;
|
||||
|
||||
bool toServer;
|
||||
if (e.Info.Server && mode == NetworkManagerMode::Client)
|
||||
{
|
||||
// Client -> Server
|
||||
#if USE_NETWORK_REPLICATOR_LOG
|
||||
if (e.Targets.Length() != 0)
|
||||
NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Server RPC '{}.{}' called with non-empty list of targets is not supported (only server will receive it)", e.Name.First.ToString(), e.Name.Second.ToString());
|
||||
#endif
|
||||
toServer = true;
|
||||
}
|
||||
else if (e.Info.Client && (mode == NetworkManagerMode::Server || mode == NetworkManagerMode::Host))
|
||||
{
|
||||
// Server -> Client(s)
|
||||
BuildCachedTargets(NetworkManager::Clients, item.TargetClientIds, e.Targets, NetworkManager::LocalClientId);
|
||||
if (CachedTargets.IsEmpty())
|
||||
return;
|
||||
toServer = false;
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
// Send RPC message
|
||||
//NETWORK_REPLICATOR_LOG(Info, "[NetworkReplicator] Rpc {}.{} object ID={}", e.Name.First.ToString(), e.Name.Second.ToString(), item.ToString());
|
||||
NetworkMessageObjectRpc msgData;
|
||||
msgData.OwnerFrame = ++RpcId;
|
||||
Guid objectId = item.ObjectId;
|
||||
Guid parentId = item.ParentId;
|
||||
{
|
||||
// Remap local client object ids into server ids
|
||||
IdsRemappingTable.KeyOf(objectId, &objectId);
|
||||
IdsRemappingTable.KeyOf(parentId, &parentId);
|
||||
}
|
||||
NetworkMessage msg = peer->BeginSendMessage();
|
||||
msg.WriteStructure(msgData);
|
||||
msg.WriteNetworkId(objectId);
|
||||
msg.WriteNetworkId(parentId);
|
||||
msg.WriteNetworkName(obj->GetType().Fullname);
|
||||
msg.WriteNetworkName(e.Name.First.GetType().Fullname);
|
||||
msg.WriteNetworkName(e.Name.Second);
|
||||
NetworkChannelType channel = (NetworkChannelType)e.Info.Channel;
|
||||
SendInParts(peer, channel, e.ArgsData.Get(), e.ArgsData.Length(), msg, e.Name, toServer, objectId, msgData.OwnerFrame, NetworkMessageIDs::ObjectRpcPart);
|
||||
}
|
||||
|
||||
void DeleteNetworkObject(ScriptingObject* obj)
|
||||
{
|
||||
// Remove from the mapping table
|
||||
@@ -708,38 +935,43 @@ FORCE_INLINE void DirtyObjectImpl(NetworkReplicatedObject& item, ScriptingObject
|
||||
Hierarchy->DirtyObject(obj);
|
||||
}
|
||||
|
||||
ReplicateItem* AddObjectReplicateItem(NetworkEvent& event, uint32 ownerFrame, uint16 partsCount, uint16 dataSize, const Guid& objectId, uint16 partStart, uint16 partSize, uint32 senderClientId)
|
||||
PartsItem* AddPartsItem(Array<PartsItem>& items, NetworkEvent& event, uint32 ownerFrame, uint16 partsCount, uint16 dataSize, const Guid& objectId, uint16 partStart, uint16 partSize, uint32 senderClientId)
|
||||
{
|
||||
// Reuse or add part item
|
||||
ReplicateItem* replicateItem = nullptr;
|
||||
for (auto& e : ReplicationParts)
|
||||
PartsItem* item = nullptr;
|
||||
for (auto& e : items)
|
||||
{
|
||||
if (e.OwnerFrame == ownerFrame && e.Data.Count() == dataSize && e.ObjectId == objectId)
|
||||
{
|
||||
// Reuse
|
||||
replicateItem = &e;
|
||||
item = &e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!replicateItem)
|
||||
if (!item)
|
||||
{
|
||||
// Add
|
||||
replicateItem = &ReplicationParts.AddOne();
|
||||
replicateItem->ObjectId = objectId;
|
||||
replicateItem->PartsLeft = partsCount;
|
||||
replicateItem->OwnerFrame = ownerFrame;
|
||||
replicateItem->OwnerClientId = senderClientId;
|
||||
replicateItem->Data.Resize(dataSize);
|
||||
item = &items.AddOne();
|
||||
item->ObjectId = objectId;
|
||||
item->PartsLeft = partsCount;
|
||||
item->OwnerFrame = ownerFrame;
|
||||
item->OwnerClientId = senderClientId;
|
||||
item->Data.Resize(dataSize);
|
||||
}
|
||||
|
||||
// Copy part data
|
||||
ASSERT(replicateItem->PartsLeft > 0);
|
||||
replicateItem->PartsLeft--;
|
||||
ASSERT(partStart + partSize <= replicateItem->Data.Count());
|
||||
ASSERT(item->PartsLeft > 0);
|
||||
item->PartsLeft--;
|
||||
ASSERT(partStart + partSize <= item->Data.Count());
|
||||
const void* partData = event.Message.SkipBytes(partSize);
|
||||
Platform::MemoryCopy(replicateItem->Data.Get() + partStart, partData, partSize);
|
||||
Platform::MemoryCopy(item->Data.Get() + partStart, partData, partSize);
|
||||
|
||||
return replicateItem;
|
||||
return item;
|
||||
}
|
||||
|
||||
FORCE_INLINE PartsItem* AddObjectReplicateItem(NetworkEvent& event, uint32 ownerFrame, uint16 partsCount, uint16 dataSize, const Guid& objectId, uint16 partStart, uint16 partSize, uint32 senderClientId)
|
||||
{
|
||||
return AddPartsItem(ReplicationParts, event, ownerFrame, partsCount, dataSize, objectId, partStart, partSize, senderClientId);
|
||||
}
|
||||
|
||||
void InvokeObjectReplication(NetworkReplicatedObject& item, uint32 ownerFrame, byte* data, uint32 dataSize, uint32 senderClientId)
|
||||
@@ -787,6 +1019,24 @@ void InvokeObjectReplication(NetworkReplicatedObject& item, uint32 ownerFrame, b
|
||||
DirtyObjectImpl(item, obj);
|
||||
}
|
||||
|
||||
FORCE_INLINE PartsItem* AddObjectRpcItem(NetworkEvent& event, uint32 ownerFrame, uint16 partsCount, uint16 dataSize, const Guid& objectId, uint16 partStart, uint16 partSize, uint32 senderClientId)
|
||||
{
|
||||
return AddPartsItem(RpcParts, event, ownerFrame, partsCount, dataSize, objectId, partStart, partSize, senderClientId);
|
||||
}
|
||||
|
||||
void InvokeObjectRpc(const NetworkRpcInfo* info, byte* data, uint32 dataSize, uint32 senderClientId, ScriptingObject* obj)
|
||||
{
|
||||
// Setup message reading stream
|
||||
if (CachedReadStream == nullptr)
|
||||
CachedReadStream = New<NetworkStream>();
|
||||
NetworkStream* stream = CachedReadStream;
|
||||
stream->SenderId = senderClientId;
|
||||
stream->Initialize(data, dataSize);
|
||||
|
||||
// Execute RPC
|
||||
info->Execute(obj, stream, info->Tag);
|
||||
}
|
||||
|
||||
void InvokeObjectSpawn(const NetworkMessageObjectSpawn& msgData, const Guid& prefabId, const NetworkMessageObjectSpawnItem* msgDataItems)
|
||||
{
|
||||
ScopeLock lock(ObjectsLock);
|
||||
@@ -1652,9 +1902,6 @@ void NetworkInternal::NetworkReplicatorUpdate()
|
||||
if (Objects.Count() == 0)
|
||||
return;
|
||||
const bool isClient = NetworkManager::IsClient();
|
||||
const bool isServer = NetworkManager::IsServer();
|
||||
const bool isHost = NetworkManager::IsHost();
|
||||
NetworkPeer* peer = NetworkManager::Peer;
|
||||
|
||||
if (!isClient && NewClients.Count() != 0)
|
||||
{
|
||||
@@ -1694,22 +1941,7 @@ void NetworkInternal::NetworkReplicatorUpdate()
|
||||
PROFILE_CPU_NAMED("DespawnQueue");
|
||||
for (DespawnItem& e : DespawnQueue)
|
||||
{
|
||||
// Send despawn message
|
||||
NETWORK_REPLICATOR_LOG(Info, "[NetworkReplicator] Despawn object ID={}", e.Id.ToString());
|
||||
NetworkMessageObjectDespawn msgData;
|
||||
Guid objectId = e.Id;
|
||||
{
|
||||
// Remap local client object ids into server ids
|
||||
IdsRemappingTable.KeyOf(objectId, &objectId);
|
||||
}
|
||||
NetworkMessage msg = peer->BeginSendMessage();
|
||||
msg.WriteStructure(msgData);
|
||||
msg.WriteNetworkId(objectId);
|
||||
BuildCachedTargets(NetworkManager::Clients, e.Targets);
|
||||
if (isClient)
|
||||
peer->EndSendMessage(NetworkChannelType::ReliableOrdered, msg);
|
||||
else
|
||||
peer->EndSendMessage(NetworkChannelType::ReliableOrdered, msg, CachedTargets);
|
||||
SendDespawn(e);
|
||||
}
|
||||
DespawnQueue.Clear();
|
||||
}
|
||||
@@ -1830,6 +2062,7 @@ void NetworkInternal::NetworkReplicatorUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove items from RpcParts after some TTL to reduce memory usage
|
||||
// TODO: remove items from SpawnParts after some TTL to reduce memory usage
|
||||
|
||||
// Replicate all owned networked objects with other clients or server
|
||||
@@ -1871,136 +2104,11 @@ void NetworkInternal::NetworkReplicatorUpdate()
|
||||
PROFILE_CPU_NAMED("Replication");
|
||||
if (CachedWriteStream == nullptr)
|
||||
CachedWriteStream = New<NetworkStream>();
|
||||
NetworkStream* stream = CachedWriteStream;
|
||||
stream->SenderId = NetworkManager::LocalClientId;
|
||||
CachedWriteStream->SenderId = NetworkManager::LocalClientId;
|
||||
// TODO: use Job System when replicated objects count is large
|
||||
for (auto& e : CachedReplicationResult->_entries)
|
||||
{
|
||||
ScriptingObject* obj = e.Object;
|
||||
auto it = Objects.Find(obj->GetID());
|
||||
if (it.IsEnd())
|
||||
continue;
|
||||
auto& item = it->Item;
|
||||
|
||||
// Skip serialization of objects that none will receive
|
||||
if (!isClient)
|
||||
{
|
||||
BuildCachedTargets(item, e.TargetClients);
|
||||
if (CachedTargets.Count() == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.AsNetworkObject)
|
||||
item.AsNetworkObject->OnNetworkSerialize();
|
||||
|
||||
// Serialize object
|
||||
stream->Initialize();
|
||||
const bool failed = NetworkReplicator::InvokeSerializer(obj->GetTypeHandle(), obj, stream, true);
|
||||
if (failed)
|
||||
{
|
||||
//NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Cannot serialize object {} of type {} (missing serialization logic)", item.ToString(), obj->GetType().ToString());
|
||||
continue;
|
||||
}
|
||||
const uint32 size = stream->GetPosition();
|
||||
if (size > MAX_uint16)
|
||||
{
|
||||
LOG(Error, "Too much data for object {} replication ({} bytes provided while limit is {}).", item.ToString(), size, MAX_uint16);
|
||||
continue;
|
||||
}
|
||||
|
||||
#if USE_NETWORK_REPLICATOR_CACHE
|
||||
// Process replication cache to skip sending object data if it didn't change
|
||||
if (item.RepCache.Data.Length() == size &&
|
||||
item.RepCache.Mask == e.TargetClients &&
|
||||
Platform::MemoryCompare(item.RepCache.Data.Get(), stream->GetBuffer(), size) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
item.RepCache.Mask = e.TargetClients;
|
||||
item.RepCache.Data.Copy(stream->GetBuffer(), size);
|
||||
#endif
|
||||
// TODO: use Unreliable for dynamic objects that are replicated every frame? (eg. player state)
|
||||
constexpr NetworkChannelType repChannel = NetworkChannelType::Reliable;
|
||||
|
||||
// Send object to clients
|
||||
NetworkMessageObjectReplicate msgData;
|
||||
msgData.OwnerFrame = NetworkManager::Frame;
|
||||
Guid objectId = item.ObjectId, parentId = item.ParentId;
|
||||
{
|
||||
// Remap local client object ids into server ids
|
||||
IdsRemappingTable.KeyOf(objectId, &objectId);
|
||||
IdsRemappingTable.KeyOf(parentId, &parentId);
|
||||
}
|
||||
NetworkMessage msg = peer->BeginSendMessage();
|
||||
msg.WriteStructure(msgData);
|
||||
msg.WriteNetworkId(objectId);
|
||||
msg.WriteNetworkId(parentId);
|
||||
msg.WriteNetworkName(obj->GetType().Fullname);
|
||||
NetworkMessageObjectReplicatePayload msgDataPayload;
|
||||
msgDataPayload.DataSize = size;
|
||||
const uint32 networkKeyIdWorstCaseSize = sizeof(uint32) + sizeof(Guid);
|
||||
const uint32 msgMaxData = peer->Config.MessageSize - msg.Position - sizeof(NetworkMessageObjectReplicatePayload);
|
||||
const uint32 partMaxData = peer->Config.MessageSize - sizeof(NetworkMessageObjectReplicatePart) - networkKeyIdWorstCaseSize;
|
||||
uint32 partsCount = 1;
|
||||
uint32 dataStart = 0;
|
||||
uint32 msgDataSize = size;
|
||||
if (size > msgMaxData)
|
||||
{
|
||||
// Send msgMaxData within first message
|
||||
msgDataSize = msgMaxData;
|
||||
dataStart += msgMaxData;
|
||||
|
||||
// Send rest of the data in separate parts
|
||||
partsCount += Math::DivideAndRoundUp(size - dataStart, partMaxData);
|
||||
}
|
||||
else
|
||||
dataStart += size;
|
||||
ASSERT(partsCount <= MAX_uint8);
|
||||
msgDataPayload.PartsCount = partsCount;
|
||||
msgDataPayload.PartSize = msgDataSize;
|
||||
msg.WriteStructure(msgDataPayload);
|
||||
msg.WriteBytes(stream->GetBuffer(), msgDataSize);
|
||||
uint32 dataSize = msgDataSize, messageSize = msg.Length;
|
||||
if (isClient)
|
||||
peer->EndSendMessage(repChannel, msg);
|
||||
else
|
||||
peer->EndSendMessage(repChannel, msg, CachedTargets);
|
||||
|
||||
// Send all other parts
|
||||
for (uint32 partIndex = 1; partIndex < partsCount; partIndex++)
|
||||
{
|
||||
NetworkMessageObjectReplicatePart msgDataPart;
|
||||
msgDataPart.OwnerFrame = msgData.OwnerFrame;
|
||||
msgDataPart.DataSize = msgDataPayload.DataSize;
|
||||
msgDataPart.PartsCount = msgDataPayload.PartsCount;
|
||||
msgDataPart.PartStart = dataStart;
|
||||
msgDataPart.PartSize = Math::Min(size - dataStart, partMaxData);
|
||||
msg = peer->BeginSendMessage();
|
||||
msg.WriteStructure(msgDataPart);
|
||||
msg.WriteNetworkId(objectId);
|
||||
msg.WriteBytes(stream->GetBuffer() + msgDataPart.PartStart, msgDataPart.PartSize);
|
||||
messageSize += msg.Length;
|
||||
dataSize += msgDataPart.PartSize;
|
||||
dataStart += msgDataPart.PartSize;
|
||||
if (isClient)
|
||||
peer->EndSendMessage(repChannel, msg);
|
||||
else
|
||||
peer->EndSendMessage(repChannel, msg, CachedTargets);
|
||||
}
|
||||
ASSERT_LOW_LAYER(dataStart == size);
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
// Network stats recording
|
||||
if (EnableProfiling)
|
||||
{
|
||||
const Pair<ScriptingTypeHandle, StringAnsiView> name(obj->GetTypeHandle(), StringAnsiView::Empty);
|
||||
auto& profileEvent = ProfilerEvents[name];
|
||||
profileEvent.Count++;
|
||||
profileEvent.DataSize += dataSize;
|
||||
profileEvent.MessageSize += messageSize;
|
||||
profileEvent.Receivers += isClient ? 1 : CachedTargets.Count();
|
||||
}
|
||||
#endif
|
||||
SendReplication(e.Object, e.TargetClients);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2009,70 +2117,7 @@ void NetworkInternal::NetworkReplicatorUpdate()
|
||||
PROFILE_CPU_NAMED("Rpc");
|
||||
for (auto& e : RpcQueue)
|
||||
{
|
||||
ScriptingObject* obj = e.Object.Get();
|
||||
if (!obj)
|
||||
continue;
|
||||
auto it = Objects.Find(obj->GetID());
|
||||
if (it == Objects.End())
|
||||
{
|
||||
#if USE_EDITOR || !BUILD_RELEASE
|
||||
if (!DespawnedObjects.Contains(obj->GetID()))
|
||||
LOG(Error, "Cannot invoke RPC method '{0}.{1}' on object '{2}' that is not registered in networking (use 'NetworkReplicator.AddObject').", e.Name.First.ToString(), String(e.Name.Second), obj->GetID());
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
auto& item = it->Item;
|
||||
|
||||
// Send RPC message
|
||||
//NETWORK_REPLICATOR_LOG(Info, "[NetworkReplicator] Rpc {}::{} object ID={}", e.Name.First.ToString(), String(e.Name.Second), item.ToString());
|
||||
NetworkMessageObjectRpc msgData;
|
||||
Guid msgObjectId = item.ObjectId;
|
||||
Guid msgParentId = item.ParentId;
|
||||
{
|
||||
// Remap local client object ids into server ids
|
||||
IdsRemappingTable.KeyOf(msgObjectId, &msgObjectId);
|
||||
IdsRemappingTable.KeyOf(msgParentId, &msgParentId);
|
||||
}
|
||||
msgData.ArgsSize = (uint16)e.ArgsData.Length();
|
||||
NetworkMessage msg = peer->BeginSendMessage();
|
||||
msg.WriteStructure(msgData);
|
||||
msg.WriteNetworkId(msgObjectId);
|
||||
msg.WriteNetworkId(msgParentId);
|
||||
msg.WriteNetworkName(obj->GetType().Fullname);
|
||||
msg.WriteNetworkName(e.Name.First.GetType().Fullname);
|
||||
msg.WriteNetworkName(e.Name.Second);
|
||||
msg.WriteBytes(e.ArgsData.Get(), e.ArgsData.Length());
|
||||
uint32 dataSize = e.ArgsData.Length(), messageSize = msg.Length, receivers = 0;
|
||||
NetworkChannelType channel = (NetworkChannelType)e.Info.Channel;
|
||||
if (e.Info.Server && isClient)
|
||||
{
|
||||
// Client -> Server
|
||||
#if USE_NETWORK_REPLICATOR_LOG
|
||||
if (e.Targets.Length() != 0)
|
||||
NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Server RPC '{}::{}' called with non-empty list of targets is not supported (only server will receive it)", e.Name.First.ToString(), e.Name.Second.ToString());
|
||||
#endif
|
||||
peer->EndSendMessage(channel, msg);
|
||||
receivers = 1;
|
||||
}
|
||||
else if (e.Info.Client && (isServer || isHost))
|
||||
{
|
||||
// Server -> Client(s)
|
||||
BuildCachedTargets(NetworkManager::Clients, item.TargetClientIds, e.Targets, NetworkManager::LocalClientId);
|
||||
peer->EndSendMessage(channel, msg, CachedTargets);
|
||||
receivers = CachedTargets.Count();
|
||||
}
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
// Network stats recording
|
||||
if (EnableProfiling && receivers)
|
||||
{
|
||||
auto& profileEvent = ProfilerEvents[e.Name];
|
||||
profileEvent.Count++;
|
||||
profileEvent.DataSize += dataSize;
|
||||
profileEvent.MessageSize += messageSize;
|
||||
profileEvent.Receivers += receivers;
|
||||
}
|
||||
#endif
|
||||
SendRpc(e);
|
||||
}
|
||||
RpcQueue.Clear();
|
||||
}
|
||||
@@ -2085,7 +2130,7 @@ void NetworkInternal::OnNetworkMessageObjectReplicate(NetworkEvent& event, Netwo
|
||||
{
|
||||
PROFILE_CPU();
|
||||
NetworkMessageObjectReplicate msgData;
|
||||
NetworkMessageObjectReplicatePayload msgDataPayload;
|
||||
NetworkMessageObjectPartPayload msgDataPayload;
|
||||
Guid objectId, parentId;
|
||||
StringAnsiView objectTypeName;
|
||||
event.Message.ReadStructure(msgData);
|
||||
@@ -2095,7 +2140,7 @@ void NetworkInternal::OnNetworkMessageObjectReplicate(NetworkEvent& event, Netwo
|
||||
event.Message.ReadStructure(msgDataPayload);
|
||||
ScopeLock lock(ObjectsLock);
|
||||
if (DespawnedObjects.Contains(objectId))
|
||||
return; // Skip replicating not-existing objects
|
||||
return; // Skip replicating non-existing objects
|
||||
NetworkReplicatedObject* e = ResolveObject(objectId, parentId, objectTypeName);
|
||||
if (!e)
|
||||
return;
|
||||
@@ -2114,7 +2159,7 @@ void NetworkInternal::OnNetworkMessageObjectReplicate(NetworkEvent& event, Netwo
|
||||
else
|
||||
{
|
||||
// Add to replication from multiple parts
|
||||
ReplicateItem* replicateItem = AddObjectReplicateItem(event, msgData.OwnerFrame, msgDataPayload.PartsCount, msgDataPayload.DataSize, objectId, 0, msgDataPayload.PartSize, senderClientId);
|
||||
PartsItem* replicateItem = AddObjectReplicateItem(event, msgData.OwnerFrame, msgDataPayload.PartsCount, msgDataPayload.DataSize, objectId, 0, msgDataPayload.PartSize, senderClientId);
|
||||
replicateItem->Object = e->Object;
|
||||
}
|
||||
}
|
||||
@@ -2122,13 +2167,13 @@ void NetworkInternal::OnNetworkMessageObjectReplicate(NetworkEvent& event, Netwo
|
||||
void NetworkInternal::OnNetworkMessageObjectReplicatePart(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
NetworkMessageObjectReplicatePart msgData;
|
||||
NetworkMessageObjectPart msgData;
|
||||
Guid objectId;
|
||||
event.Message.ReadStructure(msgData);
|
||||
event.Message.ReadNetworkId(objectId);
|
||||
ScopeLock lock(ObjectsLock);
|
||||
if (DespawnedObjects.Contains(objectId))
|
||||
return; // Skip replicating not-existing objects
|
||||
return; // Skip replicating non-existing objects
|
||||
|
||||
const uint32 senderClientId = client ? client->ClientId : NetworkManager::ServerClientId;
|
||||
AddObjectReplicateItem(event, msgData.OwnerFrame, msgData.PartsCount, msgData.DataSize, objectId, msgData.PartStart, msgData.PartSize, senderClientId);
|
||||
@@ -2288,14 +2333,16 @@ void NetworkInternal::OnNetworkMessageObjectRpc(NetworkEvent& event, NetworkClie
|
||||
{
|
||||
PROFILE_CPU();
|
||||
NetworkMessageObjectRpc msgData;
|
||||
Guid msgObjectId, msgParentId;
|
||||
NetworkMessageObjectPartPayload msgDataPayload;
|
||||
Guid objectId, parentId;
|
||||
StringAnsiView objectTypeName, rpcTypeName, rpcName;
|
||||
event.Message.ReadStructure(msgData);
|
||||
event.Message.ReadNetworkId(msgObjectId);
|
||||
event.Message.ReadNetworkId(msgParentId);
|
||||
event.Message.ReadNetworkId(objectId);
|
||||
event.Message.ReadNetworkId(parentId);
|
||||
event.Message.ReadNetworkName(objectTypeName);
|
||||
event.Message.ReadNetworkName(rpcTypeName);
|
||||
event.Message.ReadNetworkName(rpcName);
|
||||
event.Message.ReadStructure(msgDataPayload);
|
||||
ScopeLock lock(ObjectsLock);
|
||||
|
||||
// Find RPC info
|
||||
@@ -2305,11 +2352,11 @@ void NetworkInternal::OnNetworkMessageObjectRpc(NetworkEvent& event, NetworkClie
|
||||
const NetworkRpcInfo* info = NetworkRpcInfo::RPCsTable.TryGet(name);
|
||||
if (!info)
|
||||
{
|
||||
NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Unknown RPC {}::{} for object {}", String(rpcTypeName), String(rpcName), msgObjectId);
|
||||
NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Unknown RPC {}::{} for object {}", String(rpcTypeName), String(rpcName), objectId);
|
||||
return;
|
||||
}
|
||||
|
||||
NetworkReplicatedObject* e = ResolveObject(msgObjectId, msgParentId, objectTypeName);
|
||||
NetworkReplicatedObject* e = ResolveObject(objectId, parentId, objectTypeName);
|
||||
if (e)
|
||||
{
|
||||
auto& item = *e;
|
||||
@@ -2329,18 +2376,50 @@ void NetworkInternal::OnNetworkMessageObjectRpc(NetworkEvent& event, NetworkClie
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup message reading stream
|
||||
if (CachedReadStream == nullptr)
|
||||
CachedReadStream = New<NetworkStream>();
|
||||
NetworkStream* stream = CachedReadStream;
|
||||
stream->SenderId = client ? client->ClientId : NetworkManager::ServerClientId;
|
||||
stream->Initialize(event.Message.Buffer + event.Message.Position, msgData.ArgsSize);
|
||||
|
||||
// Execute RPC
|
||||
info->Execute(obj, stream, info->Tag);
|
||||
const uint32 senderClientId = client ? client->ClientId : NetworkManager::ServerClientId;
|
||||
if (msgDataPayload.PartsCount == 1)
|
||||
{
|
||||
// Call RPC
|
||||
InvokeObjectRpc(info, event.Message.Buffer + event.Message.Position, msgDataPayload.DataSize, senderClientId, obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add to RPC from multiple parts
|
||||
PartsItem* rpcItem = AddObjectRpcItem(event, msgData.OwnerFrame, msgDataPayload.PartsCount, msgDataPayload.DataSize, objectId, 0, msgDataPayload.PartSize, senderClientId);
|
||||
rpcItem->Object = e->Object;
|
||||
rpcItem->Tag = info;
|
||||
}
|
||||
}
|
||||
else if (info->Channel != static_cast<uint8>(NetworkChannelType::Unreliable) && info->Channel != static_cast<uint8>(NetworkChannelType::UnreliableOrdered))
|
||||
{
|
||||
NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Unknown object {} RPC {}::{}", msgObjectId, String(rpcTypeName), String(rpcName));
|
||||
NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Unknown object {} RPC {}::{}", objectId, String(rpcTypeName), String(rpcName));
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkInternal::OnNetworkMessageObjectRpcPart(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
NetworkMessageObjectPart msgData;
|
||||
Guid objectId;
|
||||
event.Message.ReadStructure(msgData);
|
||||
event.Message.ReadNetworkId(objectId);
|
||||
ScopeLock lock(ObjectsLock);
|
||||
if (DespawnedObjects.Contains(objectId))
|
||||
return; // Skip replicating non-existing objects
|
||||
|
||||
const uint32 senderClientId = client ? client->ClientId : NetworkManager::ServerClientId;
|
||||
PartsItem* rpcItem = AddObjectRpcItem(event, msgData.OwnerFrame, msgData.PartsCount, msgData.DataSize, objectId, msgData.PartStart, msgData.PartSize, senderClientId);
|
||||
if (rpcItem && rpcItem->PartsLeft == 0)
|
||||
{
|
||||
// Got all parts so invoke RPC
|
||||
ScriptingObject* obj = rpcItem->Object.Get();
|
||||
if (obj)
|
||||
{
|
||||
InvokeObjectRpc((const NetworkRpcInfo*)rpcItem->Tag, rpcItem->Data.Get(), rpcItem->Data.Count(), rpcItem->OwnerClientId, obj);
|
||||
}
|
||||
|
||||
// Remove item
|
||||
int32 partIndex = (int32)((RpcParts.Get() - rpcItem) / sizeof(rpcItem));
|
||||
RpcParts.RemoveAt(partIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1969,6 +1969,7 @@ void PhysicsBackend::EndSimulateScene(void* scene)
|
||||
scenePhysX->EventsCallback.SendTriggerEvents();
|
||||
scenePhysX->EventsCallback.SendCollisionEvents();
|
||||
scenePhysX->EventsCallback.SendJointEvents();
|
||||
scenePhysX->EventsCallback.Clear();
|
||||
}
|
||||
|
||||
// Clear delta after simulation ended
|
||||
@@ -4466,14 +4467,14 @@ void PhysicsBackend::FlushRequests(void* scene)
|
||||
}
|
||||
if (scenePhysX->RemoveColliders.HasItems())
|
||||
{
|
||||
for (int32 i = 0; i < scenePhysX->RemoveColliders.Count(); i++)
|
||||
scenePhysX->EventsCallback.OnColliderRemoved(scenePhysX->RemoveColliders[i]);
|
||||
for (PhysicsColliderActor* e : scenePhysX->RemoveColliders)
|
||||
scenePhysX->EventsCallback.OnColliderRemoved(e);
|
||||
scenePhysX->RemoveColliders.Clear();
|
||||
}
|
||||
if (scenePhysX->RemoveJoints.HasItems())
|
||||
{
|
||||
for (int32 i = 0; i < scenePhysX->RemoveJoints.Count(); i++)
|
||||
scenePhysX->EventsCallback.OnJointRemoved(scenePhysX->RemoveJoints[i]);
|
||||
for (Joint* e : scenePhysX->RemoveJoints)
|
||||
scenePhysX->EventsCallback.OnJointRemoved(e);
|
||||
scenePhysX->RemoveJoints.Clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -543,11 +543,9 @@ void WindowsPlatform::ReleaseMutex()
|
||||
}
|
||||
}
|
||||
|
||||
void WindowsPlatform::PreInit(void* hInstance)
|
||||
PRAGMA_DISABLE_OPTIMIZATION;
|
||||
void CheckInstructionSet()
|
||||
{
|
||||
ASSERT(hInstance);
|
||||
Instance = hInstance;
|
||||
|
||||
#if PLATFORM_ARCH_X86 || PLATFORM_ARCH_X64
|
||||
// Check the minimum vector instruction set support
|
||||
int32 cpuInfo[4] = { -1 };
|
||||
@@ -597,10 +595,19 @@ void WindowsPlatform::PreInit(void* hInstance)
|
||||
{
|
||||
// Not supported CPU
|
||||
CPUBrand cpu;
|
||||
Error(String::Format(TEXT("Cannot start program due to lack of CPU feature {}.\n\n{}"), missingFeature, String(cpu.Buffer)));
|
||||
Platform::Error(String::Format(TEXT("Cannot start program due to lack of CPU feature {}.\n\n{}"), missingFeature, String(cpu.Buffer)));
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
PRAGMA_ENABLE_OPTIMIZATION;
|
||||
|
||||
void WindowsPlatform::PreInit(void* hInstance)
|
||||
{
|
||||
ASSERT(hInstance);
|
||||
Instance = hInstance;
|
||||
|
||||
CheckInstructionSet();
|
||||
|
||||
// Disable the process from being showing "ghosted" while not responding messages during slow tasks
|
||||
DisableProcessWindowsGhosting();
|
||||
|
||||
@@ -47,6 +47,9 @@ public:
|
||||
Data CachedData;
|
||||
ToneMappingMode Mode = ToneMappingMode::None;
|
||||
Texture* LutTexture = nullptr;
|
||||
#if COMPILE_WITH_DEV_ENV
|
||||
uint64 FrameRendered = 0;
|
||||
#endif
|
||||
|
||||
~ColorGradingCustomBuffer()
|
||||
{
|
||||
@@ -54,6 +57,17 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#if COMPILE_WITH_DEV_ENV
|
||||
|
||||
void ColorGradingPass::OnShaderReloading(Asset* obj)
|
||||
{
|
||||
_psLut.Release();
|
||||
invalidateResources();
|
||||
_reloadedFrame = Engine::FrameCount;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
String ColorGradingPass::ToString() const
|
||||
{
|
||||
return TEXT("ColorGradingPass");
|
||||
@@ -194,6 +208,9 @@ GPUTexture* ColorGradingPass::RenderLUT(RenderContext& renderContext)
|
||||
// Check if LUT parameter hasn't been changed since the last time
|
||||
if (Platform::MemoryCompare(&colorGradingBuffer.CachedData , &data, sizeof(Data)) == 0 &&
|
||||
colorGradingBuffer.Mode == toneMapping.Mode &&
|
||||
#if COMPILE_WITH_DEV_ENV
|
||||
colorGradingBuffer.FrameRendered > _reloadedFrame &&
|
||||
#endif
|
||||
Engine::FrameCount > 30 && // Skip caching when engine is starting TODO: find why this hack is needed
|
||||
colorGradingBuffer.LutTexture == lutTexture)
|
||||
{
|
||||
@@ -203,6 +220,9 @@ GPUTexture* ColorGradingPass::RenderLUT(RenderContext& renderContext)
|
||||
colorGradingBuffer.CachedData = data;
|
||||
colorGradingBuffer.Mode = toneMapping.Mode;
|
||||
colorGradingBuffer.LutTexture = lutTexture;
|
||||
#if COMPILE_WITH_DEV_ENV
|
||||
colorGradingBuffer.FrameRendered = Engine::FrameCount;
|
||||
#endif
|
||||
|
||||
// Render LUT
|
||||
PROFILE_GPU("Color Grading LUT");
|
||||
|
||||
@@ -25,11 +25,8 @@ public:
|
||||
|
||||
private:
|
||||
#if COMPILE_WITH_DEV_ENV
|
||||
void OnShaderReloading(Asset* obj)
|
||||
{
|
||||
_psLut.Release();
|
||||
invalidateResources();
|
||||
}
|
||||
uint64 _reloadedFrame = 0;
|
||||
void OnShaderReloading(Asset* obj);
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
@@ -98,6 +98,7 @@ void EyeAdaptationPass::Render(RenderContext& renderContext, GPUTexture* colorBu
|
||||
if (mode == EyeAdaptationMode::Manual)
|
||||
{
|
||||
// Apply fixed manual exposure
|
||||
context->ResetSR();
|
||||
context->SetRenderTarget(*colorBuffer);
|
||||
context->SetViewportAndScissors((float)colorBuffer->Width(), (float)colorBuffer->Height());
|
||||
context->SetState(_psManual);
|
||||
|
||||
@@ -32,7 +32,7 @@ public class Scripting : EngineModule
|
||||
options.ScriptingAPI.Defines.Add("NET");
|
||||
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"
|
||||
AddFrameworkDefines("NET{0}_{1}_OR_GREATER", i, 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);
|
||||
|
||||
@@ -65,6 +65,8 @@
|
||||
|
||||
#endif
|
||||
|
||||
#undef MessageBox
|
||||
|
||||
static void stbWrite(void* context, void* data, int size)
|
||||
{
|
||||
auto file = (FileWriteStream*)context;
|
||||
|
||||
@@ -104,13 +104,20 @@ namespace FlaxEngine.GUI
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether enable drop down icon drawing.
|
||||
/// </summary>
|
||||
[EditorOrder(1)]
|
||||
[EditorOrder(2)]
|
||||
public bool EnableDropDownIcon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get or sets a value indicating whether the panel can be opened or closed via the user interacting with the ui.
|
||||
/// Changing the open/ closed state from code or the Properties panel will still work regardless.
|
||||
/// </summary>
|
||||
[EditorOrder(1)]
|
||||
public bool CanOpenClose { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to enable containment line drawing,
|
||||
/// </summary>
|
||||
[EditorOrder(2)]
|
||||
[EditorOrder(3)]
|
||||
public bool EnableContainmentLines { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
@@ -369,7 +376,7 @@ namespace FlaxEngine.GUI
|
||||
}
|
||||
|
||||
// Header
|
||||
var color = _mouseOverHeader ? HeaderColorMouseOver : HeaderColor;
|
||||
var color = _mouseOverHeader && CanOpenClose ? HeaderColorMouseOver : HeaderColor;
|
||||
if (color.A > 0.0f)
|
||||
{
|
||||
Render2D.FillRectangle(new Rectangle(0, 0, Width, HeaderHeight), color);
|
||||
@@ -510,7 +517,7 @@ namespace FlaxEngine.GUI
|
||||
if (button == MouseButton.Left && _mouseButtonLeftDown)
|
||||
{
|
||||
_mouseButtonLeftDown = false;
|
||||
if (_mouseOverHeader)
|
||||
if (_mouseOverHeader && CanOpenClose)
|
||||
Toggle();
|
||||
return true;
|
||||
}
|
||||
@@ -540,7 +547,7 @@ namespace FlaxEngine.GUI
|
||||
if (button == MouseButton.Left && _mouseButtonLeftDown)
|
||||
{
|
||||
_mouseButtonLeftDown = false;
|
||||
if (_mouseOverHeader)
|
||||
if (_mouseOverHeader && CanOpenClose)
|
||||
Toggle();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ namespace FlaxEngine.GUI
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
public override void DrawSelf()
|
||||
{
|
||||
var bounds = new Rectangle(Float2.Zero, Size);
|
||||
|
||||
@@ -205,21 +205,6 @@ namespace FlaxEngine.GUI
|
||||
Render2D.DrawTexture(buffer, bounds, color);
|
||||
else
|
||||
Render2D.FillRectangle(bounds, Color.Black);
|
||||
|
||||
// Push clipping mask
|
||||
if (ClipChildren)
|
||||
{
|
||||
GetDesireClientArea(out var clientArea);
|
||||
Render2D.PushClip(ref clientArea);
|
||||
}
|
||||
|
||||
DrawChildren();
|
||||
|
||||
// Pop clipping mask
|
||||
if (ClipChildren)
|
||||
{
|
||||
Render2D.PopClip();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libGenericCodeGen.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libGenericCodeGen.a
LFS
vendored
Binary file not shown.
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libHLSL.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libHLSL.a
LFS
vendored
Binary file not shown.
Binary file not shown.
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libNvCloth.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libNvCloth.a
LFS
vendored
Binary file not shown.
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libOGLCompiler.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libOGLCompiler.a
LFS
vendored
Binary file not shown.
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libOSDependent.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libOSDependent.a
LFS
vendored
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libPhysX_static_64.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libPhysX_static_64.a
LFS
vendored
Binary file not shown.
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libSPIRV-Tools-opt.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libSPIRV-Tools-opt.a
LFS
vendored
Binary file not shown.
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libSPIRV-Tools.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libSPIRV-Tools.a
LFS
vendored
Binary file not shown.
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libSPIRV.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libSPIRV.a
LFS
vendored
Binary file not shown.
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a
LFS
vendored
Binary file not shown.
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libcurl.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libcurl.a
LFS
vendored
Binary file not shown.
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libfreetype.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libfreetype.a
LFS
vendored
Binary file not shown.
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libglslang.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libglslang.a
LFS
vendored
Binary file not shown.
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libopenal.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libopenal.a
LFS
vendored
Binary file not shown.
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libvorbis.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libvorbis.a
LFS
vendored
Binary file not shown.
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libvorbisenc.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libvorbisenc.a
LFS
vendored
Binary file not shown.
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libvorbisfile.a
LFS
vendored
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libvorbisfile.a
LFS
vendored
Binary file not shown.
@@ -164,16 +164,14 @@ float3 TonemapACES(float3 linearColor)
|
||||
// The code was originally written by Stephen Hill (@self_shadow).
|
||||
|
||||
// sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT
|
||||
static const float3x3 ACESInputMat =
|
||||
{
|
||||
static const float3x3 ACESInputMat = {
|
||||
{0.59719, 0.35458, 0.04823},
|
||||
{0.07600, 0.90834, 0.01566},
|
||||
{0.02840, 0.13383, 0.83777}
|
||||
};
|
||||
|
||||
// ODT_SAT => XYZ => D60_2_D65 => sRGB
|
||||
static const float3x3 ACESOutputMat =
|
||||
{
|
||||
static const float3x3 ACESOutputMat = {
|
||||
{ 1.60475, -0.53108, -0.07367},
|
||||
{-0.10208, 1.10813, -0.00605},
|
||||
{-0.00327, -0.07276, 1.07602}
|
||||
@@ -188,6 +186,7 @@ float3 TonemapACES(float3 linearColor)
|
||||
color = a / b;
|
||||
|
||||
color = mul(ACESOutputMat, color);
|
||||
|
||||
return saturate(color);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ float4 FastTonemapInvert(float4 c)
|
||||
return float4(FastTonemapInvert(c.rgb), c.a);
|
||||
}
|
||||
|
||||
float LinearToSrgbChannel(float linearColor)
|
||||
float LinearToSrgb(float linearColor)
|
||||
{
|
||||
if (linearColor < 0.00313067)
|
||||
return linearColor * 12.92;
|
||||
@@ -46,10 +46,7 @@ float LinearToSrgbChannel(float linearColor)
|
||||
|
||||
float3 LinearToSrgb(float3 linearColor)
|
||||
{
|
||||
return float3(
|
||||
LinearToSrgbChannel(linearColor.r),
|
||||
LinearToSrgbChannel(linearColor.g),
|
||||
LinearToSrgbChannel(linearColor.b));
|
||||
return float3(LinearToSrgb(linearColor.r), LinearToSrgb(linearColor.g), LinearToSrgb(linearColor.b));
|
||||
}
|
||||
|
||||
float3 sRGBToLinear(float3 color)
|
||||
|
||||
4
Source/ThirdParty/detex/detex.h
vendored
4
Source/ThirdParty/detex/detex.h
vendored
@@ -72,7 +72,11 @@ __BEGIN_DECLS
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define DETEX_INLINE_ONLY __forceinline
|
||||
#else
|
||||
#define DETEX_INLINE_ONLY __attribute__((always_inline)) inline
|
||||
#endif
|
||||
#define DETEX_RESTRICT __restrict
|
||||
|
||||
/* Maximum uncompressed block size in bytes. */
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
|
||||
#include "../common/TracyYield.hpp"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
extern void CheckInstructionSet();
|
||||
#endif
|
||||
|
||||
namespace tracy
|
||||
{
|
||||
|
||||
@@ -18,6 +22,10 @@ tracy_no_inline static void InitRpmallocPlumbing()
|
||||
const auto done = RpInitDone.load( std::memory_order_acquire );
|
||||
if( !done )
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
// Check instruction set before executing any code (Tracy init static vars before others)
|
||||
CheckInstructionSet();
|
||||
#endif
|
||||
int expected = 0;
|
||||
while( !RpInitLock.compare_exchange_weak( expected, 1, std::memory_order_release, std::memory_order_relaxed ) ) { expected = 0; YieldThread(); }
|
||||
const auto done = RpInitDone.load( std::memory_order_acquire );
|
||||
|
||||
@@ -127,11 +127,12 @@ namespace Flax.Deps.Dependencies
|
||||
{ "CC", "clang-" + Configuration.LinuxClangMinVer },
|
||||
{ "CC_FOR_BUILD", "clang-" + Configuration.LinuxClangMinVer },
|
||||
{ "CXX", "clang++-" + Configuration.LinuxClangMinVer },
|
||||
{ "CMAKE_BUILD_PARALLEL_LEVEL", CmakeBuildParallel },
|
||||
};
|
||||
|
||||
// Build for Linux
|
||||
RunCmake(root, platform, TargetArchitecture.x64, " -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF " + globalConfig, envVars);
|
||||
Utilities.Run("make", null, null, root, Utilities.RunOptions.ThrowExceptionOnError, envVars);
|
||||
Utilities.Run("make", null, null, root, Utilities.RunOptions.DefaultTool, envVars);
|
||||
configHeaderFilePath = Path.Combine(root, "include", "assimp", "config.h");
|
||||
var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.x64);
|
||||
Utilities.FileCopy(Path.Combine(root, "lib", "libassimp.a"), Path.Combine(depsFolder, "libassimp.a"));
|
||||
@@ -143,11 +144,11 @@ namespace Flax.Deps.Dependencies
|
||||
foreach (var architecture in new[] { TargetArchitecture.x64, TargetArchitecture.ARM64 })
|
||||
{
|
||||
RunCmake(root, platform, architecture, " -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF " + globalConfig);
|
||||
Utilities.Run("make", null, null, root, Utilities.RunOptions.ThrowExceptionOnError);
|
||||
Utilities.Run("make", null, null, root, Utilities.RunOptions.DefaultTool);
|
||||
configHeaderFilePath = Path.Combine(root, "include", "assimp", "config.h");
|
||||
var depsFolder = GetThirdPartyFolder(options, platform, architecture);
|
||||
Utilities.FileCopy(Path.Combine(root, "lib", "libassimp.a"), Path.Combine(depsFolder, "libassimp.a"));
|
||||
Utilities.Run("make", "clean", null, root, Utilities.RunOptions.ThrowExceptionOnError);
|
||||
Utilities.Run("make", "clean", null, root, Utilities.RunOptions.DefaultTool);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@ namespace Flax.Deps.Dependencies
|
||||
var buildFolder = Path.Combine(nvCloth, "compiler", platform.ToString() + '_' + architecture.ToString());
|
||||
var envVars = new Dictionary<string, string>();
|
||||
envVars["GW_DEPS_ROOT"] = root;
|
||||
envVars["CMAKE_BUILD_PARALLEL_LEVEL"] = CmakeBuildParallel;
|
||||
switch (platform)
|
||||
{
|
||||
case TargetPlatform.Windows:
|
||||
@@ -166,6 +167,8 @@ namespace Flax.Deps.Dependencies
|
||||
cmakeArgs += " -DTARGET_BUILD_PLATFORM=linux";
|
||||
cmakeName = "linux";
|
||||
binariesPrefix = "lib";
|
||||
envVars.Add("CC", "clang-" + Configuration.LinuxClangMinVer);
|
||||
envVars.Add("CXX", "clang++-" + Configuration.LinuxClangMinVer);
|
||||
break;
|
||||
default: throw new InvalidPlatformException(platform);
|
||||
}
|
||||
|
||||
@@ -123,6 +123,7 @@ namespace Flax.Deps.Dependencies
|
||||
{
|
||||
{ "CC", "clang-" + Configuration.LinuxClangMinVer },
|
||||
{ "CC_FOR_BUILD", "clang-" + Configuration.LinuxClangMinVer },
|
||||
{ "CXX", "clang++-" + Configuration.LinuxClangMinVer },
|
||||
{ "CMAKE_BUILD_PARALLEL_LEVEL", CmakeBuildParallel },
|
||||
};
|
||||
var config = $"-DALSOFT_REQUIRE_ALSA=ON " +
|
||||
|
||||
@@ -238,6 +238,8 @@ namespace Flax.Deps.Dependencies
|
||||
case TargetPlatform.Linux:
|
||||
envVars.Add("CC", "clang-" + Configuration.LinuxClangMinVer);
|
||||
envVars.Add("CC_FOR_BUILD", "clang-" + Configuration.LinuxClangMinVer);
|
||||
envVars.Add("CXX", "clang++-" + Configuration.LinuxClangMinVer);
|
||||
envVars.Add("CMAKE_BUILD_PARALLEL_LEVEL", CmakeBuildParallel);
|
||||
break;
|
||||
case TargetPlatform.Mac: break;
|
||||
default: throw new InvalidPlatformException(BuildPlatform);
|
||||
@@ -258,7 +260,7 @@ namespace Flax.Deps.Dependencies
|
||||
Log.Info("Building PhysX version " + File.ReadAllText(Path.Combine(root, "physx", "version.txt")) + " to " + binariesSubDir);
|
||||
|
||||
// Generate project files
|
||||
Utilities.Run(projectGenPath, preset, null, projectGenDir, Utilities.RunOptions.ThrowExceptionOnError, envVars);
|
||||
Utilities.Run(projectGenPath, preset, null, projectGenDir, Utilities.RunOptions.DefaultTool, envVars);
|
||||
|
||||
switch (targetPlatform)
|
||||
{
|
||||
@@ -304,10 +306,10 @@ namespace Flax.Deps.Dependencies
|
||||
}
|
||||
break;
|
||||
case TargetPlatform.Linux:
|
||||
Utilities.Run("make", null, null, Path.Combine(projectGenDir, "compiler", "linux-" + configuration), Utilities.RunOptions.ConsoleLogOutput);
|
||||
Utilities.Run("make", null, null, Path.Combine(projectGenDir, "compiler", "linux-" + configuration), Utilities.RunOptions.ConsoleLogOutput, envVars);
|
||||
break;
|
||||
case TargetPlatform.Mac:
|
||||
Utilities.Run("xcodebuild", "-project PhysXSDK.xcodeproj -alltargets -configuration " + configuration, null, Path.Combine(projectGenDir, "compiler", preset), Utilities.RunOptions.ConsoleLogOutput);
|
||||
Utilities.Run("xcodebuild", "-project PhysXSDK.xcodeproj -alltargets -configuration " + configuration, null, Path.Combine(projectGenDir, "compiler", preset), Utilities.RunOptions.ConsoleLogOutput, envVars);
|
||||
break;
|
||||
default: throw new InvalidPlatformException(BuildPlatform);
|
||||
}
|
||||
|
||||
@@ -107,13 +107,14 @@ namespace Flax.Deps.Dependencies
|
||||
{
|
||||
{ "CC", "clang-" + Configuration.LinuxClangMinVer },
|
||||
{ "CC_FOR_BUILD", "clang-" + Configuration.LinuxClangMinVer },
|
||||
{ "CMAKE_BUILD_PARALLEL_LEVEL", CmakeBuildParallel },
|
||||
};
|
||||
var buildDir = Path.Combine(root, "build");
|
||||
SetupDirectory(buildDir, true);
|
||||
Utilities.Run("chmod", "+x configure", null, root, Utilities.RunOptions.ThrowExceptionOnError);
|
||||
Utilities.Run(Path.Combine(root, "configure"), string.Join(" ", settings) + " --prefix=\"" + buildDir + "\"", null, root, Utilities.RunOptions.ThrowExceptionOnError, envVars);
|
||||
Utilities.Run("make", null, null, root, Utilities.RunOptions.ThrowExceptionOnError);
|
||||
Utilities.Run("make", "install", null, root, Utilities.RunOptions.ThrowExceptionOnError);
|
||||
Utilities.Run("chmod", "+x configure", null, root, Utilities.RunOptions.DefaultTool);
|
||||
Utilities.Run(Path.Combine(root, "configure"), string.Join(" ", settings) + " --prefix=\"" + buildDir + "\"", null, root, Utilities.RunOptions.DefaultTool, envVars);
|
||||
Utilities.Run("make", null, null, root, Utilities.RunOptions.DefaultTool);
|
||||
Utilities.Run("make", "install", null, root, Utilities.RunOptions.DefaultTool);
|
||||
var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.x64);
|
||||
var filename = "libcurl.a";
|
||||
Utilities.FileCopy(Path.Combine(buildDir, "lib", filename), Path.Combine(depsFolder, filename));
|
||||
@@ -153,11 +154,11 @@ namespace Flax.Deps.Dependencies
|
||||
};
|
||||
var buildDir = Path.Combine(root, "build");
|
||||
SetupDirectory(buildDir, true);
|
||||
Utilities.Run("chmod", "+x configure", null, root, Utilities.RunOptions.ThrowExceptionOnError);
|
||||
Utilities.Run("chmod", "+x install-sh", null, root, Utilities.RunOptions.ThrowExceptionOnError);
|
||||
Utilities.Run(Path.Combine(root, "configure"), string.Join(" ", settings) + " --host=" + archName + " --prefix=\"" + buildDir + "\"", null, root, Utilities.RunOptions.ThrowExceptionOnError, envVars);
|
||||
Utilities.Run("make", null, null, root, Utilities.RunOptions.ThrowExceptionOnError);
|
||||
Utilities.Run("make", "install", null, root, Utilities.RunOptions.ThrowExceptionOnError);
|
||||
Utilities.Run("chmod", "+x configure", null, root, Utilities.RunOptions.DefaultTool);
|
||||
Utilities.Run("chmod", "+x install-sh", null, root, Utilities.RunOptions.DefaultTool);
|
||||
Utilities.Run(Path.Combine(root, "configure"), string.Join(" ", settings) + " --host=" + archName + " --prefix=\"" + buildDir + "\"", null, root, Utilities.RunOptions.DefaultTool, envVars);
|
||||
Utilities.Run("make", null, null, root, Utilities.RunOptions.DefaultTool);
|
||||
Utilities.Run("make", "install", null, root, Utilities.RunOptions.DefaultTool);
|
||||
var depsFolder = GetThirdPartyFolder(options, platform, architecture);
|
||||
var filename = "libcurl.a";
|
||||
Utilities.FileCopy(Path.Combine(buildDir, "lib", filename), Path.Combine(depsFolder, filename));
|
||||
|
||||
@@ -114,19 +114,22 @@ namespace Flax.Deps.Dependencies
|
||||
}
|
||||
case TargetPlatform.Linux:
|
||||
{
|
||||
var envVars = new Dictionary<string, string>
|
||||
var envVars = new Dictionary<string, string>
|
||||
{
|
||||
{ "CC", "clang-" + Configuration.LinuxClangMinVer },
|
||||
{ "CC_FOR_BUILD", "clang-" + Configuration.LinuxClangMinVer }
|
||||
{ "CC_FOR_BUILD", "clang-" + Configuration.LinuxClangMinVer },
|
||||
{ "CMAKE_BUILD_PARALLEL_LEVEL", CmakeBuildParallel },
|
||||
};
|
||||
|
||||
// Fix scripts
|
||||
Utilities.Run("sed", "-i -e \'s/\r$//\' autogen.sh", null, root, Utilities.RunOptions.ThrowExceptionOnError, envVars);
|
||||
Utilities.Run("sed", "-i -e \'s/\r$//\' configure", null, root, Utilities.RunOptions.ThrowExceptionOnError, envVars);
|
||||
Utilities.Run("dos2unix", "autogen.sh", null, root, Utilities.RunOptions.ThrowExceptionOnError, envVars);
|
||||
Utilities.Run("dos2unix", "configure", null, root, Utilities.RunOptions.ThrowExceptionOnError, envVars);
|
||||
//Utilities.Run("sed", "-i -e \'s/\r$//\' autogen.sh", null, root, Utilities.RunOptions.ThrowExceptionOnError, envVars);
|
||||
//Utilities.Run("sed", "-i -e \'s/\r$//\' configure", null, root, Utilities.RunOptions.ThrowExceptionOnError, envVars);
|
||||
Utilities.Run("chmod", "+x autogen.sh", null, root, Utilities.RunOptions.ThrowExceptionOnError);
|
||||
Utilities.Run("chmod", "+x configure", null, root, Utilities.RunOptions.ThrowExceptionOnError);
|
||||
|
||||
Utilities.Run(Path.Combine(root, "autogen.sh"), null, null, root, Utilities.RunOptions.Default, envVars);
|
||||
Utilities.Run(Path.Combine(root, "autogen.sh"), null, null, root, Utilities.RunOptions.ThrowExceptionOnError, envVars);
|
||||
|
||||
// Disable using libpng even if it's found on the system
|
||||
var cmakeFile = Path.Combine(root, "CMakeLists.txt");
|
||||
@@ -140,8 +143,8 @@ namespace Flax.Deps.Dependencies
|
||||
// Build for Linux
|
||||
SetupDirectory(buildDir, true);
|
||||
var toolchain = UnixToolchain.GetToolchainName(platform, TargetArchitecture.x64);
|
||||
Utilities.Run("cmake", string.Format("-G \"Unix Makefiles\" -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DFT_WITH_BZIP2=OFF -DFT_WITH_ZLIB=OFF -DFT_WITH_PNG=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER_TARGET={0} ..", toolchain), null, buildDir, Utilities.RunOptions.ThrowExceptionOnError, envVars);
|
||||
Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ThrowExceptionOnError, envVars);
|
||||
Utilities.Run("cmake", string.Format("-G \"Unix Makefiles\" -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DFT_WITH_BZIP2=OFF -DFT_WITH_ZLIB=OFF -DFT_WITH_PNG=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER_TARGET={0} ..", toolchain), null, buildDir, Utilities.RunOptions.DefaultTool, envVars);
|
||||
Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.DefaultTool, envVars);
|
||||
var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.x64);
|
||||
Utilities.FileCopy(Path.Combine(buildDir, libraryFileName), Path.Combine(depsFolder, libraryFileName));
|
||||
|
||||
|
||||
@@ -303,9 +303,9 @@ namespace Flax.Deps.Dependencies
|
||||
}
|
||||
|
||||
// Ensure to have dependencies installed
|
||||
Utilities.Run("ninja", "--version", null, null, Utilities.RunOptions.ThrowExceptionOnError);
|
||||
Utilities.Run("cmake", "--version", null, null, Utilities.RunOptions.ThrowExceptionOnError);
|
||||
Utilities.Run("python", "--version", null, null, Utilities.RunOptions.ThrowExceptionOnError);
|
||||
Utilities.Run("ninja", "--version", null, null, Utilities.RunOptions.DefaultTool);
|
||||
Utilities.Run("cmake", "--version", null, null, Utilities.RunOptions.DefaultTool);
|
||||
Utilities.Run("python", "--version", null, null, Utilities.RunOptions.DefaultTool);
|
||||
|
||||
// Get the source
|
||||
if (!Directory.Exists(Path.Combine(root, ".git")))
|
||||
|
||||
@@ -366,15 +366,17 @@ namespace Flax.Deps.Dependencies
|
||||
var envVars = new Dictionary<string, string>
|
||||
{
|
||||
{ "CC", "clang-" + Configuration.LinuxClangMinVer },
|
||||
{ "CC_FOR_BUILD", "clang-" + Configuration.LinuxClangMinVer }
|
||||
{ "CC_FOR_BUILD", "clang-" + Configuration.LinuxClangMinVer },
|
||||
{ "CXX", "clang++-" + Configuration.LinuxClangMinVer },
|
||||
{ "CMAKE_BUILD_PARALLEL_LEVEL", CmakeBuildParallel },
|
||||
};
|
||||
var buildDir = Path.Combine(root, "build");
|
||||
|
||||
Utilities.Run(Path.Combine(root, "autogen.sh"), null, null, root, Utilities.RunOptions.Default, envVars);
|
||||
Utilities.Run(Path.Combine(root, "autogen.sh"), null, null, root, Utilities.RunOptions.DefaultTool, envVars);
|
||||
|
||||
// Build for Linux
|
||||
var toolchain = UnixToolchain.GetToolchainName(platform, TargetArchitecture.x64);
|
||||
Utilities.Run(Path.Combine(root, "configure"), string.Format("--host={0}", toolchain), null, root, Utilities.RunOptions.Default, envVars);
|
||||
Utilities.Run(Path.Combine(root, "configure"), string.Format("--host={0}", toolchain), null, root, Utilities.RunOptions.ThrowExceptionOnError, envVars);
|
||||
SetupDirectory(buildDir, true);
|
||||
Utilities.Run("cmake", "-G \"Unix Makefiles\" -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release ..", null, buildDir, Utilities.RunOptions.ConsoleLogOutput, envVars);
|
||||
Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput, envVars);
|
||||
|
||||
@@ -456,7 +456,7 @@ namespace Flax.Deps
|
||||
case TargetPlatform.Mac: break;
|
||||
default: throw new InvalidPlatformException(BuildPlatform);
|
||||
}
|
||||
Utilities.Run(path, args, null, workspace, Utilities.RunOptions.ThrowExceptionOnError, envVars);
|
||||
Utilities.Run(path, args, null, workspace, Utilities.RunOptions.DefaultTool, envVars);
|
||||
}
|
||||
|
||||
internal bool GetMsBuildForPlatform(TargetPlatform targetPlatform, out VisualStudioVersion vsVersion, out string msBuildPath)
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Flax.Build
|
||||
/// Specifies the minimum Clang compiler version to use on Linux (eg. 10).
|
||||
/// </summary>
|
||||
[CommandLine("linuxClangMinVer", "<version>", "Specifies the minimum Clang compiler version to use on Linux (eg. 10).")]
|
||||
public static string LinuxClangMinVer = "13";
|
||||
public static string LinuxClangMinVer = "14";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user