Server sends UpdateMotion whenever an entity's motion state changes: NPCs starting a walk cycle, creatures switching to a combat stance, doors opening, a player waving, etc. Phase 6.1-6.4 already handles rendering different (stance, forward-command) pairs for the INITIAL CreateObject, but without this message NPCs freeze in whatever pose they spawned with and never transition to walking/fighting. Added UpdateMotion.TryParse with the same ServerMotionState the CreateObject path uses, reached via a slightly different outer layout (guid + instance seq + header'd MovementData; the MovementData starts with the 8-byte sequence/autonomous header this time rather than being preceded by a length field). Only the (stance, forward- command) pair is extracted — same subset CreateObject grabs. WorldSession dispatches MotionUpdated(guid, state) when a 0xF74C body parses successfully. The App-side wiring (guid→entity lookup and AnimatedEntity cycle swap) is intentionally deferred to a separate commit because it touches GameWindow which is currently being edited by the Phase 9.1 translucent-pass work. 89 Core.Net tests (was 83, +6 for UpdateMotion coverage). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
62 lines
1.9 KiB
C#
62 lines
1.9 KiB
C#
using System.Numerics;
|
|
using Silk.NET.OpenGL;
|
|
|
|
namespace AcDream.App.Rendering;
|
|
|
|
public sealed class Shader : IDisposable
|
|
{
|
|
private readonly GL _gl;
|
|
public uint Program { get; }
|
|
|
|
public Shader(GL gl, string vertexPath, string fragmentPath)
|
|
{
|
|
_gl = gl;
|
|
uint vert = Compile(File.ReadAllText(vertexPath), ShaderType.VertexShader);
|
|
uint frag = Compile(File.ReadAllText(fragmentPath), ShaderType.FragmentShader);
|
|
|
|
Program = _gl.CreateProgram();
|
|
_gl.AttachShader(Program, vert);
|
|
_gl.AttachShader(Program, frag);
|
|
_gl.LinkProgram(Program);
|
|
_gl.GetProgram(Program, ProgramPropertyARB.LinkStatus, out int linked);
|
|
if (linked == 0)
|
|
throw new Exception("program link failed: " + _gl.GetProgramInfoLog(Program));
|
|
_gl.DetachShader(Program, vert);
|
|
_gl.DetachShader(Program, frag);
|
|
_gl.DeleteShader(vert);
|
|
_gl.DeleteShader(frag);
|
|
}
|
|
|
|
private uint Compile(string source, ShaderType type)
|
|
{
|
|
uint id = _gl.CreateShader(type);
|
|
_gl.ShaderSource(id, source);
|
|
_gl.CompileShader(id);
|
|
_gl.GetShader(id, ShaderParameterName.CompileStatus, out int ok);
|
|
if (ok == 0)
|
|
throw new Exception($"{type} compile failed: " + _gl.GetShaderInfoLog(id));
|
|
return id;
|
|
}
|
|
|
|
public void Use() => _gl.UseProgram(Program);
|
|
|
|
public unsafe void SetMatrix4(string name, Matrix4x4 m)
|
|
{
|
|
int loc = _gl.GetUniformLocation(Program, name);
|
|
_gl.UniformMatrix4(loc, 1, false, (float*)&m);
|
|
}
|
|
|
|
public void SetInt(string name, int value)
|
|
{
|
|
int loc = _gl.GetUniformLocation(Program, name);
|
|
_gl.Uniform1(loc, value);
|
|
}
|
|
|
|
public void SetFloat(string name, float value)
|
|
{
|
|
int loc = _gl.GetUniformLocation(Program, name);
|
|
_gl.Uniform1(loc, value);
|
|
}
|
|
|
|
public void Dispose() => _gl.DeleteProgram(Program);
|
|
}
|