This commit is contained in:
Oscar
2025-05-25 18:16:55 +03:00
commit df4b259d17
551 changed files with 32089 additions and 0 deletions

4
Code/Assembly.cs Normal file
View File

@@ -0,0 +1,4 @@
global using Sandbox;
global using System;
global using System.Collections.Generic;
global using System.Linq;

226
Code/Dedugan.cs Normal file
View File

@@ -0,0 +1,226 @@
using System;
using Sandbox;
using Sandbox.Citizen;
using ShrimpleCharacterController;
public sealed class Dedugan : Component
{
[RequireComponent] public ShrimpleCharacterController.ShrimpleCharacterController Controller { get; set; }
[RequireComponent] public CitizenAnimationHelper AnimationHelper { get; set; }
public SkinnedModelRenderer Renderer { get; set; }
public GameObject Camera { get; set; }
[Property][Range(1f, 200f, 1f)] public float CamOffsetX { get; set; }
[Property] public GameObject CameraPivot { get; set; }
[Property] [Range(50f, 1200f, 10f)] public float WalkSpeed { get; set; } = 100f;
[Property] [Range(100f, 1500f, 20f)] public float RunSpeed { get; set; } = 300f;
[Property] [Range(25f, 1100f, 5f)] public float DuckSpeed { get; set; } = 50f;
[Property] [Range(200f, 1500f, 20f)] public float JumpStrength { get; set; } = 350f;
[Sync] public Angles NetworkedEyeAngles { get; set; } // для передачи углов другим клиентам
private RagdollController RagdollController { get; set; }
public Angles EyeAngles { get; set; }
public Vector3 OverrideGravity { get; set; } = Vector3.Zero;
private Vector3 _directionToAxis = Vector3.Up;
private Vector3 _up = Vector3.Up;
private Vector3 _forward = Vector3.Forward;
private Vector3 _right = Vector3.Right;
[Sync] private float IsDucking { get; set; } = 0f;
private Vector3 wishDirection;
protected override void OnStart()
{
base.OnStart();
RagdollController = Components.Get<RagdollController>();
Renderer = Components.Get<SkinnedModelRenderer>(FindMode.EverythingInSelfAndDescendants);
if (!Network.IsOwner) return;
// var cameraComponent = GameObject.GetComponentInParent<CameraComponent>(true, true) ;//new GameObject(true, "Camera");
var cameraComponent = Scene.Camera ;//new GameObject(true, "Camera");
Camera = cameraComponent.GameObject;
Camera.SetParent(GameObject);
// var cameraComponent = Camera.Components.Create<CameraComponent>();
cameraComponent.ZFar = 32768f;
cameraComponent.FieldOfView = 100f;
}
protected override void DrawGizmos()
{
base.DrawGizmos();
Gizmo.Transform = global::Transform.Zero;
Gizmo.Draw.LineThickness = 2f;
Gizmo.Draw.IgnoreDepth = true;
Gizmo.Draw.Color = Color.Blue;
Gizmo.Draw.Arrow(WorldPosition, WorldPosition + (_up * 1200f));
Gizmo.Draw.Color = Color.Red;
Gizmo.Draw.Arrow(WorldPosition, WorldPosition + (_forward * 1200f));
Gizmo.Draw.Color = Color.Green;
Gizmo.Draw.Arrow(WorldPosition, WorldPosition + (_right * 1200f));
Gizmo.Draw.Color = Color.Black;
Gizmo.Draw.Arrow(WorldPosition, WorldPosition + (-_up * 100f));
Gizmo.Draw.Color = Color.Magenta;
Gizmo.Draw.Arrow(WorldPosition, WorldPosition + wishDirection * 10f);
var textStartPos = new Vector2(10f);
Gizmo.Draw.ScreenText($"IsOnGround: {Controller.IsOnGround}", textStartPos);
Gizmo.Draw.ScreenText($"IsSlipping: {Controller.IsSlipping}", textStartPos.WithY(30f));
Gizmo.Draw.ScreenText($"WishVelocity: {Controller.WishVelocity}", textStartPos.WithY(50f));
Gizmo.Draw.ScreenText($"Test: {Vector3.Dot(_right, _up)}", textStartPos.WithY(70f));
Gizmo.Draw.ScreenBiasedHalfCircle(WorldPosition, 3f);
}
protected override void OnFixedUpdate()
{
base.OnFixedUpdate();
if ( OverrideGravity == Vector3.Zero )
{
_directionToAxis = Vector3.VectorPlaneProject(WorldPosition, Vector3.Right).Normal;
}
else
{
_directionToAxis = OverrideGravity;
}
_up = -_directionToAxis;
_forward = Vector3.Right;
_right = Vector3.Cross(_up, _forward).Normal;
Controller.Up = _up;
Controller.VectorGravity = -_up * 850f;
if (Network.IsOwner)
{
LookAtSurfaceNormal(_up, _forward);
wishDirection = Input.AnalogMove.Normal * Rotation.FromYaw(EyeAngles.yaw) * WorldRotation;
var isDucking = Input.Down("Duck");
var isRunning = Input.Down("Run");
var wishSpeed = isDucking ? DuckSpeed :
isRunning ? RunSpeed : WalkSpeed;
var ragdollMul = RagdollController.Enabled ? 0f : 1f;
Controller.WishVelocity = wishDirection * wishSpeed * ragdollMul;
if (Input.Pressed("Jump") && Controller.IsOnGround)
{
Controller.Punch(-Controller.AppliedGravity.Normal * JumpStrength);
AnimationHelper?.TriggerJump();
}
if (!AnimationHelper.IsValid()) return;
IsDucking = Input.Down("Duck") ? 1f : 0f;
}
Controller.Move();
if (!AnimationHelper.IsValid()) return;
AnimationHelper.DuckLevel = IsDucking;
AnimationHelper.WithWishVelocity(Controller.WishVelocity);
AnimationHelper.WithVelocity(Controller.Velocity);
AnimationHelper.IsGrounded = Controller.IsOnGround;
}
private void LookAtSurfaceNormal(Vector3 up, Vector3 moveDirection)
{
var newRotation = Rotation.LookAt(moveDirection, up);
WorldRotation = Rotation.Lerp(WorldRotation, newRotation, Time.Delta * 10f);
}
protected override void OnUpdate()
{
base.OnUpdate();
if (Network.IsOwner)
{
EyeAngles += Input.AnalogLook;
EyeAngles = EyeAngles.WithPitch(MathX.Clamp(EyeAngles.pitch, -89f, 89f));
NetworkedEyeAngles = EyeAngles;
RotateCamera();
var targetRotation = Rotation.LookAt(Rotation.FromYaw(EyeAngles.yaw).Forward, -_directionToAxis);
var currentForward = Renderer.LocalRotation.Forward;
float angleDiff = currentForward.Angle(targetRotation.Forward);
if (angleDiff > 15f && Controller.Velocity.Length > 10f)
{
Renderer.LocalRotation = Rotation.Slerp(Renderer.LocalRotation, Rotation.FromYaw(EyeAngles.yaw), Time.Delta * 3f);
}
if ( Input.Pressed( "Use" ) )
{
var tr = Scene.Trace
.Ray( Camera.WorldPosition, Camera.WorldPosition + Camera.WorldRotation.Forward * 500f ).IgnoreGameObjectHierarchy(GameObject).Run();
if ( tr.Hit)
{
tr.GameObject.GetComponent<IInteractable>()?.OnUse();
}
}
}
else
{
EyeAngles = NetworkedEyeAngles;
Renderer.LocalRotation = Rotation.Slerp(Renderer.LocalRotation, Rotation.FromYaw(EyeAngles.yaw), Time.Delta * 5f);
}
}
void RotateCamera()
{
var cameraOffset = CameraPivot.LocalPosition + CameraPivot.LocalRotation.Backward * (CamOffsetX + EyeAngles.pitch * .5f);
Camera.LocalRotation = EyeAngles.ToRotation();
Camera.LocalPosition = cameraOffset * Camera.LocalRotation;
}
// void RotateCamera()
// {
// // 1. Задание локального вращения камеры
// Rotation camRot = EyeAngles.ToRotation();
// Camera.LocalRotation = camRot;
//
// // 2. Позиция Pivot'а в мире (нужно для трейса)
// var pivotWorldPos = CameraPivot.LocalPosition;
//
// // 3. Смещение плеча (локально → в мир)
// var shoulderOffsetWorld = Vector3.Zero;
//
// // 4. Желаемая мировая позиция камеры
// var desiredWorldPos = pivotWorldPos - camRot.Forward * 10f + shoulderOffsetWorld;
//
// // 5. Трейс от Pivot до желаемой позиции камеры
// var tr = Scene.Trace
// .Ray(pivotWorldPos, desiredWorldPos)
// .Radius(4f)
// .IgnoreGameObjectHierarchy(GameObject)
// .Run();
//
// // 6. Получаем локальную позицию относительно CameraPivot
// var finalWorldCamPos = tr.EndPosition;
// var finalLocalCamPos = CameraPivot.Transform.WorldToLocal.Transform(finalWorldCamPos);
//
// // 7. Применяем к камере
// Camera.LocalPosition = finalLocalCamPos;
// Camera.LocalRotation = camRot;
// }
}

90
Code/DspReverb.cs Normal file
View File

@@ -0,0 +1,90 @@
using Sandbox;
using Sandbox.Audio;
using System.Threading;
using System.Threading.Tasks;
namespace Sandbox;
public sealed class DSPReverb : Component, Component.ITriggerListener
{
[Property] public MixerHandle TargetMixer { get; set; }
[Property] public DspPresetHandle Preset { get; set; }
[Property] [Range(0f, 10f, 0.1f)] public float FadeDuration { get; set; } = 1f;
[Property] public BBox Bounds { get; set; } = new BBox(Vector3.One * -100f, Vector3.One * 100f);
private DspProcessor _processor;
private BoxCollider _triggerCollider;
private CancellationTokenSource _cts;
protected override void OnAwake()
{
base.OnAwake();
_triggerCollider = Components.Create<BoxCollider>();
_triggerCollider.IsTrigger = true;
_triggerCollider.Static = true;
_triggerCollider.Scale = Bounds.Size;
_triggerCollider.Center = Bounds.Center;
}
public void OnTriggerEnter(Collider other)
{
_cts?.Cancel();
_cts = new CancellationTokenSource();
if(_processor != null) { TargetMixer.Get().RemoveProcessor(_processor);}
_processor = new DspProcessor(Preset.Name);
_processor.Mix = 0f;
TargetMixer.Get().AddProcessor(_processor);
_ = UpdateMixAsync(1f);
}
private async Task UpdateMixAsync(float targetMix)
{
float startMix = _processor.Mix;
float elapsed = FadeDuration * ((targetMix == 0f || startMix == 0f) ? 0f : Math.Min(startMix / targetMix, 1f));
float lastTime = Time.Now;
while (elapsed < FadeDuration && !_cts.IsCancellationRequested)
{
await Task.FixedUpdate();
float delta = Time.Now - lastTime;
elapsed += delta;
float t = Math.Clamp(elapsed / FadeDuration, 0f, 1f);
_processor.Mix = Math.Clamp(startMix + (targetMix - startMix) * t, 0f, 1f);
lastTime = Time.Now;
}
if (!_cts.IsCancellationRequested)
{
_processor.Mix = targetMix;
}
}
public void OnTriggerExit(Collider other)
{
_cts?.Cancel();
_cts = new CancellationTokenSource();
_ = UpdateMixAsync(0f).ContinueWith( (_) =>
{
if (_processor == null) return;
TargetMixer.Get().RemoveProcessor(_processor);
_processor = null;
} );
}
protected override void DrawGizmos()
{
base.DrawGizmos();
Gizmo.Draw.Color = Color.Green;
Gizmo.Draw.LineBBox(Bounds);
}
}

6
Code/IInteractable.cs Normal file
View File

@@ -0,0 +1,6 @@
namespace Sandbox;
public interface IInteractable
{
public void OnUse();
}

118
Code/MusicPlayer.cs Normal file
View File

@@ -0,0 +1,118 @@
namespace Sandbox;
public sealed class MusicPlayer : Component
{
[Property] private List<SoundEvent> _sounds;
[Property] private List<SoundPointComponent> _speakers;
[Property] private bool PlayOnStart { get; set; } = true;
private List<int> _shuffleOrder = new();
private int _shuffleIndex = 0;
[Sync, Change("OnFileNameChanged")] private string FileName { get; set; }
protected override void OnAwake()
{
base.OnAwake();
_sounds = new();
_speakers = new();
foreach (var resource in ResourceLibrary.GetAll<SoundEvent>("music"))
{
Log.Info(resource);
_sounds.Add(resource);
}
_speakers = GameObject.GetComponentsInChildren<SoundPointComponent>().ToList();
Log.Info("speaker count: " + _speakers.Count);
GenerateShuffleOrder();
}
protected override void OnStart()
{
base.OnStart();
if (PlayOnStart)
Next();
}
private void GenerateShuffleOrder()
{
_shuffleOrder = Enumerable.Range(0, _sounds.Count).ToList();
_shuffleOrder = _shuffleOrder.OrderBy(_ => Guid.NewGuid()).ToList();
_shuffleIndex = 0;
}
public void Stop()
{
foreach (var speaker in _speakers)
{
speaker.StopSound();
}
}
[Rpc.Broadcast]
public void Next()
{
if (_sounds.Count == 0)
return;
if (_shuffleIndex >= _shuffleOrder.Count)
{
GenerateShuffleOrder();
}
int soundIndex = _shuffleOrder[_shuffleIndex];
_shuffleIndex++;
FileName = _sounds[soundIndex].ResourceName;
}
public void OnFileNameChanged()
{
var currentSound = _sounds.Find((sound) => sound.ResourceName == FileName);
foreach (var speaker in _speakers)
{
speaker.StopSound();
Log.Info(currentSound);
speaker.SoundEvent = currentSound;
speaker.StartSound();
}
}
private TimeSince _lastCheckTime;
private bool _isPlaying = false;
protected override void OnUpdate()
{
if ( _lastCheckTime < 1.0f ) return;
_lastCheckTime = 0;
bool isAnyPlaying = _speakers.Any(IsSpeakerPlaying);
// Log.Info(isAnyPlaying);
if (!_isPlaying && isAnyPlaying)
{
_isPlaying = true;
}
else if (_isPlaying && !isAnyPlaying)
{
_isPlaying = false;
Next();
}
}
private static bool IsSpeakerPlaying(SoundPointComponent speaker)
{
var effect = speaker as ITemporaryEffect;
return effect != null && effect.IsActive;
}
}

View File

@@ -0,0 +1,26 @@
using Sandbox;
public sealed class NormalGravityTrigger : Component, Component.ITriggerListener
{
// public void OnTriggerEnter(Collider other)
// {
// var otherEntity = other.GameObject;
//
// if (otherEntity.Components.TryGet<Dedugan>(out var controller))
// {
// Log.Info($"{otherEntity.Name} вошел в зону нормальной гравитации");
//
// controller.OverrideGravity = Vector3.Down;
// }
// }
public void OnTriggerExit(Collider other)
{
var otherEntity = other.GameObject;
if (otherEntity.Components.TryGet<Dedugan>(out var controller))
{
controller.OverrideGravity = Vector3.Zero;
}
}
}

17
Code/PlayerDresser.cs Normal file
View File

@@ -0,0 +1,17 @@
using System;
namespace Sandbox;
public class PlayerDresser : Component, Component.INetworkSpawn
{
[Property]
public SkinnedModelRenderer BodyRenderer { get; set; }
public void OnNetworkSpawn( Connection owner )
{
Log.Info( $"Hello {owner.Name}" );
var clothing = new ClothingContainer();
clothing.Deserialize( owner.GetUserData( "avatar" ) );
clothing.Apply( BodyRenderer );
}
}

49
Code/RagdollController.cs Normal file
View File

@@ -0,0 +1,49 @@
using Sandbox;
public sealed class RagdollController : Component
{
[Group("Setup"), Order(-100), Property] public ModelPhysics bodyPhysics { get; set; }
[Group("Setup"), Order(-100), Property] public SkinnedModelRenderer bodyRenderer { get; set; }
[Group("Config"), Order(0), Property] public bool isLocked { get; set; }
[Sync]
public new bool Enabled
{
get => bodyPhysics.Enabled;
private set
{
bodyPhysics.Enabled = value;
bodyPhysics.MotionEnabled = value;
bodyRenderer.UseAnimGraph = !value;
bodyPhysics.
if ( !value )
{
WorldPosition = bodyRenderer.WorldPosition;
bodyRenderer.LocalPosition = Vector3.Zero;
}
}
}
protected override void OnUpdate()
{
if ( Network.IsOwner )
{
if (Input.Pressed( "Ragdoll" ))
{
Enabled = !Enabled;
}
}
var bodyLock = new PhysicsLock();
bodyLock.Pitch = isLocked;
bodyLock.Yaw = isLocked;
bodyLock.Roll = isLocked;
bodyLock.X = isLocked;
bodyLock.Y = isLocked;
bodyLock.Z = isLocked;
bodyPhysics.Locking = bodyLock;
bodyPhysics.MotionEnabled = !isLocked;
WorldPosition = bodyRenderer.WorldPosition;
}
}

25
Code/Teleporter.cs Normal file
View File

@@ -0,0 +1,25 @@
using Sandbox;
public sealed class Teleporter : Component, Component.ITriggerListener
{
[Property] public GameObject ToPosGameObject { get; set; }
public void OnTriggerEnter( Collider other )
{
var otherEntity = other.GameObject;
Log.Info($"{otherEntity.Name} Телепорт");
if (otherEntity.Components.TryGet<Dedugan>(out var controller))
{
Log.Info($"{otherEntity.Name} вошел в зону телепорта");
otherEntity.WorldPosition = ToPosGameObject.WorldPosition;
controller.OverrideGravity = Vector3.Down;
controller.EyeAngles = new Angles( 0, 180, 0 ).ToRotation();
controller.Renderer.LocalRotation = new Angles( 0, 180, 0 ).ToRotation();
}
}
}

9
Code/Test.cs Normal file
View File

@@ -0,0 +1,9 @@
using Sandbox;
public sealed class Test : Component
{
protected override void OnUpdate()
{
}
}

6
Code/VectorExtension.cs Normal file
View File

@@ -0,0 +1,6 @@
namespace Sandbox;
public class VectorExtension
{
}

15
Code/button.cs Normal file
View File

@@ -0,0 +1,15 @@
using System;
using Sandbox;
using Sandbox.UI;
namespace Sandbox;
public sealed class ButtonComponent : Component, IInteractable
{
[Property] public Action OnClick { get; set; }
public void OnUse()
{
OnClick?.Invoke();
}
}