This commit is contained in:
Oscar 2025-06-08 23:47:32 +03:00
parent 160429eae6
commit 38754d2b59
45 changed files with 9857 additions and 0 deletions

77
Assets/LaserMesh.vmdl Normal file
View File

@ -0,0 +1,77 @@
<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:modeldoc29:version{3cec427c-1b0e-4d48-a90a-0436f33a6041} -->
{
rootNode =
{
_class = "RootNode"
children =
[
{
_class = "MaterialGroupList"
children =
[
{
_class = "DefaultMaterialGroup"
remaps =
[
]
use_global_default = false
global_default_material = "materials/default.vmat"
},
]
},
{
_class = "RenderMeshList"
children =
[
{
_class = "RenderMeshFile"
filename = "models/LaserMesh/LaserMesh.fbx"
import_translation = [ 0.0, 0.0, 0.0 ]
import_rotation = [ 0.0, 0.0, 0.0 ]
import_scale = 1
align_origin_x_type = "None"
align_origin_y_type = "None"
align_origin_z_type = "None"
parent_bone = ""
import_filter =
{
exclude_by_default = false
exception_list = []
}
},
]
},
{
_class = "ModelModifierList"
children =
[
{
_class = "ModelModifier_ScaleAndMirror"
scale = 0.3937000036239624
mirror_x = false
mirror_y = false
mirror_z = false
flip_bone_forward = false
swap_left_and_right_bones = false
},
]
},
{
_class = "PhysicsShapeList"
children =
[
{
_class = "PhysicsMeshFromRender"
parent_bone = ""
surface_prop = "default"
collision_tags = "solid"
},
]
}
]
model_archetype = ""
primary_associated_entity = ""
anim_graph_name = ""
base_model_name = ""
}
}

146
Assets/Pistol.vmdl Normal file
View File

@ -0,0 +1,146 @@
<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:modeldoc29:version{3cec427c-1b0e-4d48-a90a-0436f33a6041} -->
{
rootNode =
{
_class = "RootNode"
children =
[
{
_class = "MaterialGroupList"
children =
[
{
_class = "DefaultMaterialGroup"
remaps =
[
{
from = "fabric.003.vmat"
to = "materials/pistol/fabric.003.vmat"
},
{
from = "glow.vmat"
to = "materials/pistol/glow.vmat"
},
{
from = "plastic.vmat"
to = "materials/pistol/plastic.vmat"
},
{
from = "metal.1.vmat"
to = "materials/pistol/metal.1.vmat"
},
]
use_global_default = false
global_default_material = "materials/default.vmat"
},
]
},
{
_class = "RenderMeshList"
children =
[
{
_class = "RenderMeshFile"
filename = "models/my_citizen/pistol_new.fbx"
import_translation = [ 0.0, 0.0, 0.0 ]
import_rotation = [ 0.0, 0.0, 0.0 ]
import_scale = 1.0
align_origin_x_type = "None"
align_origin_y_type = "None"
align_origin_z_type = "None"
parent_bone = ""
import_filter =
{
exclude_by_default = false
exception_list = [ ]
}
},
]
},
{
_class = "ModelModifierList"
children =
[
{
_class = "ModelModifier_ScaleAndMirror"
scale = 0.3937
mirror_x = false
mirror_y = false
mirror_z = false
flip_bone_forward = false
swap_left_and_right_bones = false
},
]
},
{
_class = "PhysicsShapeList"
children =
[
{
_class = "PhysicsMeshFromRender"
parent_bone = ""
surface_prop = "default"
collision_tags = "solid"
},
]
},
{
_class = "AnimationList"
children =
[
{
_class = "AnimFile"
name = "pistol_new"
activity_name = ""
activity_weight = 1
weight_list_name = ""
fade_in_time = 0.2
fade_out_time = 0.2
looping = false
delta = false
worldSpace = false
hidden = false
anim_markup_ordered = false
disable_compression = false
disable_interpolation = false
enable_scale = false
source_filename = "models/my_citizen/pistol_new.fbx"
start_frame = -1
end_frame = -1
framerate = -1.0
take = 1
reverse = false
},
{
_class = "AnimFile"
name = "pistol_new1"
activity_name = "Fire"
activity_weight = 1
weight_list_name = ""
fade_in_time = 0.2
fade_out_time = 0.2
looping = false
delta = false
worldSpace = false
hidden = false
anim_markup_ordered = false
disable_compression = false
disable_interpolation = false
enable_scale = false
source_filename = "models/my_citizen/pistol_new.fbx"
start_frame = -1
end_frame = -1
framerate = -1.0
take = 0
reverse = false
},
]
default_root_bone_name = ""
},
]
model_archetype = ""
primary_associated_entity = ""
anim_graph_name = "animgraphs/pistol.vanmgrph"
base_model_name = ""
}
}

View File

@ -0,0 +1,282 @@
<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:animgraph2:version{0f7898b8-5471-45c4-9867-cd9c46bcfdb5} -->
{
_class = "CAnimationGraph"
m_nodeManager =
{
_class = "CAnimNodeManager"
m_nodes =
[
{
key =
{
m_id = 80340519
}
value =
{
_class = "CStateMachineAnimNode"
m_sName = "Unnamed"
m_vecPosition = [ -256.0, -192.0 ]
m_nNodeID =
{
m_id = 80340519
}
m_sNote = ""
m_states =
[
{
_class = "CAnimState"
m_transitions =
[
{
_class = "CAnimStateTransition"
m_conditions =
[
{
_class = "CParameterAnimCondition"
m_comparisonOp = 0
m_paramID =
{
m_id = 99224662
}
m_comparisonValue =
{
m_nType = 1
m_data = true
}
},
]
m_blendDuration = 0.2
m_destState =
{
m_id = 52598034
}
m_bReset = true
m_resetCycleOption = "Beginning"
m_flFixedCycleValue = 0.0
m_bBlendCycle = false
m_blendCurve =
{
m_vControlPoint1 = [ 0.5, 0.0 ]
m_vControlPoint2 = [ 0.5, 1.0 ]
}
m_bForceFootPlant = false
m_bDisabled = false
m_bRandomTimeBetween = false
m_flRandomTimeStart = 0.0
m_flRandomTimeEnd = 0.0
},
]
m_tags = [ ]
m_tagBehaviors = [ ]
m_name = "idle"
m_inputConnection =
{
m_nodeID =
{
m_id = 4294967295
}
m_outputID =
{
m_id = 4294967295
}
}
m_stateID =
{
m_id = 556431534
}
m_position = [ -144.0, -96.0 ]
m_bIsStartState = true
m_bIsEndtState = false
m_bIsPassthrough = false
m_bIsRootMotionExclusive = false
m_bAlwaysEvaluate = false
},
{
_class = "CAnimState"
m_transitions =
[
{
_class = "CAnimStateTransition"
m_conditions =
[
{
_class = "CFinishedCondition"
m_comparisonOp = 0
m_option = "FinishedConditionOption_OnFinished"
m_bIsFinished = true
},
{
_class = "CTimeCondition"
m_comparisonOp = 3
m_comparisonValue = 0.1
},
]
m_blendDuration = 0.2
m_destState =
{
m_id = 556431534
}
m_bReset = true
m_resetCycleOption = "Beginning"
m_flFixedCycleValue = 0.0
m_bBlendCycle = false
m_blendCurve =
{
m_vControlPoint1 = [ 0.5, 0.0 ]
m_vControlPoint2 = [ 0.5, 1.0 ]
}
m_bForceFootPlant = false
m_bDisabled = false
m_bRandomTimeBetween = false
m_flRandomTimeStart = 0.0
m_flRandomTimeEnd = 0.0
},
]
m_tags = [ ]
m_tagBehaviors = [ ]
m_name = "shoot"
m_inputConnection =
{
m_nodeID =
{
m_id = 478164850
}
m_outputID =
{
m_id = 4294967295
}
}
m_stateID =
{
m_id = 52598034
}
m_position = [ -16.0, -96.0 ]
m_bIsStartState = false
m_bIsEndtState = false
m_bIsPassthrough = false
m_bIsRootMotionExclusive = false
m_bAlwaysEvaluate = false
},
]
m_bBlockWaningTags = false
m_bLockStateWhenWaning = false
}
},
{
key =
{
m_id = 478164850
}
value =
{
_class = "CSequenceAnimNode"
m_sName = "fire"
m_vecPosition = [ -464.0, -48.0 ]
m_nNodeID =
{
m_id = 478164850
}
m_sNote = ""
m_tagSpans = [ ]
m_sequenceName = "pistol_new"
m_playbackSpeed = 2.0
m_bLoop = false
}
},
{
key =
{
m_id = 1221959074
}
value =
{
_class = "CRootAnimNode"
m_sName = "Unnamed"
m_vecPosition = [ -16.0, -48.0 ]
m_nNodeID =
{
m_id = 1221959074
}
m_sNote = ""
m_inputConnection =
{
m_nodeID =
{
m_id = 80340519
}
m_outputID =
{
m_id = 4294967295
}
}
}
},
]
}
m_pParameterList =
{
_class = "CAnimParameterList"
m_Parameters =
[
{
_class = "CBoolAnimParameter"
m_name = "Fire"
m_id =
{
m_id = 99224662
}
m_previewButton = "ANIMPARAM_BUTTON_NONE"
m_bUseMostRecentValue = false
m_bAutoReset = true
m_bDefaultValue = false
},
]
}
m_pTagManager =
{
_class = "CAnimTagManager"
m_tags = [ ]
}
m_pMovementManager =
{
_class = "CAnimMovementManager"
m_MotorList =
{
_class = "CAnimMotorList"
m_motors = [ ]
}
m_MovementSettings =
{
_class = "CAnimMovementSettings"
m_bShouldCalculateSlope = false
}
}
m_pSettingsManager =
{
_class = "CAnimGraphSettingsManager"
m_settingsGroups =
[
{
_class = "CAnimGraphGeneralSettings"
m_iGridSnap = 16
},
]
}
m_pActivityValuesList =
{
_class = "CActivityValueList"
m_activities = [ ]
}
m_previewModels =
[
"models/my_citizen/pistol_new.vmdl",
]
m_boneMergeModels = [ ]
m_cameraSettings =
{
m_flFov = 60.0
m_sLockBoneName = "Bone"
m_bLockCamera = false
m_bViewModelCamera = false
}
}

View File

@ -0,0 +1,42 @@
// THIS FILE IS AUTO-GENERATED
Layer0
{
shader "shaders/complex.shader"
//---- PBR ----
F_SPECULAR 1
//---- Ambient Occlusion ----
g_flAmbientOcclusionDirectDiffuse "0.000"
g_flAmbientOcclusionDirectSpecular "0.000"
TextureAmbientOcclusion "materials/default/default_ao.tga"
//---- Color ----
g_flModelTintAmount "1.000"
g_vColorTint "[1.000000 1.000000 1.000000 1.000000]"
TextureColor "textures/Pistol/Fabric080_1K-PNG_Color.png"
//---- Fade ----
g_flFadeExponent "1.000"
//---- Fog ----
g_bFogEnabled "1"
//---- Metalness ----
g_flMetalness "0.000"
//---- Normal ----
TextureNormal "textures/Pistol/Fabric080_1K-PNG_NormalGL_norm.png"
//---- Roughness ----
g_flRoughnessScaleFactor "2.000"
TextureRoughness "textures/Pistol/Fabric080_1K-PNG_Roughness.png"
//---- Texture Coordinates ----
g_nScaleTexCoordUByModelScaleAxis "0"
g_nScaleTexCoordVByModelScaleAxis "0"
g_vTexCoordOffset "[0.000 0.000]"
g_vTexCoordScale "[1.000 1.000]"
g_vTexCoordScrollSpeed "[0.000 0.000]"
}

View File

@ -0,0 +1,51 @@
// THIS FILE IS AUTO-GENERATED
Layer0
{
shader "shaders/complex.shader"
//---- PBR ----
F_SELF_ILLUM 1
F_SPECULAR 1
//---- Ambient Occlusion ----
g_flAmbientOcclusionDirectDiffuse "0.000"
g_flAmbientOcclusionDirectSpecular "0.000"
TextureAmbientOcclusion "materials/default/default_ao.tga"
//---- Color ----
g_flModelTintAmount "1.000"
g_vColorTint "[0.019608 0.000000 1.000000 1.000000]"
TextureColor "materials/default/default_color.tga"
//---- Fade ----
g_flFadeExponent "1.000"
//---- Fog ----
g_bFogEnabled "1"
//---- Metalness ----
g_flMetalness "0.000"
//---- Normal ----
TextureNormal "materials/default/default_normal.tga"
//---- Roughness ----
g_flRoughnessScaleFactor "0.000"
TextureRoughness "materials/default/default_rough.tga"
//---- Self Illum ----
g_flSelfIllumAlbedoFactor "1.000"
g_flSelfIllumBrightness "10.000"
g_flSelfIllumScale "16.000"
g_vSelfIllumScrollSpeed "[0.000 0.000]"
g_vSelfIllumTint "[0.054902 0.043137 0.807843 1.000000]"
TextureSelfIllumMask "[1.000000 1.000000 1.000000 0.000000]"
//---- Texture Coordinates ----
g_nScaleTexCoordUByModelScaleAxis "0"
g_nScaleTexCoordVByModelScaleAxis "0"
g_vTexCoordOffset "[0.000 0.000]"
g_vTexCoordScale "[1.000 1.000]"
g_vTexCoordScrollSpeed "[0.000 0.000]"
}

View File

@ -0,0 +1,36 @@
// THIS FILE IS AUTO-GENERATED
Layer0
{
shader "shaders/glass_scope.shader"
//---- Fog ----
g_bFogEnabled "0"
//---- Glass ----
g_flBlurAmount "0.696"
g_flIridescence "821.429"
g_flIridescenceScale "10.000"
g_flRefractionStrength "1.009"
g_flSightDistanceScale "4.167"
g_vSightLightColor "[0.019608 0.019608 0.458824 1.000000]"
//---- Material ----
g_flTintColor "[1.000000 0.262745 0.000000 0.000000]"
TextureAmbientOcclusion "materials/default/default_ao.tga"
TextureBlendMask "[0.000000 0.000000 0.000000 0.000000]"
TextureColor "[0.254902 0.411765 0.882353 1.000000]"
TextureMetalness "[0.000000 0.000000 0.000000 0.000000]"
TextureNormal "materials/default/default_normal.tga"
TextureRoughness "[1.000000 1.000000 1.000000 0.000000]"
TextureTintMask "[0.983000 0.983000 0.983000 0.000000]"
TextureTranslucency "[0.000000 0.000000 0.000000 0.000000]"
//---- Sight Dot ----
RedDot "materials/default/default_color.tga"
RedDot2 "materials/default/default_color.tga"
RedDot3 "materials/default/default_color.tga"
//---- Translucent ----
g_flOpacityScale "0.054"
}

View File

@ -0,0 +1,43 @@
// THIS FILE IS AUTO-GENERATED
Layer0
{
shader "shaders/complex.shader"
//---- PBR ----
F_METALNESS_TEXTURE 1
F_SPECULAR 1
//---- Ambient Occlusion ----
g_flAmbientOcclusionDirectDiffuse "0.000"
g_flAmbientOcclusionDirectSpecular "0.000"
TextureAmbientOcclusion "materials/default/default_ao.tga"
//---- Color ----
g_flModelTintAmount "1.000"
g_vColorTint "[1.000000 1.000000 1.000000 1.000000]"
TextureColor "textures/Pistol/Metal055A_1K-PNG_Color.png"
//---- Fade ----
g_flFadeExponent "1.000"
//---- Fog ----
g_bFogEnabled "1"
//---- Metalness ----
TextureMetalness "textures/Pistol/Metal055A_1K-PNG_Metalness.png"
//---- Normal ----
TextureNormal "textures/Pistol/Metal055A_1K-PNG_NormalGL_norm.png"
//---- Roughness ----
g_flRoughnessScaleFactor "1.012"
TextureRoughness "textures/Pistol/Metal055A_1K-PNG_Roughness.png"
//---- Texture Coordinates ----
g_nScaleTexCoordUByModelScaleAxis "0"
g_nScaleTexCoordVByModelScaleAxis "0"
g_vTexCoordOffset "[0.000 0.000]"
g_vTexCoordScale "[1.000 1.000]"
g_vTexCoordScrollSpeed "[0.000 0.000]"
}

View File

@ -0,0 +1,42 @@
// THIS FILE IS AUTO-GENERATED
Layer0
{
shader "shaders/complex.shader"
//---- PBR ----
F_SPECULAR 1
//---- Ambient Occlusion ----
g_flAmbientOcclusionDirectDiffuse "0.000"
g_flAmbientOcclusionDirectSpecular "0.000"
TextureAmbientOcclusion "materials/default/default_ao.tga"
//---- Color ----
g_flModelTintAmount "1.000"
g_vColorTint "[0.141176 0.141176 0.141176 1.000000]"
TextureColor "materials/default/default_color.tga"
//---- Fade ----
g_flFadeExponent "1.000"
//---- Fog ----
g_bFogEnabled "1"
//---- Metalness ----
g_flMetalness "0.000"
//---- Normal ----
TextureNormal "textures/Pistol/Plastic018A_1K-PNG_NormalDX_norm.png"
//---- Roughness ----
g_flRoughnessScaleFactor "0.607"
TextureRoughness "textures/Pistol/Plastic018A_1K-PNG_Roughness.png"
//---- Texture Coordinates ----
g_nScaleTexCoordUByModelScaleAxis "0"
g_nScaleTexCoordVByModelScaleAxis "0"
g_vTexCoordOffset "[0.000 0.000]"
g_vTexCoordScale "[1.000 1.000]"
g_vTexCoordScrollSpeed "[0.000 0.000]"
}

BIN
Assets/models/LaserMesh/LaserMesh.fbx (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Assets/models/my_citizen/pistol_1.fbx (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,89 @@
<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:modeldoc29:version{3cec427c-1b0e-4d48-a90a-0436f33a6041} -->
{
rootNode =
{
_class = "RootNode"
children =
[
{
_class = "MaterialGroupList"
children =
[
{
_class = "DefaultMaterialGroup"
remaps = [ ]
use_global_default = true
global_default_material = "materials/default.vmat"
},
]
},
{
_class = "RenderMeshList"
children =
[
{
_class = "RenderMeshFile"
filename = "models/my_citizen/pistol_1.fbx"
import_translation = [ 0.0, 0.0, 0.0 ]
import_rotation = [ 0.0, 0.0, 0.0 ]
import_scale = 1.0
align_origin_x_type = "None"
align_origin_y_type = "None"
align_origin_z_type = "None"
parent_bone = ""
import_filter =
{
exclude_by_default = true
exception_list =
[
"Laser_low",
"Mag_low",
"Magdown_low",
"Slide_low",
"Trigger_low",
"Barell_low",
"Body_low",
"Button_low",
"Hook_low",
]
}
},
]
},
{
_class = "AnimationList"
children =
[
{
_class = "AnimFile"
name = "shoot"
activity_name = " "
activity_weight = 1
weight_list_name = ""
fade_in_time = 0.2
fade_out_time = 0.2
looping = false
delta = false
worldSpace = false
hidden = false
anim_markup_ordered = false
disable_compression = false
disable_interpolation = false
enable_scale = false
source_filename = "models/my_citizen/shoot.fbx"
start_frame = -1
end_frame = -1
framerate = -1.0
take = 0
reverse = false
},
]
default_root_bone_name = ""
},
]
model_archetype = ""
primary_associated_entity = ""
anim_graph_name = ""
base_model_name = ""
}
}

BIN
Assets/models/my_citizen/pistol_new.fbx (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,89 @@
<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:modeldoc29:version{3cec427c-1b0e-4d48-a90a-0436f33a6041} -->
{
rootNode =
{
_class = "RootNode"
children =
[
{
_class = "MaterialGroupList"
children =
[
{
_class = "DefaultMaterialGroup"
remaps = [ ]
use_global_default = true
global_default_material = "materials/default.vmat"
},
]
},
{
_class = "RenderMeshList"
children =
[
{
_class = "RenderMeshFile"
filename = "models/my_citizen/pistol_new.fbx"
import_translation = [ 0.0, 0.0, 0.0 ]
import_rotation = [ 0.0, 0.0, 0.0 ]
import_scale = 1.0
align_origin_x_type = "None"
align_origin_y_type = "None"
align_origin_z_type = "None"
parent_bone = ""
import_filter =
{
exclude_by_default = true
exception_list =
[
"Barell_low",
"Body_low",
"Button_low",
"Hook_low",
"Laser_low",
"Mag_low",
"Magdown_low",
"Trigger_low",
"Slide_low",
]
}
},
]
},
{
_class = "AnimationList"
children =
[
{
_class = "AnimFile"
name = "pistol_new"
activity_name = ""
activity_weight = 1
weight_list_name = ""
fade_in_time = 0.2
fade_out_time = 0.2
looping = false
delta = false
worldSpace = false
hidden = false
anim_markup_ordered = false
disable_compression = false
disable_interpolation = false
enable_scale = false
source_filename = "models/my_citizen/pistol_new.fbx"
start_frame = -1
end_frame = -1
framerate = -1.0
take = 1
reverse = false
},
]
default_root_bone_name = ""
},
]
model_archetype = ""
primary_associated_entity = ""
anim_graph_name = ""
base_model_name = ""
}
}

BIN
Assets/models/pistol/pistol.fbx (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,111 @@
<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:modeldoc29:version{3cec427c-1b0e-4d48-a90a-0436f33a6041} -->
{
rootNode =
{
_class = "RootNode"
children =
[
{
_class = "MaterialGroupList"
children =
[
{
_class = "DefaultMaterialGroup"
remaps =
[
{
from = "metal.1.vmat"
to = "materials/pistol/metal.1.vmat"
},
{
from = "glow.vmat"
to = "materials/pistol/glow.vmat"
},
{
from = "fabric.003.vmat"
to = "materials/pistol/fabric.003.vmat"
},
{
from = "plastic.vmat"
to = "materials/pistol/plastic.vmat"
},
]
use_global_default = false
global_default_material = "materials/default.vmat"
},
]
},
{
_class = "RenderMeshList"
children =
[
{
_class = "RenderMeshFile"
filename = "models/pistol/pistol.fbx"
import_translation = [ 0.0, 0.0, 0.0 ]
import_rotation = [ 0.0, 0.0, 0.0 ]
import_scale = 1.0
align_origin_x_type = "None"
align_origin_y_type = "None"
align_origin_z_type = "None"
parent_bone = ""
import_filter =
{
exclude_by_default = false
exception_list = [ ]
}
},
]
},
{
_class = "ModelModifierList"
children =
[
{
_class = "ModelModifier_ScaleAndMirror"
scale = 0.3937
mirror_x = false
mirror_y = false
mirror_z = false
flip_bone_forward = false
swap_left_and_right_bones = false
},
]
},
{
_class = "AnimationList"
children =
[
{
_class = "AnimFile"
name = "shoot"
activity_name = ""
activity_weight = 1
weight_list_name = ""
fade_in_time = 0.2
fade_out_time = 0.2
looping = false
delta = false
worldSpace = false
hidden = false
anim_markup_ordered = false
disable_compression = false
disable_interpolation = false
enable_scale = false
source_filename = "models/my_citizen/shoot.fbx"
start_frame = -1
end_frame = -1
framerate = -1.0
take = 0
reverse = false
},
]
default_root_bone_name = ""
},
]
model_archetype = ""
primary_associated_entity = ""
anim_graph_name = ""
base_model_name = ""
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,308 @@
{
"RootObject": {
"__guid": "ede7b66f-b9b2-4524-9933-4c2919ff6ae0",
"__version": 1,
"Flags": 0,
"Name": "citizen_enemy",
"Position": "0,0,0",
"Rotation": "0,0,0,1",
"Scale": "1,1,1",
"Tags": "",
"Enabled": true,
"NetworkMode": 1,
"NetworkInterpolation": true,
"NetworkOrphaned": 0,
"OwnerTransfer": 1,
"Components": [
{
"__type": "Sandbox.NavMeshAgent",
"__guid": "dae8d611-15ad-4020-b1ab-c13b66ff07e9",
"__enabled": true,
"Acceleration": 520,
"AutoTraverseLinks": true,
"Height": 90.799995,
"MaxSpeed": 400,
"OnComponentDestroy": null,
"OnComponentDisabled": null,
"OnComponentEnabled": null,
"OnComponentFixedUpdate": null,
"OnComponentStart": null,
"OnComponentUpdate": null,
"Radius": 16,
"Separation": 0.22,
"UpdatePosition": true,
"UpdateRotation": true
},
{
"__type": "Enemy",
"__guid": "f1949fb9-f84d-44f2-b7e1-d964942ced50",
"__enabled": true,
"agent": {
"_type": "component",
"component_id": "dae8d611-15ad-4020-b1ab-c13b66ff07e9",
"go": "ede7b66f-b9b2-4524-9933-4c2919ff6ae0",
"component_type": "NavMeshAgent"
},
"AnimationHelper": {
"_type": "component",
"component_id": "984e8c33-bf4a-4058-8cba-2da8bbc75f75",
"go": "ede7b66f-b9b2-4524-9933-4c2919ff6ae0",
"component_type": "CitizenAnimationHelper"
},
"AttackCooldown": 1,
"AttackRadius": 110,
"bloodParticle": {
"_type": "gameobject",
"prefab": "prefabs/impacts/impact.flesh.mist.prefab"
},
"CurrentState": "Idle",
"DetectionRadius": 600,
"Health": 100,
"HitSound": {
"_type": "component",
"component_id": "88969834-8bec-4a74-8b16-c258c0377501",
"go": "ede7b66f-b9b2-4524-9933-4c2919ff6ae0",
"component_type": "SoundPointComponent"
},
"MaxSpeed": 400,
"OnComponentDestroy": null,
"OnComponentDisabled": null,
"OnComponentEnabled": null,
"OnComponentFixedUpdate": null,
"OnComponentStart": null,
"OnComponentUpdate": null,
"RagdollController": {
"_type": "component",
"component_id": "16b8ed44-1abd-4f32-bf92-2bc21b785bc0",
"go": "ede7b66f-b9b2-4524-9933-4c2919ff6ae0",
"component_type": "RagdollController"
},
"renderer": {
"_type": "component",
"component_id": "981fee12-feca-4cff-b1fe-32b783e1a1dc",
"go": "ede7b66f-b9b2-4524-9933-4c2919ff6ae0",
"component_type": "SkinnedModelRenderer"
}
},
{
"__type": "Sandbox.SkinnedModelRenderer",
"__guid": "981fee12-feca-4cff-b1fe-32b783e1a1dc",
"__enabled": true,
"AnimationGraph": null,
"BodyGroups": 341,
"BoneMergeTarget": null,
"CreateAttachments": false,
"CreateBoneObjects": false,
"MaterialGroup": null,
"MaterialOverride": "models/terryisdead/citizen_skin04.vmat",
"Model": "models/terryisdead/citizen_terryisdead.vmdl",
"Morphs": {},
"OnComponentDestroy": null,
"OnComponentDisabled": null,
"OnComponentEnabled": null,
"OnComponentFixedUpdate": null,
"OnComponentStart": null,
"OnComponentUpdate": null,
"Parameters": {
"bools": {},
"ints": {},
"floats": {},
"vectors": {},
"rotations": {}
},
"PlaybackRate": 1,
"RenderOptions": {
"GameLayer": true,
"OverlayLayer": false,
"BloomLayer": false,
"AfterUILayer": false
},
"RenderType": "On",
"Sequence": {
"Name": null,
"Looping": true,
"Blending": false
},
"Tint": "1,1,1,1",
"UseAnimGraph": true
},
{
"__type": "Sandbox.Citizen.CitizenAnimationHelper",
"__guid": "984e8c33-bf4a-4058-8cba-2da8bbc75f75",
"__enabled": true,
"BodyWeight": 1,
"EyeSource": null,
"EyesWeight": 1,
"HeadWeight": 1,
"Height": null,
"IkLeftFoot": null,
"IkLeftHand": null,
"IkRightFoot": null,
"IkRightHand": null,
"LookAt": null,
"LookAtEnabled": false,
"OnComponentDestroy": null,
"OnComponentDisabled": null,
"OnComponentEnabled": null,
"OnComponentFixedUpdate": null,
"OnComponentStart": null,
"OnComponentUpdate": null,
"Target": {
"_type": "component",
"component_id": "981fee12-feca-4cff-b1fe-32b783e1a1dc",
"go": "ede7b66f-b9b2-4524-9933-4c2919ff6ae0",
"component_type": "SkinnedModelRenderer"
}
},
{
"__type": "Sandbox.ModelHitboxes",
"__guid": "63936f84-7057-4c17-bf2a-27702ca5258c",
"__enabled": true,
"OnComponentDestroy": null,
"OnComponentDisabled": null,
"OnComponentEnabled": null,
"OnComponentFixedUpdate": null,
"OnComponentStart": null,
"OnComponentUpdate": null,
"Renderer": {
"_type": "component",
"component_id": "981fee12-feca-4cff-b1fe-32b783e1a1dc",
"go": "ede7b66f-b9b2-4524-9933-4c2919ff6ae0",
"component_type": "SkinnedModelRenderer"
},
"Target": {
"_type": "gameobject",
"go": "ede7b66f-b9b2-4524-9933-4c2919ff6ae0"
}
},
{
"__type": "Sandbox.ModelPhysics",
"__guid": "c3b90741-9d94-4b5e-baa4-6b30b3b107d3",
"__enabled": false,
"Locking": {
"X": false,
"Y": false,
"Z": false,
"Pitch": false,
"Yaw": false,
"Roll": false
},
"Model": "models/terryisdead/citizen_terryisdead.vmdl",
"MotionEnabled": false,
"OnComponentDestroy": null,
"OnComponentDisabled": null,
"OnComponentEnabled": null,
"OnComponentFixedUpdate": null,
"OnComponentStart": null,
"OnComponentUpdate": null,
"Renderer": {
"_type": "component",
"component_id": "981fee12-feca-4cff-b1fe-32b783e1a1dc",
"go": "ede7b66f-b9b2-4524-9933-4c2919ff6ae0",
"component_type": "SkinnedModelRenderer"
},
"RigidbodyFlags": 0
},
{
"__type": "RagdollController",
"__guid": "16b8ed44-1abd-4f32-bf92-2bc21b785bc0",
"__enabled": true,
"bodyPhysics": {
"_type": "component",
"component_id": "c3b90741-9d94-4b5e-baa4-6b30b3b107d3",
"go": "ede7b66f-b9b2-4524-9933-4c2919ff6ae0",
"component_type": "ModelPhysics"
},
"bodyRenderer": {
"_type": "component",
"component_id": "981fee12-feca-4cff-b1fe-32b783e1a1dc",
"go": "ede7b66f-b9b2-4524-9933-4c2919ff6ae0",
"component_type": "SkinnedModelRenderer"
},
"isLocked": false,
"OnComponentDestroy": null,
"OnComponentDisabled": null,
"OnComponentEnabled": null,
"OnComponentFixedUpdate": null,
"OnComponentStart": null,
"OnComponentUpdate": null
},
{
"__type": "Sandbox.SoundPointComponent",
"__guid": "88969834-8bec-4a74-8b16-c258c0377501",
"__enabled": true,
"Distance": 512,
"DistanceAttenuation": false,
"DistanceAttenuationOverride": false,
"Falloff": [
{
"x": 0,
"y": 1,
"in": 3.1415927,
"out": -3.1415927,
"mode": "Mirrored"
},
{
"x": 1,
"y": 0,
"in": 0,
"out": 0,
"mode": "Mirrored"
}
],
"Force2d": false,
"MaxRepeatTime": 1,
"MinRepeatTime": 1,
"Occlusion": false,
"OcclusionOverride": false,
"OcclusionRadius": 32,
"OnComponentDestroy": null,
"OnComponentDisabled": null,
"OnComponentEnabled": null,
"OnComponentFixedUpdate": null,
"OnComponentStart": null,
"OnComponentUpdate": null,
"Pitch": 1,
"PlayOnStart": false,
"ReflectionOverride": false,
"Reflections": false,
"Repeat": false,
"SoundEvent": "sounds/hit_sound.sound",
"SoundOverride": false,
"StopOnNew": true,
"TargetMixer": {
"Name": "unknown",
"Id": "00000000-0000-0000-0000-000000000000"
},
"Volume": 1
}
],
"Children": [],
"__properties": {
"NetworkInterpolation": true,
"TimeScale": 1,
"WantsSystemScene": true,
"Metadata": {},
"NavMesh": {
"Enabled": false,
"IncludeStaticBodies": true,
"IncludeKeyframedBodies": true,
"EditorAutoUpdate": true,
"AgentHeight": 64,
"AgentRadius": 16,
"AgentStepSize": 18,
"AgentMaxSlope": 40,
"ExcludedBodies": "",
"IncludedBodies": ""
}
},
"__variables": []
},
"ResourceVersion": 2,
"ShowInMenu": false,
"MenuPath": null,
"MenuIcon": null,
"DontBreakAsTemplate": false,
"__references": [],
"__version": 2
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,385 @@
{
"RootObject": {
"__guid": "dec3b7f3-79ae-4bb4-b868-8de9d0306ebb",
"__version": 1,
"Flags": 0,
"Name": "pistol_1",
"Position": "0,0,0",
"Rotation": "0,0,0,1",
"Scale": "1,1,1",
"Tags": "light_spot,light,light_point,weapon",
"Enabled": true,
"NetworkMode": 2,
"NetworkInterpolation": false,
"NetworkOrphaned": 0,
"OwnerTransfer": 1,
"Components": [
{
"__type": "Sandbox.SkinnedModelRenderer",
"__guid": "6017d24d-39d0-4acf-bf9f-010c345fd13d",
"__enabled": true,
"AnimationGraph": "animgraphs/pistol.vanmgrph",
"BodyGroups": 18446744073709551615,
"BoneMergeTarget": null,
"CreateAttachments": false,
"CreateBoneObjects": false,
"MaterialGroup": null,
"MaterialOverride": null,
"Model": "pistol.vmdl",
"Morphs": {},
"OnComponentDestroy": null,
"OnComponentDisabled": null,
"OnComponentEnabled": null,
"OnComponentFixedUpdate": null,
"OnComponentStart": null,
"OnComponentUpdate": null,
"Parameters": {
"bools": {
"Fire": true
},
"ints": {},
"floats": {},
"vectors": {},
"rotations": {}
},
"PlaybackRate": 1,
"RenderOptions": {
"GameLayer": true,
"OverlayLayer": false,
"BloomLayer": false,
"AfterUILayer": false
},
"RenderType": "On",
"Sequence": {
"Name": null,
"Looping": true,
"Blending": false
},
"Tint": "1,1,1,1",
"UseAnimGraph": true
},
{
"__type": "Sandbox.Weapons.Weapon",
"__guid": "c8d294ad-32d0-413a-a5cf-c51acaa19920",
"__enabled": true,
"bloodParticle": {
"_type": "gameobject",
"prefab": "prefabs/impacts/impact.flesh.mist.prefab"
},
"BulletOut": {
"_type": "gameobject",
"go": "d81748e9-bc3d-4d68-97b5-5602bf5e0e15"
},
"GunRenderer": {
"_type": "component",
"component_id": "6017d24d-39d0-4acf-bf9f-010c345fd13d",
"go": "dec3b7f3-79ae-4bb4-b868-8de9d0306ebb",
"component_type": "SkinnedModelRenderer"
},
"ImpactDecal": null,
"ImpactSound": null,
"MuzzleLight": {
"_type": "gameobject",
"go": "eda01dbe-7e56-4e66-af99-673e197e7dc0"
},
"OnComponentDestroy": null,
"OnComponentDisabled": null,
"OnComponentEnabled": null,
"OnComponentFixedUpdate": null,
"OnComponentStart": null,
"OnComponentUpdate": null,
"particlePrefab": {
"_type": "gameobject",
"prefab": "prefabs/impacts/impact.metal.prefab"
}
},
{
"__type": "Sandbox.SoundPointComponent",
"__guid": "be95c906-5f2f-4239-8fd6-a42a148dea6e",
"__enabled": true,
"Distance": 2219,
"DistanceAttenuation": true,
"DistanceAttenuationOverride": true,
"Falloff": [
{
"x": 0,
"y": 1,
"in": 3.1415927,
"out": -3.1415927,
"mode": "Mirrored"
},
{
"x": 1,
"y": 0,
"in": 0,
"out": 0,
"mode": "Mirrored"
}
],
"Force2d": false,
"MaxRepeatTime": 1,
"MinRepeatTime": 1,
"Occlusion": false,
"OcclusionOverride": false,
"OcclusionRadius": 32,
"OnComponentDestroy": null,
"OnComponentDisabled": null,
"OnComponentEnabled": null,
"OnComponentFixedUpdate": null,
"OnComponentStart": null,
"OnComponentUpdate": null,
"Pitch": 1,
"PlayOnStart": false,
"ReflectionOverride": false,
"Reflections": false,
"Repeat": false,
"SoundEvent": "sounds/shoot_sound_1.sound",
"SoundOverride": false,
"StopOnNew": true,
"TargetMixer": {
"Name": "game",
"Id": "fa65adf3-a336-4d2b-9e2f-37f15349175a"
},
"Volume": 1
}
],
"Children": [
{
"__guid": "eda01dbe-7e56-4e66-af99-673e197e7dc0",
"__version": 1,
"Flags": 0,
"Name": "MuzzleLight",
"Position": "19.65036,0.000002036104,11.18876",
"Rotation": "0,0,0,1",
"Scale": "1,1,1",
"Tags": "",
"Enabled": false,
"NetworkMode": 2,
"NetworkInterpolation": true,
"NetworkOrphaned": 0,
"OwnerTransfer": 1,
"Components": [
{
"__type": "Sandbox.PointLight",
"__guid": "1e1e54b4-ebf1-4211-9ca9-0eaa37f7bf7e",
"__enabled": true,
"Attenuation": 2.56,
"FogMode": "Enabled",
"FogStrength": 0.19,
"LightColor": "0,0.11667,1,1",
"OnComponentDestroy": null,
"OnComponentDisabled": null,
"OnComponentEnabled": null,
"OnComponentFixedUpdate": null,
"OnComponentStart": null,
"OnComponentUpdate": null,
"Radius": 160.99942,
"Shadows": true
}
],
"Children": []
},
{
"__guid": "d81748e9-bc3d-4d68-97b5-5602bf5e0e15",
"__version": 1,
"Flags": 0,
"Name": "BulletOut",
"Position": "11.14736,-0.2659489,5.71905",
"Rotation": "0,0,0,1",
"Scale": "1,1,1",
"Tags": "",
"Enabled": true,
"NetworkMode": 2,
"NetworkInterpolation": true,
"NetworkOrphaned": 0,
"OwnerTransfer": 1,
"Components": [],
"Children": []
},
{
"__guid": "47bb3ba1-b0de-4af4-b639-235a5ad2c312",
"__version": 1,
"Flags": 0,
"Name": "Laser2",
"Position": "11.14736,-0.2659489,3.71905",
"Rotation": "0,0,0,1",
"Scale": "1,0.1,0.1",
"Tags": "",
"Enabled": false,
"NetworkMode": 2,
"NetworkInterpolation": true,
"NetworkOrphaned": 0,
"OwnerTransfer": 1,
"Components": [
{
"__type": "Sandbox.SkinnedModelRenderer",
"__guid": "862e0738-e57f-456a-b0c8-ff03a165faf9",
"__enabled": true,
"AnimationGraph": null,
"BodyGroups": 18446744073709551615,
"BoneMergeTarget": null,
"CreateAttachments": false,
"CreateBoneObjects": false,
"MaterialGroup": null,
"MaterialOverride": "materials/pistol/glow_2.vmat",
"Model": "lasermesh.vmdl",
"Morphs": {},
"OnComponentDestroy": null,
"OnComponentDisabled": null,
"OnComponentEnabled": null,
"OnComponentFixedUpdate": null,
"OnComponentStart": null,
"OnComponentUpdate": null,
"Parameters": {
"bools": {},
"ints": {},
"floats": {},
"vectors": {},
"rotations": {}
},
"PlaybackRate": 1,
"RenderOptions": {
"GameLayer": true,
"OverlayLayer": false,
"BloomLayer": false,
"AfterUILayer": false
},
"RenderType": "On",
"Sequence": {
"Name": null,
"Looping": true,
"Blending": false
},
"Tint": "1,1,1,1",
"UseAnimGraph": true
}
],
"Children": []
},
{
"__guid": "a9d8c3d0-cbcb-4ebe-994c-5f4c36f08996",
"__version": 1,
"Flags": 0,
"Name": "Laser",
"Position": "11.14736,-0.2659489,5.71905",
"Rotation": "0,0,0,1",
"Scale": "1,0.1,0.1",
"Tags": "",
"Enabled": false,
"NetworkMode": 2,
"NetworkInterpolation": true,
"NetworkOrphaned": 0,
"OwnerTransfer": 1,
"Components": [
{
"__type": "Sandbox.SkinnedModelRenderer",
"__guid": "e1b93001-f96d-474d-bd6f-aaa2acb0d33e",
"__enabled": true,
"AnimationGraph": null,
"BodyGroups": 18446744073709551615,
"BoneMergeTarget": null,
"CreateAttachments": false,
"CreateBoneObjects": false,
"MaterialGroup": null,
"MaterialOverride": "materials/pistol/glow_2.vmat",
"Model": "lasermesh.vmdl",
"Morphs": {},
"OnComponentDestroy": null,
"OnComponentDisabled": null,
"OnComponentEnabled": null,
"OnComponentFixedUpdate": null,
"OnComponentStart": null,
"OnComponentUpdate": null,
"Parameters": {
"bools": {},
"ints": {},
"floats": {},
"vectors": {},
"rotations": {}
},
"PlaybackRate": 1,
"RenderOptions": {
"GameLayer": true,
"OverlayLayer": false,
"BloomLayer": false,
"AfterUILayer": false
},
"RenderType": "On",
"Sequence": {
"Name": null,
"Looping": true,
"Blending": false
},
"Tint": "1,1,1,1",
"UseAnimGraph": true
}
],
"Children": []
},
{
"__guid": "0e9f41d3-8000-4c3c-9cdd-076056da9d0a",
"__version": 1,
"Flags": 0,
"Name": "Light",
"Position": "11.08827,0,3.583341",
"Rotation": "0,0,0,1",
"Scale": "1,1,1",
"Tags": "",
"Enabled": true,
"NetworkMode": 2,
"NetworkInterpolation": true,
"NetworkOrphaned": 0,
"OwnerTransfer": 1,
"Components": [
{
"__type": "Sandbox.SpotLight",
"__guid": "3803bdb5-aa92-46f7-91a6-1dfad9549cf4",
"__enabled": true,
"Attenuation": 1.8,
"ConeInner": 28.06,
"ConeOuter": 33.99,
"Cookie": null,
"FogMode": "Enabled",
"FogStrength": 0.19,
"LightColor": "0.91373,0.98039,1,1",
"OnComponentDestroy": null,
"OnComponentDisabled": null,
"OnComponentEnabled": null,
"OnComponentFixedUpdate": null,
"OnComponentStart": null,
"OnComponentUpdate": null,
"Radius": 500,
"Shadows": true
}
],
"Children": []
}
],
"__properties": {
"NetworkInterpolation": false,
"TimeScale": 1,
"WantsSystemScene": true,
"Metadata": {},
"NavMesh": {
"Enabled": false,
"IncludeStaticBodies": true,
"IncludeKeyframedBodies": true,
"EditorAutoUpdate": true,
"AgentHeight": 64,
"AgentRadius": 16,
"AgentStepSize": 18,
"AgentMaxSlope": 40,
"ExcludedBodies": "",
"IncludedBodies": ""
}
},
"__variables": []
},
"ResourceVersion": 2,
"ShowInMenu": false,
"MenuPath": null,
"MenuIcon": null,
"DontBreakAsTemplate": false,
"__references": [],
"__version": 2
}

BIN
Assets/sounds/hit_sound.mp3 (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,52 @@
{
"UI": false,
"Volume": "1",
"Pitch": "1",
"Decibels": 70,
"SelectionMode": "Random",
"Sounds": [
"sounds/hit_sound.vsnd"
],
"Occlusion": true,
"AirAbsorption": true,
"Transmission": true,
"OcclusionRadius": 64,
"DistanceAttenuation": true,
"Distance": 15000,
"Falloff": [
{
"x": 0,
"y": 1,
"in": 0,
"out": -1.8,
"mode": "Mirrored"
},
{
"x": 0.05,
"y": 0.22,
"in": 3.5,
"out": -3.5,
"mode": "Mirrored"
},
{
"x": 0.2,
"y": 0.04,
"in": 0.16,
"out": -0.16,
"mode": "Mirrored"
},
{
"x": 1,
"y": 0,
"in": 0,
"out": 0,
"mode": "Mirrored"
}
],
"DefaultMixer": {
"Name": "unknown",
"Id": "00000000-0000-0000-0000-000000000000"
},
"__references": [],
"__version": 1
}

BIN
Assets/sounds/shoot_sound_1.mp3 (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,52 @@
{
"UI": false,
"Volume": "1",
"Pitch": "1",
"Decibels": 70,
"SelectionMode": "Random",
"Sounds": [
"sounds/shoot_sound_1.vsnd"
],
"Occlusion": true,
"AirAbsorption": true,
"Transmission": true,
"OcclusionRadius": 64,
"DistanceAttenuation": true,
"Distance": 15000,
"Falloff": [
{
"x": 0,
"y": 1,
"in": 0,
"out": -1.8,
"mode": "Mirrored"
},
{
"x": 0.05,
"y": 0.22,
"in": 3.5,
"out": -3.5,
"mode": "Mirrored"
},
{
"x": 0.2,
"y": 0.04,
"in": 0.16,
"out": -0.16,
"mode": "Mirrored"
},
{
"x": 1,
"y": 0,
"in": 0,
"out": 0,
"mode": "Mirrored"
}
],
"DefaultMixer": {
"Name": "unknown",
"Id": "00000000-0000-0000-0000-000000000000"
},
"__references": [],
"__version": 1
}

BIN
Assets/textures/pistol/Fabric080_1K-PNG_Color.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Assets/textures/pistol/Fabric080_1K-PNG_NormalGL_norm.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Assets/textures/pistol/Fabric080_1K-PNG_Roughness.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Assets/textures/pistol/Metal055A_1K-PNG_Color.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Assets/textures/pistol/Metal055A_1K-PNG_Metalness.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Assets/textures/pistol/Metal055A_1K-PNG_NormalGL_norm.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Assets/textures/pistol/Metal055A_1K-PNG_Roughness.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Assets/textures/pistol/Plastic018A_1K-PNG_NormalDX_norm.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Assets/textures/pistol/Plastic018A_1K-PNG_Roughness.png (Stored with Git LFS) Normal file

Binary file not shown.

321
Code/AI/Enemy.cs Normal file
View File

@ -0,0 +1,321 @@
using Sandbox;
using Sandbox.Citizen;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
public sealed partial class Enemy : Component
{
public enum EnemyState
{
Idle,
Chase,
Attack,
Patrol,
Death
}
[Property, Sync] public int Health { get; set; } = 100;
[Property] public float MaxSpeed { get; set; } = 400;
[Property] public NavMeshAgent agent;
[Property] public SkinnedModelRenderer renderer;
[Property] public CitizenAnimationHelper AnimationHelper;
[Property, Sync] public EnemyState CurrentState { get; set; } = EnemyState.Idle;
[Property] public float DetectionRadius = 1000f;
[Property] public float AttackRadius = 80f;
[Property] public float AttackCooldown = 1f;
[Property] public RagdollController RagdollController;
[Property] public SoundPointComponent HitSound { get; set; }
[Property] public GameObject bloodParticle { get; set; }
private TimeSince _timeSinceLastAttack;
private Dedugan _currentTarget;
private TimeSince _lastTargetCheck;
private const float TargetCheckInterval = 1.5f;
private List<Dedugan> _potentialTargets = new();
private TimeSince _lastSearchRefresh;
private TimeSince _stateEnterTime;
public event Action<EnemyState, EnemyState> OnStateChanged;
protected override void OnStart()
{
renderer.Set( "scale_height", 2f );
_timeSinceLastAttack = 0;
_lastTargetCheck = 0;
RefreshPotentialTargets();
SwitchState( EnemyState.Idle );
// if ( !Network.IsOwner ) return;
if ( renderer is null )
return;
renderer.OnFootstepEvent += OnFootstepEvent;
}
protected override void OnUpdate()
{
// Всегда проверяем ближайшую цель
if ( _lastTargetCheck > TargetCheckInterval && CurrentState != EnemyState.Death )
{
FindClosestTarget();
_lastTargetCheck = 0;
}
switch ( CurrentState )
{
case EnemyState.Idle:
UpdateIdleState();
break;
case EnemyState.Chase:
UpdateChaseState();
break;
case EnemyState.Attack:
UpdateAttackState();
break;
case EnemyState.Patrol:
UpdatePatrolState();
break;
case EnemyState.Death:
UpdateDeathState();
break;
}
}
private void SwitchState( EnemyState newState )
{
if ( CurrentState == newState ) return;
if ( CurrentState == EnemyState.Death ) return;
var previousState = CurrentState;
CurrentState = newState;
_stateEnterTime = 0;
OnStateChanged?.Invoke( previousState, newState );
switch ( newState )
{
case EnemyState.Idle:
agent.Stop();
AnimationHelper.HoldType = CitizenAnimationHelper.HoldTypes.None;
AnimationHelper.WithVelocity( Vector3.Zero );
renderer.Set( "scale_height", 2f );
break;
case EnemyState.Chase:
agent.MaxSpeed = MaxSpeed;
AnimationHelper.HoldType = CitizenAnimationHelper.HoldTypes.Punch;
break;
case EnemyState.Patrol:
agent.MaxSpeed = MaxSpeed / 4;
break;
case EnemyState.Death:
EnterDeathState();
break;
}
}
private void RefreshPotentialTargets()
{
_potentialTargets.Clear();
foreach ( var player in Scene.Components.GetAll<Dedugan>() )
{
if ( player.IsValid() && player.Health > 0 )
{
_potentialTargets.Add( player );
}
}
_lastSearchRefresh = 0;
}
private void FindClosestTarget()
{
// Обновляем список целей при необходимости
if ( _lastSearchRefresh > 1f ) RefreshPotentialTargets();
Dedugan closestTarget = null;
float closestDistance = float.MaxValue;
foreach ( var target in _potentialTargets )
{
if ( !target.IsValid() || target.Health <= 0 ) continue;
float distance = Vector3.DistanceBetween( WorldPosition, target.WorldPosition );
if ( distance <= DetectionRadius && distance < closestDistance )
{
closestDistance = distance;
closestTarget = target;
}
else
{
_currentTarget = null;
}
}
// Если нашли более близкую цель, переключаемся на нее
if ( closestTarget != null && closestTarget != _currentTarget )
{
_currentTarget = closestTarget;
// Если мы в состоянии атаки/погони и цель сменилась, перезапускаем движение
if ( CurrentState == EnemyState.Chase || CurrentState == EnemyState.Attack )
{
agent.MoveTo( _currentTarget.WorldPosition );
}
}
}
private bool HasValidTarget()
{
return _currentTarget != null &&
_currentTarget.IsValid() &&
_currentTarget.Health > 0;
}
private void UpdateIdleState()
{
if ( HasValidTarget() )
{
Log.Info(_currentTarget);
SwitchState( EnemyState.Chase );
return;
}
if ( new Random().Next( 0, 100 ) > 90 )
{
SwitchState( EnemyState.Patrol );
}
SwitchState( EnemyState.Patrol );
AnimationHelper.WithVelocity( Vector3.Zero );
}
private void UpdatePatrolState()
{
if ( HasValidTarget() )
{
SwitchState( EnemyState.Chase );
return;
}
if ( agent.Velocity.Length <= 10 )
{
agent.MoveTo( Scene.NavMesh.GetRandomPoint() ?? WorldPosition );
}
AnimationHelper.WithVelocity( agent.Velocity );
}
private void UpdateChaseState()
{
if ( !HasValidTarget() )
{
SwitchState( EnemyState.Idle );
return;
}
float distance = Vector3.DistanceBetween( _currentTarget.WorldPosition, WorldPosition );
if ( distance <= AttackRadius )
{
SwitchState( EnemyState.Attack );
return;
}
if ( distance > DetectionRadius )
{
SwitchState( EnemyState.Idle );
return;
}
agent.MoveTo( _currentTarget.WorldPosition );
AnimationHelper.WithVelocity( agent.Velocity );
}
private void UpdateAttackState()
{
if ( !HasValidTarget() )
{
SwitchState( EnemyState.Idle );
return;
}
float distance = Vector3.DistanceBetween( _currentTarget.WorldPosition, WorldPosition );
if ( distance > AttackRadius )
{
SwitchState( EnemyState.Chase );
return;
}
agent.Stop();
AnimationHelper.WithVelocity( Vector3.Zero );
if ( _timeSinceLastAttack >= AttackCooldown )
{
var dir = _currentTarget.WorldPosition - WorldPosition;
renderer.Set( "b_attack", true );
_timeSinceLastAttack = 0;
_currentTarget.ReportHit( dir, 1, 15 );
CreateHitEffects( _currentTarget.WorldPosition + _currentTarget.WorldRotation.Up * 60, dir );
}
}
private void EnterDeathState()
{
agent.Stop();
AnimationHelper.WithVelocity( Vector3.Zero );
if ( RagdollController != null ) RagdollController.Enabled = true;
}
private void UpdateDeathState()
{
// Логика состояния смерти
}
public void Die()
{
SwitchState( EnemyState.Death );
DestroyAsync( GameObject, 5f );
}
[Rpc.Broadcast]
public void ReportHit( Vector3 dir, int boneIndex, int damage = 25 )
{
renderer.Set( "hit", true );
renderer.Set( "hit_bone", boneIndex );
renderer.Set( "hit_direction", dir );
renderer.Set( "hit_offset", dir );
renderer.Set( "hit_strength", 5 );
Health -= damage;
if ( Health <= 0 )
{
Die();
}
}
[Rpc.Broadcast]
private void CreateHitEffects( Vector3 position, Vector3 normal )
{
if ( HitSound != null ) HitSound.StartSound();
if ( bloodParticle != null )
{
var rot = Rotation.LookAt( normal );
DestroyAsync( bloodParticle.Clone( position, rot ), 0.5f );
}
}
async void DestroyAsync( GameObject go, float delay )
{
await GameTask.DelaySeconds( delay );
if ( go != null && go.IsValid() ) go.Destroy();
}
}

551
Code/Maze/Maze.cs Normal file
View File

@ -0,0 +1,551 @@
public sealed class Maze : Component
{
[Property, Sync] public int Width { get; set; } = 10;
[Property, Sync] public int Height { get; set; } = 10;
[Property, Sync] public float WallHeight { get; set; } = 5f;
[Property, Sync] public float WallThickness { get; set; } = 5f;
[Property, Sync] public float CellSize { get; set; } = 200f;
[Property, Sync] public float PassThrougthPercent { get; set; } = 0.1f;
[Property] public int CenterClearRadius { get; set; } = 1;
[Property] public GameObject EnemyPrefab { get; set; }
private GameObject _mazeWallsObject;
public Cell[,] Cells;
private List<GameObject> _walls = new();
[Property] public GameObject Floor { get; set; }
[Property] public bool IsReady { get; set; } = false;
[Property] public Material WallMaterial { get; set; } // Добавлено свойство для материала
private static readonly string WallModelPath = "models/dev/box.vmdl_c";
private Vector3 mazeOffset =>
new Vector3( -(Width * CellSize) / 2 + CellSize / 2, -(Height * CellSize) / 2 + CellSize / 2, 0 );
[Property, Sync( SyncFlags.FromHost ), Change( "OnSeedChanged" )]
public int MazeSeed { get; set; } = -1;
void OnSeedChanged( int oldValue, int newValue )
{
if ( newValue != oldValue )
{
IsReady = false;
CreateMaze();
}
}
[Rpc.Broadcast]
public void RpcRequestMaze()
{
if ( Networking.IsHost )
{
MazeSeed = Game.Random.Int( 0, 999999999 );
}
}
public async void CreateMaze()
{
Log.Info( $"CREATE MAZE {MazeSeed}" );
ScaleFloor();
ClearMaze();
GenerateMaze();
await Task.Delay( 10 );
BuildMazeOptimized();
await Task.Delay( 10 );
SpawnEnemy();
IsReady = true;
}
private void RemoveCenterWalls()
{
if ( Cells == null )
{
Log.Warning( "RemoveCenterWalls: _cells is null" );
return;
}
int centerX = Width / 2;
int centerY = Height / 2;
int startX = Math.Max( 0, centerX - CenterClearRadius );
int endX = Math.Min( Width - 1, centerX + CenterClearRadius );
int startY = Math.Max( 0, centerY - CenterClearRadius );
int endY = Math.Min( Height - 1, centerY + CenterClearRadius );
for ( int x = startX; x <= endX; x++ )
{
for ( int y = startY; y <= endY; y++ )
{
if ( Cells[x, y] == null ) continue;
var cell = Cells[x, y];
for ( int i = 0; i < 4; i++ )
{
if ( i >= 0 && i < cell.Walls.Length )
cell.Walls[i] = false;
}
// Сброс стен у соседей
if ( x > 0 && Cells[x - 1, y] != null )
Cells[x - 1, y].Walls[1] = false; // Left neighbor's Right
if ( x < Width - 1 && Cells[x + 1, y] != null )
Cells[x + 1, y].Walls[3] = false; // Right neighbor's Left
if ( y > 0 && Cells[x, y - 1] != null )
Cells[x, y - 1].Walls[2] = false; // Bottom neighbor's Top
if ( y < Height - 1 && Cells[x, y + 1] != null )
Cells[x, y + 1].Walls[0] = false; // Top neighbor's Bottom
}
}
}
public Vector3 GetRandomCellPosition()
{
var randomCell = Cells[Game.Random.Int( 0, Width - 1 ), Game.Random.Int( 0, Height - 1 )];
return WorldPosition + new Vector3(
randomCell.X * CellSize,
randomCell.Y * CellSize,
0
) + mazeOffset;
}
private void SpawnEnemy()
{
if ( !Networking.IsHost ) return;
var enemy = EnemyPrefab.Clone();
enemy.WorldPosition = GetRandomCellPosition();
enemy.NetworkSpawn( null );
var agent = enemy.Components.Get<NavMeshAgent>();
if ( agent != null )
{
agent.Enabled = false;
agent.WorldPosition = enemy.WorldPosition;
agent.Enabled = true;
}
}
private void ClearMaze()
{
// Удаляем оптимизированные стены
if ( _mazeWallsObject.IsValid() )
{
_mazeWallsObject.Destroy();
_mazeWallsObject = null;
}
// Удаляем старые стены (для обратной совместимости)
foreach ( var wall in _walls )
{
if ( wall.IsValid ) wall.Destroy();
}
_walls.Clear();
}
private void GenerateMaze()
{
Cells = new Cell[Width, Height];
for ( int x = 0; x < Width; x++ )
{
for ( int y = 0; y < Height; y++ )
{
Cells[x, y] = new Cell( x, y );
}
}
var stack = new Stack<Cell>();
var rng = new Random( MazeSeed );
var startCell = Cells[0, 0];
startCell.Visited = true;
stack.Push( startCell );
while ( stack.Count > 0 )
{
var current = stack.Peek();
var neighbors = GetUnvisitedNeighbors( current );
if ( neighbors.Count > 0 )
{
var next = neighbors[rng.Next( neighbors.Count )];
RemoveWall( current, next );
next.Visited = true;
stack.Push( next );
}
else
{
stack.Pop();
}
}
AddExtraPassages( count: (int)(Width * Height * PassThrougthPercent) ); // 10% от клеток
RemoveCenterWalls();
}
private List<Cell> GetUnvisitedNeighbors( Cell cell )
{
var neighbors = new List<Cell>();
int x = cell.X;
int y = cell.Y;
if ( x > 0 && !Cells[x - 1, y].Visited ) neighbors.Add( Cells[x - 1, y] );
if ( x < Width - 1 && !Cells[x + 1, y].Visited ) neighbors.Add( Cells[x + 1, y] );
if ( y > 0 && !Cells[x, y - 1].Visited ) neighbors.Add( Cells[x, y - 1] );
if ( y < Height - 1 && !Cells[x, y + 1].Visited ) neighbors.Add( Cells[x, y + 1] );
return neighbors;
}
private void RemoveWall( Cell current, Cell next )
{
int dx = next.X - current.X;
int dy = next.Y - current.Y;
if ( dx == 1 )
{
current.Walls[1] = false; // Right
next.Walls[3] = false; // Left
}
else if ( dx == -1 )
{
current.Walls[3] = false; // Left
next.Walls[1] = false; // Right
}
else if ( dy == 1 )
{
current.Walls[2] = false; // Top
next.Walls[0] = false; // Bottom
}
else if ( dy == -1 )
{
current.Walls[0] = false; // Bottom
next.Walls[2] = false; // Top
}
}
private void BuildMaze()
{
for ( int x = 0; x < Width; x++ )
{
for ( int y = 0; y < Height; y++ )
{
var cell = Cells[x, y];
Vector3 cellCenter = new Vector3( x * CellSize, y * CellSize, 0 );
if ( cell.Walls[0] ) // Bottom
{
Vector3 pos = cellCenter + new Vector3( 0, -CellSize / 2, 0 );
SpawnWall( pos, Rotation.FromYaw( 0 ) );
}
if ( cell.Walls[1] ) // Right
{
Vector3 pos = cellCenter + new Vector3( CellSize / 2, 0, 0 );
SpawnWall( pos, Rotation.FromYaw( 90 ) );
}
if ( cell.Walls[2] ) // Top
{
Vector3 pos = cellCenter + new Vector3( 0, CellSize / 2, 0 );
SpawnWall( pos, Rotation.FromYaw( 0 ) );
}
if ( cell.Walls[3] ) // Left
{
Vector3 pos = cellCenter + new Vector3( -CellSize / 2, 0, 0 );
SpawnWall( pos, Rotation.FromYaw( 90 ) );
}
}
}
}
private void AddBox( ModelBuilder builder, Matrix transform, Vector3 size )
{
Vector3 halfSize = size / 2;
Vector3[] localVerts = new Vector3[]
{
new(-halfSize.x, -halfSize.y, -halfSize.z), // 0
new(halfSize.x, -halfSize.y, -halfSize.z), // 1
new(halfSize.x, halfSize.y, -halfSize.z), // 2
new(-halfSize.x, halfSize.y, -halfSize.z), // 3
new(-halfSize.x, -halfSize.y, halfSize.z), // 4
new(halfSize.x, -halfSize.y, halfSize.z), // 5
new(halfSize.x, halfSize.y, halfSize.z), // 6
new(-halfSize.x, halfSize.y, halfSize.z) // 7
};
int[] indices = new int[]
{
0, 2, 1, 0, 3, 2, // bottom (задом наперёд)
4, 5, 6, 4, 6, 7, // top
0, 5, 4, 0, 1, 5, // front
1, 6, 5, 1, 2, 6, // right
2, 7, 6, 2, 3, 7, // back
3, 4, 7, 3, 0, 4 // left
};
Vector3[] faceNormals = new Vector3[]
{
Vector3.Down, // bottom
Vector3.Up, // top
Vector3.Backward, // front
Vector3.Right, // right
Vector3.Forward, // back
Vector3.Left // left
};
var vertices = new List<Vertex>();
var finalIndices = new List<int>();
for ( int i = 0; i < indices.Length; i += 6 )
{
Vector3 localNormal = faceNormals[i / 6];
Vector3 worldNormal = transform.TransformNormal( localNormal );
for ( int j = 0; j < 6; j++ )
{
int vertexIndex = indices[i + j];
Vector3 localPos = localVerts[vertexIndex];
Vector3 worldPos = transform.Transform( localPos );
// Vector4 texCoord = new Vector4( 0, 0, 0, 0 ); // упрощённые UV
Vector4 texCoord = new Vector4( GetUVForVertex( j ).x, GetUVForVertex( j ).y, 0, 0 );
Vertex vertex = new Vertex(
position: worldPos,
normal: worldNormal,
tangent: Vector3.Right,
texCoord0: texCoord
);
vertex.Color = Color32.White;
vertex.TexCoord1 = new Vector4( 0, 0, 0, 0 );
vertices.Add( vertex );
finalIndices.Add( vertices.Count - 1 );
}
}
if ( WallMaterial == null )
{
Log.Error( "WallMaterial not set!" );
return;
}
var mesh = new Mesh( WallMaterial, MeshPrimitiveType.Triangles );
mesh.CreateVertexBuffer<Vertex>( vertices.Count, Vertex.Layout, vertices );
mesh.CreateIndexBuffer( finalIndices.Count, finalIndices );
builder.AddMesh( mesh ).AddCollisionMesh( vertices.Select( x => x.Position ).ToList(), indices.ToList() );
}
private Vector2 GetUVForVertex( int index )
{
return (index % 4) switch
{
0 => new Vector2( 0, 0 ),
1 => new Vector2( 1, 0 ),
2 => new Vector2( 1, 1 ),
3 => new Vector2( 0, 1 ),
_ => Vector2.Zero
};
}
/// <summary>
/// Создание матрицы трансформации
/// </summary>
private Matrix CreateTransform( Vector3 position, Rotation rotation, Vector3 scale )
{
return Matrix.CreateScale( scale )
* Matrix.CreateRotation( rotation )
* Matrix.CreateTranslation( position );
}
/// <summary>
/// Оптимизированное построение стен лабиринта (единый меш)
/// </summary>
private void BuildMazeOptimized()
{
var builder = Model.Builder;
// Создаем коллектор вершин для коллайдера
var collisionVertices = new List<Vector3>();
for ( int x = 0; x < Width; x++ )
{
for ( int y = 0; y < Height; y++ )
{
var cell = Cells[x, y];
Vector3 cellCenter =
new Vector3( x * CellSize, y * CellSize, 0 ) +
mazeOffset; // + new Vector3( 0, 0, WallHeight * 24);
void AddWall( Vector3 position, Rotation rotation, Vector3 size )
{
var transform = Matrix.CreateScale( size )
* Matrix.CreateRotation( rotation )
* Matrix.CreateTranslation( position );
// Добавляем меш к модели (используй свой AddBox)
AddBox( builder, transform, new Vector3( 1, 1, WallHeight * 24 ) );
// Добавляем коллизию — формируем коллизионный hull из углов куба
// Куб - 8 вершин (как в твоём AddBox), трансформируем и добавляем
Vector3 half = new Vector3( 0.5f, 0.5f, 0.5f );
Vector3[] localVerts = new Vector3[]
{
new Vector3( -half.x, -half.y, -half.z ), new Vector3( half.x, -half.y, -half.z ),
new Vector3( half.x, half.y, -half.z ), new Vector3( -half.x, half.y, -half.z ),
new Vector3( -half.x, -half.y, half.z ), new Vector3( half.x, -half.y, half.z ),
new Vector3( half.x, half.y, half.z ), new Vector3( -half.x, half.y, half.z ),
};
foreach ( var v in localVerts )
collisionVertices.Add( transform.Transform( v ) );
}
if ( cell.Walls[0] )
AddWall( cellCenter + new Vector3( 0, -CellSize / 2, 0 ), Rotation.Identity,
new Vector3( CellSize, WallThickness, WallHeight ) );
if ( cell.Walls[1] )
AddWall( cellCenter + new Vector3( CellSize / 2, 0, 0 ), Rotation.FromYaw( 90 ),
new Vector3( CellSize, WallThickness, WallHeight ) );
if ( cell.Walls[2] )
AddWall( cellCenter + new Vector3( 0, CellSize / 2, 0 ), Rotation.Identity,
new Vector3( CellSize, WallThickness, WallHeight ) );
if ( cell.Walls[3] )
AddWall( cellCenter + new Vector3( -CellSize / 2, 0, 0 ), Rotation.FromYaw( 90 ),
new Vector3( CellSize, WallThickness, WallHeight ) );
}
}
// Создаем модель с коллизией из всех добавленных hull вершин
var model = builder
.WithMass( 0 ) // Статическая модель
.Create();
if ( _mazeWallsObject.IsValid() )
_mazeWallsObject.Destroy();
_mazeWallsObject = new GameObject();
_mazeWallsObject.Name = "Maze Walls";
_mazeWallsObject.SetParent( GameObject );
_mazeWallsObject.LocalPosition = new Vector3( 0, 0, WallHeight * 24 );
var renderer = _mazeWallsObject.Components.Create<ModelRenderer>();
renderer.Model = model;
renderer.RenderType = ModelRenderer.ShadowRenderType.Off;
if ( WallMaterial.IsValid() )
renderer.MaterialOverride = WallMaterial;
var collider = _mazeWallsObject.Components.Create<ModelCollider>();
collider.Static = true;
// var navMesh = _mazeWallsObject.Components.Create<NavMeshArea>();
// navMesh.LinkedCollider = collider;
// navMesh.IsBlocker = true;
// _mazeWallsObject.NetworkSpawn( null );
Scene.NavMesh.SetDirty();
}
private void ScaleFloor()
{
Floor.LocalPosition = new Vector3( 0, 0, -WallHeight );
Floor.LocalScale = new Vector3( CellSize / 100 * Width, CellSize / 100 * Height, 0.5f );
var renderer = Floor.Components.Get<ModelRenderer>();
var material = renderer.MaterialOverride;
material?.Set( "g_vTexCoordScale", new Vector2( Width, Height ) );
Floor.NetworkSpawn( null );
}
private void SpawnWall( Vector3 position, Rotation rotation )
{
var wall = new GameObject();
wall.SetParent( GameObject );
wall.LocalPosition = position + mazeOffset + new Vector3( 0, 0, WallHeight * 24 );
wall.WorldRotation = rotation;
wall.LocalScale = new Vector3( CellSize / 50, WallThickness / 10, WallHeight );
var collider = wall.Components.Create<BoxCollider>();
var renderer = wall.Components.Create<ModelRenderer>();
var navMeshArea = wall.Components.Create<NavMeshArea>();
navMeshArea.IsBlocker = true;
navMeshArea.LinkedCollider = collider;
renderer.Model = Model.Load( WallModelPath );
collider.Static = true;
wall.NetworkSpawn( null );
_walls.Add( wall );
}
private void AddExtraPassages( int count )
{
var rng = new Random( MazeSeed );
int added = 0;
while ( added < count )
{
int x = rng.Next( 1, Width - 1 );
int y = rng.Next( 1, Height - 1 );
var cell = Cells[x, y];
// Выбери случайного соседа
List<(int dx, int dy, int dir)> directions = new()
{
(0, -1, 0), // Bottom
(1, 0, 1), // Right
(0, 1, 2), // Top
(-1, 0, 3) // Left
};
var (dx, dy, dir) = directions[rng.Next( directions.Count )];
int nx = x + dx;
int ny = y + dy;
if ( nx < 0 || nx >= Width || ny < 0 || ny >= Height )
continue;
var neighbor = Cells[nx, ny];
if ( cell.Walls[dir] )
{
RemoveWall( cell, neighbor );
added++;
}
}
}
public class Cell
{
public int X;
public int Y;
public bool Visited;
public bool[] Walls = { true, true, true, true }; // Bottom, Right, Top, Left
public Cell( int x, int y )
{
X = x;
Y = y;
}
}
}

113
Code/NetworkManager.cs Normal file
View File

@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Sandbox;
/// <summary>
/// Creates a networked game lobby and assigns player prefabs to connected clients.
/// </summary>
[Title( "Network Manager" )]
[Category( "Networking" )]
[Icon( "electrical_services" )]
public sealed class NetworkManager : Component, Component.INetworkListener
{
/// <summary>
/// Create a server (if we're not joining one)
/// </summary>
[Property]
public bool StartServer { get; set; } = true;
/// <summary>
/// The prefab to spawn for the player to control.
/// </summary>
[Property]
public GameObject PlayerPrefab { get; set; }
/// <summary>
/// A list of points to choose from randomly to spawn the player in. If not set, we'll spawn at the
/// location of the NetworkHelper object.
/// </summary>
[Property]
public List<GameObject> SpawnPoints { get; set; }
protected override async Task OnLoad()
{
if ( Scene.IsEditor )
return;
if ( StartServer && !Networking.IsActive )
{
LoadingScreen.Title = "Creating Lobby";
await Task.DelayRealtimeSeconds( 0.1f );
Networking.CreateLobby( new() );
}
}
/// <summary>
/// A client is fully connected to the server. This is called on the host.
/// </summary>
public void OnActive( Connection channel )
{
Log.Info( $"Player '{channel.DisplayName}' has joined the game" );
if ( !PlayerPrefab.IsValid() )
return;
//
// Find a spawn location for this player
//
var startLocation = FindSpawnLocation().WithScale( 1 );
// Spawn this object and make the client the owner
var player = PlayerPrefab.Clone( startLocation, name: $"Player - {channel.DisplayName}" );
player.NetworkSpawn( channel );
var dedugan = player.Components.Get<Dedugan>( true );
dedugan.SetupConnection( channel );
}
/// <summary>
/// Called when a client disconnects from the server.
/// </summary>
public void OnDisconnected( Connection channel )
{
}
/// <summary>
/// Called when the connection is being torn down.
/// </summary>
public void OnBecomeInactive( Connection channel )
{
// Optional: Handle any cleanup before player becomes fully inactive
}
/// <summary>
/// Find the most appropriate place to respawn
/// </summary>
Transform FindSpawnLocation()
{
//
// If they have spawn point set then use those
//
if ( SpawnPoints is not null && SpawnPoints.Count > 0 )
{
return Random.Shared.FromList( SpawnPoints, default ).WorldTransform;
}
//
// If we have any SpawnPoint components in the scene, then use those
//
var spawnPoints = Scene.GetAllComponents<SpawnPoint>().ToArray();
if ( spawnPoints.Length > 0 )
{
return Random.Shared.FromArray( spawnPoints ).WorldTransform;
}
//
// Failing that, spawn where we are
//
return WorldTransform;
}
}

138
Code/UI/Chat.razor Normal file
View File

@ -0,0 +1,138 @@
@using System;
@using Sandbox.UI;
@namespace Sandbox
@inherits PanelComponent
@implements Component.INetworkListener
<root>
<div class="output">
@foreach (var entry in Entries)
{
<div class="chat_entry">
@if (entry.steamid > 0)
{
<div class="avatar" style="background-image: url( avatar:@entry.steamid )"></div>
}
<div class="author">@entry.author</div>
<div class="message">@entry.message</div>
</div>
}
</div>
<div class="input">
<TextEntry @ref="InputBox" onsubmit="@ChatFinished"></TextEntry>
</div>
</root>
@code
{
public static Chat Instance;
public Chat() => Instance = this;
public static bool IsActive => Instance.InputBox.HasFocus;
public static void Open()
{
Instance.InputBox.Focus();
}
public static void AddText(string text)
{
Instance.AddTextInternal(text);
}
public event Action<string> OnChat;
public TextEntry InputBox;
public record Entry(ulong steamid, string author, string message, RealTimeSince timeSinceAdded);
List<Entry> Entries = new();
protected override void OnUpdate()
{
if (InputBox is null)
return;
Panel.AcceptsFocus = false;
if (Input.Pressed("chat"))
Open();
if (Entries.RemoveAll(x => x.timeSinceAdded > 20.0f) > 0)
{
StateHasChanged();
}
if (InputBox.HasFocus && Input.EscapePressed)
{
Input.EscapePressed = false;
ChatClosed();
}
SetClass("open", InputBox.HasFocus);
}
void ChatFinished()
{
var text = InputBox.Text;
Mouse.Visibility = MouseVisibility.Auto;
OnChat?.Invoke(text);
OnChat = null;
if (string.IsNullOrWhiteSpace(text))
return;
AddTextInternal(InputBox.Text);
InputBox.Text = "";
}
void ChatClosed()
{
var text = InputBox.Text;
InputBox.Text = "";
OnChat = null;
}
[Rpc.Broadcast]
public void AddTextInternal(string message)
{
message = message.Truncate(300);
if (string.IsNullOrWhiteSpace(message))
return;
var author = Rpc.Caller.DisplayName;
var steamid = Rpc.Caller.SteamId;
Log.Info($"{author}: {message}");
Entries.Add(new Entry(steamid, author, message, 0.0f));
StateHasChanged();
}
[Rpc.Broadcast]
void AddSystemText(string message)
{
message = message.Truncate(300);
if (string.IsNullOrWhiteSpace(message))
return;
Entries.Add(new Entry(0, "", message, 0.0f));
StateHasChanged();
}
void Component.INetworkListener.OnConnected(Connection channel)
{
if (IsProxy) return;
AddSystemText($"{channel.DisplayName} has joined the game");
}
void Component.INetworkListener.OnDisconnected(Connection channel)
{
if (IsProxy) return;
AddSystemText($"{channel.DisplayName} has left the game");
}
}

70
Code/UI/Chat.razor.scss Normal file
View File

@ -0,0 +1,70 @@
Chat {
position: absolute;
top: 100px;
left: 200px;
bottom: 200px;
width: 600px;
justify-content: center;
align-items: center;
font-weight: bold;
border-radius: 20px;
flex-direction: column;
align-items: stretch;
font-size: 17px;
font-family: Poppins;
gap: 10px;
.output {
flex-grow: 1;
flex-direction: column;
justify-content: flex-end;
align-items: stretch;
gap: 5px;
.chat_entry {
padding: 2px;
gap: 10px;
text-shadow: 2px 2px 2px #000a;
.avatar {
width: 32px;
height: 32px;
background-position: center;
background-size: cover;
border-radius: 4px;
aspect-ratio: 1;
min-width: 32px;
max-width: 32px;
}
.author {
color: #2d95ce;
white-space: nowrap;
flex-shrink: 0;
}
.message {
color: #fff;
}
}
}
.input {
color: white;
.textentry {
align-items: flex-start;
white-space: normal;
}
}
&.open {
.input {
border-radius: 8px;
background-color: rgba(0,0,0,0.2);
backdrop-filter: blur(10px);
padding: 8px;
pointer-events: all;
}
}
}

25
Code/UI/GUI.razor Normal file
View File

@ -0,0 +1,25 @@
@using Sandbox
@using Sandbox.UI
@inherits PanelComponent
@namespace Sandbox
<root>
<div class="crosshair"></div>
</root>
<style>
.crosshair {
position: absolute;
top: 50%;
left: 50%;
width: 4px;
height: 4px;
background-color: rgba(255, 255, 255, 0.5);
border-radius: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
}
</style>
@code {
}

95
Code/UI/Scoreboard.razor Normal file
View File

@ -0,0 +1,95 @@
@using Sandbox;
@using Sandbox.UI;
@inherits PanelComponent
<root class="@(Visible ? "" : "hidden")">
@* <div class="decoration top-left"></div> *@
@* <div class="decoration top-right"></div> *@
@* <div class="decoration bottom-left"></div> *@
@* <div class="decoration bottom-right"></div> *@
<label class="title">Players</label>
<div class="content">
<div class="header">
<label class="column nick">Player</label>
<label class="column status">Status</label>
<label class="column ping">Ping</label>
</div>
<div class="player-list">
@if (Dedugan.All is not null)
{
foreach (var ded in Dedugan.All)
{
<div class="player" onclick="@(() => OpenProfile(ded.Connection))">
<div class="avatar">
<img src="avatar:@ded.SteamID"/>
</div>
<label class="column nick">@ded.Connection.DisplayName</label>
<label class="column status">@GetPlayerStatus(ded.Connection)</label>
<label class="column ping">@ded.Connection.Ping</label>
</div>
}
}
</div>
</div>
</root>
@code
{
public static bool Visible => Input.Down("Score");
private NetworkManager _networkManager;
private NetworkManager NetworkManager
{
get
{
if (_networkManager == null || !_networkManager.IsValid)
{
_networkManager = Scene.Directory.FindByName("Network Manager")
.FirstOrDefault()?
.GetComponent<NetworkManager>();
}
return _networkManager;
}
}
protected override void OnEnabled()
{
// Кэшируем NetworkManager при включении компонента
_networkManager = Scene.Directory.FindByName("Network Manager")
.FirstOrDefault()?
.GetComponent<NetworkManager>();
}
private string GetPlayerStatus(Connection conn)
{
var playerObj = Dedugan.GetByID( conn.Id ).GameObject;
return playerObj?.IsValid == true ? "In Game" : "Connecting";
}
private void OpenProfile(Connection connection)
{
Log.Info($"Opening profile: {connection.SteamId}");
Game.Overlay.ShowPlayer(connection.SteamId);
}
protected override int BuildHash()
{
if (!Visible || Dedugan.All == null)
return -1;
var hash = new System.HashCode();
hash.Add(Visible);
foreach (var ded in Dedugan.All)
{
hash.Add(ded.Id);
hash.Add(ded.Connection.Ping);
hash.Add(ded.Name);
}
return hash.ToHashCode();
}
}

View File

@ -0,0 +1,191 @@
Scoreboard {
background: linear-gradient(135deg, #0a1a2b 0%, #08111f 100%);
border: 3px solid #2a3d54;
border-radius: 16px;
//box-shadow:
// 0 0 15px rgba(0, 150, 255, 0.2),
// inset 0 0 10px rgba(0, 100, 200, 0.1);
font-family: 'Orbitron', 'Poppins', sans-serif;
position: absolute;
width: 60%;
height: 70vh;
top: 15vh;
left: 20%;
padding: 30px;
display: flex;
flex-direction: column;
gap: 20px;
transition: all 0.2s ease;
z-index: 100;
overflow: hidden;
&.hidden {
opacity: 0;
}
.decoration {
position: absolute;
width: 60px;
height: 60px;
border: 2px solid rgba(0, 180, 255, 0.25);
opacity: 0.8;
box-shadow: 0 0 8px rgba(100, 200, 255, 0.1);
&.top-left {
top: 10px;
left: 10px;
border-right: none;
border-bottom: none;
border-radius: 12px 0 0 0;
}
&.top-right {
top: 10px;
right: 10px;
border-left: none;
border-bottom: none;
border-radius: 0 12px 0 0;
}
&.bottom-left {
bottom: 10px;
left: 10px;
border-right: none;
border-top: none;
border-radius: 0 0 0 12px;
}
&.bottom-right {
bottom: 10px;
right: 10px;
border-left: none;
border-top: none;
border-radius: 0 0 12px 0;
}
}
.title {
font-size: 42px;
color: #a0e0ff;
text-align: center;
//text-shadow:
// 0 0 10px rgba(100, 200, 255, 0.7),
// 0 0 20px rgba(80, 180, 255, 0.4);
letter-spacing: 4px;
margin-bottom: 15px;
font-weight: 600;
text-transform: uppercase;
}
.content {
display: flex;
flex-direction: column;
background-color: rgba(10, 25, 40, 0.6);
border-radius: 12px;
border: 1px solid #253a50;
overflow: hidden;
flex-grow: 1;
//box-shadow: inset 0 0 20px rgba(0, 30, 60, 0.5);
.header {
display: flex;
padding: 15px 20px 15px 85px;
background: linear-gradient(90deg, #0f2a42 0%, #0a1d30 100%);
border-bottom: 2px solid #1e3a5c;
text-shadow: 0 0 5px rgba(100, 200, 255, 0.5);
.column {
font-size: 18px;
color: #6eb4ff;
font-weight: 600;
letter-spacing: 1px;
&.nick {
flex: 3;
text-align: left;
}
&.status {
flex: 1;
text-align: center;
}
&.ping {
flex: 1;
text-align: right;
padding-right: 20px;
}
}
}
.player-list {
pointer-events: all;
flex-grow: 1;
height: 100%;
flex-direction: column;
overflow-x: hidden;
overflow-y: scroll;
.player {
flex-shrink: 0;
display: flex;
align-items: center;
padding: 15px 25px;
transition: all 0.2s ease;
width: 100%;
//background: rgba(15, 30, 50, 0.4);
border-bottom: 1px solid rgba(40, 80, 120, 0.2);
cursor: pointer;
&:hover {
//background: rgba(25, 60, 90, 0.4);
box-shadow: 0 0 15px rgba(0, 150, 255, 0.1);
}
.avatar {
width: 45px;
height: 45px;
border-radius: 4px;
overflow: hidden;
margin-right: 20px;
border: 2px solid #2a4a6b;
box-shadow: 0 0 8px rgba(100, 180, 255, 0.2);
background: #0c1a2a;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.column {
font-size: 17px;
color: #c0e8ff;
text-shadow: 0 0 5px rgba(100, 180, 255, 0.3);
&.nick {
flex: 3;
text-align: left;
font-weight: 500;
letter-spacing: 0.5px;
}
&.status {
flex: 1;
text-align: center;
color: #6ecbff;
}
&.ping {
flex: 1;
text-align: right;
padding-right: 20px;
font-family: 'Courier New', monospace;
color: #88d6ff;
}
}
}
}
}
}

View File

@ -0,0 +1,60 @@
public sealed class PhysBullet : Component, Component.ICollisionListener
{
[Property] public Collider collider { get; set; }
[Property] public Rigidbody BRigidbody { get; set; }
protected override async void OnStart()
{
if ( collider != null )
{
collider.OnTriggerEnter += OnTriggerEnter;
}
await Task.DelaySeconds( 5 );
GameObject.Destroy();
}
protected override void OnUpdate()
{
}
async void ICollisionListener.OnCollisionStart( Collision collision )
{
await Task.DelaySeconds( 1 );
GameObject.Destroy();
}
// var a= Scene.Trace.Ray( collision.Contact.Point, collision.Contact.Point + collision.Contact.Normal * 10 ).Run();
// Log.Info(collision.Other.GameObject);
// Log.Info(a.GameObject);
// DebugOverlay.Line(a.StartPosition,a.EndPosition, duration: 5.5f);
// DestroyGameObject();
public void OnTriggerEnter( Collider other )
{
var components = other.Components;
if ( components.TryGet<RagdollController>( out var controller ) )
{
if ( Network.IsOwner )
return;
controller.Enabled = true;
// ModelHitboxes sas = controller.Components.Get<ModelHitboxes>();
// collider.FindClosestPoint(other.WorldPosition);
// var d = controller.GameObject.GetComponent<Dedugan>();
//
// d.Controller.Velocity = Vector3.Up * 2500;
// rb.MassOverride = 500f;
//
// rb.ApplyImpulse( Vector3.Up * 5000000 );
// rb.Destroy();
// controller.bodyPhysics.
}
}
}

View File

@ -0,0 +1,10 @@
{
"UseFixedUpdate": true,
"SubSteps": 25,
"FixedUpdateFrequency": 50,
"MaxFixedUpdates": 2,
"__guid": "6b9cc867-c971-4214-8b8f-69fbbd018bd8",
"__schema": "configdata",
"__type": "PhysicsSettings",
"__version": 1
}