Netcode Bootstrap
This commit is contained in:
Generated
+15
@@ -0,0 +1,15 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Rider ignored files
|
||||
/.idea.Project M.iml
|
||||
/modules.xml
|
||||
/contentModel.xml
|
||||
/projectSettingsUpdater.xml
|
||||
# Ignored default folder with query files
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||
</project>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="UserContentModel">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -19,7 +19,7 @@ MonoBehaviour:
|
||||
m_StripRuntimeDebugShaders: 1
|
||||
m_URPShaderStrippingSetting:
|
||||
m_Version: 0
|
||||
m_StripUnusedPostProcessingVariants: 1
|
||||
m_StripUnusedPostProcessingVariants: 0
|
||||
m_StripUnusedVariants: 1
|
||||
m_StripScreenCoordOverrideVariants: 1
|
||||
m_ShaderVariantLogLevel: 0
|
||||
@@ -60,16 +60,21 @@ MonoBehaviour:
|
||||
- rid: 6670095613664165896
|
||||
- rid: 6670095613664165897
|
||||
- rid: 6670095613664165898
|
||||
- rid: 6670095613664165899
|
||||
- rid: 6670095613664165900
|
||||
- rid: -2
|
||||
- rid: -2
|
||||
- rid: 6670095613664165901
|
||||
- rid: 6670095613664165902
|
||||
- rid: 6670095613664165903
|
||||
- rid: 6670095613664165904
|
||||
- rid: 6670095613664165905
|
||||
- rid: -2
|
||||
- rid: -2
|
||||
- rid: -2
|
||||
- rid: 6670095651985424593
|
||||
- rid: 6670095651985424594
|
||||
m_RuntimeSettings:
|
||||
m_List: []
|
||||
m_AssetVersion: 10
|
||||
m_AssetVersion: 11
|
||||
m_ObsoleteDefaultVolumeProfile: {fileID: 0}
|
||||
m_RenderingLayerNames:
|
||||
- Light Layer default
|
||||
@@ -99,6 +104,8 @@ MonoBehaviour:
|
||||
references:
|
||||
version: 2
|
||||
RefIds:
|
||||
- rid: -2
|
||||
type: {class: , ns: , asm: }
|
||||
- rid: 6670095613664165891
|
||||
type: {class: RayTracingRenderPipelineResources, ns: UnityEngine.Rendering.UnifiedRayTracing, asm: Unity.UnifiedRayTracing.Runtime}
|
||||
data:
|
||||
@@ -209,23 +216,6 @@ MonoBehaviour:
|
||||
data:
|
||||
version: 1
|
||||
useReflectionProbeRotation: 0
|
||||
- rid: 6670095613664165899
|
||||
type: {class: ScreenSpaceAmbientOcclusionDynamicResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_BlueNoise256Textures:
|
||||
- {fileID: 2800000, guid: 36f118343fc974119bee3d09e2111500, type: 3}
|
||||
- {fileID: 2800000, guid: 4b7b083e6b6734e8bb2838b0b50a0bc8, type: 3}
|
||||
- {fileID: 2800000, guid: c06cc21c692f94f5fb5206247191eeee, type: 3}
|
||||
- {fileID: 2800000, guid: cb76dd40fa7654f9587f6a344f125c9a, type: 3}
|
||||
- {fileID: 2800000, guid: e32226222ff144b24bf3a5a451de54bc, type: 3}
|
||||
- {fileID: 2800000, guid: 3302065f671a8450b82c9ddf07426f3a, type: 3}
|
||||
- {fileID: 2800000, guid: 56a77a3e8d64f47b6afe9e3c95cb57d5, type: 3}
|
||||
m_Version: 0
|
||||
- rid: 6670095613664165900
|
||||
type: {class: ScreenSpaceAmbientOcclusionPersistentResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_Shader: {fileID: 4800000, guid: 0849e84e3d62649e8882e9d6f056a017, type: 3}
|
||||
m_Version: 0
|
||||
- rid: 6670095613664165901
|
||||
type: {class: URPTerrainShaderSetting, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
@@ -278,11 +268,28 @@ MonoBehaviour:
|
||||
_skyBoxMesh: {fileID: 4300000, guid: 0529e6c5f6dea8c4a8c2835ed7de57cb, type: 2}
|
||||
_sixFaceSkyBoxMesh: {fileID: 4300000, guid: a80925ceebd011741b42509226cefc74, type: 2}
|
||||
_buildLightGridShader: {fileID: 7200000, guid: 16e47c1641bd0104e92b624601457bb0, type: 3}
|
||||
- rid: 6670095651985424593
|
||||
type: {class: ScreenSpaceAmbientOcclusionDynamicResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_BlueNoise256Textures:
|
||||
- {fileID: 2800000, guid: 36f118343fc974119bee3d09e2111500, type: 3}
|
||||
- {fileID: 2800000, guid: 4b7b083e6b6734e8bb2838b0b50a0bc8, type: 3}
|
||||
- {fileID: 2800000, guid: c06cc21c692f94f5fb5206247191eeee, type: 3}
|
||||
- {fileID: 2800000, guid: cb76dd40fa7654f9587f6a344f125c9a, type: 3}
|
||||
- {fileID: 2800000, guid: e32226222ff144b24bf3a5a451de54bc, type: 3}
|
||||
- {fileID: 2800000, guid: 3302065f671a8450b82c9ddf07426f3a, type: 3}
|
||||
- {fileID: 2800000, guid: 56a77a3e8d64f47b6afe9e3c95cb57d5, type: 3}
|
||||
m_Version: 0
|
||||
- rid: 6670095651985424594
|
||||
type: {class: ScreenSpaceAmbientOcclusionPersistentResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_Shader: {fileID: 4800000, guid: 0849e84e3d62649e8882e9d6f056a017, type: 3}
|
||||
m_Version: 0
|
||||
- rid: 6852985685364965376
|
||||
type: {class: URPShaderStrippingSetting, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_Version: 0
|
||||
m_StripUnusedPostProcessingVariants: 1
|
||||
m_StripUnusedPostProcessingVariants: 0
|
||||
m_StripUnusedVariants: 1
|
||||
m_StripScreenCoordOverrideVariants: 1
|
||||
- rid: 6852985685364965377
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d457270f9cc024880891ec4f93a2366b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,148 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &2218851646297572645
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 194292233036670670}
|
||||
- component: {fileID: 7298513067680060886}
|
||||
- component: {fileID: 5990132956580680787}
|
||||
- component: {fileID: 8290370249712404227}
|
||||
- component: {fileID: 304484164735584996}
|
||||
- component: {fileID: 1666753161128106451}
|
||||
m_Layer: 0
|
||||
m_Name: Player
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &194292233036670670
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2218851646297572645}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!33 &7298513067680060886
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2218851646297572645}
|
||||
m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!23 &5990132956580680787
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2218851646297572645}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_ForceMeshLod: -1
|
||||
m_MeshLodSelectionBias: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 1
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_GlobalIlluminationMeshLod: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_MaskInteraction: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!114 &8290370249712404227
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2218851646297572645}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 766c44362be2b4fcaa872e6fb44fc42f, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: ProjectM.Authoring::ProjectM.Authoring.PlayerAuthoring
|
||||
MoveSpeed: 6
|
||||
TurnRateDegreesPerSec: 720
|
||||
--- !u!114 &304484164735584996
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2218851646297572645}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: c16549610bfe4458aa9389201d072bb6, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.Entities.Hybrid::Unity.Entities.Hybrid.Baking.LinkedEntityGroupAuthoring
|
||||
--- !u!114 &1666753161128106451
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2218851646297572645}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 7c79d771cedb4794bf100ce60df5f764, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.NetCode.Authoring.Hybrid::Unity.NetCode.GhostAuthoringComponent
|
||||
HasOwner: 1
|
||||
SupportAutoCommandTarget: 1
|
||||
TrackInterpolationDelay: 0
|
||||
GhostGroup: 0
|
||||
UsePreSerialization: 0
|
||||
UseSingleBaseline: 0
|
||||
RollbackPredictedSpawnedGhostState: 0
|
||||
RollbackPredictionOnStructuralChanges: 1
|
||||
DefaultGhostMode: 2
|
||||
SupportedGhostModes: 3
|
||||
OptimizationMode: 0
|
||||
Importance: 1
|
||||
MaxSendRate: 0
|
||||
SingleWorldHostInterpolationSmoothing: 1
|
||||
prefabId:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a27bbed2662454377bd25279ee4a14d2
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e118095ea29346b188e4c17f8d29181
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,37 @@
|
||||
using ProjectM.Simulation;
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ProjectM.Authoring
|
||||
{
|
||||
/// <summary>
|
||||
/// Authoring for the player ghost prefab. Bakes the gameplay components onto the entity and
|
||||
/// exposes movement tunables for designers. Ghost replication, <c>GhostOwner</c> and
|
||||
/// AutoCommandTarget are supplied by the GhostAuthoringComponent added on the same prefab
|
||||
/// GameObject. <c>GetEntity(TransformUsageFlags.Dynamic)</c> ensures a runtime-mutable
|
||||
/// LocalTransform exists.
|
||||
/// </summary>
|
||||
public class PlayerAuthoring : MonoBehaviour
|
||||
{
|
||||
[Min(0f)] public float MoveSpeed = 6f;
|
||||
[Min(0f)] public float TurnRateDegreesPerSec = 720f;
|
||||
|
||||
private class PlayerBaker : Baker<PlayerAuthoring>
|
||||
{
|
||||
public override void Bake(PlayerAuthoring authoring)
|
||||
{
|
||||
var entity = GetEntity(authoring, TransformUsageFlags.Dynamic);
|
||||
|
||||
AddComponent<PlayerTag>(entity);
|
||||
AddComponent(entity, new PlayerMoveStats
|
||||
{
|
||||
MoveSpeed = authoring.MoveSpeed,
|
||||
TurnRateRadiansPerSec = math.radians(authoring.TurnRateDegreesPerSec)
|
||||
});
|
||||
AddComponent<PlayerFacing>(entity);
|
||||
AddComponent<PlayerInput>(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 766c44362be2b4fcaa872e6fb44fc42f
|
||||
@@ -4,6 +4,8 @@
|
||||
"references": [
|
||||
"ProjectM.Simulation",
|
||||
"Unity.Entities",
|
||||
"Unity.Entities.Hybrid",
|
||||
"Unity.Collections",
|
||||
"Unity.Mathematics",
|
||||
"Unity.NetCode"
|
||||
],
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5cd4882c5ffe499fb63c8c385ddf8d2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
using ProjectM.Simulation;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ProjectM.Authoring
|
||||
{
|
||||
/// <summary>
|
||||
/// Authoring placed once in the gameplay subscene. Bakes a <see cref="PlayerSpawner"/> singleton
|
||||
/// holding the player ghost prefab entity and a spawn point, which the server's
|
||||
/// GoInGameServerSystem instantiates on each connect.
|
||||
/// </summary>
|
||||
public class PlayerSpawnerAuthoring : MonoBehaviour
|
||||
{
|
||||
[Tooltip("The Player ghost prefab to spawn for each connected client.")]
|
||||
public GameObject PlayerPrefab;
|
||||
|
||||
public Vector3 SpawnPoint = Vector3.zero;
|
||||
|
||||
private class PlayerSpawnerBaker : Baker<PlayerSpawnerAuthoring>
|
||||
{
|
||||
public override void Bake(PlayerSpawnerAuthoring authoring)
|
||||
{
|
||||
// The spawner itself needs no transform; it is a data singleton.
|
||||
var entity = GetEntity(authoring, TransformUsageFlags.None);
|
||||
|
||||
AddComponent(entity, new PlayerSpawner
|
||||
{
|
||||
PlayerPrefab = GetEntity(authoring.PlayerPrefab, TransformUsageFlags.Dynamic),
|
||||
SpawnPoint = authoring.SpawnPoint
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e56c91ba352644bd900142035ff2799
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2913bc88b49f3421c82223b996a66a4b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,47 @@
|
||||
using ProjectM.Simulation;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using Unity.NetCode;
|
||||
|
||||
namespace ProjectM.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Client-side connection handshake: for every connection that has been assigned a
|
||||
/// <see cref="NetworkId"/> but is not yet <see cref="NetworkStreamInGame"/>, mark it in-game and
|
||||
/// fire a <see cref="GoInGameRequest"/> RPC so the server spawns this client's player ghost.
|
||||
/// Adding NetworkStreamInGame is what gates snapshot/command flow on. Mirrors the netcode
|
||||
/// "networked-cube" go-in-game sample.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation | WorldSystemFilterFlags.ThinClientSimulation)]
|
||||
public partial struct GoInGameClientSystem : ISystem
|
||||
{
|
||||
[BurstCompile]
|
||||
public void OnCreate(ref SystemState state)
|
||||
{
|
||||
var builder = new EntityQueryBuilder(Allocator.Temp)
|
||||
.WithAll<NetworkId>()
|
||||
.WithNone<NetworkStreamInGame>();
|
||||
state.RequireForUpdate(state.GetEntityQuery(builder));
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public void OnUpdate(ref SystemState state)
|
||||
{
|
||||
var ecb = new EntityCommandBuffer(Allocator.Temp);
|
||||
|
||||
foreach (var (_, connection) in
|
||||
SystemAPI.Query<RefRO<NetworkId>>().WithNone<NetworkStreamInGame>().WithEntityAccess())
|
||||
{
|
||||
ecb.AddComponent<NetworkStreamInGame>(connection);
|
||||
|
||||
var request = ecb.CreateEntity();
|
||||
ecb.AddComponent<GoInGameRequest>(request);
|
||||
ecb.AddComponent(request, new SendRpcCommandRequest { TargetConnection = connection });
|
||||
}
|
||||
|
||||
ecb.Playback(state.EntityManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2b0386021d7340d0b023ab1d954ce14
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb249fc7c6daa49478fb318eb553b719
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,68 @@
|
||||
using ProjectM.Simulation;
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
using Unity.NetCode;
|
||||
|
||||
namespace ProjectM.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Client-only twin-stick input gather. Samples the Input System once per frame (WASD /
|
||||
/// left-stick -> Move, right-stick -> Aim) and writes <see cref="PlayerInput"/> on the
|
||||
/// locally-owned player ghost (filtered to <see cref="GhostOwnerIsLocal"/>). Runs in
|
||||
/// <see cref="GhostInputSystemGroup"/> — NOT the prediction loop — so devices are read once per
|
||||
/// frame, never re-read during rollback. Implemented as a non-Burst <see cref="ISystem"/>
|
||||
/// because it reads the managed Input System.
|
||||
/// <para>
|
||||
/// NOTE: the Input System device types are fully qualified rather than imported via
|
||||
/// <c>using UnityEngine.InputSystem;</c> on purpose — that namespace also defines a
|
||||
/// <c>PlayerInput</c> type which would collide with <see cref="ProjectM.Simulation.PlayerInput"/>
|
||||
/// and make the Entities source generator bind <c>RefRW<PlayerInput></c> to the managed
|
||||
/// class (a spurious CS8377 "must be unmanaged").
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(GhostInputSystemGroup))]
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
|
||||
public partial struct PlayerInputGatherSystem : ISystem
|
||||
{
|
||||
public void OnCreate(ref SystemState state)
|
||||
{
|
||||
state.RequireForUpdate<PlayerInput>();
|
||||
}
|
||||
|
||||
public void OnUpdate(ref SystemState state)
|
||||
{
|
||||
float2 move = float2.zero;
|
||||
float2 aim = float2.zero;
|
||||
|
||||
var keyboard = UnityEngine.InputSystem.Keyboard.current;
|
||||
if (keyboard != null)
|
||||
{
|
||||
if (keyboard.wKey.isPressed) move.y += 1f;
|
||||
if (keyboard.sKey.isPressed) move.y -= 1f;
|
||||
if (keyboard.dKey.isPressed) move.x += 1f;
|
||||
if (keyboard.aKey.isPressed) move.x -= 1f;
|
||||
}
|
||||
|
||||
var gamepad = UnityEngine.InputSystem.Gamepad.current;
|
||||
if (gamepad != null)
|
||||
{
|
||||
float2 leftStick = gamepad.leftStick.ReadValue();
|
||||
if (math.lengthsq(leftStick) > math.lengthsq(move))
|
||||
move = leftStick;
|
||||
|
||||
aim = gamepad.rightStick.ReadValue();
|
||||
}
|
||||
|
||||
// Right-stick deadzone: a resting stick yields zero Aim so PlayerAimSystem falls back to
|
||||
// the movement heading (controller-first directional aim).
|
||||
if (math.lengthsq(aim) < 0.04f)
|
||||
aim = float2.zero;
|
||||
|
||||
foreach (var input in SystemAPI.Query<RefRW<PlayerInput>>().WithAll<GhostOwnerIsLocal>())
|
||||
{
|
||||
input.ValueRW.Move = move;
|
||||
input.ValueRW.Aim = aim;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27c80caff08534f239e39ff4732fbdfd
|
||||
@@ -8,7 +8,8 @@
|
||||
"Unity.Mathematics",
|
||||
"Unity.Burst",
|
||||
"Unity.NetCode",
|
||||
"Unity.Entities.Graphics"
|
||||
"Unity.Entities.Graphics",
|
||||
"Unity.InputSystem"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e45f23db9544e4b1d94a4914c10f35d3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
using ProjectM.Simulation;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using Unity.NetCode;
|
||||
using Unity.Transforms;
|
||||
|
||||
namespace ProjectM.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Server-authoritative player spawn. On each received <see cref="GoInGameRequest"/>: mark the
|
||||
/// source connection in-game, instantiate the player ghost from the baked
|
||||
/// <see cref="PlayerSpawner"/>, stamp <see cref="GhostOwner"/> with the connection's
|
||||
/// <see cref="NetworkId"/>, place it at the spawn point, and link it to the connection's
|
||||
/// LinkedEntityGroup so it auto-despawns on disconnect. Mirrors the netcode "networked-cube"
|
||||
/// ModifiedGoInGameServer sample. All structural changes are batched through an
|
||||
/// <see cref="EntityCommandBuffer"/>.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
|
||||
public partial struct GoInGameServerSystem : ISystem
|
||||
{
|
||||
[BurstCompile]
|
||||
public void OnCreate(ref SystemState state)
|
||||
{
|
||||
state.RequireForUpdate<PlayerSpawner>();
|
||||
|
||||
var builder = new EntityQueryBuilder(Allocator.Temp)
|
||||
.WithAll<GoInGameRequest, ReceiveRpcCommandRequest>();
|
||||
state.RequireForUpdate(state.GetEntityQuery(builder));
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public void OnUpdate(ref SystemState state)
|
||||
{
|
||||
var spawner = SystemAPI.GetSingleton<PlayerSpawner>();
|
||||
var ecb = new EntityCommandBuffer(Allocator.Temp);
|
||||
|
||||
foreach (var (receive, requestEntity) in
|
||||
SystemAPI.Query<RefRO<ReceiveRpcCommandRequest>>().WithAll<GoInGameRequest>().WithEntityAccess())
|
||||
{
|
||||
var connection = receive.ValueRO.SourceConnection;
|
||||
ecb.AddComponent<NetworkStreamInGame>(connection);
|
||||
|
||||
var networkId = SystemAPI.GetComponent<NetworkId>(connection);
|
||||
|
||||
var player = ecb.Instantiate(spawner.PlayerPrefab);
|
||||
ecb.SetComponent(player, LocalTransform.FromPosition(spawner.SpawnPoint));
|
||||
ecb.SetComponent(player, new GhostOwner { NetworkId = networkId.Value });
|
||||
|
||||
// Auto-despawn the player when its owning connection is removed.
|
||||
ecb.AppendToBuffer(connection, new LinkedEntityGroup { Value = player });
|
||||
|
||||
ecb.DestroyEntity(requestEntity);
|
||||
}
|
||||
|
||||
ecb.Playback(state.EntityManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c89f67860a64492bb09af8cc38f3c83
|
||||
@@ -4,6 +4,7 @@
|
||||
"references": [
|
||||
"ProjectM.Simulation",
|
||||
"Unity.Entities",
|
||||
"Unity.Transforms",
|
||||
"Unity.Collections",
|
||||
"Unity.Mathematics",
|
||||
"Unity.Burst",
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08533a9dddc374862b7e3259cb8f872d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
using Unity.NetCode;
|
||||
|
||||
namespace ProjectM.Simulation
|
||||
{
|
||||
/// <summary>
|
||||
/// Client -> server one-off request to enter gameplay. On receipt the server adds
|
||||
/// NetworkStreamInGame to the connection (enabling snapshot/command flow) and spawns the
|
||||
/// client's player ghost. Lives in Simulation so both worlds see the type for RPC source-gen.
|
||||
/// </summary>
|
||||
public struct GoInGameRequest : IRpcCommand { }
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b633994e24f874e0796d1fa93cc46679
|
||||
@@ -15,8 +15,11 @@ namespace ProjectM.Simulation
|
||||
{
|
||||
public override bool Initialize(string defaultWorldName)
|
||||
{
|
||||
// 0 = do not auto-connect; worlds are still created. Set a port later to auto-connect.
|
||||
AutoConnectPort = 0;
|
||||
// Auto-connect in-editor: the server listens and the in-process client connects (over
|
||||
// IPC) on the default BinaryWorlds host mode — one process hosts both worlds (M1 listen
|
||||
// server). M3 replaces this with an explicit Unity Relay host/join flow. Set to 0 to
|
||||
// disable auto-connect.
|
||||
AutoConnectPort = 7979;
|
||||
CreateDefaultClientServerWorlds();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 78b348213a4864001bf105954525fbda
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,41 @@
|
||||
using Unity.Burst;
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
using Unity.NetCode;
|
||||
using Unity.Transforms;
|
||||
|
||||
namespace ProjectM.Simulation
|
||||
{
|
||||
/// <summary>
|
||||
/// Predicted aim/facing: writes <see cref="PlayerFacing"/> from twin-stick Aim, falling back to
|
||||
/// the movement direction when Aim is zero (controller-first directional aim). Also turns the
|
||||
/// ghost transform toward the facing direction for top-down presentation. When there is no input
|
||||
/// this tick the previous facing is held. Deterministic (pure math); filtered to
|
||||
/// <see cref="Simulate"/> so it runs only for predicted ghosts.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(PredictedSimulationSystemGroup))]
|
||||
[BurstCompile]
|
||||
public partial struct PlayerAimSystem : ISystem
|
||||
{
|
||||
[BurstCompile]
|
||||
public void OnUpdate(ref SystemState state)
|
||||
{
|
||||
foreach (var (facing, transform, input) in
|
||||
SystemAPI.Query<RefRW<PlayerFacing>, RefRW<LocalTransform>, RefRO<PlayerInput>>()
|
||||
.WithAll<Simulate>())
|
||||
{
|
||||
float2 aim = input.ValueRO.Aim;
|
||||
if (math.lengthsq(aim) < 1e-6f)
|
||||
aim = input.ValueRO.Move; // fall back to movement heading
|
||||
if (math.lengthsq(aim) < 1e-6f)
|
||||
continue; // no input this tick: keep last facing
|
||||
|
||||
aim = math.normalize(aim);
|
||||
facing.ValueRW.Direction = aim;
|
||||
|
||||
float3 forward = new float3(aim.x, 0f, aim.y);
|
||||
transform.ValueRW.Rotation = quaternion.LookRotationSafe(forward, math.up());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a274d036dc034cbaa70f6a782d8784a
|
||||
@@ -0,0 +1,18 @@
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
using Unity.NetCode;
|
||||
|
||||
namespace ProjectM.Simulation
|
||||
{
|
||||
/// <summary>
|
||||
/// Authoritative aim/facing direction, decoupled from movement heading so twin-stick aim is
|
||||
/// independent of travel direction. Written in predicted sim from PlayerInput.Aim; consumed by
|
||||
/// presentation now and ability systems (M2). Replicated so interpolated remote players show
|
||||
/// the correct facing.
|
||||
/// </summary>
|
||||
public struct PlayerFacing : IComponentData
|
||||
{
|
||||
/// <summary>Normalized planar facing direction (world XZ mapped to float2 x,y).</summary>
|
||||
[GhostField(Quantization = 1000)] public float2 Direction;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d0adf0e4def842a89a3017de243aca9
|
||||
@@ -0,0 +1,30 @@
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
using Unity.NetCode;
|
||||
|
||||
namespace ProjectM.Simulation
|
||||
{
|
||||
/// <summary>
|
||||
/// Twin-stick player input (server-authoritative, input-only clients). Gathered once per frame
|
||||
/// on the owning client in <see cref="GhostInputSystemGroup"/> and streamed to the server via
|
||||
/// AutoCommandTarget. Netcode source-gen produces InputBufferData<PlayerInput> plus the
|
||||
/// copy/apply systems from this type. The [GhostField]s let remote owners be predicted; the
|
||||
/// data replays deterministically under rollback.
|
||||
/// </summary>
|
||||
public struct PlayerInput : IInputComponentData
|
||||
{
|
||||
/// <summary>WASD / left-stick movement, normalized to roughly -1..1 per axis.</summary>
|
||||
[GhostField(Quantization = 1000)] public float2 Move;
|
||||
|
||||
/// <summary>Right-stick / cursor aim direction (normalized). Zero => face movement direction.</summary>
|
||||
[GhostField(Quantization = 1000)] public float2 Aim;
|
||||
|
||||
public FixedString512Bytes ToFixedString()
|
||||
{
|
||||
var s = new FixedString512Bytes();
|
||||
s.Append(Move.x); s.Append(','); s.Append(Move.y); s.Append(';');
|
||||
s.Append(Aim.x); s.Append(','); s.Append(Aim.y);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 72ac3666802bf49f891f49a0d03201e5
|
||||
@@ -0,0 +1,17 @@
|
||||
using Unity.Entities;
|
||||
|
||||
namespace ProjectM.Simulation
|
||||
{
|
||||
/// <summary>
|
||||
/// Per-player movement tunables, baked from authoring. Identical on client (re-prediction) and
|
||||
/// server so movement is deterministic. Not replicated.
|
||||
/// </summary>
|
||||
public struct PlayerMoveStats : IComponentData
|
||||
{
|
||||
/// <summary>Planar movement speed in units/second.</summary>
|
||||
public float MoveSpeed;
|
||||
|
||||
/// <summary>Max turn rate (radians/second) when rotating toward the facing direction.</summary>
|
||||
public float TurnRateRadiansPerSec;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf5fc79d6c67d4ef39ba4e7e9457dd85
|
||||
@@ -0,0 +1,39 @@
|
||||
using Unity.Burst;
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
using Unity.NetCode;
|
||||
using Unity.Transforms;
|
||||
|
||||
namespace ProjectM.Simulation
|
||||
{
|
||||
/// <summary>
|
||||
/// Canonical predicted system: advances each player's planar (XZ) position from twin-stick Move
|
||||
/// input. Runs inside the prediction loop on the owning client (re-simulated on rollback) and
|
||||
/// once per tick on the server; filtered to <see cref="Simulate"/> so only predicted ghosts move.
|
||||
/// Deterministic by construction: uses <c>SystemAPI.Time.DeltaTime</c> (the fixed tick step)
|
||||
/// only — no wall-clock, no <c>System.Random</c>. Move is clamped to unit length so diagonal
|
||||
/// keyboard movement is not faster than cardinal.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(PredictedSimulationSystemGroup))]
|
||||
[BurstCompile]
|
||||
public partial struct PlayerMoveSystem : ISystem
|
||||
{
|
||||
[BurstCompile]
|
||||
public void OnUpdate(ref SystemState state)
|
||||
{
|
||||
float dt = SystemAPI.Time.DeltaTime;
|
||||
|
||||
foreach (var (transform, input, stats) in
|
||||
SystemAPI.Query<RefRW<LocalTransform>, RefRO<PlayerInput>, RefRO<PlayerMoveStats>>()
|
||||
.WithAll<Simulate>())
|
||||
{
|
||||
float2 move = input.ValueRO.Move;
|
||||
if (math.lengthsq(move) > 1f)
|
||||
move = math.normalize(move);
|
||||
|
||||
float3 delta = new float3(move.x, 0f, move.y) * stats.ValueRO.MoveSpeed * dt;
|
||||
transform.ValueRW.Position += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35cd3eacccc2f4172b557b2807a6df22
|
||||
@@ -0,0 +1,10 @@
|
||||
using Unity.Entities;
|
||||
|
||||
namespace ProjectM.Simulation
|
||||
{
|
||||
/// <summary>
|
||||
/// Zero-size marker identifying a player-character ghost. Lets movement/aim/ability systems
|
||||
/// query players without coupling to other gameplay components. Added by PlayerBaker.
|
||||
/// </summary>
|
||||
public struct PlayerTag : IComponentData { }
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f967358256a44853bfc5be66e13bf3b
|
||||
@@ -3,6 +3,7 @@
|
||||
"rootNamespace": "ProjectM.Simulation",
|
||||
"references": [
|
||||
"Unity.Entities",
|
||||
"Unity.Transforms",
|
||||
"Unity.Collections",
|
||||
"Unity.Mathematics",
|
||||
"Unity.Burst",
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 37f2ed4a443ac4a18aba505897f9e6fa
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace ProjectM.Simulation
|
||||
{
|
||||
/// <summary>
|
||||
/// Singleton baked into the gameplay subscene, holding the baked player ghost prefab entity so
|
||||
/// the server spawn system can instantiate it on connect. Mirrors the netcode CubeSpawner sample.
|
||||
/// </summary>
|
||||
public struct PlayerSpawner : IComponentData
|
||||
{
|
||||
public Entity PlayerPrefab;
|
||||
public float3 SpawnPoint;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d1945139846b49a7943b7149188aa45
|
||||
@@ -119,7 +119,54 @@ NavMeshSettings:
|
||||
debug:
|
||||
m_Flags: 0
|
||||
m_NavMeshData: {fileID: 0}
|
||||
--- !u!1 &1498433570
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1498433572}
|
||||
- component: {fileID: 1498433571}
|
||||
m_Layer: 0
|
||||
m_Name: PlayerSpawner
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &1498433571
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1498433570}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5e56c91ba352644bd900142035ff2799, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: ProjectM.Authoring::ProjectM.Authoring.PlayerSpawnerAuthoring
|
||||
PlayerPrefab: {fileID: 2218851646297572645, guid: a27bbed2662454377bd25279ee4a14d2, type: 3}
|
||||
SpawnPoint: {x: 0, y: 1, z: 0}
|
||||
--- !u!4 &1498433572
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1498433570}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1660057539 &9223372036854775807
|
||||
SceneRoots:
|
||||
m_ObjectHideFlags: 0
|
||||
m_Roots: []
|
||||
m_Roots:
|
||||
- {fileID: 1498433572}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
using NUnit.Framework;
|
||||
using ProjectM.Simulation;
|
||||
using Unity.Core;
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Transforms;
|
||||
|
||||
namespace ProjectM.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Plain-Entities determinism test for <see cref="PlayerMoveSystem"/> (the M1 predicted move
|
||||
/// system). Boots a bare ECS world, registers the system in the SimulationSystemGroup, creates a
|
||||
/// synthetic player (PlayerInput + PlayerMoveStats + LocalTransform + enabled Simulate), injects
|
||||
/// a fixed delta-time, ticks N times, and asserts the position advanced by exactly
|
||||
/// MoveSpeed * dt * N. Version-independent and netcode-free, mirroring HeartbeatSystemTests.
|
||||
/// </summary>
|
||||
public class PlayerMoveSystemTests
|
||||
{
|
||||
[Test]
|
||||
public void PlayerMove_Advances_By_MoveSpeed_Times_Dt_Each_Tick()
|
||||
{
|
||||
using var world = new World("PlayerMoveTestWorld");
|
||||
var simulationGroup = world.GetOrCreateSystemManaged<SimulationSystemGroup>();
|
||||
var moveSystem = world.GetOrCreateSystem<PlayerMoveSystem>();
|
||||
simulationGroup.AddSystemToUpdateList(moveSystem);
|
||||
simulationGroup.SortSystems();
|
||||
|
||||
var em = world.EntityManager;
|
||||
var entity = em.CreateEntity(
|
||||
typeof(PlayerInput), typeof(PlayerMoveStats), typeof(LocalTransform), typeof(Simulate));
|
||||
|
||||
const float moveSpeed = 5f;
|
||||
const float dt = 0.1f;
|
||||
const int ticks = 10;
|
||||
|
||||
em.SetComponentData(entity, LocalTransform.FromPosition(float3.zero));
|
||||
em.SetComponentData(entity, new PlayerMoveStats { MoveSpeed = moveSpeed, TurnRateRadiansPerSec = 0f });
|
||||
em.SetComponentData(entity, new PlayerInput { Move = new float2(1f, 0f), Aim = float2.zero });
|
||||
|
||||
for (int i = 0; i < ticks; i++)
|
||||
{
|
||||
// Fixed delta so the predicted move is fully deterministic (no wall-clock).
|
||||
world.SetTime(new TimeData(elapsedTime: dt * (i + 1), deltaTime: dt));
|
||||
simulationGroup.Update();
|
||||
}
|
||||
|
||||
var position = em.GetComponentData<LocalTransform>(entity).Position;
|
||||
|
||||
Assert.AreEqual(moveSpeed * dt * ticks, position.x, 1e-3f,
|
||||
"X should advance by MoveSpeed * dt each tick for Move=(1,0).");
|
||||
Assert.AreEqual(0f, position.y, 1e-3f, "Movement is planar; Y should stay 0.");
|
||||
Assert.AreEqual(0f, position.z, 1e-3f, "Move=(1,0) maps to +X only; Z should stay 0.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PlayerMove_Is_Idempotent_Across_Equal_Tick_Batches()
|
||||
{
|
||||
// Determinism/idempotence: the same inputs and dt must yield the same result regardless
|
||||
// of how the ticks are grouped (mirrors the prediction loop re-simulating a tick).
|
||||
float3 RunTicks(int ticks)
|
||||
{
|
||||
using var world = new World("PlayerMoveDetWorld");
|
||||
var group = world.GetOrCreateSystemManaged<SimulationSystemGroup>();
|
||||
group.AddSystemToUpdateList(world.GetOrCreateSystem<PlayerMoveSystem>());
|
||||
group.SortSystems();
|
||||
|
||||
var em = world.EntityManager;
|
||||
var e = em.CreateEntity(
|
||||
typeof(PlayerInput), typeof(PlayerMoveStats), typeof(LocalTransform), typeof(Simulate));
|
||||
em.SetComponentData(e, LocalTransform.FromPosition(float3.zero));
|
||||
em.SetComponentData(e, new PlayerMoveStats { MoveSpeed = 3f, TurnRateRadiansPerSec = 0f });
|
||||
em.SetComponentData(e, new PlayerInput { Move = new float2(0f, 1f), Aim = float2.zero });
|
||||
|
||||
for (int i = 0; i < ticks; i++)
|
||||
{
|
||||
world.SetTime(new TimeData(0.05f * (i + 1), 0.05f));
|
||||
group.Update();
|
||||
}
|
||||
|
||||
return em.GetComponentData<LocalTransform>(e).Position;
|
||||
}
|
||||
|
||||
var a = RunTicks(20);
|
||||
var b = RunTicks(20);
|
||||
Assert.AreEqual(a.z, b.z, 1e-4f, "Two identical runs must produce identical positions.");
|
||||
Assert.AreEqual(3f * 0.05f * 20f, a.z, 1e-3f, "Move=(0,1) maps to +Z by MoveSpeed*dt*N.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aed328b85e7264aa9aedca0a628c6169
|
||||
@@ -4,8 +4,10 @@
|
||||
"references": [
|
||||
"ProjectM.Simulation",
|
||||
"Unity.Entities",
|
||||
"Unity.Transforms",
|
||||
"Unity.Collections",
|
||||
"Unity.Mathematics",
|
||||
"Unity.NetCode",
|
||||
"UnityEngine.TestRunner",
|
||||
"UnityEditor.TestRunner"
|
||||
],
|
||||
|
||||
@@ -2,20 +2,22 @@
|
||||
|
||||
Multiplayer game on **Unity DOTS (Entities) + Netcode for Entities** — server-authoritative, input-only clients, client prediction. This file is committed and is the authoritative, cross-machine source of conventions. The `/dots-dev` skill drives feature work; the one-time stack setup lives in `Docs/dots-setup-task.md`.
|
||||
|
||||
## Stack (installed versions — Unity 6.4.7 / `6000.4.7f1`)
|
||||
## Stack — reverting to Unity 6.4.7 (stable) as of 2026-05-30
|
||||
|
||||
| Package | Version | Notes |
|
||||
|---|---|---|
|
||||
| `com.unity.entities` | **6.4.0** | Entities/Collections/Graphics now track the **Editor** version (6.x), not the old 1.x line. |
|
||||
| `com.unity.entities` | **6.4.0** | Entities/Collections/Graphics track the **Editor** version (6.x). |
|
||||
| `com.unity.entities.graphics` | **6.4.0** | Renders entities under URP 17.4. |
|
||||
| `com.unity.collections` | 6.4.0 | (transitive) |
|
||||
| `com.unity.netcode` | **1.13.2** | Netcode **for Entities** (ECS). NOT `com.unity.netcode.gameobjects`. Independent 1.x versioning. |
|
||||
| `com.unity.physics` | **1.4.6** | Unity Physics (DOTS). Independent 1.x. |
|
||||
| `com.unity.netcode` | **1.13.2** | Netcode **for Entities** (ECS). NOT `com.unity.netcode.gameobjects`. Independent 1.x line on Unity 6.4. |
|
||||
| `com.unity.physics` | **1.4.6** | Unity Physics (DOTS). Independent 1.x line on Unity 6.4. |
|
||||
| `com.unity.transport` | 2.7.2 | (transitive) |
|
||||
| `com.unity.burst` | 1.8.29 | (transitive) |
|
||||
| `com.unity.mathematics` | 1.3.3 | (transitive) |
|
||||
|
||||
> **Upgrading Unity 6.4 → 6.6:** Entities/Collections/Graphics would renumber to 6.6.x; Netcode/Physics stay independent 1.x (slated to become Core packages later in 2026). The setup here (asmdefs, bootstrap, subscene, smoke test) is forward-compatible — just let packages re-resolve. The `NetCodeTestWorld` access constraint below is **unchanged** by the upgrade.
|
||||
> ⚠️ The values above are the **Unity 6.4.7** set being reverted to — **verify against `packages-lock.json` after the editor downgrade re-resolves**, and reconcile `manifest.json` if the brief 6.6 upgrade left explicit version pins.
|
||||
|
||||
> **Version history & status (2026-05-30):** built on **6.4.7** (`6000.4.7f1`; Netcode 1.13.2 / Physics 1.4.6 / Entities 6.4.0). Briefly upgraded to **6.6.0a6**, where Netcode→6.6.0, Physics→6.5.0, Entities→6.5.0 all **renumbered** into the editor line — BUT the alpha's **Netcode/Transport runtime is broken** (all in-editor connections fail with "invalid wrapped network interface"; **confirmed engine bug** via a zero-gameplay repro — see `Docs/Vault` DR-002 and `Docs/UnityBugReport-Netcode-Transport-6.6.0a6.md`). **→ Reverting to Unity 6.4.7 for stable netcode runtime.** If returning to 6.6 later, expect the renumber and re-test the runtime. The M1 player slice should port to 6.4 / Netcode 1.13.2 with no or minimal changes — recompile and `read_console` after the downgrade.
|
||||
|
||||
## Namespaces & assembly split
|
||||
|
||||
@@ -23,17 +25,25 @@ Root namespace: **`ProjectM`**. Code lives under `Assets/_Project/Scripts/` in f
|
||||
|
||||
| Assembly | Namespace | Runs in | References |
|
||||
|---|---|---|---|
|
||||
| `ProjectM.Simulation` | `ProjectM.Simulation` | **client + server** worlds | Entities, Collections, Mathematics, Burst, Unity.Physics, Unity.NetCode |
|
||||
| `ProjectM.Client` | `ProjectM.Client` | client world only | + Simulation, Unity.Entities.Graphics |
|
||||
| `ProjectM.Server` | `ProjectM.Server` | server world only | + Simulation, Unity.NetCode |
|
||||
| `ProjectM.Authoring` | `ProjectM.Authoring` | bake time (+ scene runtime) | Simulation, Entities, Mathematics, Unity.NetCode |
|
||||
| `ProjectM.Simulation` | `ProjectM.Simulation` | **client + server** worlds | Entities, **Unity.Transforms**, Collections, Mathematics, Burst, Unity.Physics, Unity.NetCode |
|
||||
| `ProjectM.Client` | `ProjectM.Client` | client world only | + Simulation, Unity.Entities.Graphics, **Unity.InputSystem** |
|
||||
| `ProjectM.Server` | `ProjectM.Server` | server world only | + Simulation, **Unity.Transforms**, Unity.NetCode |
|
||||
| `ProjectM.Authoring` | `ProjectM.Authoring` | bake time (+ scene runtime) | Simulation, Entities, **Unity.Entities.Hybrid**, Collections, Mathematics, Unity.NetCode |
|
||||
|
||||
- **Simulation** = components + systems shared by both worlds (most gameplay). **Client/Server** = world-specific. **Authoring** = `…Authoring` MonoBehaviours + `Baker<T>`.
|
||||
- Other folders: `Assets/_Project/Subscenes/` (baked entity subscenes), `Assets/_Project/Prefabs/`, `Assets/_Project/Tests/EditMode/`.
|
||||
|
||||
### Build gotchas (learned — M1, 2026-05-30)
|
||||
|
||||
- **`Unity.Transforms` must be a DIRECT asmdef reference** for any assembly whose source-gen'd systems use `LocalTransform`/`LocalToWorld`. It is its own assembly; transitive visibility compiles your hand-written code but the Entities generator emits **CS0246** inside the `*.g.cs`.
|
||||
- **Authoring asmdefs need `Unity.Entities.Hybrid`** (defines `Baker<T>`) **and `Unity.Collections`** (baking source-gen). A nested baker class must **not** be named `Baker` (it shadows `Baker<T>` → CS0308/CS0246) — name it `FooBaker`.
|
||||
- **Never name an `IComponentData` `PlayerInput`**, and don't `using UnityEngine.InputSystem;` in a file that references such a component: it collides with `UnityEngine.InputSystem.PlayerInput`, and the Entities generator binds `RefRW<…>` to the *managed* class → a misleading **CS8377 "must be a non-nullable value type"**. Fully-qualify Input System types (`UnityEngine.InputSystem.Keyboard.current`) instead.
|
||||
- `IInputComponentData` requires implementing **`FixedString512Bytes ToFixedString()`**.
|
||||
- An input-gather system that reads the managed Input System belongs in `GhostInputSystemGroup` as a **non-Burst `ISystem`** (or `SystemBase`), never inside the prediction loop.
|
||||
|
||||
## Bootstrap & worlds
|
||||
|
||||
- `ProjectM.Simulation.GameBootstrap : ClientServerBootstrap` → overrides `Initialize`, sets `AutoConnectPort = 0` (no auto-connect), calls `CreateDefaultClientServerWorlds()`. Entering Play Mode creates separate `ServerWorld` (`WorldFlags.GameServer`) and `ClientWorld` (`WorldFlags.GameClient`) — verified.
|
||||
- `ProjectM.Simulation.GameBootstrap : ClientServerBootstrap` → overrides `Initialize`, sets `AutoConnectPort = 7979` (in-editor auto-connect over IPC; set in M1 — was 0), calls `CreateDefaultClientServerWorlds()`. Entering Play Mode creates separate `ServerWorld` (`WorldFlags.GameServer`) and `ClientWorld` (`WorldFlags.GameClient`) — verified.
|
||||
- `Assets/_Project/Subscenes/Gameplay.unity` is wired into `SampleScene` (GameObject `GameplaySubScene`) as a baking target. Replace `SampleScene` with a dedicated bootstrap scene when building for real.
|
||||
|
||||
## DOTS / ECS conventions (authoritative summary)
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
> 🛑 **DO NOT FILE — WITHDRAWN 2026-05-31.** This was **not** an engine bug. A clean, fresh Unity `6000.6.0a6` project (`../Local Reference`, a full Netcode-for-Entities framework) runs netcode fine on the same alpha. The failure was specific to Project M's environment (in-place 6.4→6.6 upgrade + embedded Entities-1.x `com.rukhanka.animation` package + default driver/AutoConnect path). See `Docs/Vault` DR-002 → "Correction". Kept only as a record of the investigation.
|
||||
|
||||
# Unity Bug Report — Netcode for Entities / Unity Transport (6000.6.0a6)
|
||||
|
||||
> Copy-paste into the Unity Bug Reporter (Help ▸ Report a Bug) or the Unity Discussions/issue tracker.
|
||||
> Captured 2026-05-30 from Project M. Background: [[DR-002_Unity66_Alpha_Netcode_Transport]].
|
||||
|
||||
**Title:** [Netcode for Entities] In-editor client↔server connection never establishes — Unity Transport throws `Trying to access an invalid wrapped network interface` every frame (6000.6.0a6)
|
||||
|
||||
**Package(s):** Netcode for Entities `com.unity.netcode` 6.6.0 · Unity Transport `com.unity.transport` 6.6.0
|
||||
|
||||
**Severity:** Blocker — no Netcode-for-Entities connection can be established in the Editor; networked play is unusable.
|
||||
|
||||
**Unity version:** 6000.6.0a6
|
||||
|
||||
**Re-resolved package versions on this editor:**
|
||||
- `com.unity.netcode` 6.6.0
|
||||
- `com.unity.transport` 6.6.0
|
||||
- `com.unity.entities` / `com.unity.collections` / `com.unity.entities.graphics` 6.5.0
|
||||
- `com.unity.physics` 6.5.0
|
||||
- `com.unity.burst` 1.8.29 · `com.unity.mathematics` 1.4.0
|
||||
|
||||
**Environment:** macOS (Apple Silicon), `OSXEditor`, URP 17.6. In-Editor (not batch mode).
|
||||
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Any standard Netcode-for-Entities setup that creates a `ServerWorld` + `ClientWorld` and auto-connects (the default `ClientServerBootstrap` with `AutoConnectPort` set, `RequestedPlayType = ClientAndServer`) **fails to ever establish a connection in the Editor**. The client creates a `NetworkStreamConnection` entity, but the server never accepts it and **no `NetworkId` is ever assigned** to either side.
|
||||
|
||||
Every frame, the Console floods with:
|
||||
|
||||
```
|
||||
Exception thrown in a managed function called from unmanaged code:
|
||||
System.InvalidOperationException: Trying to access an invalid wrapped network interface.
|
||||
```
|
||||
|
||||
When the Jobs Debugger is enabled, this is accompanied by a cascade of dependency-safety exceptions across Unity Transport's internal layered-driver jobs, e.g.:
|
||||
|
||||
```
|
||||
InvalidOperationException: The previously scheduled job NetworkDriver:UpdateJob writes to the
|
||||
Unity.Collections.NativeList`1[...]. You are trying to schedule a new job
|
||||
SimpleConnectionLayer:ReceiveJob`1 / SequenceReorderingLayer:ReceiveJob / TopLayer:CompleteReceiveJob /
|
||||
AnalyticsLayer:AnalyticsJob / BottomLayer:ClearJob / RpcSystem:RpcExecJob ...
|
||||
To guarantee safety, you must include NetworkDriver:UpdateJob as a dependency of the newly scheduled job.
|
||||
```
|
||||
|
||||
and subsequently:
|
||||
|
||||
```
|
||||
[Netcode] Server Tick Batching has occurred due to the server falling behind its desired SimulationTickRate ...
|
||||
```
|
||||
|
||||
**Disabling the Jobs Debugger** (`JobsUtility.JobDebuggerEnabled = false`) removes the dependency-safety exceptions, but the **`Trying to access an invalid wrapped network interface`** error persists and the connection still never forms — so the invalid network interface is the root cause, independent of the safety checks.
|
||||
|
||||
## Steps to reproduce (minimal — no gameplay content required)
|
||||
|
||||
1. New project on **6000.6.0a6**; add `com.unity.netcode` (6.6.0; Entities 6.5.0 / Transport 6.6.0 resolve automatically).
|
||||
2. Add this bootstrap (the only script needed):
|
||||
```csharp
|
||||
using Unity.Entities;
|
||||
using Unity.NetCode;
|
||||
using UnityEngine.Scripting;
|
||||
|
||||
[Preserve]
|
||||
public class TestBootstrap : ClientServerBootstrap
|
||||
{
|
||||
public override bool Initialize(string defaultWorldName)
|
||||
{
|
||||
AutoConnectPort = 7979; // in-editor auto-connect (ClientAndServer, IPC)
|
||||
CreateDefaultClientServerWorlds();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
3. Open any scene — an **empty scene** (camera + light only; no SubScene, no ghosts, no systems) is sufficient.
|
||||
4. Enter Play Mode.
|
||||
|
||||
## Expected
|
||||
|
||||
The in-process client connects to the server over IPC; the server assigns a `NetworkId`; a `NetworkStreamConnection` is established on both worlds. No Transport exceptions.
|
||||
|
||||
## Actual
|
||||
|
||||
No connection forms.
|
||||
- `ServerWorld`: 0 `NetworkStreamConnection`, 0 `NetworkId`.
|
||||
- `ClientWorld`: 1 `NetworkStreamConnection`, **0 `NetworkId`**.
|
||||
- Console floods every frame with `Trying to access an invalid wrapped network interface` (plus Transport job-safety exceptions when the Jobs Debugger is on).
|
||||
|
||||
## Frequency
|
||||
|
||||
100% reproducible. Occurs with **zero gameplay content** (empty scene + the bootstrap above), confirming it is not project-specific.
|
||||
|
||||
## Regression / likely cause
|
||||
|
||||
- Netcode for Entities + Unity Transport are transitioning to built-in Core packages (since 6000.5.0a7), which renumbered them into the 6.x editor line.
|
||||
- The **6000.6.0a5** changelog states Netcode snapshots were reworked to use Unity Transport's *"unreliable sequenced pipeline"* — the same `SequenceReorderingLayer` / layered-driver path that throws here. The regression appears to coincide with that rework.
|
||||
|
||||
## Known-good baseline
|
||||
|
||||
The same setup works on **Unity 6.4.x** (Netcode for Entities 1.13.2 / Unity Transport 2.7.2).
|
||||
@@ -13,11 +13,18 @@ permalink: gamevault/01-vision/pillars
|
||||
|
||||
## Pillars
|
||||
|
||||
- _TBD — define the 3–5 experiential pillars of Project M._
|
||||
1. **Action-ARPG combat** — twin-stick, controller-first (LoL / Diablo 4 / PoE2 feel); skill expression over stat-checks.
|
||||
2. **Co-op base power fantasy** — 2–4 friends build and grow a shared home base (V Rising feel).
|
||||
3. **Automation as progression** — production runs itself so play time compounds; the loop rewards setup, not grind.
|
||||
4. **Server-authoritative & deterministic** — input-only clients, client prediction; the simulation is the source of truth.
|
||||
|
||||
## Locked decisions
|
||||
|
||||
- **Tech stack:** Unity DOTS (Entities) + Netcode for Entities — server-authoritative, input-only clients, client prediction. Established [[2026-05-29_Project_Setup]].
|
||||
- **Control (locked 2026-05-30):** WASD movement, controller-first, **directional / twin-stick aim** with soft auto-target in-arc. [[2026-05-30_M1_Player_Slice]]
|
||||
- **Multiplayer (locked):** small co-op **2–4, client-hosted listen-server** (BinaryWorlds + in-proc IPC; not the experimental SingleWorld host mode), PvE.
|
||||
- **World (locked):** persistent buildable **home base + instanced/procedural expeditions**.
|
||||
- **Automation (locked):** **progression accelerator** — self-running production chains; data model designed to grow toward full logistics.
|
||||
|
||||
## Related
|
||||
|
||||
|
||||
@@ -12,7 +12,11 @@ One design doc per gameplay system, linked here. Each should state: purpose, com
|
||||
|
||||
## Systems
|
||||
|
||||
- _None yet._
|
||||
### M1 — Player (twin-stick predicted movement) · [[2026-05-30_M1_Player_Slice]]
|
||||
|
||||
- **Components** (`ProjectM.Simulation`): `PlayerTag`; `PlayerInput` (IInputComponentData — `float2` Move/Aim, `[GhostField]`, flows via AutoCommandTarget); `PlayerMoveStats` (baked tunables); `PlayerFacing` (`[GhostField]` Direction); `PlayerSpawner` (baked prefab singleton); `GoInGameRequest` (IRpcCommand).
|
||||
- **Systems:** `PlayerMoveSystem`, `PlayerAimSystem` (`PredictedSimulationSystemGroup`, `.WithAll<Simulate>()`, deterministic — `SystemAPI.Time.DeltaTime` only); `PlayerInputGatherSystem` (client, `GhostInputSystemGroup`); `GoInGameClientSystem` (client) / `GoInGameServerSystem` (server — spawns the owner-predicted ghost, stamps `GhostOwner`, `LinkedEntityGroup` auto-despawn).
|
||||
- **Netcode shape:** player = **owner-predicted** ghost; client sends input only; server is authoritative. Status: **code-complete + EditMode-verified**; live runtime blocked by [[DR-002_Unity66_Alpha_Netcode_Transport]].
|
||||
|
||||
## Conventions
|
||||
|
||||
|
||||
@@ -10,7 +10,11 @@ permalink: gamevault/06-roadmap/backlog
|
||||
|
||||
Unordered pool of candidate work. Promote to a [[Milestones|milestone]] when committed.
|
||||
|
||||
- [ ] Decide whether to upgrade Unity 6.4 → 6.6 for newer Entities (6.6.x). Stack is forward-compatible; `NetCodeTestWorld` stays internal regardless — see [[DR-001_Netcode_Test_Harness]].
|
||||
- [ ] Define the core gameplay loop and the first predicted player ghost.
|
||||
- [x] Upgrade Unity 6.4 → 6.6 — done (now `6000.6.0a6`). Entities/Collections/Graphics → 6.5.0; **Netcode → 6.6.0 and Physics → 6.5.0 also renumbered into the editor line** (not independent 1.x as [[DR-001_Netcode_Test_Harness]] assumed). See [[2026-05-30_M1_Player_Slice]].
|
||||
- [x] Define the core gameplay loop and the first predicted player ghost — delivered as M1 ([[2026-05-30_M1_Player_Slice]]).
|
||||
- [ ] **Re-validate the M1 play-tick on a stable Unity 6.x** — live runtime blocked on the 6.6 alpha ([[DR-002_Unity66_Alpha_Netcode_Transport]]); optionally reproduce with the `networked-cube` sample to file a bug.
|
||||
- [ ] Replace template `SampleScene` with a dedicated bootstrap scene + gameplay subscene.
|
||||
- [ ] Optional template cleanup: remove `com.unity.visualscripting`, `Assets/TutorialInfo/`, `Assets/Readme.asset` (delete each asset **with** its `.meta`).
|
||||
- [ ] Optional template cleanup: remove `com.unity.visualscripting`, `Assets/TutorialInfo/`, `Assets/Readme.asset` (delete each asset **with** its `.meta`).
|
||||
- [ ] Decide **relay provider** (default Unity Relay) before M3.
|
||||
- [ ] Decide home-base **grid 2D vs 3D** before M5.
|
||||
- [ ] Decide **production replication** (predicted vs server-only) before M6.
|
||||
@@ -11,6 +11,11 @@ permalink: gamevault/06-roadmap/milestones
|
||||
| Milestone | Goal | Status |
|
||||
|---|---|---|
|
||||
| **M0 — Foundation** | DOTS + Netcode stack, asmdef split, bootstrap, smoke test green | ✅ Done 2026-05-29 — [[2026-05-29_Project_Setup]] |
|
||||
| **M1 — _TBD_** | Define the first playable slice (core loop + first predicted ghost) | ⬜ |
|
||||
| **M1 — Player slice** | Server-spawned owner-predicted player; twin-stick WASD + directional aim | ✅ Done 2026-05-31 — runtime-validated on Unity 6.4.7 (connect→spawn→owner-predicted ghost→replication; EditMode 3/3). The 6.6 failure was environment-specific, see [[DR-002_Unity66_Alpha_Netcode_Transport]] — [[2026-05-30_M1_Player_Slice]] |
|
||||
| **M2 — Combat** | Directional ability fire + deterministic soft auto-target; server-authoritative damage/health | ⬜ |
|
||||
| **M3 — Co-op** | 2–4 players; client-hosted listen-server over Unity Relay | ⬜ |
|
||||
| **M4 — Home base + physics** | Persistent base subscene streaming + Unity Physics in the predicted loop | ⬜ |
|
||||
| **M5 — Build/placement** | Server-authoritative grid build placement via RPC | ⬜ |
|
||||
| **M6 — Automation** | Self-running tick-based production chains (deterministic offline catch-up) | ⬜ |
|
||||
|
||||
Promote items from [[Backlog]] here when committed.
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
date: 2026-05-30
|
||||
type: session
|
||||
tags: [session, dots, netcode, m1]
|
||||
permalink: gamevault/07-sessions/2026/2026-05-30-m1-player-slice
|
||||
---
|
||||
|
||||
# Session 2026-05-30 — M1 Player Slice + foundation direction
|
||||
|
||||
## Goal
|
||||
|
||||
Kick off real dev via `/dots-dev`: lock the genre/foundation direction for a **V Rising × factory-automation co-op ARPG** (small team), plan the initial phases, and build **M1** — a server-spawned, owner-predicted player ghost that moves via twin-stick WASD + directional aim.
|
||||
|
||||
## Done
|
||||
|
||||
### Direction locked — see [[Pillars]]
|
||||
- **Genre:** V Rising mechanics + action-ARPG combat (LoL / Diablo 4 / PoE2) + factory automation; small-team scope.
|
||||
- **Control:** WASD movement, controller-first, **directional / twin-stick** aim (soft auto-target in-arc).
|
||||
- **Multiplayer:** small co-op **2–4, client-hosted listen-server** (BinaryWorlds + in-proc IPC), PvE.
|
||||
- **World:** persistent buildable **home base + instanced/procedural expeditions**.
|
||||
- **Automation:** **progression accelerator** — self-running production chains; data model designed to grow toward full logistics.
|
||||
- 6-phase roadmap M1–M6 — see [[Milestones]].
|
||||
|
||||
### M1 built — code-complete, EditMode-verified
|
||||
All four asmdefs compile clean (source-gen OK); EditMode tests **3/3 green**.
|
||||
- **Simulation:** `PlayerTag`, `PlayerInput` (IInputComponentData, `float2` Move/Aim `[GhostField]`, `ToFixedString`), `PlayerMoveStats`, `PlayerFacing` (`[GhostField]` Direction), `GoInGameRequest` (IRpcCommand), `PlayerSpawner`; `PlayerMoveSystem` + `PlayerAimSystem` (PredictedSimulationSystemGroup, `.WithAll<Simulate>()`, `SystemAPI.Time.DeltaTime` only — deterministic).
|
||||
- **Client:** `GoInGameClientSystem`; `PlayerInputGatherSystem` (GhostInputSystemGroup, non-Burst ISystem reading the Input System).
|
||||
- **Server:** `GoInGameServerSystem` (instantiate player + `GhostOwner` from `NetworkId` + `LinkedEntityGroup` auto-despawn).
|
||||
- **Authoring/asset:** `PlayerAuthoring` / `PlayerSpawnerAuthoring` bakers; `Player.prefab` (GhostAuthoringComponent **OwnerPredicted**, HasOwner, AutoCommandTarget); `PlayerSpawner` wired into `Gameplay.unity`; `GameBootstrap.AutoConnectPort = 7979`.
|
||||
- **Tests:** `PlayerMoveSystemTests` — deterministic advance + idempotence across tick batches.
|
||||
- Live Netcode 6.6 API shapes verified via `unity_reflect` before coding (`GhostOwner.NetworkId`, `NetworkId.Value`, `Receive`/`SendRpcCommandRequest`, `GhostOwnerIsLocal`, `IInputComponentData.ToFixedString` → `FixedString512Bytes`).
|
||||
|
||||
### Build gotchas learned — now in repo `CLAUDE.md`
|
||||
- Source-gen'd systems need **`Unity.Transforms`** as a *direct* asmdef reference (`LocalTransform`); transitive visibility doesn't satisfy the generator.
|
||||
- Authoring asmdefs need **`Unity.Entities.Hybrid`** (for `Baker<T>`) and **`Unity.Collections`**.
|
||||
- A component named **`PlayerInput`** collides with `UnityEngine.InputSystem.PlayerInput`; with `using UnityEngine.InputSystem;` the Entities generator binds `RefRW<PlayerInput>` to the *managed* class → misleading **CS8377** "must be unmanaged". Fix: fully-qualify Input System types, don't import the namespace.
|
||||
- A nested baker class must not be named `Baker` (shadows `Unity.Entities.Baker<T>` → CS0308/CS0246).
|
||||
|
||||
## Decisions
|
||||
- [[DR-002_Unity66_Alpha_Netcode_Transport]] — runtime netcode is blocked on the 6.6 alpha.
|
||||
- **Host mode = BinaryWorlds + IPC** (stable), not the experimental `HostWorldMode.SingleWorld` (internal unless `NETCODE_EXPERIMENTAL_SINGLE_WORLD_HOST`).
|
||||
- Correction to [[DR-001_Netcode_Test_Harness]] assumption: on the 6.6 upgrade, **Netcode (→6.6.0) and Physics (→6.5.0) DID renumber** into the editor line — they did **not** stay independent 1.x. `CLAUDE.md` updated.
|
||||
|
||||
## Open / deferred
|
||||
- **BLOCKER — env-specific, NOT an engine bug (corrected 2026-05-31):** the in-editor connection never formed on Project M @ `6000.6.0a6` ("invalid wrapped network interface"). Initially mis-attributed to a Unity engine bug, but a **clean fresh `6000.6.0a6` project (`../Local Reference`, a full Netcode-for-Entities framework) connects fine**. The bare-scene repro still ran inside Project M's contaminated environment (embedded Entities-1.x `rukhanka` + in-place-upgrade `Library`/manifest residue + default driver/AutoConnect), so it isolated gameplay code but not the environment. Bug report withdrawn. See [[DR-002_Unity66_Alpha_Netcode_Transport]] → Correction.
|
||||
- **RESOLVED 2026-05-31:** M1 runtime **fully validated on Unity 6.4.7 / Netcode 1.13.2** — connect → GoInGame → server-spawn → owner-predicted ghost → client replication all confirmed (`players=1`/`netIds=1`/`inGame=1`/`ownerLocal=1` in both worlds), no transport error. One-time fix: forced asset reimport to rebake the stale entity-subscene after the in-place downgrade. Minor follow-ups: enable `Application.runInBackground`; re-save URP global settings (cosmetic missing-types from the 17.6→17.4 downgrade).
|
||||
- Deferred decisions (revisit at their phase): **relay provider** (default Unity Relay) before M3; home-base **grid 2D vs 3D** before M5; **production predicted vs server-only** before M6; **character controller** (custom kinematic vs vendor ECS-samples) at M4.
|
||||
|
||||
## Next
|
||||
Re-run the M1 play-tick on a **stable Unity 6.x** (or reproduce with the `networked-cube` sample to file a bug). When green, proceed to **M2 — twin-stick combat / abilities**.
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: DR-002
|
||||
title: Unity 6.6.0-alpha Netcode/Transport runtime regression blocks in-editor play-tick
|
||||
status: superseded
|
||||
date: 2026-05-30
|
||||
superseded: 2026-05-31 — see Correction below
|
||||
tags:
|
||||
- decision
|
||||
- netcode
|
||||
- transport
|
||||
- engine
|
||||
permalink: gamevault/07-sessions/decisions/dr-002-unity66-alpha-netcode-transport
|
||||
---
|
||||
|
||||
# DR-002 — Unity 6.6.0-alpha Netcode/Transport runtime regression
|
||||
|
||||
> ⚠️ **SUPERSEDED 2026-05-31 — this was NOT a universal engine bug. See "## Correction" at the bottom.** A clean, fresh Unity `6000.6.0a6` project (`../Local Reference`) runs Netcode for Entities successfully. The failure was specific to **Project M's environment** (in-place 6.4→6.6 upgrade + embedded `com.rukhanka.animation` Entities-1.x package + default driver/AutoConnect path), not Unity itself. The drafted Unity bug report should **not** be filed.
|
||||
|
||||
## Context
|
||||
|
||||
The project runs on **Unity `6000.6.0a6`** (6.6.0 **alpha**) with `com.unity.netcode` 6.6.0, `com.unity.transport` 6.6.0, `com.unity.entities`/`collections`/`graphics` 6.5.0, `com.unity.physics` 6.5.0.
|
||||
|
||||
Building [[2026-05-30_M1_Player_Slice|M1]], the code compiled clean and EditMode tests passed (3/3), but the in-editor two-world play-tick **never establishes a network connection** (`NetworkId` connection count stays 0; no player ghost spawns). Every frame the console floods with exceptions located **entirely inside Unity packages**:
|
||||
|
||||
- `com.unity.transport`: `System.InvalidOperationException: Trying to access an invalid wrapped network interface.` (dominant, ~20×/sample)
|
||||
- A cascade of Jobs-Debugger dependency-safety violations across Transport's internal layer jobs: `NetworkDriver:UpdateJob`, `SimpleConnectionLayer`, `SequenceReorderingLayer`, `AnalyticsLayer`, `BottomLayer`/`TopLayer`, `RpcSystem:RpcExecJob` ("you must include X as a dependency of the newly scheduled job").
|
||||
- `com.unity.netcode`: "Server Tick Batching … falling behind its desired `SimulationTickRate`".
|
||||
|
||||
No `ProjectM.*` code appears in any stack trace. Reproduced across two clean play sessions. Disabling the Jobs Debugger (`JobsUtility.JobDebuggerEnabled = false`) removed the job-safety exceptions, but the **"invalid wrapped network interface"** persisted and the connection still never formed — so the root failure is Transport network-interface initialization, not the safety checks.
|
||||
|
||||
## Decision
|
||||
|
||||
Treat this as an **engine-alpha regression**, not an M1 code defect. M1 is **code-complete and statically verified**: clean compile + source-gen, EditMode determinism tests green, both `ServerWorld`/`ClientWorld` boot with correct flags. Runtime validation of the connect → spawn → predicted-move loop is **deferred to a stable Unity 6.x build**.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Do **not** burn effort debugging Transport internals from game code; the fault is below our layer.
|
||||
- Tracked action items: (1) re-run the M1 play-tick on a stable Unity 6.x; (2) optionally reproduce with Unity's own `networked-cube` sample to confirm + file a bug.
|
||||
- Until resolved, treat in-editor netcode **runtime** on `6000.6.0a6` as unreliable; rely on plain-Entities EditMode tests (see [[DR-001_Netcode_Test_Harness]]) for deterministic logic coverage.
|
||||
- **Recommendation:** for netcode runtime work, prefer a **stable** Unity 6.x release over the alpha.
|
||||
|
||||
## Confirmation — clean-room repro (2026-05-30)
|
||||
|
||||
Reproduced with **zero Project M code**: a fresh empty scene (camera + light only — no Gameplay subscene, no ghosts/components/systems) where Unity's canonical bootstrap creates `ServerWorld` + `ClientWorld` and auto-connects. The identical `Trying to access an invalid wrapped network interface` flood appears; `ClientWorld` opens a `NetworkStreamConnection` but the server never accepts and **no `NetworkId` is assigned** on either side. ⇒ the fault is entirely in Unity Transport/Netcode, not our gameplay or bootstrap logic.
|
||||
|
||||
## Web corroboration
|
||||
|
||||
- Netcode for Entities + Unity Transport are **mid-migration to built-in (Core) packages bundled with the Editor, since Unity `6000.5.0a7`** — which is why they renumbered into the 6.x line on our upgrade. ([status update](https://discussions.unity.com/t/netcode-for-entities-and-unity-transport-status-update/1707400))
|
||||
- The netcode↔transport pipeline was **actively reworked this alpha cycle**: the `6000.6.0a5` changelog states "Netcode for Entities snapshots now use Unity Transport's unreliable sequenced pipeline instead of a home-baked solution." That unreliable-sequenced / `SequenceReorderingLayer` path is exactly what throws in our logs.
|
||||
- Transport's `NetworkDriver.Concurrent` multi-job safety behaviour has acknowledged rough edges (Unity Transport maintainer, Jan 2026, Transport 2.6 / Unity 6.3) with no fix. ([thread](https://discussions.unity.com/t/using-the-same-networkdriver-concurrent-in-two-jobs-causes-an-error/1703439))
|
||||
- **No public report matches the exact `invalid wrapped network interface` connection-blocking failure on `6000.6.0a6`** — consistent with an unreported in-flight alpha regression. Worth **filing a Unity bug** with the minimal bare-scene repro above.
|
||||
|
||||
## Resolution (2026-05-30)
|
||||
|
||||
**Reverting the project to Unity 6.4.7** (Netcode for Entities 1.13.2 / Transport 2.7.2 — the known-good baseline) to unblock runtime netcode. A file-ready bug report was drafted at `Docs/UnityBugReport-Netcode-Transport-6.6.0a6.md`. Next: re-validate the M1 connect→spawn→predicted-move loop on 6.4 (the M1 code should port with no/minimal changes — recompile + `read_console`). Revisit Unity 6.6 once the Transport regression is fixed in a later alpha/beta.
|
||||
|
||||
## Correction (2026-05-31)
|
||||
|
||||
The "confirmed engine bug" conclusion above is **withdrawn**. A side-by-side file diff against a fresh project (`Projects/Rain/Games/Unity/Local Reference`) showed:
|
||||
|
||||
- **`Local Reference` is a clean Unity `6000.6.0a6` Netcode-for-Entities framework project** (dedicated-server bootstraps, GhostBridge ghost framework, prediction, **its own custom `EntityDriverConstructor`** + explicit connect flow) — and it runs netcode successfully on the same alpha.
|
||||
- **Project M @ 6.6 differed in three ways the template does not have:** (1) an embedded third-party **`com.rukhanka.animation` 2.9.0** built for **Unity 2022.3 / Entities 1.x** (depends on `entities.graphics 1.4.16`); (2) it was **upgraded in-place 6.4→6.6** (stale `Library/` + leftover/mixed `manifest.json` pins); (3) it used the **default `IPCAndSocketDriverConstructor` + `AutoConnectPort`**, whereas the template uses a custom driver constructor.
|
||||
|
||||
**Why my repro misled me:** the "bare scene" repro still ran inside Project M's contaminated environment (rukhanka + dirty `Library` load regardless of scene), so it isolated *gameplay code* but not the *project environment*. The correct control — a clean 6.6 project — works.
|
||||
|
||||
**Revised stance:** environment-specific, not an engine bug. **Do not file the Unity bug.** Candidate causes (unranked, not yet isolated): stale upgrade `Library`, the Entities-1.x `rukhanka` package, the default-driver/AutoConnect path, manifest-pin inconsistency. **To run on 6.6:** clean a 6.6 Project M (remove/replace rukhanka, delete `Library/` + reimport, reconcile manifest pins) and re-test. Project M is currently on **6.4.7** (stable baseline) where M1 should run regardless.
|
||||
|
||||
**Confirmed 2026-05-31:** M1 runtime **works on Unity 6.4.7** — the full connect → GoInGame → server-spawn → owner-predicted ghost → client replication loop validated (1 player ghost in both worlds, no transport error). This + the working clean 6.6 template settles it: the 6.6 failure was **environment-specific**, not an engine bug. (Note: the in-place 6.6→6.4.7 downgrade left a stale entity-subscene cache that hung the first play-mode entry until a forced reimport rebaked it — the same in-place-version-change dirtiness lesson.)
|
||||
@@ -0,0 +1,7 @@
|
||||
# Rukhanka Animation System
|
||||
|
||||
* Documentation: [https://docs.rukhanka.com](https://docs.rukhanka.com)
|
||||
* Youtube channel: [https://www.youtube.com/@rukhankaanimation](https://www.youtube.com/@rukhankaanimation)
|
||||
* Discord Support Server: [https://discord.gg/AwzFjWdHfq](https://discord.com/invite/utdMamGbR8)
|
||||
* Support e-mail: [support@rukhanka.com](mailto:support@rukhanka.com)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 45e49eed75d9d7f47b605c85d225c6e5
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/README.md
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0ae226541db4914a81bcc1588700ea7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,974 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using Rukhanka.Toolbox;
|
||||
using Unity.Burst;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.DebugDrawer
|
||||
{
|
||||
[BurstCompile]
|
||||
public struct Drawer: IComponentData
|
||||
{
|
||||
[NativeDisableParallelForRestriction]
|
||||
internal NativeArray<DrawerManagedSingleton.LineData> lineData;
|
||||
[NativeDisableParallelForRestriction]
|
||||
internal NativeArray<DrawerManagedSingleton.TriangleData> triData;
|
||||
[NativeDisableParallelForRestriction]
|
||||
internal NativeArray<DrawerManagedSingleton.ThickLineData> thickLineData;
|
||||
[NativeDisableParallelForRestriction]
|
||||
internal NativeArray<DrawerManagedSingleton.BoneData> boneData;
|
||||
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
internal UnsafeAtomicCounter32 lineCounter;
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
internal UnsafeAtomicCounter32 triCounter;
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
internal UnsafeAtomicCounter32 thickLineCounter;
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
internal UnsafeAtomicCounter32 boneMeshCounter;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static Drawer Create(DrawerManagedSingleton ds)
|
||||
{
|
||||
var rv = new Drawer()
|
||||
{
|
||||
lineCounter = ds.linesBuf.counterAtomic,
|
||||
lineData = ds.lineData,
|
||||
triCounter = ds.trianglesBuf.counterAtomic,
|
||||
triData = ds.triData,
|
||||
thickLineCounter = ds.thickLinesBuf.counterAtomic,
|
||||
thickLineData = ds.thickLineData,
|
||||
boneMeshCounter = ds.bonesBuf.counterAtomic,
|
||||
boneData = ds.boneData
|
||||
};
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int GetTriangleWriteIndex(int numTrianglesToDraw) => GetWriteIndex(numTrianglesToDraw, triCounter, triData.Length);
|
||||
int GetLineWriteIndex(int numLinesToDraw) => GetWriteIndex(numLinesToDraw, lineCounter, lineData.Length);
|
||||
int GetThickLineWriteIndex(int numLinesToDraw) => GetWriteIndex(numLinesToDraw, thickLineCounter, thickLineData.Length);
|
||||
int GetBoneMeshWriteIndex(int numBonesToDraw) => GetWriteIndex(numBonesToDraw, boneMeshCounter, boneData.Length);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int GetWriteIndex(int numPrimitivesToDraw, UnsafeAtomicCounter32 counter, int maxCount)
|
||||
{
|
||||
var writeIndex = counter.Add(numPrimitivesToDraw);
|
||||
|
||||
if (writeIndex + numPrimitivesToDraw >= maxCount)
|
||||
return -1;
|
||||
|
||||
return writeIndex;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawThickLine(float3 p0, float3 p1, uint color, float thickness)
|
||||
{
|
||||
// Make line as two triangles
|
||||
var writeIndex = GetThickLineWriteIndex(1);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
var tlc = new DrawerManagedSingleton.ThickLineData()
|
||||
{
|
||||
p0 = p0,
|
||||
p1 = p1,
|
||||
thickness = thickness,
|
||||
color = color
|
||||
};
|
||||
|
||||
thickLineData[writeIndex] = tlc;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public unsafe void DrawWireFrustum(float4x4 cullingMatrix, uint color)
|
||||
{
|
||||
var writeIndex = GetLineWriteIndex(12);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
// Frustum corners in NDC
|
||||
Span<float4> frustumCorners = stackalloc float4[]
|
||||
{
|
||||
new float4(-1, -1, -1, 1),
|
||||
new float4(+1, -1, -1, 1),
|
||||
new float4(+1, +1, -1, 1),
|
||||
new float4(-1, +1, -1, 1),
|
||||
new float4(-1, -1, +1, 1),
|
||||
new float4(+1, -1, +1, 1),
|
||||
new float4(+1, +1, +1, 1),
|
||||
new float4(-1, +1, +1, 1),
|
||||
};
|
||||
|
||||
cullingMatrix = math.inverse(cullingMatrix);
|
||||
|
||||
for (int i = 0; i < frustumCorners.Length; ++i)
|
||||
{
|
||||
frustumCorners[i] = math.mul(cullingMatrix, frustumCorners[i]);
|
||||
frustumCorners[i] /= frustumCorners[i].w;
|
||||
}
|
||||
|
||||
var nearPlaneSlice = frustumCorners.Slice(0, 4);
|
||||
var farPlaneSlice = frustumCorners.Slice(4, 4);
|
||||
for (var i = 0; i < nearPlaneSlice.Length; ++i)
|
||||
{
|
||||
// Near plane line
|
||||
var nl = new DrawerManagedSingleton.LineData()
|
||||
{
|
||||
color = color,
|
||||
p0 = nearPlaneSlice[i].xyz,
|
||||
p1 = nearPlaneSlice[(i + 1) % 4].xyz
|
||||
};
|
||||
lineData[writeIndex + i] = nl;
|
||||
|
||||
// Far plane line
|
||||
var fl = new DrawerManagedSingleton.LineData()
|
||||
{
|
||||
color = color,
|
||||
p0 = farPlaneSlice[i].xyz,
|
||||
p1 = farPlaneSlice[(i + 1) % 4].xyz
|
||||
};
|
||||
lineData[writeIndex + 4 + i] = fl;
|
||||
|
||||
// Near to far plane line
|
||||
var nfl = new DrawerManagedSingleton.LineData()
|
||||
{
|
||||
color = color,
|
||||
p0 = nearPlaneSlice[i].xyz,
|
||||
p1 = farPlaneSlice[i].xyz
|
||||
};
|
||||
lineData[writeIndex + 8 + i] = nfl;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawRectangle(float2 xySize, uint color, in RigidTransform xform)
|
||||
{
|
||||
var writeIndex = GetTriangleWriteIndex(2);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
var p0 = new float3(xySize, 0) * 0.5f;
|
||||
var p1 = new float3(xySize.x, -xySize.y, 0) * 0.5f;
|
||||
var p2 = new float3(-xySize, 0) * 0.5f;
|
||||
var p3 = new float3(-xySize.x, xySize.y, 0) * 0.5f;
|
||||
|
||||
p0 = math.transform(xform, p0);
|
||||
p1 = math.transform(xform, p1);
|
||||
p2 = math.transform(xform, p2);
|
||||
p3 = math.transform(xform, p3);
|
||||
|
||||
var t0 = new DrawerManagedSingleton.TriangleData()
|
||||
{
|
||||
p0 = p0,
|
||||
p1 = p1,
|
||||
p2 = p2,
|
||||
color = color
|
||||
};
|
||||
|
||||
var t1 = new DrawerManagedSingleton.TriangleData()
|
||||
{
|
||||
p0 = p2,
|
||||
p1 = p3,
|
||||
p2 = p0,
|
||||
color = color
|
||||
};
|
||||
|
||||
triData[writeIndex + 0] = t0;
|
||||
triData[writeIndex + 1] = t1;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawCuboid(float3 size, uint color, in RigidTransform xform)
|
||||
{
|
||||
var halfSize = size * 0.5f;
|
||||
|
||||
var f0c = math.transform(xform, new float3(halfSize.x, 0, 0));
|
||||
var f0s = size.yz;
|
||||
var r0 = quaternion.RotateY(math.PI * 0.5f);
|
||||
r0 = math.mul(quaternion.RotateX(math.PI * 0.5f), r0);
|
||||
r0 = math.mul(xform.rot, r0);
|
||||
DrawRectangle(f0s, color, new RigidTransform(r0, f0c));
|
||||
|
||||
var f1c = math.transform(xform, new float3(-halfSize.x, 0, 0));
|
||||
var f1s = size.yz;
|
||||
var r1 = quaternion.RotateY(-math.PI * 0.5f);
|
||||
r1 = math.mul(quaternion.RotateX(math.PI * 0.5f), r1);
|
||||
r1 = math.mul(xform.rot, r1);
|
||||
DrawRectangle(f1s, color, new RigidTransform(r1, f1c));
|
||||
|
||||
var f2c = math.transform(xform, new float3(0, halfSize.y, 0));
|
||||
var f2s = size.xz;
|
||||
var r2 = quaternion.RotateX(-math.PI * 0.5f);
|
||||
r2 = math.mul(xform.rot, r2);
|
||||
DrawRectangle(f2s, color, new RigidTransform(r2, f2c));
|
||||
|
||||
var f3c = math.transform(xform, new float3(0, -halfSize.y, 0));
|
||||
var f3s = size.xz;
|
||||
var r3 = quaternion.RotateX(math.PI * 0.5f);
|
||||
r3 = math.mul(xform.rot, r3);
|
||||
DrawRectangle(f3s, color, new RigidTransform(r3, f3c));
|
||||
|
||||
var f4c = math.transform(xform, new float3(0, 0, halfSize.z));
|
||||
var f4s = size.xy;
|
||||
DrawRectangle(f4s, color, new RigidTransform(xform.rot, f4c));
|
||||
|
||||
var f5c = math.transform(xform, new float3(0, 0, -halfSize.z));
|
||||
var f5s = size.xy;
|
||||
var r5 = quaternion.RotateX(math.PI);
|
||||
r5 = math.mul(xform.rot, r5);
|
||||
DrawRectangle(f5s, color, new RigidTransform(r5, f5c));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawWireCuboid(float3 size, uint color, in RigidTransform xform)
|
||||
{
|
||||
var writeIndex = GetLineWriteIndex(12);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
Span<float3> corners = stackalloc float3[8];
|
||||
var halfSize = size * 0.5f;
|
||||
|
||||
corners[0] = halfSize.xyz;
|
||||
corners[1] = new float3(halfSize.x, -halfSize.y, halfSize.z);
|
||||
corners[2] = new float3(-halfSize.x, -halfSize.y, halfSize.z);
|
||||
corners[3] = new float3(-halfSize.x, halfSize.y, halfSize.z);
|
||||
corners[4] = new float3(halfSize.x, halfSize.y, -halfSize.z);
|
||||
corners[5] = new float3(halfSize.x, -halfSize.y, -halfSize.z);
|
||||
corners[6] = new float3(-halfSize.x, -halfSize.y, -halfSize.z);
|
||||
corners[7] = new float3(-halfSize.x, halfSize.y, -halfSize.z);
|
||||
|
||||
for (var i = 0; i < corners.Length; ++i)
|
||||
{
|
||||
corners[i] = math.transform(xform, corners[i]);
|
||||
}
|
||||
|
||||
var l0 = new DrawerManagedSingleton.LineData() { p0 = corners[0], p1 = corners[1], color = color };
|
||||
lineData[writeIndex + 0] = l0;
|
||||
var l1 = new DrawerManagedSingleton.LineData() { p0 = corners[1], p1 = corners[2], color = color };
|
||||
lineData[writeIndex + 1] = l1;
|
||||
var l2 = new DrawerManagedSingleton.LineData() { p0 = corners[2], p1 = corners[3], color = color };
|
||||
lineData[writeIndex + 2] = l2;
|
||||
var l3 = new DrawerManagedSingleton.LineData() { p0 = corners[3], p1 = corners[0], color = color };
|
||||
lineData[writeIndex + 3] = l3;
|
||||
|
||||
var l4 = new DrawerManagedSingleton.LineData() { p0 = corners[4], p1 = corners[5], color = color };
|
||||
lineData[writeIndex + 4] = l4;
|
||||
var l5 = new DrawerManagedSingleton.LineData() { p0 = corners[5], p1 = corners[6], color = color };
|
||||
lineData[writeIndex + 5] = l5;
|
||||
var l6 = new DrawerManagedSingleton.LineData() { p0 = corners[6], p1 = corners[7], color = color };
|
||||
lineData[writeIndex + 6] = l6;
|
||||
var l7 = new DrawerManagedSingleton.LineData() { p0 = corners[7], p1 = corners[4], color = color };
|
||||
lineData[writeIndex + 7] = l7;
|
||||
|
||||
var l8 = new DrawerManagedSingleton.LineData() { p0 = corners[0], p1 = corners[4], color = color };
|
||||
lineData[writeIndex + 8] = l8;
|
||||
var l9 = new DrawerManagedSingleton.LineData() { p0 = corners[1], p1 = corners[5], color = color };
|
||||
lineData[writeIndex + 9] = l9;
|
||||
var l10 = new DrawerManagedSingleton.LineData() { p0 = corners[2], p1 = corners[6], color = color };
|
||||
lineData[writeIndex + 10] = l10;
|
||||
var l11 = new DrawerManagedSingleton.LineData() { p0 = corners[3], p1 = corners[7], color = color };
|
||||
lineData[writeIndex + 11] = l11;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawWireTriangle(float3 p0, float3 p1, float3 p2, uint color)
|
||||
{
|
||||
var writeIndex = GetLineWriteIndex(3);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
var l0 = new DrawerManagedSingleton.LineData()
|
||||
{
|
||||
p0 = p0,
|
||||
p1 = p1,
|
||||
color = color,
|
||||
};
|
||||
|
||||
var l1 = new DrawerManagedSingleton.LineData()
|
||||
{
|
||||
p0 = p1,
|
||||
p1 = p2,
|
||||
color = color,
|
||||
};
|
||||
|
||||
var l2 = new DrawerManagedSingleton.LineData()
|
||||
{
|
||||
p0 = p2,
|
||||
p1 = p0,
|
||||
color = color,
|
||||
};
|
||||
|
||||
lineData[writeIndex + 0] = l0;
|
||||
lineData[writeIndex + 1] = l1;
|
||||
lineData[writeIndex + 2] = l2;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawWirePyramid(float baseRadius, float apexHeight, int numBaseEdges, uint color, in RigidTransform xform)
|
||||
{
|
||||
if (numBaseEdges < 3)
|
||||
return;
|
||||
|
||||
var writeIndex = GetLineWriteIndex(numBaseEdges * 2);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
Span<float3> basePoints = stackalloc float3[numBaseEdges];
|
||||
CreateCircleEdgePointsXY(ref basePoints, baseRadius);
|
||||
DrawWireCircleInternal(basePoints, color, xform, writeIndex);
|
||||
|
||||
var apex = math.transform(xform, new float3(0, 0, apexHeight));
|
||||
for (var i = 0; i < basePoints.Length; ++i)
|
||||
{
|
||||
var l = new DrawerManagedSingleton.LineData()
|
||||
{
|
||||
p0 = basePoints[i],
|
||||
p1 = apex,
|
||||
color = color
|
||||
};
|
||||
lineData[writeIndex + numBaseEdges + i] = l;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawPyramid(float baseRadius, float height, int numBaseEdges, uint color, in RigidTransform xform)
|
||||
{
|
||||
if (numBaseEdges < 3)
|
||||
return;
|
||||
|
||||
var writeIndex = GetTriangleWriteIndex(numBaseEdges * 2);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
Span<float3> basePoints = stackalloc float3[numBaseEdges];
|
||||
CreateCircleEdgePointsXY(ref basePoints, baseRadius);
|
||||
DrawCircleInternal(basePoints, color, xform, false, writeIndex);
|
||||
|
||||
var apex = math.transform(xform, new float3(0, 0, height));
|
||||
for (var i = 0; i < basePoints.Length; ++i)
|
||||
{
|
||||
var t = new DrawerManagedSingleton.TriangleData()
|
||||
{
|
||||
p0 = basePoints[i],
|
||||
p1 = basePoints[(i + 1) % basePoints.Length],
|
||||
p2 = apex,
|
||||
color = color
|
||||
};
|
||||
triData[writeIndex + numBaseEdges + i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawFreeFormOctahedron(float radius, float height, float topBottomProportion, uint color, in RigidTransform xform)
|
||||
{
|
||||
var writeIndex = GetTriangleWriteIndex(8);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
var heightVec = new float3(0, 0, height);
|
||||
var fwdVec = heightVec * topBottomProportion;
|
||||
var backVec = -heightVec * (1 - topBottomProportion);
|
||||
|
||||
Span<float3> middlePoints = stackalloc float3[4];
|
||||
CreateCircleEdgePointsXY(ref middlePoints, radius);
|
||||
|
||||
for (int i = 0; i < middlePoints.Length; ++i)
|
||||
{
|
||||
middlePoints[i] = math.transform(xform, middlePoints[i]);
|
||||
}
|
||||
|
||||
fwdVec = math.transform(xform, fwdVec);
|
||||
backVec = math.transform(xform, backVec);
|
||||
|
||||
for (var i = 0; i < middlePoints.Length; ++i)
|
||||
{
|
||||
var t0 = new DrawerManagedSingleton.TriangleData()
|
||||
{
|
||||
p0 = middlePoints[i],
|
||||
p1 = middlePoints[(i + 1) & 3],
|
||||
p2 = fwdVec,
|
||||
color = color
|
||||
};
|
||||
triData[writeIndex + i * 2] = t0;
|
||||
|
||||
var t1 = new DrawerManagedSingleton.TriangleData()
|
||||
{
|
||||
p0 = middlePoints[(i + 1) & 3],
|
||||
p1 = middlePoints[i],
|
||||
p2 = backVec,
|
||||
color = color
|
||||
};
|
||||
triData[writeIndex + i * 2 + 1] = t1;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawBoneMesh(float3 pos0, float3 pos1, uint bodyColor, uint outlineColor)
|
||||
{
|
||||
var writeIndex = GetBoneMeshWriteIndex(1);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
var bd = new DrawerManagedSingleton.BoneData()
|
||||
{
|
||||
pos0 = pos0,
|
||||
pos1 = pos1,
|
||||
colorLines = outlineColor,
|
||||
colorTri = bodyColor
|
||||
};
|
||||
|
||||
boneData[writeIndex] = bd;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawSolidArrow(float3 from, float3 to, uint color)
|
||||
{
|
||||
var v = to - from;
|
||||
var vlen = math.length(v);
|
||||
var vnrm = vlen > 0 ? v / vlen : 0;
|
||||
var xform = new RigidTransform(MathUtils.FromToRotationForNormalizedVectors(math.forward(), vnrm), from);
|
||||
DrawSolidCylinder(0.02f * vlen, math.length(v), 12, color, xform);
|
||||
xform.pos = to;
|
||||
DrawPyramid(0.04f * vlen, 0.08f * vlen, 12, color, xform);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CreateCircleEdgePointsXY(ref Span<float3> pts, float radius)
|
||||
{
|
||||
var angleStep = math.PI * 2 / pts.Length;
|
||||
|
||||
for (var i = 0; i < pts.Length; ++i)
|
||||
{
|
||||
math.sincos(i * angleStep, out var s, out var c);
|
||||
pts[i] = new float3(s, c, 0) * radius;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DrawCircleInternal(Span<float3> pts, uint color, in RigidTransform xform, bool ccw, int writeIndex)
|
||||
{
|
||||
var center = xform.pos;
|
||||
for (var i = 0; i < pts.Length; ++i)
|
||||
pts[i] = math.transform(xform, pts[i]);
|
||||
|
||||
for (var i = 0; i < pts.Length; ++i)
|
||||
{
|
||||
var p0 = pts[(i + 1) % pts.Length];
|
||||
var p1 = pts[i];
|
||||
var t = new DrawerManagedSingleton.TriangleData()
|
||||
{
|
||||
p0 = math.select(p0, p1, ccw),
|
||||
p1 = math.select(p0, p1, !ccw),
|
||||
p2 = center,
|
||||
color = color
|
||||
};
|
||||
triData[writeIndex + i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawCircle(float radius, int numEdges, uint color, in RigidTransform xform)
|
||||
{
|
||||
if (numEdges < 3)
|
||||
return;
|
||||
|
||||
var writeIndex = GetTriangleWriteIndex(numEdges);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
Span<float3> edgePoints = stackalloc float3[numEdges];
|
||||
CreateCircleEdgePointsXY(ref edgePoints, radius);
|
||||
DrawCircleInternal(edgePoints, color, xform, false, writeIndex);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DrawWireCircleInternal(Span<float3> pts, uint color, in RigidTransform xform, int writeIndex)
|
||||
{
|
||||
for (var i = 0; i < pts.Length; ++i)
|
||||
pts[i] = math.transform(xform, pts[i]);
|
||||
|
||||
for (var i = 0; i < pts.Length; ++i)
|
||||
{
|
||||
var l = new DrawerManagedSingleton.LineData()
|
||||
{
|
||||
p0 = pts[i],
|
||||
p1 = pts[(i + 1) % pts.Length],
|
||||
color = color
|
||||
};
|
||||
lineData[writeIndex + i] = l;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawWireCircle(float radius, int numEdges, uint color, in RigidTransform xform)
|
||||
{
|
||||
if (numEdges < 3)
|
||||
return;
|
||||
|
||||
var writeIndex = GetLineWriteIndex(numEdges);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
Span<float3> edgePoints = stackalloc float3[numEdges];
|
||||
CreateCircleEdgePointsXY(ref edgePoints, radius);
|
||||
|
||||
DrawWireCircleInternal(edgePoints, color, xform, writeIndex);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static NativeList<float3> MakeIcosahedronVertices()
|
||||
{
|
||||
var rv = new NativeList<float3>(12, Allocator.Temp);
|
||||
rv.Resize(12, NativeArrayOptions.UninitializedMemory);
|
||||
var sqrt5 = 2.23606797749f;
|
||||
var phi = (1.0f + sqrt5) * 0.5f;
|
||||
var a = 1.0f;
|
||||
var b = 1 / phi;
|
||||
|
||||
rv[0] = new float3(0, b, -a);
|
||||
rv[1] = new float3(b, a, 0);
|
||||
rv[2] = new float3(-b, a, 0);
|
||||
rv[3] = new float3(0, b, a);
|
||||
rv[4] = new float3(0, -b, a);
|
||||
rv[5] = new float3(-a, 0, b);
|
||||
rv[6] = new float3(0, -b, -a);
|
||||
rv[7] = new float3(a, 0, -b);
|
||||
rv[8] = new float3(a, 0, b);
|
||||
rv[9] = new float3(-a, 0, -b);
|
||||
rv[10] = new float3(b, -a, 0);
|
||||
rv[11] = new float3(-b, -a, 0);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void ProjectVerticesToUnitSphere(NativeArray<float3> v)
|
||||
{
|
||||
for (var i = 0; i < v.Length; ++i)
|
||||
{
|
||||
v[i] = math.normalize(v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MakeWireIcosahedron(out NativeList<float3> vertices, out NativeList<int2> lines)
|
||||
{
|
||||
vertices = MakeIcosahedronVertices();
|
||||
ProjectVerticesToUnitSphere(vertices.AsArray());
|
||||
|
||||
lines = new (30, Allocator.Temp);
|
||||
|
||||
lines.Add(new int2(0, 1));
|
||||
lines.Add(new int2(0, 2));
|
||||
lines.Add(new int2(0, 6));
|
||||
lines.Add(new int2(0, 7));
|
||||
lines.Add(new int2(0, 9));
|
||||
lines.Add(new int2(1, 2));
|
||||
lines.Add(new int2(1, 3));
|
||||
lines.Add(new int2(1, 7));
|
||||
lines.Add(new int2(1, 8));
|
||||
lines.Add(new int2(2, 3));
|
||||
lines.Add(new int2(2, 5));
|
||||
lines.Add(new int2(2, 9));
|
||||
lines.Add(new int2(3, 4));
|
||||
lines.Add(new int2(3, 5));
|
||||
lines.Add(new int2(3, 8));
|
||||
lines.Add(new int2(4, 5));
|
||||
lines.Add(new int2(4, 8));
|
||||
lines.Add(new int2(4, 10));
|
||||
lines.Add(new int2(4, 11));
|
||||
lines.Add(new int2(5, 9));
|
||||
lines.Add(new int2(5, 11));
|
||||
lines.Add(new int2(6, 7));
|
||||
lines.Add(new int2(6, 9));
|
||||
lines.Add(new int2(6, 10));
|
||||
lines.Add(new int2(6, 11));
|
||||
lines.Add(new int2(7, 8));
|
||||
lines.Add(new int2(7, 10));
|
||||
lines.Add(new int2(8, 10));
|
||||
lines.Add(new int2(9, 11));
|
||||
lines.Add(new int2(10, 11));
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void MakeSolidIcosahedron(out NativeList<float3> vertices, out NativeList<int3> triangles)
|
||||
{
|
||||
vertices = MakeIcosahedronVertices();
|
||||
ProjectVerticesToUnitSphere(vertices.AsArray());
|
||||
|
||||
triangles = new (20, Allocator.Temp);
|
||||
triangles.Resize(20, NativeArrayOptions.UninitializedMemory);
|
||||
|
||||
triangles[0] = new int3(2, 1, 0);
|
||||
triangles[1] = new int3(1, 2, 3);
|
||||
triangles[2] = new int3(5, 4, 3);
|
||||
triangles[3] = new int3(4, 8, 3);
|
||||
triangles[4] = new int3(7, 6, 0);
|
||||
triangles[5] = new int3(6, 9, 0);
|
||||
triangles[6] = new int3(11, 10, 4);
|
||||
triangles[7] = new int3(10, 11, 6);
|
||||
triangles[8] = new int3(9, 5, 2);
|
||||
triangles[9] = new int3(5, 9, 11);
|
||||
triangles[10] = new int3(8, 7, 1);
|
||||
triangles[11] = new int3(7, 8, 10);
|
||||
triangles[12] = new int3(2, 5, 3);
|
||||
triangles[13] = new int3(8, 1, 3);
|
||||
triangles[14] = new int3(9, 2, 0);
|
||||
triangles[15] = new int3(1, 7, 0);
|
||||
triangles[16] = new int3(11, 9, 6);
|
||||
triangles[17] = new int3(7, 10, 6);
|
||||
triangles[18] = new int3(5, 11, 4);
|
||||
triangles[19] = new int3(10, 8, 4);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawSolidIcosahedron(float radius, uint color, in RigidTransform xform)
|
||||
{
|
||||
var writeIndex = GetTriangleWriteIndex(20);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
MakeSolidIcosahedron(out var v, out var triIndices);
|
||||
|
||||
for (var i = 0; i < v.Length; ++i)
|
||||
{
|
||||
var vm = v[i] * radius;
|
||||
v[i] = math.mul(xform, new float4(vm, 1)).xyz;
|
||||
}
|
||||
|
||||
for (int i = 0; i < triIndices.Length; ++i)
|
||||
{
|
||||
var ti = triIndices[i];
|
||||
var t = new DrawerManagedSingleton.TriangleData()
|
||||
{
|
||||
color = color,
|
||||
p0 = v[ti.y],
|
||||
p1 = v[ti.x],
|
||||
p2 = v[ti.z],
|
||||
};
|
||||
triData[writeIndex + i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawWireIcosahedron(float radius, uint color, in RigidTransform xform)
|
||||
{
|
||||
var writeIndex = GetLineWriteIndex(30);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
MakeWireIcosahedron(out var v, out var lineIndices);
|
||||
|
||||
for (var i = 0; i < v.Length; ++i)
|
||||
{
|
||||
var vm = v[i] * radius;
|
||||
v[i] = math.mul(xform, new float4(vm, 1)).xyz;
|
||||
}
|
||||
|
||||
for (int i = 0; i < lineIndices.Length; ++i)
|
||||
{
|
||||
var li = lineIndices[i];
|
||||
var t = new DrawerManagedSingleton.LineData()
|
||||
{
|
||||
color = color,
|
||||
p0 = v[li.x],
|
||||
p1 = v[li.y],
|
||||
};
|
||||
lineData[writeIndex + i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void MakeSolidUnitSphere(uint numSubdivisions, out NativeList<float3> vertices, out NativeList<int3> triIndices)
|
||||
{
|
||||
MakeSolidIcosahedron(out vertices, out triIndices);
|
||||
|
||||
var newVerticesMap = new NativeHashMap<float3, int>(128, Allocator.Temp);
|
||||
for (var i = 0; i < numSubdivisions; ++i)
|
||||
{
|
||||
newVerticesMap.Clear();
|
||||
|
||||
var triCount = triIndices.Length;
|
||||
for (var l = 0; l < triCount; ++l)
|
||||
{
|
||||
var t = triIndices[0];
|
||||
// Split each edge by half
|
||||
|
||||
var i0 = t.x;
|
||||
var i1 = t.y;
|
||||
var i2 = t.z;
|
||||
|
||||
var v0 = vertices[i0];
|
||||
var v1 = vertices[i1];
|
||||
var v2 = vertices[i2];
|
||||
|
||||
var v01 = math.normalize((v1 + v0) * 0.5f);
|
||||
var v02 = math.normalize((v2 + v0) * 0.5f);
|
||||
var v12 = math.normalize((v2 + v1) * 0.5f);
|
||||
|
||||
if (!newVerticesMap.TryGetValue(v01, out var i01))
|
||||
{
|
||||
i01 = vertices.Length;
|
||||
vertices.Add(v01);
|
||||
newVerticesMap.Add(v01, i01);
|
||||
}
|
||||
|
||||
if (!newVerticesMap.TryGetValue(v02, out var i02))
|
||||
{
|
||||
i02 = vertices.Length;
|
||||
vertices.Add(v02);
|
||||
newVerticesMap.Add(v02, i02);
|
||||
}
|
||||
|
||||
if (!newVerticesMap.TryGetValue(v12, out var i12))
|
||||
{
|
||||
i12 = vertices.Length;
|
||||
vertices.Add(v12);
|
||||
newVerticesMap.Add(v12, i12);
|
||||
}
|
||||
|
||||
var t0 = new int3(i0, i01, i02);
|
||||
var t1 = new int3(i01, i1, i12);
|
||||
var t2 = new int3(i02, i12, i2);
|
||||
var t3 = new int3(i01, i12, i02);
|
||||
|
||||
triIndices.RemoveAt(0);
|
||||
triIndices.Add(t0);
|
||||
triIndices.Add(t1);
|
||||
triIndices.Add(t2);
|
||||
triIndices.Add(t3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawSolidSphere(float radius, uint color, uint numSubdivisions, in RigidTransform xform)
|
||||
{
|
||||
MakeSolidUnitSphere(numSubdivisions, out var v, out var triIndices);
|
||||
|
||||
var writeIndex = GetTriangleWriteIndex(triIndices.Length);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < v.Length; ++i)
|
||||
{
|
||||
var vm = v[i] * radius;
|
||||
v[i] = math.mul(xform, new float4(vm, 1)).xyz;
|
||||
}
|
||||
|
||||
for (var i = 0; i < triIndices.Length; ++i)
|
||||
{
|
||||
var ti = triIndices[i];
|
||||
var td = new DrawerManagedSingleton.TriangleData()
|
||||
{
|
||||
color = color,
|
||||
p0 = v[ti.y],
|
||||
p1 = v[ti.x],
|
||||
p2 = v[ti.z]
|
||||
};
|
||||
|
||||
triData[writeIndex + i] = td;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawWireSphere(float radius, uint color, uint numSubdivisions, in RigidTransform xform)
|
||||
{
|
||||
MakeSolidUnitSphere(numSubdivisions, out var v, out var triIndices);
|
||||
|
||||
var linesSet = new NativeHashSet<int2>(128, Allocator.Temp);
|
||||
|
||||
for (var i = 0; i < triIndices.Length; ++i)
|
||||
{
|
||||
var t = triIndices[i];
|
||||
var l0 = new int2(math.min(t.x, t.y), math.max(t.x, t.y));
|
||||
var l1 = new int2(math.min(t.y, t.z), math.max(t.y, t.z));
|
||||
var l2 = new int2(math.min(t.x, t.z), math.max(t.x, t.z));
|
||||
|
||||
linesSet.Add(l0);
|
||||
linesSet.Add(l1);
|
||||
linesSet.Add(l2);
|
||||
}
|
||||
|
||||
var writeIndex = GetLineWriteIndex(linesSet.Count);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < v.Length; ++i)
|
||||
{
|
||||
var vm = v[i] * radius;
|
||||
v[i] = math.mul(xform, new float4(vm, 1)).xyz;
|
||||
}
|
||||
|
||||
var le = linesSet.GetEnumerator();
|
||||
var k = 0;
|
||||
while (le.MoveNext())
|
||||
{
|
||||
var li = le.Current;
|
||||
var ld = new DrawerManagedSingleton.LineData()
|
||||
{
|
||||
color = color,
|
||||
p0 = v[li.x],
|
||||
p1 = v[li.y],
|
||||
};
|
||||
|
||||
lineData[writeIndex + k] = ld;
|
||||
++k;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawWireCylinder(float radius, float height, int numEdges, uint color, in RigidTransform xform)
|
||||
{
|
||||
if (numEdges < 3)
|
||||
return;
|
||||
|
||||
var writeIndex = GetLineWriteIndex(numEdges * 3);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
Span<float3> base0Points = stackalloc float3[numEdges];
|
||||
Span<float3> base1Points = stackalloc float3[numEdges];
|
||||
CreateCircleEdgePointsXY(ref base0Points, radius);
|
||||
base0Points.CopyTo(base1Points);
|
||||
|
||||
var base1Offset = new float3(0, 0, height);
|
||||
var base1XForm = new RigidTransform(quaternion.identity, base1Offset);
|
||||
base1XForm = math.mul(xform, base1XForm);
|
||||
|
||||
DrawWireCircleInternal(base0Points, color, xform, writeIndex);
|
||||
DrawWireCircleInternal(base1Points, color, base1XForm, writeIndex + numEdges);
|
||||
|
||||
for (var i = 0; i < base0Points.Length; ++i)
|
||||
{
|
||||
var l = new DrawerManagedSingleton.LineData()
|
||||
{
|
||||
p0 = base0Points[i],
|
||||
p1 = base1Points[i],
|
||||
color = color
|
||||
};
|
||||
lineData[writeIndex + numEdges * 2 + i] = l;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawSolidCylinder(float radius, float height, int numEdges, uint color, in RigidTransform xform)
|
||||
{
|
||||
if (numEdges < 3)
|
||||
return;
|
||||
|
||||
var writeIndex = GetTriangleWriteIndex(numEdges * 4);
|
||||
|
||||
Span<float3> base0Points = stackalloc float3[numEdges];
|
||||
Span<float3> base1Points = stackalloc float3[numEdges];
|
||||
CreateCircleEdgePointsXY(ref base0Points, radius);
|
||||
base0Points.CopyTo(base1Points);
|
||||
|
||||
var base1Offset = new float3(0, 0, height);
|
||||
var base1XForm = new RigidTransform(quaternion.identity, base1Offset);
|
||||
base1XForm = math.mul(xform, base1XForm);
|
||||
|
||||
DrawCircleInternal(base0Points, color, xform, false, writeIndex);
|
||||
DrawCircleInternal(base1Points, color, base1XForm, true, writeIndex + numEdges);
|
||||
|
||||
for (var i = 0; i < base0Points.Length; ++i)
|
||||
{
|
||||
var t0 = new DrawerManagedSingleton.TriangleData()
|
||||
{
|
||||
p0 = base0Points[i],
|
||||
p1 = base0Points[(i + 1) % base0Points.Length],
|
||||
p2 = base1Points[(i + 1) % base0Points.Length],
|
||||
color = color
|
||||
};
|
||||
|
||||
triData[writeIndex + numEdges * 2 + i * 2 + 0] = t0;
|
||||
|
||||
var t1 = new DrawerManagedSingleton.TriangleData()
|
||||
{
|
||||
p0 = base1Points[(i + 1) % base0Points.Length],
|
||||
p1 = base1Points[i],
|
||||
p2 = base0Points[i],
|
||||
color = color
|
||||
};
|
||||
|
||||
triData[writeIndex + numEdges * 2 + i * 2 + 1] = t1;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawTriangle(float3 p0, float3 p1, float3 p2, uint color)
|
||||
{
|
||||
var t = new DrawerManagedSingleton.TriangleData()
|
||||
{
|
||||
p0 = p0,
|
||||
p1 = p1,
|
||||
p2 = p2,
|
||||
color = color
|
||||
};
|
||||
|
||||
var writeIndex = GetTriangleWriteIndex(1);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
triData[writeIndex] = t;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void DrawLine(float3 p0, float3 p1, uint color)
|
||||
{
|
||||
var l = new DrawerManagedSingleton.LineData()
|
||||
{
|
||||
p0 = p0,
|
||||
p1 = p1,
|
||||
color = color
|
||||
};
|
||||
|
||||
var writeIndex = GetLineWriteIndex(1);
|
||||
if (writeIndex < 0)
|
||||
return;
|
||||
|
||||
lineData[writeIndex] = l;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 62b71091c702d104496838a7805dd03f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.DebugDrawer/DebugDrawer.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.DebugDrawer
|
||||
{
|
||||
|
||||
[UpdateInGroup(typeof(SimulationSystemGroup), OrderFirst = true)]
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.LocalSimulation | WorldSystemFilterFlags.ClientSimulation)]
|
||||
public partial class RukhankaDebugDrawerFrameStartSystem : SystemBase
|
||||
{
|
||||
private DrawerManagedSingleton ds;
|
||||
protected override void OnCreate()
|
||||
{
|
||||
ds = new DrawerManagedSingleton();
|
||||
if (ds.IsValid())
|
||||
{
|
||||
var e = EntityManager.CreateSingleton(ds, new FixedString64Bytes("Rukhanka.DebugDrawer.Singleton"));
|
||||
var dw = Drawer.Create(ds);
|
||||
EntityManager.AddComponentData(e, dw);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
if (!SystemAPI.ManagedAPI.TryGetSingleton<DrawerManagedSingleton>(out var ds))
|
||||
return;
|
||||
ds.BeginFrame();
|
||||
var dw = Drawer.Create(ds);
|
||||
SystemAPI.SetSingleton(dw);
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
if (SystemAPI.ManagedAPI.TryGetSingleton<DrawerManagedSingleton>(out var ds))
|
||||
ds.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
///===============================================================================================================///
|
||||
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup), OrderLast = true)]
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.LocalSimulation | WorldSystemFilterFlags.ClientSimulation)]
|
||||
public partial class RukhankaDebugDrawerFrameEndSystem : SystemBase
|
||||
{
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
Dependency.Complete();
|
||||
if (SystemAPI.ManagedAPI.TryGetSingleton<DrawerManagedSingleton>(out var ds))
|
||||
{
|
||||
ds.EndFrame();
|
||||
SystemAPI.SetSingleton(new Drawer());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57782ab314705df45b28d92a822f418b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.DebugDrawer/DebugDrawerSystems.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.DebugDrawer
|
||||
{
|
||||
public class DrawBuffer<T>: IDisposable where T: unmanaged
|
||||
{
|
||||
internal GraphicsBuffer gpuBuffer;
|
||||
internal int counter;
|
||||
internal UnsafeAtomicCounter32 counterAtomic;
|
||||
NativeList<T> bufferData;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public DrawBuffer()
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
fixed (void* counterPtr = &counter)
|
||||
{
|
||||
counterAtomic = new UnsafeAtomicCounter32(counterPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
internal NativeArray<T> BeginFrame()
|
||||
{
|
||||
ResizeBuffer();
|
||||
counterAtomic.Reset();
|
||||
|
||||
var rv = bufferData.AsArray();
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
internal int EndFrame()
|
||||
{
|
||||
if (counter == 0)
|
||||
return 0;
|
||||
|
||||
ResizeGPUBuffer();
|
||||
var cnt = math.min(bufferData.Length, counter);
|
||||
gpuBuffer.SetData(bufferData.AsArray(), 0, 0, cnt);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ResizeGPUBuffer()
|
||||
{
|
||||
if (gpuBuffer == null || gpuBuffer.count < counter)
|
||||
{
|
||||
if (gpuBuffer != null)
|
||||
gpuBuffer.Dispose();
|
||||
var cnt = math.max(counter, 0xffff);
|
||||
gpuBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, GraphicsBuffer.UsageFlags.LockBufferForWrite, cnt, UnsafeUtility.SizeOf<T>());
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ResizeBuffer()
|
||||
{
|
||||
if (!bufferData.IsCreated)
|
||||
{
|
||||
bufferData = new (counter, Allocator.Persistent);
|
||||
}
|
||||
var cnt = math.max(counter, 0xffff);
|
||||
bufferData.Resize(cnt, NativeArrayOptions.ClearMemory);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (gpuBuffer != null)
|
||||
gpuBuffer.Dispose();
|
||||
gpuBuffer = null;
|
||||
|
||||
bufferData.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d22adb32c09903459d5122edec1d5b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.DebugDrawer/DrawBuffer.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,240 @@
|
||||
|
||||
using Unity.Mathematics;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.DebugDrawer
|
||||
{
|
||||
public class DrawerManagedSingleton: IComponentData
|
||||
{
|
||||
internal DrawBuffer<LineData> linesBuf;
|
||||
internal DrawBuffer<ThickLineData> thickLinesBuf;
|
||||
internal DrawBuffer<TriangleData> trianglesBuf;
|
||||
internal DrawBuffer<BoneData> bonesBuf;
|
||||
|
||||
internal NativeArray<LineData> lineData;
|
||||
internal NativeArray<TriangleData> triData;
|
||||
internal NativeArray<ThickLineData> thickLineData;
|
||||
internal NativeArray<BoneData> boneData;
|
||||
|
||||
Material lineDrawMat;
|
||||
Material thickLinesDrawMat;
|
||||
Material trianglesDrawMat;
|
||||
Material boneTriDrawMat;
|
||||
Material boneOutlineDrawMat;
|
||||
|
||||
Mesh boneMesh;
|
||||
|
||||
internal struct LineData
|
||||
{
|
||||
public float3 p0, p1;
|
||||
public uint color;
|
||||
}
|
||||
|
||||
internal struct ThickLineData
|
||||
{
|
||||
public float3 p0, p1;
|
||||
public float thickness;
|
||||
public uint color;
|
||||
}
|
||||
|
||||
internal struct TriangleData
|
||||
{
|
||||
public float3 p0, p1, p2;
|
||||
public uint color;
|
||||
}
|
||||
|
||||
public struct BoneData
|
||||
{
|
||||
public float3 pos0, pos1;
|
||||
public uint colorTri, colorLines;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
linesBuf.Dispose();
|
||||
thickLinesBuf.Dispose();
|
||||
trianglesBuf.Dispose();
|
||||
bonesBuf.Dispose();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public DrawerManagedSingleton()
|
||||
{
|
||||
if (!SystemInfo.supportsComputeShaders)
|
||||
{
|
||||
Debug.LogError("System does not support compute shaders and/or graphics buffers. DebugDrawer will be disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
linesBuf = new ();
|
||||
thickLinesBuf = new ();
|
||||
trianglesBuf = new ();
|
||||
bonesBuf = new ();
|
||||
|
||||
CreateMaterials();
|
||||
boneMesh = CreateBoneMesh();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public bool IsValid()
|
||||
{
|
||||
var rv =
|
||||
linesBuf != null &&
|
||||
thickLinesBuf != null &&
|
||||
trianglesBuf != null &&
|
||||
bonesBuf != null &&
|
||||
|
||||
lineDrawMat != null &&
|
||||
thickLinesDrawMat != null &&
|
||||
trianglesDrawMat != null &&
|
||||
boneOutlineDrawMat != null &&
|
||||
boneTriDrawMat != null;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CreateMaterials()
|
||||
{
|
||||
lineDrawMat = new Material(Shader.Find($"RukhankaDebugLineDrawer"));
|
||||
thickLinesDrawMat = new Material(Shader.Find($"RukhankaDebugThickLineDrawer"));
|
||||
trianglesDrawMat = new Material(Shader.Find($"RukhankaDebugTriangleDrawer"));
|
||||
boneTriDrawMat = new Material(Shader.Find($"RukhankaBoneTriangleRenderer"));
|
||||
boneOutlineDrawMat = new Material(Shader.Find($"RukhankaBoneOutlineRenderer"));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static Mesh CreateBoneMesh()
|
||||
{
|
||||
var boneMesh = new Mesh();
|
||||
boneMesh.subMeshCount = 2;
|
||||
|
||||
var vtx = new Vector3[6];
|
||||
vtx[0] = new Vector3(0, 1, 0);
|
||||
vtx[5] = new Vector3(0, -1, 0);
|
||||
vtx[1] = new Vector3(-1, 0, 0);
|
||||
vtx[2] = new Vector3(1, 0, 0);
|
||||
vtx[3] = new Vector3(0, 0, -1);
|
||||
vtx[4] = new Vector3(0, 0, 1);
|
||||
|
||||
for (int i = 0; i < vtx.Length; ++i)
|
||||
vtx[i] *= 0.1f;
|
||||
|
||||
var triIdx = new int[]
|
||||
{
|
||||
0, 1, 4,
|
||||
0, 4, 2,
|
||||
0, 2, 3,
|
||||
0, 3, 1,
|
||||
|
||||
5, 4, 1,
|
||||
5, 2, 4,
|
||||
5, 3, 2,
|
||||
5, 1, 3,
|
||||
};
|
||||
|
||||
var lineIdx = new int[]
|
||||
{
|
||||
0, 1,
|
||||
0, 2,
|
||||
0, 3,
|
||||
0, 4,
|
||||
5, 1,
|
||||
5, 2,
|
||||
5, 3,
|
||||
5, 4,
|
||||
2, 4,
|
||||
1, 4,
|
||||
1, 3,
|
||||
2, 3,
|
||||
};
|
||||
|
||||
boneMesh.SetVertices(vtx);
|
||||
boneMesh.SetIndices(triIdx, MeshTopology.Triangles, 0);
|
||||
boneMesh.SetIndices(lineIdx, MeshTopology.Lines, 1);
|
||||
|
||||
return boneMesh;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void BeginFrame()
|
||||
{
|
||||
lineData = linesBuf.BeginFrame();
|
||||
thickLineData = thickLinesBuf.BeginFrame();
|
||||
triData = trianglesBuf.BeginFrame();
|
||||
boneData = bonesBuf.BeginFrame();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Render primitives
|
||||
public void EndFrame()
|
||||
{
|
||||
var numLines = linesBuf.EndFrame();
|
||||
lineData = default;
|
||||
var numThickLines = thickLinesBuf.EndFrame();
|
||||
thickLineData = default;
|
||||
var numTriangles = trianglesBuf.EndFrame();
|
||||
triData = default;
|
||||
var numBones = bonesBuf.EndFrame();
|
||||
boneData = default;
|
||||
|
||||
var rp = new RenderParams();
|
||||
rp.camera = null;
|
||||
rp.layer = 0;
|
||||
rp.lightProbeProxyVolume = null;
|
||||
rp.lightProbeUsage = LightProbeUsage.Off;
|
||||
rp.matProps = null;
|
||||
rp.motionVectorMode = MotionVectorGenerationMode.ForceNoMotion;
|
||||
rp.receiveShadows = false;
|
||||
rp.reflectionProbeUsage = ReflectionProbeUsage.Off;
|
||||
rp.rendererPriority = 0;
|
||||
rp.renderingLayerMask = 0xffffffff;
|
||||
rp.shadowCastingMode = ShadowCastingMode.Off;
|
||||
rp.worldBounds = new Bounds(Vector3.zero, Vector3.one * 100000);
|
||||
|
||||
if (numLines > 0)
|
||||
{
|
||||
rp.material = lineDrawMat;
|
||||
rp.material.SetBuffer("lineDataBuf", linesBuf.gpuBuffer);
|
||||
Graphics.RenderPrimitives(rp, MeshTopology.Lines, linesBuf.counter * 2);
|
||||
}
|
||||
|
||||
if (numThickLines > 0)
|
||||
{
|
||||
rp.material = thickLinesDrawMat;
|
||||
rp.material.SetBuffer("thickLineDataBuf", thickLinesBuf.gpuBuffer);
|
||||
Graphics.RenderPrimitives(rp, MeshTopology.Triangles, thickLinesBuf.counter * 6);
|
||||
}
|
||||
|
||||
if (numTriangles > 0)
|
||||
{
|
||||
rp.material = trianglesDrawMat;
|
||||
rp.material.SetBuffer("triDataBuf", trianglesBuf.gpuBuffer);
|
||||
Graphics.RenderPrimitives(rp, MeshTopology.Triangles, trianglesBuf.counter * 3);
|
||||
}
|
||||
|
||||
if (numBones > 0)
|
||||
{
|
||||
rp.material = boneTriDrawMat;
|
||||
rp.material.SetBuffer("boneDataBuf", bonesBuf.gpuBuffer);
|
||||
Graphics.RenderMeshPrimitives(rp, boneMesh, 0, bonesBuf.counter);
|
||||
|
||||
rp.material = boneOutlineDrawMat;
|
||||
rp.material.SetBuffer("boneDataBuf", bonesBuf.gpuBuffer);
|
||||
Graphics.RenderMeshPrimitives(rp, boneMesh, 1, bonesBuf.counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b19bee19b241d0c478f938eb54695008
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.DebugDrawer/DrawerManagedSingleton.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7901406cd8ae49a4cba4e5914cd4eb8a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
Shader "RukhankaBoneOutlineRenderer"
|
||||
{
|
||||
SubShader
|
||||
{
|
||||
PackageRequirements
|
||||
{
|
||||
"com.unity.render-pipelines.high-definition": "1.0.0"
|
||||
}
|
||||
Tags
|
||||
{
|
||||
"RenderPipeline" = "HDRenderPipeline"
|
||||
"RenderType" = "HDUnlitShader"
|
||||
"Queue" = "Transparent+0"
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "ForwardOnly"
|
||||
Tags
|
||||
{
|
||||
"LightMode" = "ForwardOnly"
|
||||
}
|
||||
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
ZTest off
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 3.0
|
||||
|
||||
#pragma vertex VS
|
||||
#pragma fragment PS
|
||||
#define BONE_OUTLINE
|
||||
#define IS_HDRP
|
||||
|
||||
#include "RukhankaBoneRenderer.hlsl"
|
||||
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SubShader
|
||||
{
|
||||
PackageRequirements
|
||||
{
|
||||
"com.unity.render-pipelines.universal": "1.0.0"
|
||||
}
|
||||
Tags
|
||||
{
|
||||
"RenderPipeline"="UniversalPipeline"
|
||||
"Queue" = "Transparent+0"
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
Tags
|
||||
{
|
||||
"LightMode" = "UniversalForward"
|
||||
}
|
||||
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
ZTest off
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 3.0
|
||||
|
||||
#pragma vertex VS
|
||||
#pragma fragment PS
|
||||
#define BONE_OUTLINE
|
||||
|
||||
#include "RukhankaBoneRenderer.hlsl"
|
||||
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 740a4e84dd61c564fbfc15932a58081f
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.DebugDrawer/Resources/RukhankaBoneOutlineRenderer.shader
|
||||
uploadId: 897522
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
#ifndef RUKHANKA_BONE_RENDERER_HLSL_
|
||||
#define RUKHANKA_BONE_RENDERER_HLSL_
|
||||
|
||||
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
|
||||
#include "RukhankaDebugDrawerCommon.hlsl"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct VertexInput
|
||||
{
|
||||
float3 pos: POSITION;
|
||||
uint vertexID: SV_VertexID;
|
||||
uint instanceID: SV_InstanceID;
|
||||
};
|
||||
|
||||
struct VertexToPixel
|
||||
{
|
||||
float4 pos: SV_Position;
|
||||
float4 color: COLOR0;
|
||||
};
|
||||
|
||||
struct BoneData
|
||||
{
|
||||
float3 pos0, pos1;
|
||||
uint colorTri, colorLines;
|
||||
};
|
||||
|
||||
StructuredBuffer<BoneData> boneDataBuf;
|
||||
float4x4 unity_MatrixVP;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
float3 GetStableTangent(float3 v)
|
||||
{
|
||||
float3 aV = abs(v);
|
||||
float3 rv = float3(-v.y, v.z, 0);
|
||||
|
||||
if (aV.x <= aV.y && aV.x <= aV.z) rv = float3(0, -v.z, v.y);
|
||||
else if (aV.y <= aV.y && aV.y <= aV.z) rv = float3(-v.z, 0, v.x);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
float3 ComputeVertexWorldPos(BoneData bd, float3 vertexPos, int vertexID)
|
||||
{
|
||||
float3 worldPos = 0;
|
||||
|
||||
switch (vertexID)
|
||||
{
|
||||
case 0: worldPos = bd.pos0; break;
|
||||
case 5: worldPos = bd.pos1; break;
|
||||
default:
|
||||
{
|
||||
float3 boneVec = bd.pos0 - bd.pos1;
|
||||
float l = length(boneVec);
|
||||
if (l != 0)
|
||||
{
|
||||
float3 boneVecNrm = boneVec / l;
|
||||
float3 tangent = GetStableTangent(boneVecNrm);
|
||||
float3 t = normalize(cross(boneVecNrm, tangent));
|
||||
float3 n = normalize(cross(boneVecNrm, t));
|
||||
|
||||
float3 offsetVec = t * vertexPos.x - n * vertexPos.z;
|
||||
worldPos = bd.pos1 + boneVec * 0.3f + offsetVec * l;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return worldPos;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
VertexToPixel VS(VertexInput i)
|
||||
{
|
||||
VertexToPixel o = (VertexToPixel)0;
|
||||
BoneData bd = boneDataBuf[i.instanceID];
|
||||
|
||||
float3 worldPos = ComputeVertexWorldPos(bd, i.pos, i.vertexID);
|
||||
|
||||
worldPos = GetCameraRelativePositionWS(worldPos);
|
||||
o.pos = mul(unity_MatrixVP, float4(worldPos, 1));
|
||||
#ifdef BONE_OUTLINE
|
||||
o.color = UnpackColor(bd.colorLines);
|
||||
#else
|
||||
o.color = UnpackColor(bd.colorTri);
|
||||
#endif
|
||||
return o;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
float4 PS(VertexToPixel i): SV_Target0
|
||||
{
|
||||
return i.color;
|
||||
}
|
||||
|
||||
#endif
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ad43a2adc0e63f4b9e27f8ef82924c4
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.DebugDrawer/Resources/RukhankaBoneRenderer.hlsl
|
||||
uploadId: 897522
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
Shader "RukhankaBoneTriangleRenderer"
|
||||
{
|
||||
SubShader
|
||||
{
|
||||
PackageRequirements
|
||||
{
|
||||
"com.unity.render-pipelines.high-definition": "1.0.0"
|
||||
}
|
||||
Tags
|
||||
{
|
||||
"RenderPipeline" = "HDRenderPipeline"
|
||||
"RenderType" = "HDUnlitShader"
|
||||
"Queue" = "Transparent+0"
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "ForwardOnly"
|
||||
Tags
|
||||
{
|
||||
"LightMode" = "ForwardOnly"
|
||||
}
|
||||
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
ZTest off
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 3.0
|
||||
|
||||
#pragma vertex VS
|
||||
#pragma fragment PS
|
||||
#define IS_HDRP
|
||||
|
||||
#include "RukhankaBoneRenderer.hlsl"
|
||||
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SubShader
|
||||
{
|
||||
PackageRequirements
|
||||
{
|
||||
"com.unity.render-pipelines.universal": "1.0.0"
|
||||
}
|
||||
Tags
|
||||
{
|
||||
"RenderPipeline"="UniversalPipeline"
|
||||
"Queue" = "Transparent+0"
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
Tags
|
||||
{
|
||||
"LightMode" = "UniversalForward"
|
||||
}
|
||||
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
ZTest off
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 3.0
|
||||
|
||||
#pragma vertex VS
|
||||
#pragma fragment PS
|
||||
|
||||
#include "RukhankaBoneRenderer.hlsl"
|
||||
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b3326df71f53a44188448c6506106e4
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.DebugDrawer/Resources/RukhankaBoneTriangleRenderer.shader
|
||||
uploadId: 897522
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
#ifndef RUKHANKA_DEBUG_DRAWER_HLSL_
|
||||
#define RUKHANKA_DEBUG_DRAWER_HLSL_
|
||||
|
||||
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
|
||||
#ifdef IS_HDRP
|
||||
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightDefinition.cs.hlsl"
|
||||
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs.hlsl"
|
||||
#endif
|
||||
|
||||
#include "RukhankaDebugDrawerCommon.hlsl"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct VertexInput
|
||||
{
|
||||
uint vertexID: SV_VertexID;
|
||||
};
|
||||
|
||||
struct VertexToPixel
|
||||
{
|
||||
float4 pos: SV_Position;
|
||||
float3 normal: NORMAL;
|
||||
float2 uv: TEXCOORD0;
|
||||
float4 color: COLOR0;
|
||||
};
|
||||
|
||||
struct LineData
|
||||
{
|
||||
float3 pos[2];
|
||||
uint color;
|
||||
};
|
||||
|
||||
struct ThickLineData
|
||||
{
|
||||
float3 pos[2];
|
||||
float thickness;
|
||||
uint color;
|
||||
};
|
||||
|
||||
struct TriData
|
||||
{
|
||||
float3 pos[3];
|
||||
uint color;
|
||||
};
|
||||
|
||||
StructuredBuffer<LineData> lineDataBuf;
|
||||
StructuredBuffer<ThickLineData> thickLineDataBuf;
|
||||
StructuredBuffer<TriData> triDataBuf;
|
||||
float4x4 unity_MatrixVP;
|
||||
float4x4 unity_MatrixV;
|
||||
|
||||
#ifdef IS_HDRP
|
||||
StructuredBuffer<DirectionalLightData> _DirectionalLightDatas;
|
||||
#else
|
||||
float4 _MainLightPosition;
|
||||
float4 _MainLightColor;
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
VertexToPixel VSLines(VertexInput i)
|
||||
{
|
||||
VertexToPixel o = (VertexToPixel)0;
|
||||
uint lineID = i.vertexID >> 1;
|
||||
uint vertexID = i.vertexID & 1;
|
||||
|
||||
LineData ln = lineDataBuf[lineID];
|
||||
float3 worldPos = ln.pos[vertexID];
|
||||
|
||||
worldPos = GetCameraRelativePositionWS(worldPos);
|
||||
o.pos = mul(unity_MatrixVP, float4(worldPos, 1));
|
||||
o.color = UnpackColor(ln.color);
|
||||
return o;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
VertexToPixel VSThickLines(VertexInput i)
|
||||
{
|
||||
VertexToPixel o = (VertexToPixel)0;
|
||||
uint instanceID = i.vertexID / 6;
|
||||
uint triangleID = (i.vertexID - instanceID * 6) / 3;
|
||||
uint vertexID = i.vertexID - instanceID * 6 - triangleID * 3;
|
||||
uint posID = (vertexID + triangleID) >> 1;
|
||||
uint leftRightID = (vertexID + triangleID) & 1;
|
||||
|
||||
ThickLineData tld = thickLineDataBuf[instanceID];
|
||||
float3 worldPos = tld.pos[posID];
|
||||
|
||||
float3 dp = tld.pos[0] - tld.pos[1];
|
||||
float3 viewVec = unity_MatrixV[2].xyz;
|
||||
float3 c = cross(viewVec, dp);
|
||||
c = normalize(c) * (leftRightID * 2.0f - 1) * tld.thickness;
|
||||
|
||||
worldPos += c;
|
||||
o.uv = float2(leftRightID, posID);
|
||||
|
||||
worldPos = GetCameraRelativePositionWS(worldPos);
|
||||
o.pos = mul(unity_MatrixVP, float4(worldPos, 1));
|
||||
o.color = UnpackColor(tld.color);
|
||||
o.color.a = 1;
|
||||
return o;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
VertexToPixel VSTriangle(VertexInput i)
|
||||
{
|
||||
VertexToPixel o = (VertexToPixel)0;
|
||||
uint triangleID = i.vertexID / 3;
|
||||
uint vertexID = i.vertexID - triangleID * 3;
|
||||
|
||||
TriData td = triDataBuf[triangleID];
|
||||
|
||||
const uint2 neighbourIndices[] =
|
||||
{
|
||||
uint2(2, 1),
|
||||
uint2(0, 2),
|
||||
uint2(1, 0),
|
||||
};
|
||||
|
||||
float3 p0p2 = td.pos[neighbourIndices[vertexID].x] - td.pos[vertexID];
|
||||
float3 p0p1 = td.pos[neighbourIndices[vertexID].y] - td.pos[vertexID];
|
||||
|
||||
float3 normal = 0;
|
||||
float eps = 0.00001f;
|
||||
if (length(p0p1) > eps && length(p0p2) > eps)
|
||||
{
|
||||
normal = cross(p0p2, p0p1);
|
||||
normal = normalize(normal);
|
||||
}
|
||||
|
||||
float3 worldPos = td.pos[vertexID];
|
||||
|
||||
worldPos = GetCameraRelativePositionWS(worldPos);
|
||||
o.pos = mul(unity_MatrixVP, float4(worldPos, 1));
|
||||
o.normal = normal;
|
||||
o.color = UnpackColor(td.color);
|
||||
return o;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void GetMainLight(out float3 lightDir, out float3 color)
|
||||
{
|
||||
#ifdef IS_HDRP
|
||||
if (_DirectionalLightCount > 0)
|
||||
{
|
||||
DirectionalLightData light = _DirectionalLightDatas[0];
|
||||
lightDir = -light.forward.xyz;
|
||||
color = light.color;
|
||||
}
|
||||
else
|
||||
{
|
||||
lightDir = float3(1, 0, 0);
|
||||
color = 0;
|
||||
}
|
||||
#else
|
||||
lightDir = _MainLightPosition.rgb;
|
||||
color = _MainLightColor.rgb;
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
float4 PS(VertexToPixel i): SV_Target0
|
||||
{
|
||||
float4 rv = i.color;//float4(0, 0, 0, 1);
|
||||
if (length(i.normal) > 0.1f)
|
||||
{
|
||||
float3 mainLightDir, mainLightColor;
|
||||
GetMainLight(mainLightDir, mainLightColor);
|
||||
float df = dot(mainLightDir, i.normal) * 0.5f + 0.5f;
|
||||
|
||||
rv.rgb *= df;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endif
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2600e13e03c73d4dbd65c4462783350
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.DebugDrawer/Resources/RukhankaDebugDrawer.hlsl
|
||||
uploadId: 897522
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
#ifndef RUKHANKA_DEBUG_DRAWER_COMMON_HLSL_
|
||||
#define RUKHANKA_DEBUG_DRAWER_COMMON_HLSL_
|
||||
|
||||
float3 GetCameraRelativePositionWS(float3 positionWS)
|
||||
{
|
||||
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
|
||||
positionWS -= _WorldSpaceCameraPos.xyz;
|
||||
#endif
|
||||
return positionWS;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
float4 UnpackColor(uint color)
|
||||
{
|
||||
float4 rv = float4
|
||||
(
|
||||
color >> 24,
|
||||
color >> 16 & 0xff,
|
||||
color >> 8 & 0xff,
|
||||
color & 0xff
|
||||
);
|
||||
rv = rv / 255.0f;
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endif
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1df1990c6dd59af4284e0a4cd18d791e
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.DebugDrawer/Resources/RukhankaDebugDrawerCommon.hlsl
|
||||
uploadId: 897522
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
Shader "RukhankaDebugLineDrawer"
|
||||
{
|
||||
SubShader
|
||||
{
|
||||
PackageRequirements
|
||||
{
|
||||
"com.unity.render-pipelines.high-definition": "1.0.0"
|
||||
}
|
||||
Tags
|
||||
{
|
||||
"RenderPipeline" = "HDRenderPipeline"
|
||||
"RenderType" = "HDUnlitShader"
|
||||
"Queue" = "Transparent+0"
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "ForwardOnly"
|
||||
Tags
|
||||
{
|
||||
"LightMode" = "ForwardOnly"
|
||||
}
|
||||
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
ZTest off
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 3.0
|
||||
|
||||
#pragma vertex VSLines
|
||||
#pragma fragment PS
|
||||
#define IS_HDRP
|
||||
|
||||
#include "RukhankaDebugDrawer.hlsl"
|
||||
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SubShader
|
||||
{
|
||||
PackageRequirements
|
||||
{
|
||||
"com.unity.render-pipelines.universal": "1.0.0"
|
||||
}
|
||||
Tags
|
||||
{
|
||||
"RenderPipeline"="UniversalPipeline"
|
||||
"Queue" = "Transparent+0"
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
Tags
|
||||
{
|
||||
"LightMode" = "UniversalForward"
|
||||
}
|
||||
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
ZTest off
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 3.0
|
||||
|
||||
#pragma vertex VSLines
|
||||
#pragma fragment PS
|
||||
|
||||
#include "RukhankaDebugDrawer.hlsl"
|
||||
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf9e89bd9ebe67449a5cf05c583a337b
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.DebugDrawer/Resources/RukhankaDebugLineDrawer.shader
|
||||
uploadId: 897522
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
Shader "RukhankaDebugThickLineDrawer"
|
||||
{
|
||||
SubShader
|
||||
{
|
||||
PackageRequirements
|
||||
{
|
||||
"com.unity.render-pipelines.high-definition": "1.0.0"
|
||||
}
|
||||
Tags
|
||||
{
|
||||
"RenderPipeline" = "HDRenderPipeline"
|
||||
"RenderType" = "HDUnlitShader"
|
||||
"Queue" = "Transparent+0"
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "ForwardOnly"
|
||||
Tags
|
||||
{
|
||||
"LightMode" = "ForwardOnly"
|
||||
}
|
||||
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
ZTest off
|
||||
Cull off
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 3.0
|
||||
|
||||
#pragma vertex VSThickLines
|
||||
#pragma fragment PS
|
||||
#define IS_HDRP
|
||||
|
||||
#include "RukhankaDebugDrawer.hlsl"
|
||||
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SubShader
|
||||
{
|
||||
PackageRequirements
|
||||
{
|
||||
"com.unity.render-pipelines.universal": "1.0.0"
|
||||
}
|
||||
Tags
|
||||
{
|
||||
"RenderPipeline"="UniversalPipeline"
|
||||
"Queue" = "Transparent+0"
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
Tags
|
||||
{
|
||||
"LightMode" = "UniversalForward"
|
||||
}
|
||||
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
ZTest off
|
||||
Cull off
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 3.0
|
||||
|
||||
#pragma vertex VSThickLines
|
||||
#pragma fragment PS
|
||||
|
||||
#include "RukhankaDebugDrawer.hlsl"
|
||||
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a6fef881541c584eac17bcb9bef86c9
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.DebugDrawer/Resources/RukhankaDebugThickLineDrawer.shader
|
||||
uploadId: 897522
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
Shader "RukhankaDebugTriangleDrawer"
|
||||
{
|
||||
SubShader
|
||||
{
|
||||
PackageRequirements
|
||||
{
|
||||
"com.unity.render-pipelines.high-definition": "1.0.0"
|
||||
}
|
||||
Tags
|
||||
{
|
||||
"RenderPipeline" = "HDRenderPipeline"
|
||||
"RenderType" = "HDUnlitShader"
|
||||
"Queue" = "Transparent+0"
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "ForwardOnly"
|
||||
Tags
|
||||
{
|
||||
"LightMode" = "ForwardOnly"
|
||||
}
|
||||
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
Cull Front
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 3.0
|
||||
|
||||
#pragma vertex VSTriangle
|
||||
#pragma fragment PS
|
||||
#define IS_HDRP
|
||||
|
||||
#include "RukhankaDebugDrawer.hlsl"
|
||||
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SubShader
|
||||
{
|
||||
PackageRequirements
|
||||
{
|
||||
"com.unity.render-pipelines.universal": "1.0.0"
|
||||
}
|
||||
Tags
|
||||
{
|
||||
"RenderPipeline"="UniversalPipeline"
|
||||
"Queue" = "Transparent+0"
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
Tags
|
||||
{
|
||||
"LightMode" = "UniversalForward"
|
||||
}
|
||||
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
Cull front
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 3.0
|
||||
|
||||
#pragma vertex VSTriangle
|
||||
#pragma fragment PS
|
||||
|
||||
#include "RukhankaDebugDrawer.hlsl"
|
||||
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eed38dd879f9ccb48945c1bf4d062a2b
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.DebugDrawer/Resources/RukhankaDebugTriangleDrawer.shader
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "Rukhanka.DebugDrawer",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:01e5f7c036964124aa192bf5e2d021ba",
|
||||
"GUID:734d92eba21c94caba915361bd5ac177",
|
||||
"GUID:e0cd26848372d4e5c891c569017e11f1",
|
||||
"GUID:d8b63aba1907145bea998dd612889d6b",
|
||||
"GUID:2665a8d13d1b3f18800f46e256720795"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [
|
||||
"!RUKHANKA_NO_DEBUG_DRAWER"
|
||||
],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.render-pipelines.high-definition",
|
||||
"expression": "9.9.9",
|
||||
"define": "HDRP_10_0_0_OR_NEWER"
|
||||
},
|
||||
{
|
||||
"name": "com.unity.render-pipelines.universal",
|
||||
"expression": "9.9.9",
|
||||
"define": "URP_10_0_0_OR_NEWER"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6d74d5932d072f42b5113af70b1424c
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.DebugDrawer/Rukhanka.DebugDrawer.asmdef
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 693a00209a66b3b41b89acb8dc1db140
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using Rukhanka.Hybrid;
|
||||
using UnityEditor;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Editor
|
||||
{
|
||||
[CustomEditor(typeof(AimIKAuthoring))]
|
||||
public class AimIKAuthoringEditor : UnityEditor.Editor
|
||||
{
|
||||
public VisualTreeAsset inpectorXML;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public override VisualElement CreateInspectorGUI()
|
||||
{
|
||||
var myInspector = new VisualElement();
|
||||
inpectorXML.CloneTree(myInspector);
|
||||
var t = (AimIKAuthoring)target;
|
||||
var angleLimitMinSlider = (Slider)myInspector.Q("minAngleSlider");
|
||||
var angleLimitMaxSlider = (Slider)myInspector.Q("maxAngleSlider");
|
||||
angleLimitMinSlider.RegisterValueChangedCallback((newVal) => { t.angleLimitMax = Math.Max(t.angleLimitMax, newVal.newValue); });
|
||||
angleLimitMaxSlider.RegisterValueChangedCallback((newVal) => { t.angleLimitMin = Math.Min(newVal.newValue, t.angleLimitMin); });
|
||||
|
||||
return myInspector;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea4a0d834e497c144bce3d577268dc42
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- inpectorXML: {fileID: 9197481963319205126, guid: cf4d33380a26ecf4ea08af1e93763d81, type: 3}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Editor/AimIKAuthoringEditor.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a08108865024ae459733ffbdaa4e617
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef DOTS_INSTANCING_ON
|
||||
UNITY_DOTS_INSTANCING_START(MaterialPropertyMetadata)
|
||||
UNITY_DOTS_INSTANCED_PROP(float, _DeformedMeshIndex)
|
||||
UNITY_DOTS_INSTANCED_PROP(float4, _DeformationParamsForMotionVectors)
|
||||
UNITY_DOTS_INSTANCING_END(MaterialPropertyMetadata)
|
||||
#endif
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fcd50cc09e4fac945bbdabe59f0c6e08
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Editor/AmplifyShaderEditor/RukhankaDeformationPropertyDefines.hlsl
|
||||
uploadId: 897522
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 78b2425a2284af743826c689403a4924, type: 3}
|
||||
m_Name: RukhankaMeshDeformation
|
||||
m_EditorClassIdentifier:
|
||||
m_functionInfo: "// Made with Amplify Shader Editor v1.9.8.1\n// Available at the
|
||||
Unity Asset Store - http://u3d.as/y3X \n/*ASEBEGIN\nVersion=19801\nNode;AmplifyShaderEditor.PosVertexDataNode;2;-512,-336;Inherit;False;0;0;5;FLOAT3;0;FLOAT;1;FLOAT;2;FLOAT;3;FLOAT;4\nNode;AmplifyShaderEditor.NormalVertexDataNode;3;-512,-192;Inherit;False;0;5;FLOAT3;0;FLOAT;1;FLOAT;2;FLOAT;3;FLOAT;4\nNode;AmplifyShaderEditor.TangentVertexDataNode;4;-512,-48;Inherit;False;0;0;5;FLOAT3;0;FLOAT;1;FLOAT;2;FLOAT;3;FLOAT;4\nNode;AmplifyShaderEditor.VertexIdVariableNode;5;-480,-416;Inherit;False;0;1;INT;0\nNode;AmplifyShaderEditor.CustomExpressionNode;1;-208,-208;Inherit;False;ComputeDeformedVertex_float(vertexID,
|
||||
meshVertex, meshNormal, meshTangent, deformedVertex, deformedNormal, deformedTangent)@$;7;Call;7;True;vertexID;INT;0;In;;Inherit;False;True;meshVertex;FLOAT3;0,0,0;In;;Inherit;False;True;meshNormal;FLOAT3;0,0,0;In;;Inherit;False;True;meshTangent;FLOAT3;0,0,0;In;;Inherit;False;True;deformedVertex;FLOAT3;0,0,0;Out;;Inherit;False;True;deformedNormal;FLOAT3;0,0,0;Out;;Inherit;False;True;deformedTangent;FLOAT3;0,0,0;Out;;Inherit;False;Rukhanka
|
||||
Mesh Deformation;False;False;0;;False;8;0;FLOAT;0;False;1;INT;0;False;2;FLOAT3;0,0,0;False;3;FLOAT3;0,0,0;False;4;FLOAT3;0,0,0;False;5;FLOAT3;0,0,0;False;6;FLOAT3;0,0,0;False;7;FLOAT3;0,0,0;False;4;FLOAT;0;FLOAT3;6;FLOAT3;7;FLOAT3;8\nNode;AmplifyShaderEditor.RangedFloatNode;8;-208,96;Inherit;False;Property;_DeformedMeshIndex;_DeformedMeshIndex;0;1;[HideInInspector];Create;True;0;0;0;True;0;False;0;0;0;0;0;1;FLOAT;0\nNode;AmplifyShaderEditor.Vector4Node;10;-208,192;Inherit;False;Property;_DeformationParamsForMotionVectors;_DeformationParamsForMotionVectors;1;0;Create;True;0;0;0;True;0;False;0,0,0,0;0,0,0,0;0;5;FLOAT4;0;FLOAT;1;FLOAT;2;FLOAT;3;FLOAT;4\nNode;AmplifyShaderEditor.FunctionOutput;7;192,-80;Inherit;False;False;-1;Deformed
|
||||
Tangent;2;False;1;0;FLOAT3;0,0,0;False;1;FLOAT3;0\nNode;AmplifyShaderEditor.FunctionOutput;6;192,-160;Inherit;False;False;-1;Deformed
|
||||
Normal;1;False;1;0;FLOAT3;0,0,0;False;1;FLOAT3;0\nNode;AmplifyShaderEditor.FunctionOutput;0;192,-240;Inherit;False;True;-1;Deformed
|
||||
Vertex;0;True;1;0;FLOAT3;0,0,0;False;1;FLOAT3;0\nWireConnection;1;1;5;0\nWireConnection;1;2;2;0\nWireConnection;1;3;3;0\nWireConnection;1;4;4;0\nWireConnection;7;0;1;8\nWireConnection;6;0;1;7\nWireConnection;0;0;1;6\nASEEND*/\n//CHKSM=93F12AB0D3C8468E37E48D03D4AFB0922FB79856"
|
||||
m_functionName:
|
||||
m_description: Rukhanka Mesh Deformation Node
|
||||
m_additionalIncludes:
|
||||
m_additionalIncludes: []
|
||||
m_outsideIncludes: []
|
||||
m_additionalPragmas:
|
||||
m_additionalPragmas: []
|
||||
m_outsidePragmas: []
|
||||
m_additionalDirectives:
|
||||
m_validData: 0
|
||||
m_isDirty: 1
|
||||
m_moduleName: ' Additional Directives'
|
||||
m_independentModule: 1
|
||||
m_customEdited: 0
|
||||
m_additionalDirectives:
|
||||
- {fileID: 0}
|
||||
- {fileID: 0}
|
||||
m_shaderFunctionDirectives: []
|
||||
m_nativeDirectives: []
|
||||
m_nativeDirectivesIndex: -1
|
||||
m_nativeDirectivesFoldout: 0
|
||||
m_directivesSaveItems:
|
||||
- LineType: 0
|
||||
LineValue: Packages/com.rukhanka.animation/Rukhanka.Editor/AmplifyShaderEditor/RukhankaDeformationPropertyDefines.hlsl
|
||||
GUIDToggle: 0
|
||||
GUIDValue:
|
||||
ShowConditionals: 0
|
||||
VersionMin: 0
|
||||
VersionMax: 0
|
||||
Passes:
|
||||
Origin: 2
|
||||
- LineType: 0
|
||||
LineValue: Packages/com.rukhanka.animation/Rukhanka.Runtime/Deformation/Resources/ComputeDeformedVertex.hlsl
|
||||
GUIDToggle: 0
|
||||
GUIDValue:
|
||||
ShowConditionals: 0
|
||||
VersionMin: 0
|
||||
VersionMax: 0
|
||||
Passes:
|
||||
Origin: 2
|
||||
m_nodeCategory: 3
|
||||
m_headerStyle: 0
|
||||
m_headerColor: {r: 1, g: 0.4, b: 0, a: 1}
|
||||
m_customNodeCategory:
|
||||
m_previewPosition: 0
|
||||
m_hidden: 0
|
||||
m_url:
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39064ff186f064e41ba30cef48c769b5
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Editor/AmplifyShaderEditor/RukhankaMeshDeformation.asset
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,42 @@
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Editor
|
||||
{
|
||||
[CustomEditor(typeof(AnimationCullingConfig))]
|
||||
public class AnimationCullingConfigEditor : UnityEditor.Editor
|
||||
{
|
||||
public VisualTreeAsset inpectorXML;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public override VisualElement CreateInspectorGUI()
|
||||
{
|
||||
var myInspector = new VisualElement();
|
||||
inpectorXML.CloneTree(myInspector);
|
||||
|
||||
var t = (AnimationCullingConfig)target;
|
||||
|
||||
#if !RUKHANKA_DEBUG_INFO
|
||||
var debugAndVisualization = myInspector.Q<Foldout>("debugAndVisualization");
|
||||
debugAndVisualization.text += " (available only with 'RUKHANKA_DEBUG_INFO' defined)";
|
||||
debugAndVisualization.SetEnabled(false);
|
||||
#endif
|
||||
|
||||
var drawCullingVolumesToggle = myInspector.Q<PropertyField>("drawCullingVolumes");
|
||||
var drawCullingVolumesChildren = myInspector.Q("drawCullingVolumesChildren");
|
||||
drawCullingVolumesToggle.RegisterValueChangeCallback((newVal) => { drawCullingVolumesChildren.SetEnabled(newVal.changedProperty.boolValue); });
|
||||
drawCullingVolumesChildren.SetEnabled(t.drawCullingVolumes);
|
||||
|
||||
var drawBBTogle = myInspector.Q<PropertyField>("drawSceneBoundingBoxes");
|
||||
var drawBBChildren = myInspector.Q("drawSceneBoundingBoxesChildren");
|
||||
drawBBTogle.RegisterValueChangeCallback((newVal) => { drawBBChildren.SetEnabled(newVal.changedProperty.boolValue); });
|
||||
drawBBChildren.SetEnabled(t.drawSceneBoundingBoxes);
|
||||
|
||||
return myInspector;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 432ca46b2437f4b4a8572a4b3b6be432
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- inpectorXML: {fileID: 9197481963319205126, guid: bfd1c56abbcf01e4dbf64f0298fd6d78, type: 3}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Editor/AnimationCullingConfigEditor.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a90160f1d300fcf4ca5d14bdd6c70c4d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user