Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
930391c
Process usercmds
callumok2004 Feb 22, 2026
acbf638
more server
callumok2004 Feb 23, 2026
113c16b
Merge branch 'main' of https://github.com/marchc1/Source.NET into nav…
callumok2004 Feb 23, 2026
08dc555
FIx compile
callumok2004 Feb 23, 2026
a8a28db
Server & stringtables impl
callumok2004 Feb 27, 2026
3ac6b2c
Some ServerPlugin impl
callumok2004 Feb 27, 2026
9f608c3
Allocate edicts
callumok2004 Feb 28, 2026
3d3bdc5
Fix usermessages overflowing
callumok2004 Feb 28, 2026
971a5e8
report_entities command
callumok2004 Feb 28, 2026
16e4eaf
Parse map entities
callumok2004 Feb 28, 2026
a0a7ede
Revert CLC_GMod_ClientToServer back to how it was
callumok2004 Mar 1, 2026
8ede6c6
Some HUD fixes
callumok2004 Mar 1, 2026
35e4b24
Fix remaining issues with console completions
callumok2004 Mar 2, 2026
89b5391
EntityList impl
callumok2004 Mar 3, 2026
39eb3d7
Init gamerules
callumok2004 Mar 3, 2026
ec6e9f3
Gamerules stringtable
callumok2004 Mar 3, 2026
6333ab0
Impl player spawn spot
callumok2004 Mar 3, 2026
f36e2f3
PackedEntity impl
callumok2004 Mar 4, 2026
42250d7
FrameSnapshot impl
callumok2004 Mar 4, 2026
c1ef6f4
scaffold PackedEntities
callumok2004 Mar 4, 2026
54a75de
Some PackedEntities impl
callumok2004 Mar 4, 2026
ca0d5c3
ChangeFrameList
callumok2004 Mar 4, 2026
3d2c436
More PackedEntities/SendTable impl
callumok2004 Mar 4, 2026
c2f64ea
Cleanup some stuff
callumok2004 Mar 4, 2026
77d998d
Allow server to run commands
callumok2004 Mar 5, 2026
3b34b6f
CommandClient stuff
callumok2004 Mar 5, 2026
878bf19
Fix command completions
callumok2004 Mar 5, 2026
bab9e88
temp autocomplete for map command
callumok2004 Mar 5, 2026
a855388
Cleanups
callumok2004 Mar 5, 2026
c121579
More server impl
callumok2004 Mar 6, 2026
4895093
DatatableStack funcs
callumok2004 Mar 6, 2026
26713f4
Some SendProxy funcs impl
callumok2004 Mar 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Game.Client/C_BasePlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ public override void OnDataChanged(DataUpdateType updateType) {

if (pWeaponData == null || (pWeaponData.Flags & WeaponFlags.NoAmmoPickups) == 0) {
// We got more ammo for this ammo index. Add it to the ammo history
HudHistoryResource? pHudHR = GET_HUDELEMENT<HudHistoryResource>();
HudHistoryResource? pHudHR = gHUD.FindElement("CHudHistoryResource") as HudHistoryResource;
pHudHR?.AddToHistory(HRType.Ammo, i, Math.Abs(GetAmmoCount(i) - OldAmmo[i]));
}
}
Expand Down
2 changes: 2 additions & 0 deletions Game.Client/HL2/HudDamageIndicator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

using System.Numerics;

namespace Game.Client.HL2;

[DeclareHudElement(Name = "CHudDamageIndicator")]
class HudDamageIndicator : EditableHudElement, IHudElement
{
Expand Down
5 changes: 4 additions & 1 deletion Game.Client/HUD/HudAnimationInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
using Source.Common.GUI;
using Source.GUI.Controls;

namespace Game.Client;

[DeclareHudElement(Name = "CHudAnimationInfo")]
class HudAnimationInfo : EditableHudElement, IHudElement
{
Expand All @@ -20,6 +22,7 @@ class HudAnimationInfo : EditableHudElement, IHudElement
Panel? Watch;

public HudAnimationInfo(string panelName) : base(null, "HudAnimationInfo") {
ElementName = panelName;
ANIM_INFO_WIDTH = 300 * (ScreenWidth() / 640);

Panel parent = clientMode.GetViewport();
Expand Down Expand Up @@ -161,7 +164,7 @@ public override void Paint() {

[ConCommand("cl_animationinfo", "Hud element to examine.", FCvar.None)]
static void func(in TokenizedCommand args) {
if (gHUD.FindElement("HudAnimationInfo") is not HudAnimationInfo info)
if (gHUD.FindElement("CHudAnimationInfo") is not HudAnimationInfo info)
return;

if (args.ArgC() != 2) {
Expand Down
3 changes: 2 additions & 1 deletion Game.Client/HistoryResource.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using Game.Client;
using Game.Client.HUD;
using Game.Shared;

Expand All @@ -7,6 +6,8 @@
using Source.Common.GUI;
using Source.GUI.Controls;

namespace Game.Client;

enum HRType
{
Empty,
Expand Down
2 changes: 1 addition & 1 deletion Game.Client/WeaponsResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ internal void LoadWeaponSprites(WEAPON_FILE_INFO_HANDLE weaponFileInfo) {
weaponInfo.IconZoomedAutoaim = weaponInfo.IconZoomedCrosshair; //default to zoomed crosshair
}

HudHistoryResource? hudHR = GET_HUDELEMENT<HudHistoryResource>();
HudHistoryResource? hudHR = gHUD.FindElement("CHudHistoryResource") as HudHistoryResource;
if (hudHR != null) {
p = FindHudTextureInDict(tempList, "weapon");
if (p != null) {
Expand Down
6 changes: 4 additions & 2 deletions Game.Server/BaseAnimating.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,9 @@ public float GetSequenceMoveDist(StudioHdr? studioHdr, int sequence) {
public float GetSequenceGroundSpeed(StudioHdr? studioHdr, int sequence) {
TimeUnit_t t = SequenceDuration(studioHdr, sequence);

if (t > 0)
if (t > 0)
return (GetSequenceMoveDist(studioHdr, sequence) / (float)t);
else
else
return 0;
}
public void ResetSequenceInfo() {
Expand Down Expand Up @@ -200,4 +200,6 @@ public int FindTransitionSequence(int currentSequence, int goalSequence) {
else
return sequence;
}

public override BaseAnimating? GetBaseAnimating() => this;
}
133 changes: 105 additions & 28 deletions Game.Server/BaseEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,56 @@ public partial class BaseEntity : IServerEntity
public virtual bool IsNextBot() => false;
public virtual bool IsBaseCombatWeapon() => false;
public virtual bool IsCombatItem() => false;
public bool ClassMatches(ReadOnlySpan<char> classOrWildcard) => false; // todo
public bool ClassMatches(ReadOnlySpan<char> classOrWildcard) => Classname.AsSpan().SequenceEqual(classOrWildcard);
public bool NameMatches(ReadOnlySpan<char> name) => false; // todo
public virtual bool IsPredicted() => false;
private static void SendProxy_AnimTime(SendProp prop, object instance, IFieldAccessor field, ref DVariant outData, int element, int objectID)
=> throw new NotImplementedException();
private static void SendProxy_SimulationTime(SendProp prop, object instance, IFieldAccessor field, ref DVariant outData, int element, int objectID)
=> throw new NotImplementedException();
public virtual bool IsTemplate() => false;

private static void SendProxy_AnimTime(SendProp prop, object instance, IFieldAccessor field, ref DVariant outData, int element, int objectID) {
BaseEntity entity = (BaseEntity)instance;

#if false
BaseAnimating? animating = entity.GetBaseAnimating();
Assert(animating != null);
if (animating != null)
Assert(!animating.IsUsingClientSideAnimation());
#endif

int tickNumber = TIME_TO_TICKS(entity.AnimTime);
long tickBase = gpGlobals.GetNetworkBase(gpGlobals.TickCount, entity.EntIndex());

int addt = 0;
if (tickNumber >= tickBase)
addt = (int)((tickNumber - tickBase) & 0xff);

outData.Int = addt;
}

private static void SendProxy_SimulationTime(SendProp prop, object instance, IFieldAccessor field, ref DVariant outData, int element, int objectID) {
BaseEntity entity = (BaseEntity)instance;

int tickNumber = TIME_TO_TICKS(entity.SimulationTime);
long tickBase = gpGlobals.GetNetworkBase(gpGlobals.TickCount, entity.EntIndex());

int addt = 0;
if (tickNumber >= tickBase)
addt = (int)((tickNumber - tickBase) & 0xff);

outData.Int = addt;
}

public static SendTable DT_AnimTimeMustBeFirst = new(nameof(DT_AnimTimeMustBeFirst), [
SendPropInt (FIELD.OF(nameof(AnimTime)), 8, PropFlags.Unsigned|PropFlags.ChangesOften|PropFlags.EncodedAgainstTickCount, proxyFn: SendProxy_AnimTime),
]);

public static object? SendProxy_ClientSideAnimation(SendProp prop, object instance, IFieldAccessor data, SendProxyRecipients recipients, int objectID) {
throw new NotImplementedException();
BaseEntity entity = (BaseEntity)instance;
BaseAnimating? animating = entity.GetBaseAnimating();

if (animating != null /*&& !animating.IsUsingClientSideAnimation()*/)
return data.GetValue<object>(instance);
else
return null;
}
public static SendTable DT_PredictableId = new(nameof(DT_PredictableId), [
SendPropPredictableId(FIELD.OF(nameof(PredictableId))),
Expand Down Expand Up @@ -125,18 +163,53 @@ private static void SendProxy_SimulationTime(SendProp prop, object instance, IFi
SendPropInt(FIELD.OF(nameof(MapCreatedID)), 16),
]);

public BaseEntity() {
// todo todo

// CollisionProp().Init(this);
NetworkProp().Init(this);

AddEFlags(EFL.NoThinkFunction | EFL.NoGamePhysicsSimulation | EFL.UsePartitionWhenNotSolid);

SetSolid(SolidType.None);
// ClearSolidFlags();

SetMoveType(Source.MoveType.None);
// SetModelIndex(0);

ClearFlags();
}

public string? Name;
public float Gravity;
public void SetPredictionEligible(bool canpredict) { } // nothing in game code
public ref readonly Vector3 GetLocalOrigin() => ref AbsOrigin;
public ref readonly QAngle GetLocalAngles() => ref AbsRotation;
private static void SendProxy_OverrideMaterial(SendProp prop, object instance, IFieldAccessor field, ref DVariant outData, int element, int objectID) {
Warning("SendProxy_OverrideMaterial not yet implemented\n");
BaseEntity entity = (BaseEntity)instance;
outData.Int = entity.OverrideMaterial;
}
private static void SendProxy_Angles(SendProp prop, object instance, IFieldAccessor field, ref DVariant outData, int element, int objectID) {
Warning("SendProxy_Angles not yet implemented\n");
BaseEntity entity = (BaseEntity)instance;
Assert(entity != null);

QAngle angles;
if (true /*entity.UseStepSimulationNetworkAngles*/)
angles = entity.GetLocalAngles();

outData.Vector[0] = MathLib.AngleMod(angles.X);
outData.Vector[1] = MathLib.AngleMod(angles.Y);
outData.Vector[2] = MathLib.AngleMod(angles.Z);
}
protected static object? SendProxy_SendPredictableId(SendProp prop, object instance, IFieldAccessor data, SendProxyRecipients recipients, int objectID) {
Warning("SendProxy_SendPredictableId not yet implemented\n");
return null;
BaseEntity entity = (BaseEntity)instance;
if (entity == null || !entity.PredictableId.IsActive())
return null;

int id_player_index = entity.PredictableId.GetPlayer();
// recipients.SetOnly(id_player_index);

return data.GetValue<object>(instance);
}

public static BaseEntity? GetContainingEntity(Edict ent) {
Expand All @@ -147,7 +220,7 @@ private static void SendProxy_Angles(SendProp prop, object instance, IFieldAcces

public Team? GetTeam() => GetGlobalTeam(TeamNum);

public static BaseEntity? Instance(Edict ent) => GetContainingEntity(ent);
public static BaseEntity? Instance(Edict ent) => GetContainingEntity(ent);

public byte RenderFX;
public byte RenderMode;
Expand Down Expand Up @@ -235,14 +308,14 @@ public bool FClassnameIs(BaseEntity? entity, ReadOnlySpan<char> classname) {

return 0 == strcmp(entity.GetClassname(), classname);
}

public bool IsServer() => true;
public bool IsClient() => false;
public ReadOnlySpan<char> GetDLLType() => "server";

public WaterLevel GetWaterLevel() => (WaterLevel)WaterLevel;
public void SetWaterLevel(WaterLevel level) => WaterLevel = (byte)level;
public void SetMoveCollide(MoveCollide moveCollide) => MoveCollide = (byte)moveCollide;
public void SetMoveCollide(MoveCollide moveCollide) => MoveCollide = (byte)moveCollide;
public CollisionProperty CollisionProp() => Collision;

public bool SetModel(ReadOnlySpan<char> modelName) {
Expand Down Expand Up @@ -333,13 +406,13 @@ public ref readonly Vector3 GetAbsVelocity() {
}

string? Classname;
public void SetClassname(ReadOnlySpan<char> classname){
public void SetClassname(ReadOnlySpan<char> classname) {
Classname = new(classname);
}

public Edict Edict() => NetworkProp().Edict();

public void PostConstructor(ReadOnlySpan<char> classname){
public void PostConstructor(ReadOnlySpan<char> classname) {
if (!classname.IsEmpty)
SetClassname(classname);

Expand Down Expand Up @@ -383,6 +456,8 @@ public virtual ReadOnlySpan<char> GetClassname() {
public virtual void Spawn() { }
public virtual void Precache() { }

public bool HasSpawnFlags(int flags) => (SpawnFlags & flags) != 0;

public int GetModelIndex() {
throw new NotImplementedException();
}
Expand All @@ -395,18 +470,14 @@ public ReadOnlySpan<char> GetModelName() {
throw new NotImplementedException();
}

public ref readonly BaseHandle GetRefEHandle() {
throw new NotImplementedException();
}
public ref readonly BaseHandle GetRefEHandle() => ref RefEHandle;

public void SetModelIndex(int index) {
throw new NotImplementedException();
}

public void SetRefEHandle(in BaseHandle handle) {
throw new NotImplementedException();
// throw new NotImplementedException();
}

BaseHandle RefEHandle;
public void SetRefEHandle(in BaseHandle handle) => RefEHandle = handle;

int flags;
EFL eflags;
Expand Down Expand Up @@ -450,8 +521,15 @@ public void SetAbsVelocity(in Vector3 absVelocity) {
public ref readonly Vector3 GetViewOffset() => ref ViewOffset;
public ref readonly QAngle GetAbsAngles() => ref AbsRotation;

public void SetLocalOrigin(in Vector3 origin) { } // todo
public void SetLocalAngles(in QAngle origin) { } // todo
public void SetLocalOrigin(in Vector3 origin) {
// This has a lot more logic thats needed later TODO FIXME
Origin = origin;
}

public void SetLocalAngles(in QAngle angles) {
// This has a lot more logic thats needed later TODO FIXME
Rotation = angles;
}

public ref Matrix3x4 EntityToWorldTransform() {

Expand All @@ -464,7 +542,6 @@ public ref Matrix3x4 EntityToWorldTransform() {
public float GetGravity() => Gravity;
public void SetGravity(float gravity) => Gravity = gravity;

public object? GetBaseEntity() {
return this;
}
public object? GetBaseEntity() => this;
public virtual BaseAnimating? GetBaseAnimating() => null;
}
Loading