-
Notifications
You must be signed in to change notification settings - Fork 87
Make wizard great again! Парт ту #874
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
9dc7a82
a99c852
335b7fa
68c2cc6
e743855
b6f3e54
7c19c03
e88a944
a764909
63e479d
527d866
037fd47
a12fb6d
c6bbd37
327e8d7
596055b
72cfec1
5e9f507
457199b
cf9aa8b
98b549b
eac5fa2
f74fa6c
e0a7423
53c8964
6dbefb4
d7d3cb8
2779ef4
5cc1992
a8258d6
1424310
95307f8
ba6f534
a1084f8
6ce816d
3685230
13e2058
5559a11
36a63b4
ac713b8
4bb65ce
b0eb520
22895b7
7329fef
53cacaa
e32f801
8b7c49e
86c3eb3
265128a
43b3b4b
5c922ce
ee56424
d7d81c0
b542485
2868792
db82400
86479e9
d07b70a
4a83b78
b7c7fbc
83556a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| using System.Numerics; | ||
| using Content.Client.Animations; | ||
| using Content.Shared._White.Wizard; | ||
| using Content.Shared._White.Wizard.SupermatterHalberd; | ||
| using Content.Shared.StatusIcon.Components; | ||
|
|
||
|
|
||
| namespace Content.Client._White.Wizard; | ||
|
|
||
|
|
||
| public sealed class SpellsSystem : SharedSpellsSystem | ||
| { | ||
| [Dependency] private readonly RaysSystem _rays = default!; | ||
| public override void Initialize() | ||
| { | ||
| base.Initialize(); | ||
|
|
||
| SubscribeLocalEvent<WizardComponent, GetStatusIconsEvent>(GetWizardIcon); | ||
| SubscribeLocalEvent<ApprenticeComponent, GetStatusIconsEvent>(GetApprenticeIcon); | ||
|
|
||
| SubscribeAllEvent<ChargeSpellRaysEffectEvent>(OnChargeEffect); | ||
| } | ||
|
|
||
| private void OnChargeEffect(ChargeSpellRaysEffectEvent ev) | ||
| { | ||
| var uid = GetEntity(ev.Uid); | ||
|
|
||
| CreateChargeEffect(uid, ev); | ||
| } | ||
|
|
||
| public override void CreateChargeEffect(EntityUid uid, ChargeSpellRaysEffectEvent ev) | ||
| { | ||
| if (!Timing.IsFirstTimePredicted || uid == EntityUid.Invalid) | ||
| return; | ||
|
|
||
| var rays = _rays.DoRays(TransformSystem.GetMapCoordinates(uid), | ||
| Color.Yellow, | ||
| Color.Fuchsia, | ||
| 10, | ||
| 15, | ||
| minMaxRadius: new Vector2(3f, 6f), | ||
| proto: "EffectRayCharge", | ||
| server: false); | ||
|
|
||
| if (rays == null) | ||
| return; | ||
|
|
||
| var track = EnsureComp<TrackUserComponent>(rays.Value); | ||
| track.User = uid; | ||
| } | ||
|
|
||
| private void GetWizardIcon(Entity<WizardComponent> ent, ref GetStatusIconsEvent args) | ||
| { | ||
| if (ProtoMan.TryIndex(ent.Comp.StatusIcon, out var iconPrototype)) | ||
| args.StatusIcons.Add(iconPrototype); | ||
| } | ||
|
|
||
| private void GetApprenticeIcon(Entity<ApprenticeComponent> ent, ref GetStatusIconsEvent args) | ||
| { | ||
| if (ProtoMan.TryIndex(ent.Comp.StatusIcon, out var iconPrototype)) | ||
| args.StatusIcons.Add(iconPrototype); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,166 @@ | ||
| using System.Numerics; | ||
| using Content.Shared._White.Wizard.Projectiles; | ||
| using Robust.Client.GameObjects; | ||
| using Robust.Client.Graphics; | ||
| using Robust.Shared.Enums; | ||
| using Robust.Shared.Prototypes; | ||
| using Robust.Shared.Timing; | ||
| using DrawDepth = Content.Shared.DrawDepth.DrawDepth; | ||
|
|
||
| namespace Content.Client._White.Wizard.Trail; | ||
|
|
||
| public sealed class TrailOverlay : Overlay | ||
| { | ||
| public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities; | ||
|
|
||
| private readonly IEntityManager _entManager; | ||
| private readonly IPrototypeManager _protoMan; | ||
| private readonly IGameTiming _timing; | ||
|
|
||
| private readonly SpriteSystem _sprite; | ||
| private readonly TransformSystem _transform; | ||
|
|
||
| public TrailOverlay(IEntityManager entManager, IPrototypeManager protoMan, IGameTiming timing) | ||
| { | ||
| ZIndex = (int) DrawDepth.Effects; | ||
|
|
||
| _entManager = entManager; | ||
| _protoMan = protoMan; | ||
| _timing = timing; | ||
| _sprite = _entManager.System<SpriteSystem>(); | ||
| _transform = _entManager.System<TransformSystem>(); | ||
| } | ||
|
|
||
| protected override void Draw(in OverlayDrawArgs args) | ||
| { | ||
| var eye = args.Viewport.Eye; | ||
|
|
||
| if (eye == null) | ||
| return; | ||
|
|
||
| var eyeRot = eye.Rotation; | ||
| var handle = args.WorldHandle; | ||
| var bounds = args.WorldAABB; | ||
|
|
||
| var xformQuery = _entManager.GetEntityQuery<TransformComponent>(); | ||
| var spriteQuery = _entManager.GetEntityQuery<SpriteComponent>(); | ||
|
|
||
| var query = _entManager.EntityQueryEnumerator<TrailComponent, TransformComponent>(); | ||
| while (query.MoveNext(out _, out var trail, out var xform)) | ||
| { | ||
| if (trail.TrailData.Count == 0) | ||
| continue; | ||
|
|
||
| var (position, rotation) = _transform.GetWorldPositionRotation(xform, xformQuery); | ||
|
|
||
| if (trail.Shader != null && _protoMan.TryIndex<ShaderPrototype>(trail.Shader, out var shaderProto)) | ||
| handle.UseShader(shaderProto.InstanceUnique()); | ||
|
|
||
| if (trail.RenderedEntity != null) | ||
| { | ||
| Direction? direction = null; | ||
| var rot = rotation; | ||
| switch (trail.RenderedEntityRotationStrategy) | ||
| { | ||
| case LerpPropertyData.RenderedEntityRotationStrategy.Trail: | ||
| { | ||
| var dirRot = rotation + eyeRot; | ||
| direction = dirRot.GetCardinalDir(); | ||
| break; | ||
| } | ||
| case LerpPropertyData.RenderedEntityRotationStrategy.RenderedEntity: | ||
| rot = _transform.GetWorldRotation(trail.RenderedEntity.Value); | ||
| break; | ||
| } | ||
|
|
||
| Entity<SpriteComponent?> sprite = trail.RenderedEntity.Value; | ||
| if (!spriteQuery.Resolve(sprite, ref sprite.Comp)) | ||
| continue; | ||
| foreach (var data in trail.TrailData) | ||
| { | ||
| if (data.Color.A <= 0.01f || data.Scale <= 0.01f || data.MapId != args.MapId) | ||
| continue; | ||
| var worldPosition = data.Position; | ||
| if (!bounds.Contains(worldPosition)) | ||
| continue; | ||
| if (trail.RenderedEntityRotationStrategy == LerpPropertyData.RenderedEntityRotationStrategy.Particle) | ||
| { | ||
| rot = data.Angle; | ||
| direction = (rot + eyeRot).GetCardinalDir(); | ||
| } | ||
| var originalColor = sprite.Comp.Color; | ||
| _sprite.SetColor(sprite, data.Color); | ||
| var originalScale = sprite.Comp.Scale; | ||
| _sprite.SetScale(sprite, originalScale * data.Scale); | ||
| _sprite.RenderSprite((sprite, sprite.Comp), handle, eyeRot, rot, worldPosition, direction); | ||
| _sprite.SetColor(sprite, originalColor); | ||
| _sprite.SetScale(sprite, originalScale); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| if (trail.Sprite == null) | ||
| { | ||
| if (xform.MapID == args.MapId) | ||
| { | ||
| var start = trail.TrailData[^1].Position; | ||
| DrawTrailLine(start, position, trail.Color, trail.Scale, bounds, handle); | ||
| } | ||
|
|
||
| for (var i = 1; i < trail.TrailData.Count; i++) | ||
| { | ||
| var data = trail.TrailData[i]; | ||
| var prevData = trail.TrailData[i - 1]; | ||
|
|
||
| if (data.MapId == args.MapId && prevData.MapId == args.MapId) | ||
| DrawTrailLine(prevData.Position, data.Position, data.Color, data.Scale, bounds, handle); | ||
| } | ||
|
|
||
| continue; | ||
| } | ||
|
|
||
| var textureSize = _sprite.Frame0(trail.Sprite).Size; | ||
| var pos = -(Vector2) textureSize / 2f / EyeManager.PixelsPerMeter; | ||
| foreach (var data in trail.TrailData) | ||
| { | ||
| if (data.Color.A <= 0.01f || data.Scale <= 0.01f || data.MapId != args.MapId) | ||
| continue; | ||
|
|
||
| var worldPosition = data.Position; | ||
| if (!bounds.Contains(worldPosition)) | ||
| continue; | ||
|
|
||
| var scaleMatrix = Matrix3x2.CreateScale(new Vector2(data.Scale, data.Scale)); | ||
| var worldMatrix = Matrix3Helpers.CreateTranslation(worldPosition); | ||
|
|
||
| var time = _timing.CurTime > data.SpawnTime ? _timing.CurTime - data.SpawnTime : TimeSpan.Zero; | ||
| var texture = _sprite.GetFrame(trail.Sprite, time); | ||
|
|
||
| handle.SetTransform(Matrix3x2.Multiply(scaleMatrix, worldMatrix)); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Трансформация может "протекать" на последующие трейлы. Если трейл использует рендеринг по спрайту (строка 139), то Примените этот diff для сброса трансформации перед каждым трейлом: var query = _entManager.EntityQueryEnumerator<TrailComponent, TransformComponent>();
while (query.MoveNext(out _, out var trail, out var xform))
{
+ handle.SetTransform(Matrix3x2.Identity);
+
if (trail.TrailData.Count == 0)
continue;
🤖 Prompt for AI Agents |
||
| handle.DrawTexture(texture, pos, data.Angle, data.Color); | ||
| } | ||
| } | ||
|
|
||
| handle.UseShader(null); | ||
| handle.SetTransform(Matrix3x2.Identity); | ||
| } | ||
|
|
||
| private static void DrawTrailLine( | ||
| Vector2 start, | ||
| Vector2 end, | ||
| Color color, | ||
| float scale, | ||
| Box2 bounds, | ||
| DrawingHandleWorld handle | ||
| ) | ||
| { | ||
| if (color.A <= 0.01f || scale <= 0.01f || !bounds.Contains(start) || !bounds.Contains(end)) | ||
| return; | ||
| var halfScale = scale * 0.5f; | ||
| var direction = end - start; | ||
| var angle = direction.ToAngle(); | ||
| var box = new Box2(start - new Vector2(0f, halfScale), start + new Vector2(direction.Length(), halfScale)); | ||
| var boxRotated = new Box2Rotated(box, angle, start); | ||
| handle.DrawRect(boxRotated, color); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Шейдер может "протекать" на следующие трейлы.
Если трейл A имеет шейдер, а трейл B — нет, то трейл B будет отрисован с шейдером трейла A, поскольку
handle.UseShader(null)вызывается только в конце всего цикла (строка 144), а не перед каждым трейлом.Примените этот diff для сброса шейдера перед каждым трейлом:
📝 Committable suggestion
🤖 Prompt for AI Agents