Compare commits

...

4 Commits
v1.0.10 ... v14

Author SHA1 Message Date
Roflmuffin
cef9758c12 fix: ignore -1 in get players, fixes, #46 2023-11-09 11:02:15 +10:00
Roflmuffin
0dc35818dd hotfix: native string memory leak 2023-11-09 09:18:33 +10:00
Roflmuffin
a0f9d30753 feat: add PrintToCenterHtml to player class 2023-11-09 01:12:17 +10:00
Michael Wilson
d6fe9e10e1 Generate all missing schema properties (#40) 2023-11-08 23:51:32 +10:00
25 changed files with 146271 additions and 49743 deletions

View File

@@ -77,6 +77,7 @@ SET(SOURCE_FILES
src/core/managers/server_manager.cpp
src/core/managers/server_manager.h
src/scripting/natives/natives_server.cpp
libraries/nlohmann/json.hpp
)
set(PROTO_DIRS -I${CMAKE_CURRENT_SOURCE_DIR}/libraries/GameTracking-CS2/Protobufs)

1920
configs/schema_classes.txt Normal file

File diff suppressed because it is too large Load Diff

305
configs/schema_enums.txt Normal file
View File

@@ -0,0 +1,305 @@
ActionType_t
AimMatrixBlendMode
AmmoFlags_t
AmmoPosition_t
AnimLoopMode_t
AnimNodeNetworkMode
AnimParamButton_t
AnimParamNetworkSetting
AnimParamType_t
AnimPoseControl
AnimScriptType
AnimVRFinger_t
AnimVRHandMotionRange_t
AnimVRHand_t
AnimValueSource
AnimVectorSource
AnimVrBoneTransformSource_t
AnimVrFingerSplay_t
AnimationProcessingType_t
AnimationSnapshotType_t
AnimationType_t
BBoxVolumeType_t
BaseExplosionTypes_t
BeamClipStyle_t
BeamType_t
BeginDeathLifeStateTransition_t
BinaryNodeChildOption
BinaryNodeTiming
Blend2DMode
BlendKeyType
BloomBlendMode_t
BlurFilterType_t
BoneMaskBlendSpace
BoneTransformSpace_t
BrushSolidities_e
CAnimationGraphVisualizerPrimitiveType
CLogicBranchList__LogicBranchListenerLastState_t
CRR_Response__ResponseEnum_t
CSPlayerBlockingUseAction_t
CSPlayerState
CSWeaponCategory
CSWeaponMode
CSWeaponSilencerType
CSWeaponState_t
CSWeaponType
CanPlaySequence_t
ChatIgnoreType_t
ChickenActivity
ChoiceBlendMethod
ChoiceChangeMethod
ChoiceMethod
Class_T
ClosestPointTestType_t
CommandEntitySpecType_t
CommandExecMode_t
CompMatPropertyMutatorConditionType_t
CompMatPropertyMutatorType_t
CompositeMaterialInputContainerSourceType_t
CompositeMaterialInputLooseVariableType_t
CompositeMaterialInputTextureType_t
CompositeMaterialMatchFilterType_t
CompositeMaterialVarSystemVar_t
DamageTypes_t
DampingSpeedFunction
DebugOverlayBits_t
Detail2Combo_t
DetailCombo_t
DisableShadows_t
Disposition_t
DoorState_t
EDemoBoneSelectionMode
EGrenadeThrowState
EInButtonState
EKillTypes_t
ELayoutNodeType
EOverrideBlockLOS_t
EStyleNodeType
EntFinderMethod_t
EntityDisolveType_t
EntityDormancyType_t
EntityIOTargetType_t
EntitySubclassScope_t
Explosions
FacingMode
FieldNetworkOption
FixAngleSet_t
FlexOpCode_t
FootFallTagFoot_t
FootLockSubVisualization
FootPinningTimingSource
FootstepLandedFootSoundType_t
ForcedCrouchState_t
FuncDoorSpawnPos_t
FuseVariableAccess_t
FuseVariableType_t
GameAnimEventIndex_t
GrenadeType_t
HierarchyType_t
HitGroup_t
HitboxLerpType_t
HorizJustification_e
Hull_t
IChoreoServices__ChoreoState_t
IChoreoServices__ScriptState_t
IKChannelMode
IKSolverType
IKTargetCoordinateSystem
IKTargetSource
IkEndEffectorType
IkTargetType
InheritableBoolType_t
InputBitMask_t
InputLayoutVariation_t
ItemFlagTypes_t
JiggleBoneSimSpace
JointAxis_t
JointMotion_t
JumpCorrectionMethod
LatchDirtyPermission_t
LayoutPositionType_e
LessonPanelLayoutFileTypes_t
LifeState_t
MaterialProxyType_t
Materials
MatterialAttributeTagType_t
MedalRank_t
MeshDrawPrimitiveFlags_t
MissingParentInheritBehavior_t
ModelBoneFlexComponent_t
ModelConfigAttachmentType_t
ModelSkeletonData_t__BoneFlags_t
ModifyDamageReturn_t
MoodType_t
MorphBundleType_t
MorphFlexControllerRemapType_t
MoveCollide_t
MoveLinearAuthoredPos_t
MoveMountingAmount_t
MoveType_t
NavAttributeEnum
NavDirType
ObjectTypeFlags_t
ObserverInterpState_t
ObserverMode_t
OnFrame
PFNoiseModifier_t
PFNoiseTurbulence_t
PFNoiseType_t
PFuncVisualizationType_t
ParticleAlphaReferenceType_t
ParticleAttachment_t
ParticleCollisionMode_t
ParticleColorBlendMode_t
ParticleColorBlendType_t
ParticleControlPointAxis_t
ParticleDepthFeatheringMode_t
ParticleDetailLevel_t
ParticleDirectionNoiseType_t
ParticleEndcapMode_t
ParticleFalloffFunction_t
ParticleFloatBiasType_t
ParticleFloatInputMode_t
ParticleFloatMapType_t
ParticleFloatRandomMode_t
ParticleFloatType_t
ParticleFogType_t
ParticleHitboxBiasType_t
ParticleHitboxDataSelection_t
ParticleImpulseType_t
ParticleLightBehaviorChoiceList_t
ParticleLightFogLightingMode_t
ParticleLightTypeChoiceList_t
ParticleLightUnitChoiceList_t
ParticleLightingQuality_t
ParticleLightnintBranchBehavior_t
ParticleModelType_t
ParticleOmni2LightTypeChoiceList_t
ParticleOrientationChoiceList_t
ParticleOrientationSetMode_t
ParticleOutputBlendMode_t
ParticleParentSetMode_t
ParticlePinDistance_t
ParticlePostProcessPriorityGroup_t
ParticleRotationLockType_t
ParticleSelection_t
ParticleSequenceCropOverride_t
ParticleSetMethod_t
ParticleSortingChoiceList_t
ParticleTextureLayerBlendType_t
ParticleTopology_t
ParticleTraceMissBehavior_t
ParticleTraceSet_t
ParticleTransformType_t
ParticleVRHandChoiceList_t
ParticleVecType_t
PerformanceMode_t
PermModelInfo_t__FlagEnum
PetGroundType_t
PlayerAnimEvent_t
PlayerConnectedState
PointTemplateClientOnlyEntityBehavior_t
PointTemplateOwnerSpawnGroupType_t
PointWorldTextJustifyHorizontal_t
PointWorldTextJustifyVertical_t
PointWorldTextReorientMode_t
PoseType_t
PropDoorRotatingOpenDirection_e
PropDoorRotatingSpawnPos_t
PulseInstructionCode_t
PulseMethodCallMode_t
PulseValueType_t
QuestProgress__Reason
RagdollPoseControl
RenderBufferFlags_t
RenderFx_t
RenderMode_t
RenderMultisampleType_t
RenderPrimitiveType_t
RenderSlotType_t
ResetCycleOption
RumbleEffect_t
ScalarExpressionType_t
SceneOnPlayerDeath_t
ScriptedConflictResponse_t
ScriptedMoveTo_t
ScriptedMoveType_t
ScriptedOnDeath_t
SelectorTagBehavior_t
SeqCmd_t
SeqPoseSetting_t
ShadowType_t
ShakeCommand_t
ShardSolid_t
ShatterDamageCause
ShatterGlassStressType
ShatterPanelMode
SimpleConstraintSoundProfile__SimpleConstraintsSoundProfileKeypoints_t
SolidType_t
SolveIKChainAnimNodeDebugSetting
SosActionSortType_t
SosActionStopType_t
SosEditItemType_t
SosGroupType_t
SoundEventStartType_t
SoundFlags_t
SpawnDebugOverrideState_t
SpawnDebugRestrictionOverrideState_t
SpawnPointCoopEnemy__BotDefaultBehavior_t
SpriteCardPerParticleScale_t
SpriteCardShaderType_t
SpriteCardTextureChannel_t
SpriteCardTextureType_t
StanceOverrideMode
StanceType_t
StandardLightingAttenuationStyle_t
StateActionBehavior
StepPhase
SubclassVDataChangeType_t
SurroundingBoundsType_t
TOGGLE_STATE
TRAIN_CODE
TakeDamageFlags_t
TextureRepetitionMode_t
ThreeState_t
TimelineCompression_t
Touch_t
TrackOrientationType_t
TrainOrientationType_t
TrainVelocityType_t
VMixChannelOperation_t
VMixFilterSlope_t
VMixFilterType_t
VMixLFOShape_t
VMixPannerType_t
VMixProcessorType_t
VMixSubgraphSwitchInterpolationType_t
VPhysXAggregateData_t__VPhysXFlagEnum_t
VPhysXBodyPart_t__VPhysXFlagEnum_t
VPhysXConstraintParams_t__EnumFlags0_t
VPhysXJoint_t__Flags_t
ValueRemapperHapticsType_t
ValueRemapperInputType_t
ValueRemapperMomentumType_t
ValueRemapperOutputType_t
ValueRemapperRatchetType_t
VectorExpressionType_t
VectorFloatExpressionType_t
VelocityMetricMode
VertJustification_e
ViewFadeMode_t
WaterLevel_t
WeaponAttackType_t
WeaponSound_t
WorldTextPanelHorizontalAlign_t
WorldTextPanelOrientation_t
WorldTextPanelVerticalAlign_t
attributeprovidertypes_t
doorCheck_e
fieldtype_t
filter_t
gear_slot_t
loadout_slot_t
navproperties_t
soundlevel_t
vote_create_failed_t

24596
libraries/nlohmann/json.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -6,8 +6,6 @@ namespace CounterStrikeSharp.API.Core;
public partial class CBaseEntity
{
public Vector AbsVelocity => Schema.GetDeclaredClass<Vector>(this.Handle, "CBaseEntity", "m_vecAbsVelocity");
public void Teleport(Vector position, QAngle angles, Vector velocity)
{
VirtualFunction.CreateVoid<IntPtr, IntPtr, IntPtr, IntPtr>(Handle, GameData.GetOffset("CBaseEntity_Teleport"))(
@@ -18,10 +16,9 @@ public partial class CBaseEntity
/// Shorthand for accessing an entity's CBodyComponent?.SceneNode?.AbsOrigin;
/// </summary>
public Vector? AbsOrigin => CBodyComponent?.SceneNode?.AbsOrigin;
/// <summary>
/// Shorthand for accessing an entity's CBodyComponent?.SceneNode?.AbsRotation;
/// </summary>
public QAngle? AbsRotation => CBodyComponent?.SceneNode?.AbsRotation;
}

View File

@@ -38,6 +38,18 @@ public partial class CCSPlayerController
{
VirtualFunctions.ClientPrint(this.Handle, HudDestination.Center, message, 0, 0, 0, 0);
}
public void PrintToCenterHtml(string message)
{
var @event = new EventShowSurvivalRespawnStatus(true)
{
LocToken = message,
Duration = 5,
Userid = this
};
@event.FireEvent(false);
}
public bool IsBot => ((PlayerFlags)Flags).HasFlag(PlayerFlags.FL_FAKECLIENT);
@@ -49,7 +61,7 @@ public partial class CCSPlayerController
{
VirtualFunctions.SwitchTeam(this.Handle, (byte)team);
}
/// <summary>
/// Switches the team of the player, has the same effect as the "jointeam" console command.
/// <remarks>
@@ -62,4 +74,9 @@ public partial class CCSPlayerController
VirtualFunction.CreateVoid<IntPtr, CsTeam>(Handle, GameData.GetOffset("CCSPlayerController_ChangeTeam"))(Handle,
team);
}
/// <summary>
/// Gets the active pawns button state. Will work even if the player is dead or observing.
/// </summary>
public PlayerButtons Buttons => (PlayerButtons)Pawn.Value.MovementServices!.Buttons.ButtonStates[0];
}

View File

@@ -51,9 +51,4 @@ public partial class CEntityIdentity
{
public unsafe CEntityInstance EntityInstance => new(Unsafe.Read<IntPtr>((void*)Handle));
public unsafe CHandle<CEntityInstance> EntityHandle => new(Handle + 0x10);
public unsafe string DesignerName => Utilities.ReadStringUtf8(Handle + 0x20);
public unsafe PointerTo<CEntityIdentity> Prev => new(Handle + 0x58);
public unsafe PointerTo<CEntityIdentity> Next => new(Handle + 0x60);
public unsafe PointerTo<CEntityIdentity> PrevByClass => new(Handle + 0x68);
public unsafe PointerTo<CEntityIdentity> NextByClass => new(Handle + 0x70);
}

View File

@@ -1,22 +0,0 @@
using System;
using System.Runtime.CompilerServices;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Utils;
namespace CounterStrikeSharp.API.Core;
public class CInButtonState : NativeObject
{
public CInButtonState(IntPtr pointer) : base(pointer)
{
}
public unsafe ref PlayerButtons Value =>
ref Unsafe.AsRef<PlayerButtons>((void*)(Handle + Schema.GetSchemaOffset("CInButtonState", "m_pButtonStates")));
}
public partial class CPlayer_MovementServices
{
public CInButtonState ButtonState =>
Schema.GetDeclaredClass<CInButtonState>(this.Handle, "CPlayer_MovementServices", "m_nButtons");
}

File diff suppressed because it is too large Load Diff

View File

@@ -103,6 +103,7 @@ namespace CounterStrikeSharp.API.Core
public void Invoke()
{
InvokeNativeInternal();
GlobalCleanUp();
}
[SecurityCritical]

View File

@@ -52,7 +52,7 @@ namespace CounterStrikeSharp.API.Modules.Memory
{ typeof(string), DataType.DATA_TYPE_STRING },
{ typeof(long), DataType.DATA_TYPE_LONG },
{ typeof(ulong), DataType.DATA_TYPE_ULONG },
{ typeof(short), DataType.DATA_TYPE_VARIANT },
{ typeof(short), DataType.DATA_TYPE_SHORT },
{ typeof(sbyte), DataType.DATA_TYPE_UCHAR },
{ typeof(byte), DataType.DATA_TYPE_CHAR },
};

View File

@@ -0,0 +1,13 @@
using System;
using System.Runtime.CompilerServices;
namespace CounterStrikeSharp.API.Modules.Utils;
public partial class matrix3x4_t : NativeObject
{
public matrix3x4_t(IntPtr pointer) : base(pointer)
{
}
public unsafe ref float this[int row, int column] => ref Unsafe.Add(ref *(float*)Handle, row * 4 + column);
}

View File

@@ -61,7 +61,7 @@ namespace CounterStrikeSharp.API
public static IEnumerable<T> FindAllEntitiesByDesignerName<T>(string designerName) where T : CEntityInstance
{
var pEntity = new CEntityIdentity(NativeAPI.GetFirstActiveEntity());
for (; pEntity.Handle != IntPtr.Zero; pEntity = pEntity.Next.Value)
for (; pEntity != null && pEntity.Handle != IntPtr.Zero; pEntity = pEntity.Next)
{
if (!pEntity.DesignerName.Contains(designerName)) continue;
yield return new PointerTo<T>(pEntity.Handle).Value;
@@ -79,7 +79,7 @@ namespace CounterStrikeSharp.API
{
var controller = GetPlayerFromIndex(i);
if (!controller.IsValid || controller.UserId < 0)
if (!controller.IsValid || controller.UserId == -1)
continue;
players.Add(controller);

View File

@@ -1,8 +1,9 @@
/**
* This project has been copied & modified from the demofile-net project under the MIT license.
* This project has been copied & modified from the demofile-net project under the MIT license.
* See ACKNOWLEDGEMENTS file for more information.
* https://github.com/saul/demofile-net
*/
using System.Collections.Immutable;
using System.Diagnostics;
using System.Text;
@@ -20,7 +21,14 @@ internal static partial class Program
"GameTick_t",
"AttachmentHandle_t",
"CGameSceneNodeHandle",
"HSequence"
"HSequence",
"CAttributeManager::cached_attribute_float_t",
"QuestProgress::Reason",
"IChoreoServices::ScriptState_t",
"IChoreoServices::ChoreoState_t",
"SpawnPointCoopEnemy::BotDefaultBehavior_t",
"CLogicBranchList::LogicBranchListenerLastState_t",
"SimpleConstraintSoundProfile::SimpleConstraintsSoundProfileKeypoints_t"
};
public static string SanitiseTypeName(string typeName) => typeName.Replace(":", "");
@@ -35,7 +43,7 @@ internal static partial class Program
var allEnums = new SortedDictionary<string, SchemaEnum>();
var allClasses = new SortedDictionary<string, SchemaClass>();
var schemaFiles = new[] { "server.json", "!GlobalTypes.json" };
var schemaFiles = new[] { "server.json" };
foreach (var schemaFile in schemaFiles)
{
@@ -200,28 +208,20 @@ internal static partial class Program
foreach (var field in schemaClass.Fields)
{
var defaultValue = field.Type.Category switch
// Putting these in the too hard basket for now.
if (field.Name == "m_VoteOptions" || field.Type.Name.Contains("CEntityOutputTemplate") ||
field.Type.Name.Contains("CVariantBase") ||
field.Type.Name == "HSCRIPT" || field.Type.Name == "KeyValues3") continue;
if (field.Type is { Category: SchemaTypeCategory.Atomic, Atomic: SchemaAtomicCategory.Collection })
{
SchemaTypeCategory.DeclaredClass =>
" = new();",
SchemaTypeCategory.FixedArray =>
field.Type.IsString
? $" = \"\";"
: $" = Array.Empty<{field.Type.Inner!.CsTypeName}>();",
SchemaTypeCategory.Atomic when field.Type.Atomic == SchemaAtomicCategory.Collection =>
$" = new NetworkedVector<{field.Type.Inner!.CsTypeName}>();",
_ => null
};
if (IgnoreClasses.Contains(field.Type.Inner!.Name)) continue;
}
var handleParams = $"this.Handle, \"{schemaClassName}\", \"{field.Name}\"";
builder.AppendLine($" // {field.Name}");
foreach (var (metadataKey, value) in field.Metadata)
{
builder.AppendLine($" // {metadataKey}{(value == "" ? "" : $" \"{value}\"")}");
}
if (field.Type is { Category: SchemaTypeCategory.FixedArray, CsTypeName: "string" })
{
var getter = $"return Schema.GetString({handleParams});";
@@ -237,7 +237,7 @@ internal static partial class Program
builder.AppendLine();
}
// Networked Strings require UTF8 encoding/decoding
else if ( field.Type is { Category: SchemaTypeCategory.Atomic, CsTypeName: "string" })
else if (field.Type is { Category: SchemaTypeCategory.Atomic, CsTypeName: "string" })
{
var getter = $"return Schema.GetUtf8String({handleParams});";
var setter = $"Schema.SetString({handleParams}, value);";
@@ -253,19 +253,23 @@ internal static partial class Program
}
else if (field.Type.Category == SchemaTypeCategory.FixedArray)
{
var getter = $"Schema.GetFixedArray<{SanitiseTypeName(field.Type.Inner!.CsTypeName)}>({handleParams}, {field.Type.ArraySize});";
var getter =
$"Schema.GetFixedArray<{SanitiseTypeName(field.Type.Inner!.CsTypeName)}>({handleParams}, {field.Type.ArraySize});";
builder.AppendLine(
$" public Span<{SanitiseTypeName(field.Type.Inner!.CsTypeName)}> {schemaClass.CsPropertyNameForField(schemaClassName, field)} => {getter}");
builder.AppendLine();
}
else if (field.Type.Category == SchemaTypeCategory.DeclaredClass && !IgnoreClasses.Contains(field.Type.Name))
else if (field.Type.Category == SchemaTypeCategory.DeclaredClass &&
!IgnoreClasses.Contains(field.Type.Name))
{
var getter = $"Schema.GetDeclaredClass<{SanitiseTypeName(field.Type.CsTypeName)}>({handleParams});";
builder.AppendLine(
$" public {SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)} => {getter}");
builder.AppendLine();
}
else if ((field.Type.Category == SchemaTypeCategory.Builtin || field.Type.Category == SchemaTypeCategory.DeclaredEnum) && !IgnoreClasses.Contains(field.Type.Name))
else if ((field.Type.Category == SchemaTypeCategory.Builtin ||
field.Type.Category == SchemaTypeCategory.DeclaredEnum) &&
!IgnoreClasses.Contains(field.Type.Name))
{
var getter = $"ref Schema.GetRef<{SanitiseTypeName(field.Type.CsTypeName)}>({handleParams});";
builder.AppendLine(
@@ -275,13 +279,13 @@ internal static partial class Program
else if (field.Type.Category == SchemaTypeCategory.Ptr)
{
var inner = field.Type.Inner!;
Debug.Assert(inner.Category == SchemaTypeCategory.DeclaredClass);
if (inner.Category != SchemaTypeCategory.DeclaredClass) continue;
builder.AppendLine(
$" public {SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)} => Schema.GetPointer<{SanitiseTypeName(inner.CsTypeName)}>({handleParams});");
builder.AppendLine();
}
else if (field.Type is { Category: SchemaTypeCategory.Atomic, Name: "Color"})
}
else if (field.Type is { Category: SchemaTypeCategory.Atomic, Name: "Color" })
{
var getter = $"return Schema.GetCustomMarshalledType<{field.Type.CsTypeName}>({handleParams});";
var setter = $"Schema.SetCustomMarshalledType<{field.Type.CsTypeName}>({handleParams}, value);";
@@ -355,4 +359,4 @@ internal static partial class Program
builder.AppendLine("}");
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -32,6 +32,7 @@ public partial record SchemaClass(
case ("CEnvScreenOverlay", "m_bIsActive"): return "IsOverlayActive";
case ("CPlayerSprayDecal", "m_nEntity"): return "DecalEntity";
case ("CHandleTest", "m_Handle"): return "TestHandle";
case ("FilterTeam", "m_iFilterTeam"): return "Value";
}
string CleanFieldName(string fieldName) =>

View File

@@ -1,14 +1,39 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions;
namespace CounterStrikeSharp.SchemaGen;
public record SchemaFieldType(
string Name,
SchemaTypeCategory Category,
SchemaAtomicCategory? Atomic,
SchemaFieldType? Inner,
int? ArraySize)
public record SchemaFieldType
{
public SchemaFieldType(string Name,
SchemaTypeCategory Category,
SchemaAtomicCategory? Atomic,
SchemaFieldType? Inner)
{
this.Name = Name;
this.Category = Category;
this.Atomic = Atomic;
this.Inner = Inner;
if (this.Name == "GameTime_t")
{
this.Category = SchemaTypeCategory.Builtin;
this.Name = "float32";
}
else if
(this.Name == "CPlayerSlot" || this.Name == "HSequence" || this.Name == "CSplitScreenSlot" || this.Name == "GameTick_t")
{
this.Category = SchemaTypeCategory.Builtin;
this.Name = "int32";
}
else if (this.Name == "CBitVec< 64 >")
{
this.Category = SchemaTypeCategory.FixedArray;
this.Inner = new SchemaFieldType("uint8", SchemaTypeCategory.Builtin, null, null);
this.Name = "uint8[8]";
}
}
public bool IsString =>
Category == SchemaTypeCategory.FixedArray
&& Inner!.Category == SchemaTypeCategory.Builtin
@@ -46,19 +71,22 @@ public record SchemaFieldType(
_ => throw new ArgumentOutOfRangeException(nameof(name), name, $"Unknown built-in: {name}")
};
private static string AtomicToCsTypeName(string name, SchemaAtomicCategory atomic, SchemaFieldType? inner) => atomic switch
{
SchemaAtomicCategory.Basic => name switch
private static string AtomicToCsTypeName(string name, SchemaAtomicCategory atomic, SchemaFieldType? inner) =>
atomic switch
{
"CUtlString" or "CUtlSymbolLarge" => "string",
"CEntityHandle" => "CHandle<CEntityInstance>",
"CNetworkedQuantizedFloat" => "float",
_ => name
},
SchemaAtomicCategory.T => $"{name.Split('<')[0]}<{inner!.CsTypeName}>",
SchemaAtomicCategory.Collection => $"NetworkedVector<{inner!.CsTypeName}>",
_ => throw new ArgumentOutOfRangeException(nameof(atomic), atomic, $"Unsupported atomic: {atomic}")
};
SchemaAtomicCategory.Basic => name switch
{
"CUtlString" or "CUtlSymbolLarge" => "string",
"CEntityHandle" => "CHandle<CEntityInstance>",
"CNetworkedQuantizedFloat" => "float",
"RotationVector" => "Vector",
_ => name
},
SchemaAtomicCategory.T => $"{name.Split('<')[0]}<{inner!.CsTypeName}>",
SchemaAtomicCategory.Collection => $"NetworkedVector<{inner!.CsTypeName}>",
SchemaAtomicCategory.Unknown => "CBitVec",
_ => throw new ArgumentOutOfRangeException(nameof(atomic), atomic, $"Unsupported atomic: {atomic}")
};
public string CsTypeName => Category switch
{
@@ -72,4 +100,34 @@ public record SchemaFieldType(
SchemaTypeCategory.DeclaredEnum => Name,
_ => throw new ArgumentOutOfRangeException(nameof(Category), Category, $"Unsupported type category: {Category}")
};
}
public string Name { get; init; }
public SchemaTypeCategory Category { get; init; }
public SchemaAtomicCategory? Atomic { get; init; }
public SchemaFieldType? Inner { get; init; }
public int? ArraySize
{
get
{
if (Category == SchemaTypeCategory.FixedArray)
{
// Extract number from name, e.g. `uint16[2]`
var match = Regex.Match(this.Name, @"\[(\d+)\]$");
return match.Success ? int.Parse(match.Groups[1].Value) : null;
}
return null;
}
}
public void Deconstruct(out string Name, out SchemaTypeCategory Category, out SchemaAtomicCategory? Atomic,
out SchemaFieldType? Inner, out int? ArraySize)
{
Name = this.Name;
Category = this.Category;
Atomic = this.Atomic;
Inner = this.Inner;
ArraySize = this.ArraySize;
}
}

View File

@@ -0,0 +1,130 @@
#pragma once
#include <array>
#include <cstdint>
#include <vector>
using UtlTsHashHandleT = std::uint64_t;
class CUtlMemoryPool {
public:
// returns number of allocated blocks
int BlockSize() const {
return m_blocks_per_blob_;
}
int Count() const {
return m_block_allocated_size_;
}
int PeakCount() const {
return m_peak_alloc_;
}
private:
std::int32_t m_block_size_ = 0; // 0x0558
std::int32_t m_blocks_per_blob_ = 0; // 0x055C
std::int32_t m_grow_mode_ = 0; // 0x0560
std::int32_t m_blocks_allocated_ = 0; // 0x0564
std::int32_t m_block_allocated_size_ = 0; // 0x0568
std::int32_t m_peak_alloc_ = 0; // 0x056C
};
template <class T, class Keytype = std::uint64_t>
class CUtlTSHash {
public:
// Invalid handle.
static UtlTsHashHandleT InvalidHandle(void) {
return static_cast<UtlTsHashHandleT>(0);
}
// Returns the number of elements in the hash table
[[nodiscard]] int BlockSize() const {
return m_entry_memory_.BlockSize();
}
[[nodiscard]] int Count() const {
return m_entry_memory_.Count();
}
// Returns elements in the table
std::vector<T> GetElements(void);
public:
// Templatized for memory tracking purposes
template <typename DataT>
struct HashFixedDataInternalT {
Keytype m_ui_key;
HashFixedDataInternalT<DataT>* m_next;
DataT m_data;
};
using HashFixedDataT = HashFixedDataInternalT<T>;
// Templatized for memory tracking purposes
template <typename DataT>
struct HashFixedStructDataInternalT {
DataT m_data;
Keytype m_ui_key;
char pad_0x0020[0x8];
};
using HashFixedStructDataT = HashFixedStructDataInternalT<T>;
struct HashStructDataT {
char pad_0x0000[0x10]; // 0x0000
std::array<HashFixedStructDataT, 256> m_list;
};
struct HashAllocatedDataT {
public:
auto GetList() {
return m_list_;
}
private:
char pad_0x0000[0x18]; // 0x0000
std::array<HashFixedDataT, 128> m_list_;
};
// Templatized for memory tracking purposes
template <typename DataT>
struct HashBucketDataInternalT {
DataT m_data;
HashFixedDataInternalT<DataT>* m_next;
Keytype m_ui_key;
};
using HashBucketDataT = HashBucketDataInternalT<T>;
struct HashUnallocatedDataT {
HashUnallocatedDataT* m_next_ = nullptr; // 0x0000
Keytype m_6114; // 0x0008
Keytype m_ui_key; // 0x0010
Keytype m_i_unk_1; // 0x0018
std::array<HashBucketDataT, 256> m_current_block_list; // 0x0020
};
struct HashBucketT {
HashStructDataT* m_struct_data = nullptr;
void* m_mutex_list = nullptr;
HashAllocatedDataT* m_allocated_data = nullptr;
HashUnallocatedDataT* m_unallocated_data = nullptr;
};
CUtlMemoryPool m_entry_memory_;
HashBucketT m_buckets_;
bool m_needs_commit_ = false;
};
template <class T, class Keytype>
std::vector<T> CUtlTSHash<T, Keytype>::GetElements(void) {
std::vector<T> list;
const int n_count = Count();
auto n_index = 0;
auto& unallocated_data = m_buckets_.m_unallocated_data;
for (auto element = unallocated_data; element; element = element->m_next_) {
for (auto i = 0; i < BlockSize() && i != n_count; i++) {
list.emplace_back(element->m_current_block_list.at(i).m_data);
n_index++;
if (n_index >= n_count)
break;
}
}
return list;
}

View File

@@ -1,127 +1,386 @@
/**
* =============================================================================
* CS2Fixes
* Copyright (C) 2023 Source2ZE
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../../utils/virtual.h"
#include <platform.h>
struct CSchemaNetworkValue {
union {
const char* m_sz_value;
int m_n_value;
float m_f_value;
uintptr_t m_p_value;
};
#include <vector>
#include <utils/virtual.h>
#include <string_view>
#include <array>
#include "core/cs2_sdk/interfaces/CUtlTSHash.h"
#define CSGO2
#define CSCHEMATYPE_GETSIZES_INDEX 3
#define SCHEMASYSTEM_TYPE_SCOPES_OFFSET 0x190
#define SCHEMASYSTEMTYPESCOPE_OFF1 0x47E
#define SCHEMASYSTEMTYPESCOPE_OFF2 0x2808
#define SCHEMASYSTEM_FIND_DECLARED_CLASS_TYPE 2
class CSchemaClassInfo;
class CSchemaSystemTypeScope;
class CSchemaType;
struct SchemaMetadataEntryData_t;
struct SchemaMetadataSetData_t;
struct SchemaClassInfoData_t;
using SchemaString_t = const char*;
template <typename T> struct SchemaArray
{
public:
T* begin() const { return m_data; }
T* end() const { return m_data + m_size; }
T* m_data;
unsigned int m_size;
};
struct SchemaMetadataEntryData_t {
const char *m_name;
CSchemaNetworkValue* m_value;
struct CSchemaNetworkValue
{
union
{
const char* m_sz_value;
int m_n_value;
float m_f_value;
std::uintptr_t m_p_value;
};
};
struct CSchemaClassBinding
{
CSchemaClassBinding* parent;
const char* m_binary_name; // ex: C_World
const char* m_module_name; // ex: libclient.so
const char* m_class_name; // ex: client
void* m_class_info_old_synthesized;
void* m_class_info;
void* m_this_module_binding_pointer;
CSchemaType* m_schema_type;
};
struct SchemaEnumeratorInfoData_t
{
SchemaString_t m_name;
union
{
unsigned char m_value_char;
unsigned short m_value_short;
unsigned int m_value_int;
unsigned long long m_value;
};
char pad_0x0010[0x10]; // 0x0010
};
class CSchemaEnumInfo
{
public:
SchemaEnumeratorInfoData_t m_field_;
};
class CSchemaEnumBinding
{
public:
virtual const char* GetBindingName() = 0;
virtual CSchemaClassBinding* AsClassBinding() = 0;
virtual CSchemaEnumBinding* AsEnumBinding() = 0;
virtual const char* GetBinaryName() = 0;
virtual const char* GetProjectName() = 0;
public:
char* m_binding_name_; // 0x0008
char* m_dll_name_; // 0x0010
std::int8_t m_align_; // 0x0018
char pad_0x0019[0x3]; // 0x0019
std::int16_t m_size_; // 0x001C
std::int16_t m_flags_; // 0x001E
SchemaEnumeratorInfoData_t* m_enum_info_;
char pad_0x0028[0x8]; // 0x0028
CSchemaSystemTypeScope* m_type_scope_; // 0x0030
char pad_0x0038[0x8]; // 0x0038
std::int32_t m_i_unk1_; // 0x0040
};
enum SchemaClassFlags_t
{
SCHEMA_CLASS_HAS_VIRTUAL_MEMBERS = 1,
SCHEMA_CLASS_IS_ABSTRACT = 2,
SCHEMA_CLASS_HAS_TRIVIAL_CONSTRUCTOR = 4,
SCHEMA_CLASS_HAS_TRIVIAL_DESTRUCTOR = 8,
SCHEMA_CLASS_TEMP_HACK_HAS_NOSCHEMA_MEMBERS = 16,
SCHEMA_CLASS_TEMP_HACK_HAS_CONSTRUCTOR_LIKE_METHODS = 32,
SCHEMA_CLASS_TEMP_HACK_HAS_DESTRUCTOR_LIKE_METHODS = 64,
SCHEMA_CLASS_IS_NOSCHEMA_CLASS = 128,
};
enum ETypeCategory
{
Schema_Builtin = 0,
Schema_Ptr = 1,
Schema_Bitfield = 2,
Schema_FixedArray = 3,
Schema_Atomic = 4,
Schema_DeclaredClass = 5,
Schema_DeclaredEnum = 6,
Schema_None = 7
};
enum EAtomicCategory
{
Atomic_Basic,
Atomic_T,
Atomic_CollectionOfT,
Atomic_TT,
Atomic_I,
Atomic_None
};
#define __thiscall
class CSchemaType
{
public:
bool GetSizes(int* out_size1, uint8_t* unk_probably_not_size)
{
return reinterpret_cast<int(__thiscall*)(void*, int*, uint8_t*)>(
_vtable[CSCHEMATYPE_GETSIZES_INDEX])(this, out_size1, unk_probably_not_size);
}
public:
bool GetSize(int* out_size)
{
uint8_t smh = 0;
return GetSizes(out_size, &smh);
}
public:
uintptr_t* _vtable; // 0x0000
const char* m_name_; // 0x0008
CSchemaSystemTypeScope* m_type_scope_; // 0x0010
uint8_t type_category; // ETypeCategory 0x0018
uint8_t atomic_category; // EAtomicCategory 0x0019
// find out to what class pointer points.
CSchemaType* GetRefClass()
{
if (type_category != Schema_Ptr)
return nullptr;
auto ptr = m_schema_type_;
while (ptr && ptr->type_category == ETypeCategory::Schema_Ptr)
ptr = ptr->m_schema_type_;
return ptr;
}
struct array_t
{
uint32_t array_size;
uint32_t unknown;
CSchemaType* element_type_;
};
struct generic_type_t {
uint64_t unknown;
const char* m_name_; // 0x0008
};
struct atomic_t
{ // same goes for CollectionOfT
generic_type_t* generic_type;
uint64_t unknown;
CSchemaType* template_typename;
};
struct atomic_tt
{
uint64_t gap[2];
CSchemaType* templates[2];
};
struct atomic_i
{
uint64_t gap[2];
uint64_t integer;
};
// this union depends on CSchema implementation, all members above
// is from base class ( CSchemaType )
union // 0x020
{
CSchemaType* m_schema_type_;
CSchemaClassInfo* m_class_info;
CSchemaEnumBinding* m_enum_binding_;
array_t m_array_;
atomic_t m_atomic_t_;
atomic_tt m_atomic_tt_;
atomic_i m_atomic_i_;
};
};
static_assert(offsetof(CSchemaType, m_schema_type_) == 0x20);
struct SchemaMetadataEntryData_t
{
SchemaString_t m_name;
CSchemaNetworkValue* m_value;
// CSchemaType* m_pDataType;
// void* unaccounted;
};
struct SchemaMetadataSetData_t
{
SchemaMetadataEntryData_t m_static_entries;
};
struct SchemaClassFieldData_t
{
const char *m_name;
char pad0[0x8];
short m_offset;
int32_t m_metadata_size;
SchemaMetadataEntryData_t* m_metadata;
SchemaString_t m_name; // 0x0000
CSchemaType* m_type; // 0x0008
std::int32_t m_single_inheritance_offset; // 0x0010
std::int32_t m_metadata_size; // 0x0014
SchemaMetadataEntryData_t* m_metadata; // 0x0018
};
class SchemaClassInfoData_t;
struct SchemaStaticFieldData_t
{
const char* name; // 0x0000
CSchemaType* m_type; // 0x0008
void* m_instance; // 0x0010
char pad_0x0018[0x10]; // 0x0018
};
struct SchemaBaseClassInfoData_t
{
unsigned int m_offset;
SchemaClassInfoData_t *m_class;
unsigned int m_offset;
CSchemaClassInfo* m_class;
};
class SchemaClassInfoData_t
// Classes
struct SchemaClassInfoData_t
{
public:
auto GetName()
{
return m_name;
}
char pad_0x0000[0x8]; // 0x0000
auto GetFieldsSize()
{
return m_align;
}
const char* m_name; // 0x0008
char* m_module; // 0x0010
auto GetFields()
{
return m_fields;
}
int m_size; // 0x0018
std::int16_t m_align; // 0x001C
SchemaClassInfoData_t* GetParent()
{
if (!m_schema_parent)
return nullptr;
std::int16_t m_static_size; // 0x001E
std::int16_t m_metadata_size; // 0x0020
std::int16_t m_i_unk1; // 0x0022
std::int16_t m_i_unk2; // 0x0024
std::int16_t m_i_unk3; // 0x0026
return m_schema_parent->m_class;
}
SchemaClassFieldData_t* m_fields; // 0x0028
private:
char pad_0x0000[0x8]; // 0x0000
SchemaStaticFieldData_t* m_static_fields; // 0x0030
SchemaBaseClassInfoData_t* m_schema_parent; // 0x0038
const char *m_name; // 0x0008
char *m_module; // 0x0010
char pad_0x0038[0x10]; // 0x0038
int m_size; // 0x0018
int16_t m_align; // 0x001C
SchemaMetadataSetData_t* m_metadata; // 0x0048
CSchemaSystemTypeScope* m_type_scope; // 0x0050
CSchemaType* m_shema_type; // 0x0058
SchemaClassFlags_t m_class_flags : 8; // 0x0060
};
int16_t m_static_size; // 0x001E
int16_t m_metadata_size; // 0x0020
int16_t m_i_unk1; // 0x0022
int16_t m_i_unk2; // 0x0024
int16_t m_i_unk3; // 0x0026
class CSchemaClassInfo : public SchemaClassInfoData_t
{
public:
bool GetMetaStrings(const char* metaName, std::vector<const char**>& strings);
SchemaClassFieldData_t *m_fields; // 0x0028
unsigned int CalculateInheritanceDataSize(bool ignoreVirtuals = false);
char pad_0x0030[0x8]; // 0x0030
SchemaBaseClassInfoData_t *m_schema_parent; // 0x0038
bool DependsOn(CSchemaClassInfo* other);
bool InheritsFrom(CSchemaClassInfo* other);
bool UsesClass(CSchemaClassInfo* other);
bool InheritsVirtuals();
char pad_0x0038[0x10]; // 0x0038
void FillClassFieldsList(std::vector<SchemaClassFieldData_t*>& fields);
void FillInheritanceList(std::vector<const char*>& inheritance);
CSchemaClassInfo* GetParent()
{
if (!m_schema_parent)
return nullptr;
return m_schema_parent->m_class;
}
private:
};
class CSchemaSystemTypeScope
{
public:
SchemaClassInfoData_t* FindDeclaredClass(const char *pClass)
{
#ifdef _WIN32
SchemaClassInfoData_t *rv = nullptr;
CALL_VIRTUAL(void, 2, this, &rv, pClass);
return rv;
#else
return CALL_VIRTUAL(SchemaClassInfoData_t*, 2, this, pClass);
#endif
}
public:
CSchemaClassInfo* FindDeclaredClass(const char* class_name)
{
return CALL_VIRTUAL(CSchemaClassInfo*, 2, this, class_name);
}
CSchemaEnumBinding* FindDeclaredEnum(const char* name)
{
return CALL_VIRTUAL(CSchemaEnumBinding*, 3, this, name);
}
CSchemaType* FindSchemaTypeByName(const char* name, std::uintptr_t* pSchema)
{
return CALL_VIRTUAL(CSchemaType*, 4, this, name, pSchema);
}
CSchemaType* FindTypeDeclaredClass(const char* name)
{
return CALL_VIRTUAL(CSchemaType*, 5, this, name);
}
CSchemaType* FindTypeDeclaredEnum(const char* name)
{
return CALL_VIRTUAL(CSchemaType*, 6, this, name);
}
CSchemaClassBinding* FindRawClassBinding(const char* name)
{
return CALL_VIRTUAL(CSchemaClassBinding*, 7, this, name);
}
CSchemaEnumBinding* FindRawEnumBinding(const char* name)
{
return CALL_VIRTUAL(CSchemaEnumBinding*, 8, this, name);
}
std::string_view GetScopeName() {
return {m_name_.data()};
}
[[nodiscard]] CUtlTSHash<CSchemaClassBinding*> GetClasses() const {
return m_classes_;
}
[[nodiscard]] CUtlTSHash<CSchemaEnumBinding*> GetEnums() const {
return m_enumes_;
}
private:
char pad_0x0000[0x8]; // 0x0000
std::array<char, 256> m_name_ = {};
char pad_0x0108[SCHEMASYSTEMTYPESCOPE_OFF1]; // 0x0108
CUtlTSHash<CSchemaClassBinding*> m_classes_; // 0x0588
char pad_0x0594[SCHEMASYSTEMTYPESCOPE_OFF2]; // 0x05C8
CUtlTSHash<CSchemaEnumBinding*> m_enumes_; // 0x2DD0
private:
static constexpr unsigned int s_class_list = 0x580;
};
class CSchemaSystem
{
public:
auto FindTypeScopeForModule(const char *module)
{
return CALL_VIRTUAL(CSchemaSystemTypeScope *, 13, this, module, nullptr);
}
};
public:
CSchemaSystemTypeScope* GlobalTypeScope(void)
{
return CALL_VIRTUAL(CSchemaSystemTypeScope*, 11, this);
}
CSchemaSystemTypeScope* FindTypeScopeForModule(const char* m_module_name)
{
return CALL_VIRTUAL(CSchemaSystemTypeScope*, 13, this, m_module_name, nullptr);
}
};

View File

@@ -57,8 +57,8 @@ static bool InitSchemaFieldsForClass(SchemaTableMap_t* tableMap,
return false;
}
short fieldsSize = pClassInfo->GetFieldsSize();
SchemaClassFieldData_t* pFields = pClassInfo->GetFields();
short fieldsSize = pClassInfo->m_align;
SchemaClassFieldData_t* pFields = pClassInfo->m_fields;
SchemaKeyValueMap_t* keyValueMap = new SchemaKeyValueMap_t(0, 0, DefLessFunc(uint32_t));
keyValueMap->EnsureCapacity(fieldsSize);
@@ -68,7 +68,7 @@ static bool InitSchemaFieldsForClass(SchemaTableMap_t* tableMap,
SchemaClassFieldData_t& field = pFields[i];
keyValueMap->Insert(hash_32_fnv1a_const(field.m_name),
{field.m_offset, IsFieldNetworked(field)});
{field.m_single_inheritance_offset, IsFieldNetworked(field)});
}
return true;
@@ -80,16 +80,16 @@ int16_t schema::FindChainOffset(const char* className) {
if (!pType) return false;
SchemaClassInfoData_t* pClassInfo = pType->FindDeclaredClass(className);
auto* pClassInfo = pType->FindDeclaredClass(className);
do {
SchemaClassFieldData_t* pFields = pClassInfo->GetFields();
short fieldsSize = pClassInfo->GetFieldsSize();
SchemaClassFieldData_t* pFields = pClassInfo->m_fields;
short fieldsSize = pClassInfo->m_align;
for (int i = 0; i < fieldsSize; ++i) {
SchemaClassFieldData_t& field = pFields[i];
if (V_strcmp(field.m_name, "__m_pChainEntity") == 0) {
return field.m_offset;
return field.m_single_inheritance_offset;
}
}
} while ((pClassInfo = pClassInfo->GetParent()) != nullptr);

View File

@@ -39,7 +39,7 @@
#undef schema
struct SchemaKey {
int16_t offset;
int32_t offset;
bool networked;
};

View File

@@ -38,9 +38,123 @@
#include "scripting/callback_manager.h"
#include "core/log.h"
#include "core/cs2_sdk/interfaces/cschemasystem.h"
#include "core/utils.h"
#include "core/memory.h"
#include "interfaces/cs2_interfaces.h"
#include <nlohmann/json.hpp>
using json = nlohmann::json;
namespace counterstrikesharp {
json WriteTypeJson(json obj, CSchemaType* current_type)
{
obj["name"] = current_type->m_name_;
obj["category"] = current_type->type_category;
if (current_type->type_category == Schema_Atomic) {
obj["atomic"] = current_type->atomic_category;
if (current_type->atomic_category == Atomic_T &&
current_type->m_atomic_t_.generic_type != nullptr) {
obj["outer"] = current_type->m_atomic_t_.generic_type->m_name_;
}
if (current_type->atomic_category == Atomic_T ||
current_type->atomic_category == Atomic_CollectionOfT) {
obj["inner"] =
WriteTypeJson(json::object(), current_type->m_atomic_t_.template_typename);
}
} else if (current_type->type_category == Schema_FixedArray) {
obj["inner"] = WriteTypeJson(json::object(), current_type->m_array_.element_type_);
} else if (current_type->type_category == Schema_Ptr) {
obj["inner"] = WriteTypeJson(json::object(), current_type->m_schema_type_);
}
return obj;
}
CON_COMMAND(dump_schema, "dump schema symbols")
{
std::vector<std::string> classNames;
std::vector<std::string> enumNames;
// Reading these from a static file since I cannot seem to get the
// CSchemaSystemTypeScope->GetClasses() to return anything on linux.
std::ifstream inputClasses(utils::GamedataDirectory() + "/schema_classes.txt");
std::ifstream inputEnums(utils::GamedataDirectory() + "/schema_enums.txt");
std::ofstream output(utils::GamedataDirectory() + "/schema.json");
std::string line;
while (std::getline(inputClasses, line)) {
if (!line.empty() && line.back() == '\r') {
line.pop_back();
}
classNames.push_back(line);
}
while (std::getline(inputEnums, line)) {
if (!line.empty() && line.back() == '\r') {
line.pop_back();
}
enumNames.push_back(line);
}
CSchemaSystemTypeScope* pType =
interfaces::pSchemaSystem->FindTypeScopeForModule(MODULE_PREFIX "server" MODULE_EXT);
json j;
j["classes"] = json::object();
j["enums"] = json::object();
for (const auto& line : classNames) {
SchemaClassInfoData_t* pClassInfo = pType->FindDeclaredClass(line.c_str());
if (!pClassInfo)
continue;
short fieldsSize = pClassInfo->m_align;
SchemaClassFieldData_t* pFields = pClassInfo->m_fields;
j["classes"][pClassInfo->m_name] = json::object();
if (pClassInfo->m_schema_parent) {
j["classes"][pClassInfo->m_name]["parent"] =
pClassInfo->m_schema_parent->m_class->m_name;
}
j["classes"][pClassInfo->m_name]["fields"] = json::array();
for (int i = 0; i < fieldsSize; ++i) {
SchemaClassFieldData_t& field = pFields[i];
j["classes"][pClassInfo->m_name]["fields"].push_back({
{"name", field.m_name},
{"type", WriteTypeJson(json::object(), field.m_type)},
});
}
}
for (const auto& line : enumNames) {
auto* pEnumInfo = pType->FindDeclaredEnum(line.c_str());
if (!pEnumInfo)
continue;
j["enums"][pEnumInfo->m_binding_name_] = json::object();
j["enums"][pEnumInfo->m_binding_name_]["align"] = pEnumInfo->m_align_;
j["enums"][pEnumInfo->m_binding_name_]["items"] = json::array();
for (int i = 0; i < pEnumInfo->m_size_; ++i) {
auto& field = pEnumInfo->m_enum_info_[i];
j["enums"][pEnumInfo->m_binding_name_]["items"].push_back({
{"name", field.m_name},
{"value", field.m_value},
});
}
}
Msg("Schema dumped to %s\n", (utils::GamedataDirectory() + "/schema.json").c_str());
output << std::setw(2) << j << std::endl;
}
SH_DECL_HOOK2_void(
ConCommandHandle, Dispatch, SH_NOATTRIB, false, const CCommandContext&, const CCommand&);

View File

@@ -21,7 +21,7 @@ inline std::string GameDirectory() {
}
inline std::string PluginDirectory() { return GameDirectory() + "/addons/counterstrikesharp"; }
inline std::string GamedataDirectory() { return GameDirectory() + "/addons/counterstrikesharp/gamedata"; }
inline std::string ConfigDirectory() { return PluginDirectory() + "/config"; }
} // namespace utils
} // namespace counterstrikesharp