Compare commits
No commits in common. "9b50dbe33d6bde22881461d62e2c2de20f391fbb" and "d1c446b5981b8abb8fb72a692d42846d5c6d263a" have entirely different histories.
9b50dbe33d
...
d1c446b598
5
koptilnya/.idea/.gitignore
generated
vendored
Normal file
5
koptilnya/.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
12
koptilnya/.idea/koptilnya.iml
generated
Normal file
12
koptilnya/.idea/koptilnya.iml
generated
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
8
koptilnya/.idea/modules.xml
generated
Normal file
8
koptilnya/.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/koptilnya.iml" filepath="$PROJECT_DIR$/.idea/koptilnya.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
koptilnya/.idea/vcs.xml
generated
Normal file
6
koptilnya/.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@ -1,8 +1,8 @@
|
||||
--@shared
|
||||
--@name Audi A6 2012
|
||||
--@author Opti1337, DarkSupah
|
||||
--@include /libs/meshbuilder.txt
|
||||
local MeshBuilder = require("/libs/meshbuilder.txt")
|
||||
-- @shared
|
||||
-- @name Audi A6 2012
|
||||
-- @author Opti1337, DarkSupah
|
||||
-- @include /koptilnya/mesh_loader/builder.txt
|
||||
require("/koptilnya/mesh_loader/builder.txt")
|
||||
|
||||
DEBUG_MODE = true
|
||||
|
||||
@ -193,5 +193,10 @@ if SERVER then
|
||||
|
||||
builder:build("DashDials", Vector(0), Angle(0), SCALE, Colors.DashDials, Materials.DashDials, this, this)
|
||||
|
||||
builder:apply()
|
||||
local result = builder:getResult()
|
||||
else
|
||||
PERMA.onPermissionsGained = function()
|
||||
builder = MeshBuilder:new(LINK)
|
||||
end
|
||||
PERMA.build()
|
||||
end
|
||||
|
||||
@ -1,16 +1,15 @@
|
||||
--@shared
|
||||
--@name BMW 850CSi 96
|
||||
--@author Opti1337, DarkSupah
|
||||
--@include /libs/meshbuilder.txt
|
||||
|
||||
-- @shared
|
||||
-- @name BMW 850CSi 96
|
||||
-- @author Opti1337, DarkSupah
|
||||
-- @include /koptilnya/mesh_loader/builder.txt
|
||||
--@include koptilnya/libs/flux.txt
|
||||
|
||||
local flux = require("koptilnya/libs/flux.txt")
|
||||
local MeshBuilder = require("/libs/meshbuilder.txt")
|
||||
require("/koptilnya/mesh_loader/builder.txt")
|
||||
|
||||
DEBUG_MODE = true
|
||||
|
||||
local LINK = "https://raw.githubusercontent.com/koptilnya/gmod-data/main/bmw_850csi_96.obj"
|
||||
local LINK = "http://82.179.248.158/bmw_850csi_96.obj#baaz"
|
||||
local SCALE = Vector(1)
|
||||
|
||||
local Materials =
|
||||
@ -130,7 +129,7 @@ if SERVER then
|
||||
builder:build("headlightl_black_plastic", Vector(0), Angle(0), SCALE, Colors.BlackPlastic, Materials.BlackPlastic, headlightL, this)
|
||||
builder:build("headlightl_chrome", Vector(0), Angle(0), SCALE, Colors.Chrome, Materials.Chrome, headlightL, this)
|
||||
|
||||
local result = builder:apply()
|
||||
local result = builder:getResult()
|
||||
|
||||
local headlightl = {
|
||||
angle = 0
|
||||
@ -141,8 +140,8 @@ if SERVER then
|
||||
}
|
||||
|
||||
function openHeadlights()
|
||||
flux.to(headlightl, 1, { angle = 2 }):delay(0.3):ease("quartout")
|
||||
flux.to(headlightr, 1, { angle = -2 }):ease("quartout")
|
||||
flux.to(headlightl, 1, { angle = 28 }):delay(0.3):ease("quartout")
|
||||
flux.to(headlightr, 1, { angle = 28 }):ease("quartout")
|
||||
end
|
||||
|
||||
function closeHeadlights()
|
||||
@ -166,4 +165,9 @@ if SERVER then
|
||||
closeHeadlights()
|
||||
end
|
||||
end)
|
||||
else
|
||||
PERMA.onPermissionsGained = function()
|
||||
builder = MeshBuilder:new(LINK)
|
||||
end
|
||||
PERMA.build()
|
||||
end
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
--@shared
|
||||
--@name BMW M4 G82 Competition
|
||||
--@author Koptilnya1337
|
||||
--@include /libs/meshbuilder.txt
|
||||
local MeshBuilder = require("/libs/meshbuilder.txt")
|
||||
-- @shared
|
||||
-- @name BMW M4 G82 Competition
|
||||
-- @author Koptilnya1337
|
||||
-- @include /koptilnya/mesh_loader/builder.txt
|
||||
require("/koptilnya/mesh_loader/builder.txt")
|
||||
|
||||
DEBUG_MODE = true
|
||||
|
||||
@ -36,5 +36,10 @@ if SERVER then
|
||||
builder:build("Trunk", Vector(0), Angle(0), SCALE, Colors.Body, Materials.Body, this, this)
|
||||
builder:build("Roof", Vector(0), Angle(0), SCALE, Colors.Carbon, Materials.Carbon, this, this)
|
||||
|
||||
builder:apply()
|
||||
local result = builder:getResult()
|
||||
else
|
||||
PERMA.onPermissionsGained = function()
|
||||
builder = MeshBuilder:new(LINK)
|
||||
end
|
||||
PERMA.build()
|
||||
end
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
--@shared
|
||||
--@name Ford Mustang GT 2015
|
||||
--@author Opti1337, DarkSupah
|
||||
--@include /libs/meshbuilder.txt
|
||||
local MeshBuilder = require("/libs/meshbuilder.txt")
|
||||
-- @shared
|
||||
-- @name Ford Mustang GT 2015
|
||||
-- @author Opti1337, DarkSupah
|
||||
-- @include /koptilnya/mesh_loader/builder.txt
|
||||
-- @include /koptilnya/car_systems/lights_controller.txt
|
||||
require("/koptilnya/mesh_loader/builder.txt")
|
||||
require("/koptilnya/car_systems/lights_controller.txt")
|
||||
|
||||
DEBUG_MODE = true
|
||||
|
||||
@ -48,10 +50,8 @@ local COLORS = {
|
||||
local builder = {}
|
||||
local lightsController = {}
|
||||
|
||||
builder = MeshBuilder:new(LINK)
|
||||
|
||||
if SERVER then
|
||||
|
||||
builder = MeshBuilder:new(LINK)
|
||||
builder.onObjectParsed = function(builder, objectsNames)
|
||||
printTable(objectsNames)
|
||||
end
|
||||
@ -91,5 +91,52 @@ if SERVER then
|
||||
local HighBeamLights = builder:build("HighBeamLights_body1_model0.017", Vector(0), Angle(0), SCALE, COLORS.LightsBase, MATERIALS.LightsBase, chip(), chip())
|
||||
local FogLights = builder:build("FogLights_body1_model0.018", Vector(0), Angle(0), SCALE, COLORS.LightsBase, MATERIALS.LightsBase, chip(), chip())
|
||||
|
||||
builder:apply()
|
||||
local result = builder:getResult()
|
||||
|
||||
local lights = {
|
||||
StopLights = {Entities = {LeftStopLight1, LeftStopLight2, LeftStopLight3, RightStopLight1, RightStopLight2, RightStopLight3}, LerpSpeed = 0.2, Colors = {On = Color(250, 0, 0), Off = Color(30, 0, 0), Active = Color(90, 0, 0)}},
|
||||
ReverseLights = {Entities = {ReverseLights}, LerpSpeed = 0.1, Colors = {On = Color(255, 255, 255), Off = Color(20, 20, 20)}},
|
||||
LowBeamLights = {Entities = {LowBeamLights}, LerpSpeed = 0.1, Colors = {On = Color(255, 255, 255), Off = Color(20, 20, 20)}},
|
||||
HighBeamLights = {Entities = {HighBeamLights}, LerpSpeed = 0.1, Colors = {On = Color(255, 255, 255), Off = Color(20, 20, 20)}},
|
||||
FogLights = {Entities = {FogLights}, LerpSpeed = 0.1, Colors = {On = Color(255, 255, 255), Off = Color(20, 20, 20)}}
|
||||
TurnLights = {LeftEntities = {LeftStopLight1, LeftStopLight2, LeftStopLight3}, RightEntities = {RightStopLight1, RightStopLight2, RightStopLight3}, LerpSpeed = 0.2, Colors = {On = Color(250, 120, 0), Off = Color(30, 0, 0)}}
|
||||
}
|
||||
|
||||
-- local lightsEntities = {StopLights = {StopLights}, ReverseLights = {ReverseLights}, LowBeamLights = {LowBeamLights}, HighBeamLights = {HighBeamLights}}
|
||||
-- local lightColors = {StopLights = {On = Color(250, 0, 0), Off = Color(30, 0, 0), Active = Color(90, 0, 0)}, ReverseLights = {On = Color(255, 255, 255), Off = Color(20, 20, 20), Active = Color(20, 20, 20)}}
|
||||
-- local lights = {Lights = lightsEntities, Colors = lightColors}
|
||||
|
||||
lightsController = LightsController:new(lights)
|
||||
|
||||
wire.adjustPorts({LightInputs = "table"}, {})
|
||||
|
||||
hook.add("think", "lights", function()
|
||||
lightsController:useStopLights(wire.ports.LightInputs.Stop)
|
||||
lightsController:useReverseLights(wire.ports.LightInputs.Reverse)
|
||||
lightsController:useLowBeam(wire.ports.LightInputs.LowBeam)
|
||||
lightsController:useHighBeam(wire.ports.LightInputs.HighBeam)
|
||||
|
||||
lightsController:setActive(wire.ports.LightInputs.LowBeam == 1)
|
||||
|
||||
lightsController:update()
|
||||
end
|
||||
)
|
||||
else
|
||||
function init()
|
||||
builder = MeshBuilder:new(LINK)
|
||||
end
|
||||
|
||||
|
||||
if hasPermission("http.get") and hasPermission("mesh") and hasPermission("entities.setRenderProperty", chip()) then
|
||||
init()
|
||||
else
|
||||
setupPermissionRequest({"http.get", "mesh", "entities.setRenderProperty"}, "", true)
|
||||
|
||||
hook.add("permissionrequest", "_permissionrequest", function()
|
||||
if permissionRequestSatisfied() then
|
||||
init()
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
--@shared
|
||||
--@name Ford F-150 Raptor
|
||||
--@author Opti1337, .hemp
|
||||
--@include /libs/meshbuilder.txt
|
||||
local MeshBuilder = require("/libs/meshbuilder.txt")
|
||||
-- @shared
|
||||
-- @name Ford F-150 Raptor
|
||||
-- @author Opti1337, .hemp
|
||||
-- @include /koptilnya/mesh_loader/builder.txt
|
||||
require("/koptilnya/mesh_loader/builder.txt")
|
||||
|
||||
DEBUG_MODE = true
|
||||
|
||||
@ -50,5 +50,10 @@ if SERVER then
|
||||
|
||||
builder:build("Railing", Vector(0), Angle(0), SCALE, Color(255, 255, 255), "sprops/trans/wheels/wheel_d_rim1", chip(), chip())
|
||||
|
||||
builder:apply()
|
||||
local result = builder:getResult()
|
||||
else
|
||||
PERMA.onPermissionsGained = function()
|
||||
builder = MeshBuilder:new(LINK)
|
||||
end
|
||||
PERMA.build()
|
||||
end
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
--@shared
|
||||
--@name JDM Wheels
|
||||
--@author Opti1337, .hemp
|
||||
--@include /libs/meshbuilder.txt
|
||||
local MeshBuilder = require("/libs/meshbuilder.txt")
|
||||
-- @shared
|
||||
-- @name JDM Wheels
|
||||
-- @author Opti1337, .hemp
|
||||
-- @include /koptilnya/mesh_loader/builder.txt
|
||||
|
||||
require("/koptilnya/mesh_loader/builder.txt")
|
||||
|
||||
local LINK = "https://raw.githubusercontent.com/koptilnya/gmod-data/main/jdmwheel1.obj?d=1"
|
||||
local SCALE = Vector(0.6)
|
||||
@ -62,7 +63,12 @@ if SERVER then
|
||||
}, wheel, wheel)
|
||||
end
|
||||
|
||||
builder:apply()
|
||||
builder:getResult()
|
||||
end
|
||||
end)
|
||||
else
|
||||
PERMA.onPermissionsGained = function()
|
||||
builder = MeshBuilder:new(LINK)
|
||||
end
|
||||
PERMA.build()
|
||||
end
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
--@shared
|
||||
--@name Porsche 911 Turbo S 2017
|
||||
--@author Opti1337, DarkSupah
|
||||
--@include /libs/meshbuilder.txt
|
||||
local MeshBuilder = require("/libs/meshbuilder.txt")
|
||||
-- @shared
|
||||
-- @name Porsche 911 Turbo S 2017
|
||||
-- @author Opti1337, DarkSupah
|
||||
-- @include /koptilnya/mesh_loader/builder.txt
|
||||
require("/koptilnya/mesh_loader/builder.txt")
|
||||
|
||||
DEBUG_MODE = true
|
||||
|
||||
@ -11,80 +11,21 @@ local SCALE = Vector(0.9)
|
||||
|
||||
local builder = {}
|
||||
|
||||
local objectNames = {"Gear_stick_handle",
|
||||
"Locks",
|
||||
"Left_door_panel",
|
||||
"Seat_base",
|
||||
"Torpedo",
|
||||
"Front_bumper_details",
|
||||
"Dashboard_interior",
|
||||
"Right_door_body",
|
||||
"Body",
|
||||
"Seatbelts",
|
||||
"Seatbelts_caps",
|
||||
"Dials",
|
||||
"Dashboard_panel",
|
||||
"Lower_dashboard",
|
||||
"Rear_mirror",
|
||||
"Dials_base",
|
||||
"Front_lights_glass",
|
||||
"Rear_logo",
|
||||
"Exhaust_pipes",
|
||||
"Torpedo_panel",
|
||||
"Seats",
|
||||
"Dials_glass",
|
||||
"Gear_stick_base",
|
||||
"Bonnet",
|
||||
"Rear_lights_base",
|
||||
"Torpedo_buttons",
|
||||
"Seat_controls",
|
||||
"Carpets",
|
||||
"Steering_wheel",
|
||||
"Interior_base",
|
||||
"Front_bumper",
|
||||
"Front_lights_bulbs",
|
||||
"Doors_rubbers",
|
||||
"Bottom",
|
||||
"Seatbelts_caps_plastic",
|
||||
"Windows_lines",
|
||||
"Exterior_plastic",
|
||||
"Front_lights_strips",
|
||||
"Gear_stick_details",
|
||||
"Exhaust_collector",
|
||||
"Left_door_mirror",
|
||||
"Dashboard_vents",
|
||||
"Dashboard_plastic",
|
||||
"Seatbelts_locks",
|
||||
"Right_door_panel",
|
||||
"Left_door_body",
|
||||
"Right_door_mirror",
|
||||
"Rear_lights_glass",
|
||||
"Stitches",
|
||||
"Right_front_turn",
|
||||
"Timer",
|
||||
"Front_lights_borders",
|
||||
"Front_indicators_glass",
|
||||
"Door_frames",
|
||||
"Front_lights_base",
|
||||
"Left_front_turn",
|
||||
"Rear_details",
|
||||
"Rear_spoiler_glass",
|
||||
"Clothes_hooks",
|
||||
"Exhaust_bumper",
|
||||
"Left_side_indicator",
|
||||
"Dashboard",
|
||||
"Door_plastic",
|
||||
"Rear_bumper",
|
||||
"Seats_plastic",
|
||||
"Right_side_indicator",
|
||||
"Steering_wheel_details"}
|
||||
|
||||
if SERVER then
|
||||
builder = MeshBuilder:new(LINK)
|
||||
for k, v in pairs(objectNames) do
|
||||
builder.onObjectParsed = function(builder, objectsNames)
|
||||
timer.simple(3, function()
|
||||
for k, v in pairs(objectsNames) do
|
||||
|
||||
builder:build(v, Vector(0), Angle(0), SCALE, Color(360 / #objectNames * k, 1, 1):hsvToRGB(), "models/debug/debugwhite", chip(), chip())
|
||||
builder:build(v, Vector(0), Angle(0), SCALE, Color(360 / #objectsNames * k, 1, 1):hsvToRGB(), "models/debug/debugwhite", chip(), chip())
|
||||
end
|
||||
|
||||
builder:apply()
|
||||
local result = builder:getResult()
|
||||
end)
|
||||
end
|
||||
else
|
||||
PERMA.onPermissionsGained = function()
|
||||
builder = MeshBuilder:new(LINK)
|
||||
end
|
||||
PERMA.build()
|
||||
end
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
--@shared
|
||||
--@name Toyota Altezza
|
||||
--@author Opti1337, .hemp
|
||||
--@include /libs/meshbuilder.txt
|
||||
local MeshBuilder = require("/libs/meshbuilder.txt")
|
||||
-- @shared
|
||||
-- @name Toyota Altezza
|
||||
-- @author Opti1337, .hemp
|
||||
-- @include /koptilnya/mesh_loader/builder.txt
|
||||
require("/koptilnya/mesh_loader/builder.txt")
|
||||
|
||||
DEBUG_MODE = true
|
||||
|
||||
local LINK = "https://www.dropbox.com/s/0vnd3nir8cyolz5/is300_3.obj?dl=1"
|
||||
local SCALE = Vector(0.8, 0.79, 0.8)
|
||||
|
||||
local builder = MeshBuilder:new(LINK)
|
||||
local builder = {}
|
||||
|
||||
if SERVER then
|
||||
|
||||
builder = MeshBuilder:new(LINK)
|
||||
|
||||
builder:build("body_Mesh_0", Vector(0), Angle(0), SCALE, Color(40, 40, 40), "models/debug/debugwhite", chip(), chip())
|
||||
builder:build("chrome_Mesh_1", Vector(0), Angle(0), SCALE, Color(255, 255, 255), "sprops/textures/sprops_chrome", chip(), chip())
|
||||
@ -24,5 +24,33 @@ if SERVER then
|
||||
builder:build("Reshetka_Mesh_7", Vector(0), Angle(0), SCALE, Color(225, 255, 255, 255), "models/props_interiors/metalfence007a", chip(), chip())
|
||||
builder:build("w_plastic_Mesh_8", Vector(0), Angle(0), SCALE, Color(225, 255, 255, 255), "models/combine_scanner/scanner_eye", chip(), chip())
|
||||
|
||||
builder:apply()
|
||||
builder:getResult()
|
||||
else
|
||||
function init()
|
||||
builder = MeshBuilder:new(LINK)
|
||||
builder.onHologramsReceived = function(builder, objects)
|
||||
local mat = material.create("VertexLitGeneric")
|
||||
mat:setTextureURL("$basetexture", "https://i.imgur.com/gw4kfYv.jpg",
|
||||
function(m, url, w, h, layout)
|
||||
layout(0, 0, 2048, 2048)
|
||||
end,
|
||||
function(m, url)
|
||||
objects[1].holo:setMaterial("")
|
||||
objects[1].holo:setMeshMaterial(m)
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
if hasPermission("http.get") and hasPermission("mesh") and hasPermission("entities.setRenderProperty", chip()) then
|
||||
init()
|
||||
else
|
||||
setupPermissionRequest({"http.get", "mesh", "entities.setRenderProperty"}, "", true)
|
||||
|
||||
hook.add("permissionrequest", "_permissionrequest", function()
|
||||
if permissionRequestSatisfied() then
|
||||
init()
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,66 +1,19 @@
|
||||
--@name SX 240
|
||||
--@author Koptilnya
|
||||
--@server
|
||||
--@include /koptilnya/engine_remastered/vehicle.txt
|
||||
--@include /koptilnya/engine_remastered/powertrain/differential.txt
|
||||
|
||||
local Vehicle, POWERTRAIN_COMPONENT = unpack(require('/koptilnya/engine_remastered/vehicle.txt'))
|
||||
local Differential = require('/koptilnya/engine_remastered/powertrain/differential.txt')
|
||||
|
||||
-- Michelin Pilot Sport 4S (High-Performance Road Tire)
|
||||
|
||||
local WheelConfig = {
|
||||
DEBUG = true,
|
||||
BrakePower = 1200,
|
||||
CustomWheel = {
|
||||
Mass = 30,
|
||||
|
||||
LateralFrictionPreset = {
|
||||
B = 12.0,
|
||||
C = 1.3,
|
||||
D = 1.8,
|
||||
E = -1.8
|
||||
},
|
||||
LongitudinalFrictionPreset = {
|
||||
B = 18.0,
|
||||
C = 1.5,
|
||||
D = 1.5,
|
||||
E = 0.3
|
||||
},
|
||||
AligningFrictionPreset = {
|
||||
B = 2.8,
|
||||
C = 2.1,
|
||||
D = 0.10,
|
||||
E = -2.5
|
||||
},
|
||||
-- AligningFrictionPreset = {
|
||||
-- B = 13,
|
||||
-- C = 2.4,
|
||||
-- D = 1,
|
||||
-- E = 0.48
|
||||
-- }
|
||||
},
|
||||
Model = 'models/sprops/trans/wheel_a/wheel25.mdl'
|
||||
BrakePower = 800,
|
||||
CustomWheel = {},
|
||||
Model = 'models/sprops/trans/wheel_d/t_wheel25.mdl',
|
||||
RotationAxle = Angle(1, 0, 0)
|
||||
}
|
||||
local FrontWheelsConfig = table.merge(
|
||||
table.copy(WheelConfig),
|
||||
{
|
||||
CustomWheel = {
|
||||
CasterAngle = 7,
|
||||
CamberAngle = -3,
|
||||
ToeAngle = 0.5
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
local RearWheelsConfig = table.merge(
|
||||
table.copy(WheelConfig),
|
||||
{
|
||||
HandbrakePower = 2200,
|
||||
CustomWheel = {
|
||||
CamberAngle = -2,
|
||||
ToeAngle = 0.5
|
||||
}
|
||||
}
|
||||
)
|
||||
local FrontWheelsConfig = table.merge(table.copy(WheelConfig), { SteerLock = 35 })
|
||||
local RearWheelsConfig = table.merge(table.copy(WheelConfig), { HandbrakePower = 2000 })
|
||||
|
||||
Vehicle:new({
|
||||
{
|
||||
@ -68,11 +21,11 @@ Vehicle:new({
|
||||
Type = POWERTRAIN_COMPONENT.Engine,
|
||||
Config = {
|
||||
IdleRPM = 900,
|
||||
MaxRPM = 7000,
|
||||
MaxRPM = 7500,
|
||||
Inertia = 0.151,
|
||||
StartFriction = -10,
|
||||
FrictionCoeff = 0.01,
|
||||
LimiterDuration = 0.06,
|
||||
LimiterDuration = 0.08,
|
||||
TorqueMap = {
|
||||
118.89918444138, 122.0751393736, 125.25109430583, 128.42704923806, 131.60300417029, 134.77895910251, 137.95491403474, 141.13086896697, 144.3068238992, 147.48277883143, 150.65873376365, 153.83468869588, 157.01064362811, 160.18659856034, 163.36255349256,
|
||||
166.53850842479, 169.71446335702, 172.89041828925, 176.06637322148, 179.2423281537, 182.41828308593, 185.59423801816, 188.77019295039, 191.94614788261, 195.12210281484, 198.29805774707, 201.4740126793, 204.64996761153, 207.82592254375, 211.00187747598,
|
||||
@ -99,79 +52,44 @@ Vehicle:new({
|
||||
Type = POWERTRAIN_COMPONENT.Gearbox,
|
||||
Config = {
|
||||
Type = 'MANUAL',
|
||||
ShiftTime = 3,
|
||||
Inertia = 0.01,
|
||||
Ratios = { 3.626, 2.200, 1.541, 1.213, 1.000, 0.767 },
|
||||
Reverse = 3.437
|
||||
}
|
||||
},
|
||||
{
|
||||
Name = 'AxleFront',
|
||||
Input = 'Axle',
|
||||
Name = 'Axle1',
|
||||
Input = 'Gearbox',
|
||||
Type = POWERTRAIN_COMPONENT.Differential,
|
||||
Config = {
|
||||
Type = Differential.TYPES.Open,
|
||||
FinalDrive = 3.392,
|
||||
Inertia = 0.01,
|
||||
BiasAB = 0.5,
|
||||
CoastRamp = 1,
|
||||
CoastRamp = 0.5,
|
||||
PowerRamp = 1,
|
||||
Stiffness = 0.1,
|
||||
SlipTorque = 0,
|
||||
SteerLock = 45
|
||||
SlipTorque = 1000
|
||||
}
|
||||
},
|
||||
{
|
||||
Name = 'WheelFL',
|
||||
Input = 'Axle1',
|
||||
Type = POWERTRAIN_COMPONENT.Wheel,
|
||||
Input = 'AxleFront',
|
||||
Config = table.merge(table.copy(FrontWheelsConfig), { Offset = 0 })
|
||||
},
|
||||
{
|
||||
Name = 'WheelFR',
|
||||
Input = 'Axle1',
|
||||
Type = POWERTRAIN_COMPONENT.Wheel,
|
||||
Input = 'AxleFront',
|
||||
Config = table.merge(table.copy(FrontWheelsConfig), { Offset = 180 })
|
||||
},
|
||||
{
|
||||
Name = 'AxleBack',
|
||||
Input = 'Axle',
|
||||
Type = POWERTRAIN_COMPONENT.Differential,
|
||||
Config = {
|
||||
Type = Differential.TYPES.Open,
|
||||
FinalDrive = 3.392,
|
||||
Inertia = 0.01,
|
||||
BiasAB = 0.5,
|
||||
CoastRamp = 1,
|
||||
PowerRamp = 1,
|
||||
Stiffness = 0.1,
|
||||
SlipTorque = 0,
|
||||
}
|
||||
},
|
||||
{
|
||||
Name = 'Axle',
|
||||
Input = 'Gearbox',
|
||||
Type = POWERTRAIN_COMPONENT.Differential,
|
||||
Config = {
|
||||
Type = Differential.TYPES.Open,
|
||||
FinalDrive = 1,
|
||||
Inertia = 0.01,
|
||||
BiasAB = 0.5,
|
||||
CoastRamp = 1,
|
||||
PowerRamp = 1,
|
||||
Stiffness = 1,
|
||||
SlipTorque = 0
|
||||
}
|
||||
},
|
||||
{
|
||||
Name = 'WheelRL',
|
||||
Input = 'AxleBack',
|
||||
Type = POWERTRAIN_COMPONENT.Wheel,
|
||||
Config = table.merge(table.copy(RearWheelsConfig), { Offset = 0 })
|
||||
},
|
||||
{
|
||||
Name = 'WheelRR',
|
||||
Input = 'AxleBack',
|
||||
Type = POWERTRAIN_COMPONENT.Wheel,
|
||||
Config = table.merge(table.copy(RearWheelsConfig), { Offset = 180 })
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
--@name SX 240
|
||||
--@author Koptilnya1337
|
||||
--@server
|
||||
--@include /koptilnya/engine_remastered/vehicle.txt
|
||||
-- @name SX 240
|
||||
-- @author Koptilnya1337
|
||||
-- @server
|
||||
-- @include /koptilnya/engine_remastered/vehicle.txt
|
||||
require('/koptilnya/engine_remastered/vehicle.txt')
|
||||
|
||||
Vehicle:new({
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
--@include ../powertrain/gearboxes/manual.txt
|
||||
-- @include ../powertrain/gearboxes/manual.txt
|
||||
|
||||
local ManualGearbox = require('../powertrain/gearboxes/manual.txt')
|
||||
|
||||
|
||||
@ -1,85 +0,0 @@
|
||||
--@client
|
||||
local fontArial92 = render.createFont("Arial", 92, 250, true, false, false, false, 0, false, 0)
|
||||
local fontArial46 = render.createFont("Arial", 46, 250, true, false, false, false, 0, false, 0)
|
||||
ENGINE_RPM, CAR_SPEED, GEARBOX_GEAR = 0, 123, 0
|
||||
local resx, resy = render.getGameResolution()
|
||||
local linesmatrix = Matrix()
|
||||
local linesposx, linesposy = resx - 200, resy - 150
|
||||
linesmatrix:setTranslation(Vector(linesposx, linesposy, 0))
|
||||
linesmatrix:setAngles(Angle(0, 15, 0))
|
||||
linesmatrix:setScale(Vector(0.7))
|
||||
hook.add("DrawHud", "CARHUD", function()
|
||||
render.pushMatrix(linesmatrix)
|
||||
render.enableScissorRect(linesposx - 50, linesposy + 30, linesposx + 208, linesposy + 50)
|
||||
for x = 0, 208, 4 do
|
||||
|
||||
if ENGINE_RPM > x / 220 then
|
||||
col = 55 + x / 220 * 200
|
||||
render.setRGBA(col, col, col, 250)
|
||||
else
|
||||
render.setRGBA(100, 100, 100, 250)
|
||||
end
|
||||
|
||||
render.drawRectFast(x, -x / 2, 2, 150)
|
||||
end
|
||||
render.disableScissorRect()
|
||||
render.enableScissorRect(linesposx - 50, linesposy + 20, linesposx + 212, linesposy + 50)
|
||||
for x = 212, 220, 4 do
|
||||
|
||||
if ENGINE_RPM > x / 220 then
|
||||
render.setRGBA(200, 71, 71, 200)
|
||||
else
|
||||
render.setRGBA(100, 100, 100, 200)
|
||||
end
|
||||
|
||||
render.drawRectFast(x, -x / 2, 2, 150)
|
||||
end
|
||||
render.disableScissorRect()
|
||||
render.enableScissorRect(linesposx - 50, linesposy + 20, linesposx + 208, linesposy + 25)
|
||||
render.drawRectFast(0, -256, 208, 512)
|
||||
render.disableScissorRect()
|
||||
render.popMatrix()
|
||||
render.setRGBA(151, 151, 151, 220)
|
||||
|
||||
render.setFont(fontArial92)
|
||||
local str = string.rep("0", 3 - #tostring(CAR_SPEED)) .. CAR_SPEED
|
||||
render.setRGBA(51, 51, 51, 256)
|
||||
|
||||
for k = 1, 3 do
|
||||
local num = string.sub(str, k, k)
|
||||
if num ~= "0" then
|
||||
render.setRGBA(255, 255, 255, 250)
|
||||
end
|
||||
render.drawText(linesposx - 60 + k * 46, resy - 130 - 80, num)
|
||||
end
|
||||
render.setFont(fontArial46)
|
||||
render.setRGBA(200, 51, 51, 256)
|
||||
local t = "N"
|
||||
if GEARBOX_GEAR == -1 then
|
||||
t = "R"
|
||||
elseif GEARBOX_GEAR == 0 then
|
||||
t = "N"
|
||||
else
|
||||
t = GEARBOX_GEAR
|
||||
end
|
||||
render.drawText(linesposx - 35 + 164, resy - 130 - 40, t)
|
||||
end)
|
||||
|
||||
net.receive("ENGINE_RPM", function()
|
||||
local rpm = net.readFloat()
|
||||
if rpm then
|
||||
ENGINE_RPM = rpm
|
||||
end
|
||||
end)
|
||||
net.receive("CAR_SPEED", function()
|
||||
local speed = net.readUInt(12)
|
||||
if speed then
|
||||
CAR_SPEED = math.clamp(speed, 0, 999)
|
||||
end
|
||||
end)
|
||||
net.receive("GEARBOX_GEAR", function()
|
||||
local gear = net.readInt(5)
|
||||
if gear then
|
||||
GEARBOX_GEAR = gear
|
||||
end
|
||||
end)
|
||||
@ -10,8 +10,6 @@ local Clutch = class('Clutch', PowertrainComponent)
|
||||
function Clutch:initialize(vehicle, name, config)
|
||||
PowertrainComponent.initialize(self, vehicle, name, config)
|
||||
|
||||
if CLIENT then return end
|
||||
|
||||
self.wireInputs = {
|
||||
Clutch = 'number'
|
||||
}
|
||||
@ -24,8 +22,6 @@ function Clutch:initialize(vehicle, name, config)
|
||||
end
|
||||
|
||||
function Clutch:updateWireOutputs()
|
||||
PowertrainComponent.updateWireOutputs(self)
|
||||
|
||||
wire.ports.Clutch_Torque = self.torque
|
||||
end
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
--@include /koptilnya/libs/constants.txt
|
||||
--@include ./powertrain_component.txt
|
||||
|
||||
|
||||
local PowertrainComponent = require('./powertrain_component.txt')
|
||||
local WheelComponent = require('./wheel.txt')
|
||||
|
||||
@ -8,17 +9,11 @@ require('/koptilnya/libs/constants.txt')
|
||||
|
||||
local Differential = class('Differential', PowertrainComponent)
|
||||
|
||||
function Differential.getSplitStrategy(type)
|
||||
return SPLIT_STRATEGIES[type] or SPLIT_STRATEGIES[Differential.TYPES.Open]
|
||||
end
|
||||
|
||||
function Differential:initialize(vehicle, name, config)
|
||||
PowertrainComponent.initialize(self, vehicle, name, config)
|
||||
|
||||
if CLIENT then return end
|
||||
|
||||
self.wireOutputs = {
|
||||
[string.format('%s_Torque', self.name)] = 'number'
|
||||
Diff_Torque = 'number'
|
||||
}
|
||||
|
||||
self.finalDrive = config.FinalDrive or 4
|
||||
@ -29,10 +24,6 @@ function Differential:initialize(vehicle, name, config)
|
||||
self.preload = config.Preload or 10
|
||||
self.stiffness = config.Stiffness or 0.1
|
||||
self.slipTorque = config.SlipTorque or 1000
|
||||
self.splitStrategy = Differential.getSplitStrategy(config.Type or Differential.TYPES.Open)
|
||||
|
||||
self.steerLock = config.SteerLock or 0
|
||||
self.steerAngle = 0
|
||||
end
|
||||
|
||||
function Differential:linkComponent(component)
|
||||
@ -50,9 +41,7 @@ function Differential:linkComponent(component)
|
||||
end
|
||||
|
||||
function Differential:updateWireOutputs()
|
||||
PowertrainComponent.updateWireOutputs(self)
|
||||
|
||||
wire.ports[string.format('%s_Torque', self.name)] = self.torque
|
||||
wire.ports.Diff_Torque = self.torque
|
||||
|
||||
if self.outputA ~= nil then
|
||||
self.outputA:updateWireOutputs()
|
||||
@ -96,7 +85,7 @@ function Differential:forwardStep(torque, inertia)
|
||||
|
||||
self.torque = torque * self.finalDrive
|
||||
|
||||
local tqA, tqB = self:splitStrategy(
|
||||
local tqA, tqB = self:_openDiffTorqueSplit(
|
||||
self.torque,
|
||||
aW,
|
||||
bW,
|
||||
@ -110,54 +99,10 @@ function Differential:forwardStep(torque, inertia)
|
||||
self.slipTorque
|
||||
)
|
||||
|
||||
tqA = self.outputA:forwardStep(tqA, inertia * 0.5 * math.pow(self.finalDrive, 2) + aI)
|
||||
tqB = self.outputB:forwardStep(tqB, inertia * 0.5 * math.pow(self.finalDrive, 2) + bI)
|
||||
tqA = self.outputA:forwardStep(tqA, inertia * 0.5 * math.pow(self.finalDrive, 2) + aI) / self.finalDrive
|
||||
tqB = self.outputB:forwardStep(tqB, inertia * 0.5 * math.pow(self.finalDrive, 2) + bI) / self.finalDrive
|
||||
|
||||
-- // REFACTOR
|
||||
if self.steerLock ~= 0 then
|
||||
local steerInertia = (aI + bI) / 2
|
||||
local driverInput = 5
|
||||
|
||||
local localVelocityLength = chip():getVelocity():getLength()
|
||||
local MPH = localVelocityLength * (15 / 352)
|
||||
local KPH = MPH * 1.609
|
||||
|
||||
local assist = math.clamp(10.0 / math.sqrt(KPH / 3), 2.0, 10.0)
|
||||
local inputForce = driverInput * assist
|
||||
|
||||
local maxSteerSpeed = math.rad(1337)
|
||||
|
||||
local inputTorque = self.vehicle.steer * inputForce
|
||||
|
||||
local avgSteerAngle = (self.outputA.customWheel.steerAngle + self.outputB.customWheel.steerAngle) / 2
|
||||
local mz = self.outputA.customWheel.mz + self.outputB.customWheel.mz
|
||||
local mzDiff = self.outputA.customWheel.mz - self.outputB.customWheel.mz
|
||||
local avgMz = (self.outputA.customWheel.mz + self.outputB.customWheel.mz) / 2
|
||||
local maxMz = math.max(self.outputA.customWheel.mz + self.outputB.customWheel.mz)
|
||||
local minMz = math.min(self.outputA.customWheel.mz + self.outputB.customWheel.mz)
|
||||
|
||||
local steerTorque = mzDiff / 2 * -1 + inputTorque
|
||||
|
||||
local steerAngularAccel = steerTorque / steerInertia
|
||||
|
||||
self.steerAngle = math.clamp(
|
||||
self.steerAngle + steerAngularAccel * TICK_INTERVAL,
|
||||
-self.steerLock,
|
||||
self.steerLock
|
||||
)
|
||||
|
||||
local wheelbase = 2.05
|
||||
local trackWidth = 1.124
|
||||
local radius = wheelbase / math.tan(math.rad(self.steerAngle))
|
||||
|
||||
local innerAngle = math.deg(math.atan(wheelbase / (radius - (trackWidth / 2))))
|
||||
local outerAngle = math.deg(math.atan(wheelbase / (radius + (trackWidth / 2))))
|
||||
|
||||
self.outputA.customWheel.steerAngle = outerAngle
|
||||
self.outputB.customWheel.steerAngle = innerAngle
|
||||
end
|
||||
|
||||
return tqA + tqB
|
||||
return (tqA + tqB) / self.finalDrive
|
||||
end
|
||||
|
||||
function Differential:_openDiffTorqueSplit(tq, aW, bW, aI, bI, biasAB, preload, stiffness, powerRamp, coastRamp, slipTorque)
|
||||
@ -165,26 +110,17 @@ function Differential:_openDiffTorqueSplit(tq, aW, bW, aI, bI, biasAB, preload,
|
||||
end
|
||||
|
||||
function Differential:_lockingDiffTorqueSplit(tq, aW, bW, aI, bI, biasAB, preload, stiffness, powerRamp, coastRamp, slipTorque)
|
||||
Ta = tq * (1 - biasAB);
|
||||
Tb = tq * biasAB;
|
||||
local sumI = aI + bI
|
||||
local w = aI / sumI * aW + bI / sumI * bW
|
||||
local aTqCorr = (w - aW) * aI -- / dt
|
||||
aTqCorr = aTqCorr * stiffness
|
||||
|
||||
local syncTorque = (aW - bW) * stiffness * (aI + bI) * 0.5 / TICK_INTERVAL;
|
||||
local bTqCorr = (w - bW) * bI -- / dt
|
||||
bTqCorr = bTqCorr * stiffness
|
||||
|
||||
Ta = Ta - syncTorque;
|
||||
Tb = Tb + syncTorque;
|
||||
local biasA = math.clamp(0.5 + (bW - aW) * 0.1 * stiffness, 0, 1)
|
||||
|
||||
return Ta, Tb
|
||||
-- local sumI = aI + bI
|
||||
-- local w = aI / sumI * aW + bI / sumI * bW
|
||||
-- local aTqCorr = (w - aW) * aI -- / dt
|
||||
-- aTqCorr = aTqCorr * stiffness
|
||||
|
||||
-- local bTqCorr = (w - bW) * bI -- / dt
|
||||
-- bTqCorr = bTqCorr * stiffness
|
||||
|
||||
-- local biasA = math.clamp(0.5 + (bW - aW) * 0.1 * stiffness, 0, 1)
|
||||
|
||||
-- return tq * biasA + aTqCorr, tq * (1 - biasA) * bTqCorr
|
||||
return tq * biasA + aTqCorr, tq * (1 - biasA) * bTqCorr
|
||||
end
|
||||
|
||||
function Differential:_VLSDTorqueSplit(tq, aW, bW, aI, bI, biasAB, preload, stiffness, powerRamp, coastRamp, slipTorque)
|
||||
@ -220,18 +156,4 @@ function Differential:_HLSDTorqueSplit(tq, aW, bW, aI, bI, biasAB, preload, stif
|
||||
return tq * (1 - biasAB) - dTq, tq * biasAB + dTq
|
||||
end
|
||||
|
||||
Differential.TYPES = {
|
||||
Open = 'Open',
|
||||
Locking = 'Locking',
|
||||
VLSD = 'VLSD',
|
||||
HLSD = 'HLSD',
|
||||
}
|
||||
|
||||
SPLIT_STRATEGIES = {
|
||||
[Differential.TYPES.Open] = Differential._openDiffTorqueSplit,
|
||||
[Differential.TYPES.Locking] = Differential._lockingDiffTorqueSplit,
|
||||
[Differential.TYPES.VLSD] = Differential._VLSDTorqueSplit,
|
||||
[Differential.TYPES.HLSD] = Differential._HLSDTorqueSplit,
|
||||
}
|
||||
|
||||
return Differential
|
||||
|
||||
@ -3,8 +3,6 @@
|
||||
|
||||
local PowertrainComponent = require('./powertrain_component.txt')
|
||||
|
||||
|
||||
|
||||
require('/koptilnya/libs/constants.txt')
|
||||
|
||||
local Engine = class('Engine', PowertrainComponent)
|
||||
@ -32,6 +30,7 @@ function Engine:initialize(vehicle, name, config)
|
||||
self.limiterDuration = config.LimiterDuration or 0.05
|
||||
self.torqueMap = config.TorqueMap or {}
|
||||
|
||||
self.rpmFrac = 0
|
||||
self.friction = 0
|
||||
self.masterThrottle = 0
|
||||
|
||||
@ -39,18 +38,9 @@ function Engine:initialize(vehicle, name, config)
|
||||
|
||||
self.reactTorque = 0
|
||||
self.returnedTorque = 0
|
||||
|
||||
if CLIENT then
|
||||
--@include /koptilnya/engine_sound_2.txt
|
||||
local Sound = require('/koptilnya/engine_sound_2.txt')
|
||||
|
||||
Sound(config.MaxRPM or 7000, chip())
|
||||
end
|
||||
end
|
||||
|
||||
function Engine:updateWireOutputs()
|
||||
PowertrainComponent.updateWireOutputs(self)
|
||||
|
||||
wire.ports.Engine_RPM = self:getRPM()
|
||||
wire.ports.Engine_Torque = self.torque
|
||||
wire.ports.Engine_MasterThrottle = self.masterThrottle
|
||||
@ -92,7 +82,7 @@ function Engine:_generateTorque()
|
||||
return self.torque
|
||||
end
|
||||
|
||||
function Engine:forwardStep(torque, inertia)
|
||||
function Engine:forwardStep()
|
||||
if self.output == nil then
|
||||
local generatedTorque = self:_generateTorque()
|
||||
|
||||
@ -107,7 +97,7 @@ function Engine:forwardStep(torque, inertia)
|
||||
|
||||
local generatedTorque = self:_generateTorque()
|
||||
local reactTorque = (targetW - self.angularVelocity) * self.inertia / TICK_INTERVAL
|
||||
local returnedTorque = self.output:forwardStep(torque + generatedTorque - reactTorque, inertia + self.inertia)
|
||||
local returnedTorque = self.output:forwardStep(generatedTorque - reactTorque, 0) -- ??? 0 -> self.inertia
|
||||
|
||||
self.reactTorque = reactTorque
|
||||
self.returnedTorque = returnedTorque
|
||||
@ -118,15 +108,6 @@ function Engine:forwardStep(torque, inertia)
|
||||
|
||||
self.angularVelocity = self.angularVelocity + finalTorque / inertiaSum * TICK_INTERVAL
|
||||
self.angularVelocity = math.max(self.angularVelocity, 0)
|
||||
|
||||
-- net.start("ENGINE_RPM")
|
||||
-- net.writeFloat(self:getRPM() / self.maxRPM)
|
||||
-- net.send(self.vehicle.playersConnectedToHUD, true)
|
||||
|
||||
-- net.start("ENGINE_FULLRPM")
|
||||
-- net.writeUInt(self:getRPM(), 16)
|
||||
-- net.writeFloat(self.masterThrottle)
|
||||
-- net.send(nil, true)
|
||||
end
|
||||
|
||||
return Engine
|
||||
|
||||
@ -7,16 +7,14 @@ local Gearbox = class('Gearbox', PowertrainComponent)
|
||||
function Gearbox:initialize(vehicle, name, config)
|
||||
PowertrainComponent.initialize(self, vehicle, name, config)
|
||||
|
||||
if CLIENT then return end
|
||||
|
||||
self.wireInputs = {
|
||||
Upshift = 'number',
|
||||
Downshift = 'number'
|
||||
}
|
||||
self.wireOutputs = {
|
||||
[string.format('%s_RPM', self.name)] = 'number',
|
||||
[string.format('%s_Torque', self.name)] = 'number',
|
||||
[string.format('%s_Ratio', self.name)] = 'number'
|
||||
Gearbox_RPM = 'number',
|
||||
Gearbox_Torque = 'number',
|
||||
Gearbox_Ratio = 'number'
|
||||
}
|
||||
|
||||
self.type = config.Type or 'MANUAL'
|
||||
@ -26,11 +24,9 @@ function Gearbox:initialize(vehicle, name, config)
|
||||
end
|
||||
|
||||
function Gearbox:updateWireOutputs()
|
||||
PowertrainComponent.updateWireOutputs(self)
|
||||
|
||||
wire.ports[string.format('%s_RPM', self.name)] = self:getRPM()
|
||||
wire.ports[string.format('%s_Torque', self.name)] = self.torque
|
||||
wire.ports[string.format('%s_Ratio', self.name)] = self.ratio
|
||||
wire.ports.Gearbox_RPM = self:getRPM()
|
||||
wire.ports.Gearbox_Torque = self.torque
|
||||
wire.ports.Gearbox_Ratio = self.ratio
|
||||
end
|
||||
|
||||
function Gearbox:queryInertia()
|
||||
@ -52,18 +48,18 @@ function Gearbox:queryAngularVelocity(angularVelocity)
|
||||
end
|
||||
|
||||
function Gearbox:forwardStep(torque, inertia)
|
||||
self.torque = torque * self.ratio
|
||||
|
||||
if self.output == nil then
|
||||
return torque
|
||||
end
|
||||
|
||||
if self.ratio == 0 then
|
||||
self.output:forwardStep(0, self.inertia * 0.5)
|
||||
self.output:forwardStep(0, self.inertia)
|
||||
|
||||
return torque
|
||||
end
|
||||
|
||||
self.torque = torque * self.ratio
|
||||
|
||||
return self.output:forwardStep(self.torque, (inertia + self.inertia) * math.pow(self.ratio, 2)) / self.ratio
|
||||
end
|
||||
|
||||
|
||||
@ -1,21 +1,17 @@
|
||||
--@include /koptilnya/libs/watcher.txt
|
||||
--@include /koptilnya/libs/utils.txt
|
||||
--@include ./base.txt
|
||||
|
||||
local BaseGearbox = require('./base.txt')
|
||||
|
||||
require('/koptilnya/libs/watcher.txt')
|
||||
require('/koptilnya/libs/utils.txt')
|
||||
|
||||
local ManualGearbox = class('ManualGearbox', BaseGearbox)
|
||||
|
||||
function ManualGearbox:initialize(vehicle, name, config)
|
||||
BaseGearbox.initialize(self, vehicle, name, config)
|
||||
|
||||
if CLIENT then return end
|
||||
|
||||
table.merge(self.wireOutputs, {
|
||||
[string.format('%s_Gear', self.name)] = 'number'
|
||||
Gearbox_Gear = 'number'
|
||||
})
|
||||
|
||||
self.ratios = config.Ratios or { 3.6, 2.2, 1.5, 1.2, 1.0, 0.8}
|
||||
@ -24,8 +20,6 @@ function ManualGearbox:initialize(vehicle, name, config)
|
||||
self.gear = 0
|
||||
|
||||
function shiftFunc()
|
||||
if wire.ports.Clutch == 0 then return 0 end
|
||||
|
||||
local upshift = wire.ports.Upshift or 0
|
||||
local downshift = wire.ports.Downshift or 0
|
||||
|
||||
@ -44,17 +38,13 @@ end
|
||||
function ManualGearbox:updateWireOutputs()
|
||||
BaseGearbox.updateWireOutputs(self)
|
||||
|
||||
wire.ports[string.format('%s_Gear', self.name)] = self.gear
|
||||
wire.ports.Gearbox_Gear = self.gear
|
||||
end
|
||||
|
||||
function ManualGearbox:setGear(gear)
|
||||
if gear >= -1 and gear <= #self.ratios then
|
||||
self.gear = gear
|
||||
self:recalcRatio()
|
||||
|
||||
net.start('GEARBOX_GEAR')
|
||||
net.writeInt(gear, 5)
|
||||
net.send(self.vehicle.playersConnectedToHUD, true)
|
||||
end
|
||||
end
|
||||
|
||||
@ -73,10 +63,10 @@ function ManualGearbox:shift(dir)
|
||||
end
|
||||
|
||||
function ManualGearbox:forwardStep(torque, inertia)
|
||||
self.shiftWatcher()
|
||||
|
||||
local result = BaseGearbox.forwardStep(self, torque, inertia)
|
||||
|
||||
self.shiftWatcher()
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
--@include /koptilnya/libs/constants.txt
|
||||
--@include /koptilnya/libs/utils.txt
|
||||
--@include ../wire_component.txt
|
||||
|
||||
local WireComponent = require('../wire_component.txt')
|
||||
|
||||
require('/koptilnya/libs/constants.txt')
|
||||
require('/koptilnya/libs/utils.txt')
|
||||
|
||||
local PowertrainComponent = class('PowertrainComponent', WireComponent)
|
||||
|
||||
@ -17,30 +15,12 @@ function PowertrainComponent:initialize(vehicle, name, config)
|
||||
self.vehicle = vehicle
|
||||
self.name = name or 'PowertrainComponent'
|
||||
self.CONFIG = config
|
||||
self.DEBUG = config.DEBUG or false
|
||||
self.input = nil
|
||||
self.output = nil
|
||||
|
||||
self.inertia = 0.02
|
||||
self.angularVelocity = 0
|
||||
self.torque = 0
|
||||
|
||||
|
||||
if self.DEBUG then
|
||||
if CLIENT then
|
||||
self.DEBUG_DATA = {}
|
||||
|
||||
net.receive('DEBUG_' .. self.name, function()
|
||||
self:deserializeDebugData(self.DEBUG_DATA)
|
||||
end)
|
||||
end
|
||||
|
||||
self.DEBUG_SEND_DATA_DEBOUNCED = debounce(function()
|
||||
net.start("DEBUG_" .. self.name)
|
||||
self:serializeDebugData()
|
||||
net.send(self.vehicle.playersConnectedToHUD, true)
|
||||
end, 1 / 10)
|
||||
end
|
||||
end
|
||||
|
||||
function PowertrainComponent:start()
|
||||
@ -87,18 +67,4 @@ function PowertrainComponent:forwardStep(torque, inertia)
|
||||
return self.output:forwardStep(self.torque, self.inertia + inertia)
|
||||
end
|
||||
|
||||
function PowertrainComponent:updateWireOutputs()
|
||||
WireComponent.updateWireOutputs(self)
|
||||
|
||||
if self.DEBUG then
|
||||
self:DEBUG_SEND_DATA_DEBOUNCED()
|
||||
end
|
||||
end
|
||||
|
||||
function PowertrainComponent:serializeDebugData()
|
||||
end
|
||||
|
||||
function PowertrainComponent:deserializeDebugData(result)
|
||||
end
|
||||
|
||||
return PowertrainComponent
|
||||
|
||||
@ -11,67 +11,32 @@ require('/koptilnya/libs/entity.txt')
|
||||
|
||||
local Wheel = class('Wheel', PowertrainComponent)
|
||||
|
||||
local DEBUG = true
|
||||
|
||||
function Wheel:initialize(vehicle, name, config)
|
||||
PowertrainComponent.initialize(self, vehicle, name, config)
|
||||
|
||||
if CLIENT and self.DEBUG then
|
||||
local scale = 0.1
|
||||
local font = render.createFont("Roboto", 256, 400, true)
|
||||
local mat = render.createMaterial('models/debug/debugwhite')
|
||||
|
||||
local lerpLoad = 0
|
||||
local lerpForwardFrictionForce = 0
|
||||
local lerpSideFrictionForce = 0
|
||||
hook.add("PostDrawTranslucentRenderables", "DEBUG_RENDER_" .. self.name, function()
|
||||
if next(self.DEBUG_DATA) == nil then return end
|
||||
if not isValid(self.DEBUG_DATA.entity) then return end
|
||||
|
||||
local pos = self.DEBUG_DATA.entity:getPos()
|
||||
|
||||
render.setMaterial(mat)
|
||||
render.setColor(Color(255, 0, 0, 200))
|
||||
lerpForwardFrictionForce = math.lerp(0.1, lerpForwardFrictionForce, self.DEBUG_DATA.forwardFrictionForce)
|
||||
render.draw3DBeam(pos, pos + ((lerpForwardFrictionForce / 500 + 16) * self.DEBUG_DATA.forward), 1, 0, 0)
|
||||
|
||||
render.setColor(Color(0, 255, 0, 255))
|
||||
lerpSideFrictionForce = math.lerp(0.1, lerpSideFrictionForce, self.DEBUG_DATA.sideFrictionForce)
|
||||
render.draw3DBeam(pos, pos + ((lerpSideFrictionForce / 500 + 16) * self.DEBUG_DATA.right), 1, 0, 0)
|
||||
|
||||
render.setColor(Color(0, 0, 255, 200))
|
||||
lerpLoad = math.lerp(0.1, lerpLoad, self.DEBUG_DATA.load)
|
||||
render.draw3DBeam(pos, pos + ((lerpLoad * 4 + 16) * self.DEBUG_DATA.up), 1, 0, 0)
|
||||
end)
|
||||
|
||||
if player() == owner() and not render.isHUDActive() then
|
||||
enableHud(nil, true)
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self.steerLock = config.SteerLock or 0
|
||||
self.brakePower = config.BrakePower or 0
|
||||
self.handbrakePower = config.HandbrakePower or 0
|
||||
|
||||
self.direction = math.sign(math.cos(math.rad(config.Offset or 0)))
|
||||
self.rotationAxle = config.RotationAxle or Angle(0, 0, 1)
|
||||
|
||||
self.wireInputs = {
|
||||
[self.name] = 'entity'
|
||||
}
|
||||
self.wireOutputs = {
|
||||
[string.format('%s_RPM', self.name)] = 'number',
|
||||
[string.format('%s_W', self.name)] = 'number'
|
||||
[string.format('%s_Mz', self.name)] = 'number',
|
||||
[string.format('%s_Fz', self.name)] = 'number',
|
||||
}
|
||||
|
||||
self.rot = 0
|
||||
self.offset = config.Offset or 0
|
||||
|
||||
self.entity = config.Entity or NULL_ENTITY
|
||||
|
||||
self.holo = self:createHolo(self.entity)
|
||||
|
||||
self.customWheel = CustomWheel:new(table.merge(table.copy(config.CustomWheel), { Direction = self.direction }))
|
||||
self.customWheel = CustomWheel:new(config.CustomWheel)
|
||||
|
||||
hook.add('input', 'vehicle_wheel_update' .. self.name, function(name, value)
|
||||
if name == self.name then
|
||||
@ -90,7 +55,10 @@ function Wheel:initialize(vehicle, name, config)
|
||||
end
|
||||
end)
|
||||
|
||||
self.steerVelocity = 0
|
||||
local right = self.entity:getRight()
|
||||
local offsetRight = self.entity:getRight():rotateAroundAxis(self.entity:getUp(), self.offset)
|
||||
|
||||
self.dir = right:dot(offsetRight)
|
||||
end
|
||||
|
||||
function Wheel:getEntityRadius()
|
||||
@ -108,10 +76,9 @@ function Wheel:createHolo(entity)
|
||||
|
||||
local holo = holograms.create(
|
||||
entity:getPos(),
|
||||
entity:getAngles(),
|
||||
entity:getAngles() + Angle(0, self.offset, 0),
|
||||
self.CONFIG.Model or ''
|
||||
)
|
||||
|
||||
holo:setParent(entity)
|
||||
|
||||
entity:setColor(Color(0,0,0,0))
|
||||
@ -120,10 +87,9 @@ function Wheel:createHolo(entity)
|
||||
end
|
||||
|
||||
function Wheel:updateWireOutputs()
|
||||
PowertrainComponent.updateWireOutputs(self)
|
||||
|
||||
wire.ports[string.format('%s_RPM', self.name)] = self.customWheel:getRPM()
|
||||
wire.ports[string.format('%s_W', self.name)] = self.customWheel.angularVelocity
|
||||
wire.ports[string.format('%s_Mz', self.name)] = self.customWheel.mz
|
||||
wire.ports[string.format('%s_Fz', self.name)] = self.customWheel.load
|
||||
end
|
||||
|
||||
function Wheel:queryInertia()
|
||||
@ -139,6 +105,9 @@ function Wheel:forwardStep(torque, inertia)
|
||||
return 0
|
||||
end
|
||||
|
||||
self.customWheel.steerAngle = self.vehicle.steer * self.steerLock
|
||||
--self.customWheel.inertia = inertia
|
||||
--self.customWheel:setInertia(inertia)
|
||||
self.customWheel.motorTorque = torque
|
||||
self.customWheel.brakeTorque = math.max(self.brakePower * self.vehicle.brake, self.handbrakePower * self.vehicle.handbrake)
|
||||
|
||||
@ -149,44 +118,19 @@ function Wheel:forwardStep(torque, inertia)
|
||||
if self.customWheel.hasHit and isValid(self.vehicle.basePhysObject) then
|
||||
local surfaceForceVector = self.customWheel.right * self.customWheel.sideFriction.force + self.customWheel.forward * self.customWheel.forwardFriction.force
|
||||
|
||||
self.vehicle.basePhysObject:applyForceOffset(surfaceForceVector, self.entity:localToWorld(Vector(0, 0, -self.entity:getModelRadius())))
|
||||
self.vehicle.basePhysObject:applyForceOffset(surfaceForceVector, self.entity:getPos() - Vector(0, 0, self.customWheel.radius))
|
||||
end
|
||||
|
||||
if isValid(self.holo) then
|
||||
local entityAngles = self.entity:getAngles()
|
||||
self.rot = self.rot + math.deg(self.angularVelocity) * TICK_INTERVAL * self.dir
|
||||
|
||||
self.rot = self.rot + self.angularVelocity * TICK_INTERVAL
|
||||
local steerAngle = self.entity:localToWorldAngles(Angle(0, self.offset - self.customWheel.steerAngle, 0) + self.rotationAxle * self.rot)
|
||||
local angle = steerAngle
|
||||
|
||||
local steerRotated = entityAngles:rotateAroundAxis(self.customWheel.up, nil, math.rad(-self.customWheel.steerAngle) + self.customWheel.toeAngle)
|
||||
local camberRotated = steerRotated:rotateAroundAxis(self.customWheel.forward, nil, -self.customWheel.camberAngle * self.direction)
|
||||
local angularVelocityRotated = camberRotated:rotateAroundAxis(self.customWheel.right, nil, self.rot)
|
||||
|
||||
self.holo:setAngles(angularVelocityRotated)
|
||||
self.holo:setAngles(angle)
|
||||
end
|
||||
|
||||
return self.customWheel.counterTorque
|
||||
end
|
||||
|
||||
function Wheel:serializeDebugData()
|
||||
net.writeEntity(self.entity)
|
||||
net.writeVector(self.customWheel.forward)
|
||||
net.writeVector(self.customWheel.right)
|
||||
net.writeVector(self.customWheel.up)
|
||||
net.writeFloat(self.customWheel.load)
|
||||
net.writeFloat(self.customWheel.forwardFriction.force)
|
||||
net.writeFloat(self.customWheel.sideFriction.force)
|
||||
end
|
||||
|
||||
function Wheel:deserializeDebugData(result)
|
||||
net.readEntity(function(ent)
|
||||
result.entity = ent
|
||||
end)
|
||||
result.forward = net.readVector()
|
||||
result.right = net.readVector()
|
||||
result.up = net.readVector()
|
||||
result.load = net.readFloat()
|
||||
result.forwardFrictionForce = net.readFloat()
|
||||
result.sideFrictionForce = net.readFloat()
|
||||
end
|
||||
|
||||
return Wheel
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
--@server
|
||||
--@include ./enums/powertrain_component.txt
|
||||
--@include ./factories/powertrain_component.txt
|
||||
--@include /koptilnya/libs/table.txt
|
||||
--@include /koptilnya/libs/constants.txt
|
||||
--@include /libs/task.txt
|
||||
local Task = require('/libs/task.txt')
|
||||
|
||||
local PowertrainComponentFactory = require('./factories/powertrain_component.txt')
|
||||
local CustomWheel = require('./wheel/wheel.txt')
|
||||
@ -22,41 +21,24 @@ function Vehicle:initialize(config)
|
||||
|
||||
self.config = config
|
||||
self.components = {}
|
||||
self.headComponents = {}
|
||||
self.independentComponents = {}
|
||||
|
||||
self:createComponents()
|
||||
self:linkComponents()
|
||||
self:createIO()
|
||||
|
||||
if SERVER then
|
||||
self:createIO()
|
||||
end
|
||||
self.rootComponent = self:getRootComponent()
|
||||
self.steer = 0
|
||||
self.brake = 0
|
||||
self.handbrake = 0
|
||||
|
||||
if SERVER then
|
||||
self.steer = 0
|
||||
self.brake = 0
|
||||
self.handbrake = 0
|
||||
self.playersConnectedToHUD = {}
|
||||
hook.add('input', 'vehicle_wire_input', function(name, value)
|
||||
self:handleWireInput(name, value)
|
||||
end)
|
||||
|
||||
hook.add('input', 'vehicle_wire_input', function(name, value)
|
||||
self:handleWireInput(name, value)
|
||||
end)
|
||||
|
||||
hook.add('tick', 'vehicle_update', function()
|
||||
self:update()
|
||||
end)
|
||||
|
||||
hook.add('HUDConnected', 'vehicle_hudconnected', function(ent, ply)
|
||||
table.insert(self.playersConnectedToHUD, ply)
|
||||
end)
|
||||
|
||||
|
||||
hook.add('HUDDisconnected', 'vehicle_huddisconnected', function(ent, ply)
|
||||
table.removeByValue(self.playersConnectedToHUD, ply)
|
||||
end)
|
||||
else
|
||||
--@include ./hud.txt
|
||||
require("./hud.txt")
|
||||
end
|
||||
hook.add('tick', 'vehicle_update', function()
|
||||
self:update()
|
||||
end)
|
||||
end
|
||||
|
||||
function Vehicle.static:validateConfig(config)
|
||||
@ -81,8 +63,8 @@ function Vehicle:linkComponents()
|
||||
for _, componentConfig in pairs(self.config) do
|
||||
local component = self:getComponentByName(componentConfig.Name)
|
||||
|
||||
if componentConfig.Input == nil then
|
||||
table.insert(self.headComponents, component)
|
||||
if componentConfig.Type == POWERTRAIN_COMPONENT.Wheel and componentConfig.Input == nil then
|
||||
table.insert(self.independentComponents, component)
|
||||
else
|
||||
local inputComponent = self:getComponentByName(componentConfig.Input)
|
||||
|
||||
@ -130,20 +112,16 @@ function Vehicle:handleWireInput(name, value)
|
||||
end
|
||||
|
||||
function Vehicle:update()
|
||||
if SERVER then
|
||||
local base = wire.ports.Base
|
||||
local base = wire.ports.Base
|
||||
|
||||
for _, component in pairs(self.headComponents) do
|
||||
component:forwardStep(0, 0)
|
||||
end
|
||||
self.rootComponent:forwardStep()
|
||||
|
||||
for _, component in pairs(self.components) do
|
||||
component:updateWireOutputs()
|
||||
end
|
||||
for _, component in pairs(self.independentComponents) do
|
||||
component:forwardStep(0, component:queryInertia())
|
||||
end
|
||||
|
||||
-- net.start("CAR_SPEED")
|
||||
-- net.writeUInt(base:getVelocity():getLength()* 1.905 / 100000 * 3600, 12)
|
||||
-- net.send(self.playersConnectedToHUD, true)
|
||||
for _, component in pairs(self.components) do
|
||||
component:updateWireOutputs()
|
||||
end
|
||||
|
||||
--if isValid(base) and (self.clutch:getPress() == 1 or self.gearbox.ratio == 0) then
|
||||
|
||||
@ -12,22 +12,16 @@ local Wheel = class('Wheel')
|
||||
function Wheel:initialize(config)
|
||||
config = config or {}
|
||||
|
||||
self.direction = config.Direction or 1
|
||||
self.mass = config.Mass or 20
|
||||
self.radius = config.Radius or 0.27
|
||||
self.rollingResistance = config.RollingResistance or 20
|
||||
self.rollingResistance = config.RollingResistance or 40
|
||||
self.squat = config.Squat or 0.1
|
||||
self.slipCircleShape = config.SlipCircleShape or 1.05
|
||||
self.casterAngle = math.rad(config.CasterAngle or 0) * self.direction
|
||||
self.camberAngle = math.rad(config.CamberAngle or 0)
|
||||
self.toeAngle = math.rad(config.ToeAngle or 0) * -self.direction
|
||||
|
||||
self.forwardFriction = Friction:new(config.ForwardFriction)
|
||||
self.sideFriction = Friction:new(config.SideFriction)
|
||||
|
||||
self.lateralFrictionPreset = FrictionPreset:new(config.LateralFrictionPreset)
|
||||
self.longitudinalFrictionPreset = FrictionPreset:new(config.LongitudinalFrictionPreset)
|
||||
self.aligningFrictionPreset = FrictionPreset:new(config.AligningFrictionPreset)
|
||||
self.frictionPreset = FrictionPreset:new(config.FrictionPreset)
|
||||
self.satFrictionPreset = FrictionPreset:new({ B = 13, C = 2.4, D = 1, E = 0.48 })
|
||||
|
||||
self.motorTorque = 0
|
||||
self.brakeTorque = 0
|
||||
@ -41,7 +35,6 @@ function Wheel:initialize(config)
|
||||
|
||||
self.forward = Vector(0)
|
||||
self.right = Vector(0)
|
||||
self.up = Vector(0)
|
||||
self.entity = NULL_ENTITY
|
||||
self.physObj = nil
|
||||
self.baseInertia = 0.5 * self.mass * math.pow(self.radius, 2)
|
||||
@ -65,7 +58,6 @@ end
|
||||
|
||||
function Wheel:setInertia(inertia)
|
||||
if isValid(self.physObj) then
|
||||
print(inertia)
|
||||
self.physObj:setInertia(Vector(inertia))
|
||||
self.inertia = inertia
|
||||
end
|
||||
@ -110,7 +102,7 @@ function Wheel:stepLongitudinal(Tm, Tb, Vx, W, Lc, R, I, kFx, kSx)
|
||||
Tb = math.clamp(Tb, -TbCap, TbCap)
|
||||
W = W + Tb / I * TICK_INTERVAL
|
||||
|
||||
local maxTorque = self.longitudinalFrictionPreset:evaluate(math.abs(Sx)) * Lc * kFx * R
|
||||
local maxTorque = self.frictionPreset:evaluate(math.abs(Sx)) * Lc * kFx * R
|
||||
local errorTorque = (W - Vx / R) * I / TICK_INTERVAL
|
||||
local surfaceTorque = math.clamp(errorTorque, -maxTorque, maxTorque)
|
||||
|
||||
@ -136,7 +128,7 @@ function Wheel:stepLateral(Vx, Vy, Lc, kFy, kSy)
|
||||
local VxAbs = math.abs(Vx)
|
||||
local Sy = 0
|
||||
|
||||
if VxAbs > 0.1 then
|
||||
if VxAbs > 0.3 then
|
||||
Sy = math.deg(math.atan(Vy / VxAbs))
|
||||
Sy = Sy / 50
|
||||
else
|
||||
@ -146,7 +138,7 @@ function Wheel:stepLateral(Vx, Vy, Lc, kFy, kSy)
|
||||
Sy = Sy * kSy * 0.95
|
||||
Sy = math.clamp(Sy, -1, 1)
|
||||
local slipSign = Sy < 0 and -1 or 1
|
||||
local Fy = -slipSign * self.lateralFrictionPreset:evaluate(math.abs(Sy)) * Lc * kFy
|
||||
local Fy = -slipSign * self.frictionPreset:evaluate(math.abs(Sy)) * Lc * kFy
|
||||
|
||||
if Lc < 0.0001 then
|
||||
Sy = 0
|
||||
@ -176,42 +168,73 @@ function Wheel:slipCircle(Sx, Sy, Fx, Fy, slipCircleShape)
|
||||
return Sx, Sy, Fx, Fy
|
||||
end
|
||||
|
||||
function Wheel:selfAligningTorque(Sy, load)
|
||||
if math.abs(Sy) < 0.001 or load < 0.001 then
|
||||
function Wheel:selfAligningTorque(Vx, Vy, Lc)
|
||||
local VxAbs = math.abs(Vx)
|
||||
local Sy = 0
|
||||
|
||||
if VxAbs > 0.3 then
|
||||
Sy = math.deg(math.atan(Vy / VxAbs))
|
||||
else
|
||||
Sy = Vy * (0.003 / TICK_INTERVAL)
|
||||
end
|
||||
|
||||
Sy = math.clamp(Sy, -90, 90)
|
||||
--local phi = (1 - self.E) * Sy + (self.E / self.B) * math.atan(self.B * Sy)
|
||||
--local Mz = -slipSign * self.satFrictionPreset:evaluate(math.abs(phi), self.B, C, self.D, 0) * Lc
|
||||
|
||||
return self.satFrictionPreset:evaluate(math.abs(Sy)) * -math.sign(Sy)
|
||||
end
|
||||
|
||||
function Wheel:selfAligningTorque2(Vx, Vy, Fz)
|
||||
|
||||
if Fz == 0 then
|
||||
return 0
|
||||
end
|
||||
|
||||
local B = self.aligningFrictionPreset.B
|
||||
local C = self.aligningFrictionPreset.C
|
||||
local D = self.aligningFrictionPreset.D
|
||||
local E = self.aligningFrictionPreset.E
|
||||
local VxAbs = math.abs(Vx)
|
||||
local Sy = 0
|
||||
|
||||
local loadScale = load * 1000
|
||||
local mechanicalTrail = 0.15
|
||||
local casterEffect = math.tan(self.casterAngle)
|
||||
local effectiveTrail = mechanicalTrail + casterEffect * self.radius
|
||||
local D_scaled = D * loadScale * effectiveTrail
|
||||
if VxAbs > 0.3 then
|
||||
Sy = math.deg(math.atan(Vy / VxAbs))
|
||||
else
|
||||
Sy = Vy * (0.003 / TICK_INTERVAL)
|
||||
end
|
||||
|
||||
local camberEffect = 1 + 0.5 * math.abs(self.camberAngle)
|
||||
local toeEffect = 1 + 0.3 * math.abs(self.toeAngle)
|
||||
Sy = math.clamp(Sy, -1, 1)
|
||||
|
||||
local term = B * Sy - E * (B * Sy - math.atan(B * Sy))
|
||||
local Mz = D_scaled * camberEffect * toeEffect * math.sin(C * math.atan(term))
|
||||
local a = {
|
||||
-2.72,
|
||||
-2.28,
|
||||
-1.86,
|
||||
-2.73,
|
||||
0.110,
|
||||
-0.070,
|
||||
0.643,
|
||||
-4.04,
|
||||
0.015,
|
||||
-0.066,
|
||||
0.945,
|
||||
0.030,
|
||||
0.070
|
||||
}
|
||||
local FzSqr = math.pow(Fz, 2)
|
||||
|
||||
return Mz
|
||||
local C = 2.4
|
||||
local D = a[1] * FzSqr + a[2] * Fz
|
||||
local BCD = (a[3] * FzSqr + a[4] * Fz) / math.pow(math.exp(1), a[5] * Fz)
|
||||
local B = BCD / (C * D)
|
||||
local E = a[6] * FzSqr + a[7] * Fz + a[8]
|
||||
|
||||
local phi = (1 - E) * Sy + (E / B) * math.atan(B * Sy)
|
||||
self.phi = phi
|
||||
|
||||
return D * math.sin(C * math.atan(B * phi))
|
||||
end
|
||||
|
||||
function Wheel:rotateVector(vector, jopa)
|
||||
local ang = self.entity:getAngles()
|
||||
local baseForward = ang:getForward()
|
||||
local baseUp = ang:getUp()
|
||||
local baseRight = -ang:getRight()
|
||||
function Wheel:selfAligningTorque3(Mx, My, Sx, Sy)
|
||||
local M = Mx * math.cos(Sy) + My * math.cos(Sx)
|
||||
|
||||
local steerRotated = vector:rotateAroundAxis(baseUp, nil, math.rad(-self.steerAngle) + self.toeAngle)
|
||||
local camberRotated = steerRotated:rotateAroundAxis(baseForward, nil, -self.camberAngle)
|
||||
local casterRotated = camberRotated:rotateAroundAxis(baseRight, nil, -self.casterAngle)
|
||||
|
||||
return casterRotated:getNormalized()
|
||||
return self.radius * M
|
||||
end
|
||||
|
||||
function Wheel:update()
|
||||
@ -228,14 +251,10 @@ function Wheel:update()
|
||||
self.longitudinalLoadCoefficient = self:getLongitudinalLoadCoefficient(self.load * 1000)
|
||||
self.lateralLoadCoefficient = self:getLateralLoadCoefficient(self.load * 1000)
|
||||
|
||||
local ang = self.entity:getAngles()
|
||||
local baseForward = ang:getForward() * self.direction
|
||||
local baseUp = ang:getUp()
|
||||
local baseRight = -ang:getRight() * self.direction
|
||||
--self.steerAngle = self.steerAngle + self.mz / self.inertia
|
||||
|
||||
self.forward = self:rotateVector(baseForward)
|
||||
self.right = self:rotateVector(baseRight)
|
||||
self.up = self:rotateVector(baseUp)
|
||||
self.forward = self.entity:getForward():rotateAroundAxis(self.entity:getUp(), -self.steerAngle)
|
||||
self.right = self.entity:getRight():rotateAroundAxis(self.entity:getUp(), -self.steerAngle)
|
||||
|
||||
local forwardSpeed = 0
|
||||
local sideSpeed = 0
|
||||
@ -253,16 +272,16 @@ function Wheel:update()
|
||||
self.longitudinalLoadCoefficient,
|
||||
self.radius,
|
||||
self.inertia,
|
||||
0.95,
|
||||
0.9
|
||||
0.95, -- Force coeff
|
||||
0.9 -- Slip coeff
|
||||
)
|
||||
|
||||
local Sy, Fy = self:stepLateral(
|
||||
forwardSpeed,
|
||||
sideSpeed,
|
||||
self.lateralLoadCoefficient,
|
||||
0.95,
|
||||
0.9
|
||||
0.95, -- Force coeff
|
||||
0.9 -- Slip coeff
|
||||
|
||||
)
|
||||
|
||||
@ -271,10 +290,15 @@ function Wheel:update()
|
||||
Sy,
|
||||
Fx,
|
||||
Fy,
|
||||
1.05
|
||||
1.05 -- Shape of the slip circle / ellipse.
|
||||
)
|
||||
|
||||
self.mz = self:selfAligningTorque(Sy, self.load)
|
||||
--local Mx = Fy * (math.cos(Sx) - 1) + Fx * math.sin(Sx)
|
||||
--local My = Fx * (math.cos(Sy) - 1) + Fy * math.sin(Sy)
|
||||
--local Mz = self:selfAligningTorque3(Mx, My, Sx, Sy)
|
||||
local Mz = self:selfAligningTorque2(forwardSpeed, sideSpeed, self.load)
|
||||
|
||||
self.mz = Mz
|
||||
|
||||
self.angularVelocity = W
|
||||
self.counterTorque = CounterTq
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
local WireComponent = class('WireComponent')
|
||||
|
||||
function WireComponent:initialize()
|
||||
if CLIENT then return end
|
||||
|
||||
self.wireInputs = {}
|
||||
self.wireOutputs = {}
|
||||
end
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
--@include libs/utils.txt
|
||||
--@client
|
||||
-- @include libs/utils.txt
|
||||
-- @client
|
||||
require("/koptilnya/libs/utils.txt")
|
||||
|
||||
EngineSound = class("EngineSound")
|
||||
|
||||
@ -1,89 +0,0 @@
|
||||
--@client
|
||||
--@include /libs/task.txt
|
||||
local Task = require('/libs/task.txt')
|
||||
|
||||
local Sound = class("Sound")
|
||||
|
||||
local function map(x, a, b, c, d)
|
||||
return (x - a) / (b - a) * (d - c) + c
|
||||
end
|
||||
|
||||
local function fade(n, min, mid, max)
|
||||
if n < min or n > max then
|
||||
return 0
|
||||
end
|
||||
|
||||
if n > mid then
|
||||
min = mid - (max - mid)
|
||||
end
|
||||
|
||||
return math.cos((1 - ((n - min) / (mid - min))) * (math.pi / 2))
|
||||
end
|
||||
|
||||
function Sound:initialize(redline, parent, sounds)
|
||||
local sounds = sounds or {
|
||||
[900] = "https://raw.githubusercontent.com/koptilnya/gmod-data/main/engine_sounds/bmw_s54/ext_e30s54_idle.ogg",
|
||||
[2500] = "https://raw.githubusercontent.com/koptilnya/gmod-data/main/engine_sounds/bmw_s54/ext_e30s54_on_2500.ogg",
|
||||
[4000] = "https://raw.githubusercontent.com/koptilnya/gmod-data/main/engine_sounds/bmw_s54/ext_e30s54_on_4000.ogg",
|
||||
[6750] = "https://raw.githubusercontent.com/koptilnya/gmod-data/main/engine_sounds/bmw_s54/ext_e30s54_on_6750.ogg",
|
||||
[8500] = "https://raw.githubusercontent.com/koptilnya/gmod-data/main/engine_sounds/bmw_s54/ext_e30s54_on_8500.ogg"
|
||||
}
|
||||
local redline = redline or 7000
|
||||
self.active = false
|
||||
local soundObjects = {}
|
||||
local soundRpms = {}
|
||||
local maxValue = 0
|
||||
local throttle = 0
|
||||
local engineRpm = 0
|
||||
local smoothRpm = 0
|
||||
local smoothThrottle = 0
|
||||
|
||||
Task.run(function()
|
||||
for soundRpm, soundPath in pairs(sounds) do
|
||||
local sound = await* soundLoad(soundPath, "3d noblock noplay")
|
||||
soundObjects[soundRpm] = sound
|
||||
table.insert(soundRpms,soundRpm)
|
||||
if maxValue < soundRpm then
|
||||
maxValue = soundRpm
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(soundRpms)
|
||||
|
||||
hook.add("think", table.address({}), function()
|
||||
if not self.active then
|
||||
return
|
||||
end
|
||||
|
||||
smoothRpm = smoothRpm * (1 - 0.2) + engineRpm * 0.2
|
||||
smoothThrottle = smoothThrottle * (1 - 0.1) + throttle * 0.1
|
||||
|
||||
for n, rpm in ipairs(soundRpms) do
|
||||
if not soundObjects[rpm] or not soundObjects[rpm].Bass then
|
||||
goto CONTINUE
|
||||
end
|
||||
local min = n == 1 and -100000 or soundRpms[n - 1]
|
||||
local max = n == #soundRpms and 100000 or soundRpms[n + 1]
|
||||
local c = fade(smoothRpm, min - 10, rpm, max + 10)
|
||||
local vol = c * map(smoothThrottle, 0, 1, 0.5, 1)
|
||||
local soundObject = soundObjects[rpm].Bass
|
||||
soundObject:setVolume(vol)
|
||||
soundObject:setPitch(smoothRpm / rpm)
|
||||
soundObject:setPos(parent:getPos())
|
||||
soundObject:pause()
|
||||
soundObject:play()
|
||||
::CONTINUE::
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
net.receive("ENGINE_FULLRPM", function()
|
||||
local rpm = net.readUInt(16)
|
||||
engineRpm = rpm * (maxValue / redline)
|
||||
throttle = math.max(net.readFloat(), 0)
|
||||
end)
|
||||
end
|
||||
|
||||
return Sound
|
||||
|
||||
|
||||
@ -73,14 +73,3 @@ function isURL(str)
|
||||
|
||||
return prefix == "http" or prefix == "https" or prefix == "data"
|
||||
end
|
||||
|
||||
function debounce(func, delay)
|
||||
local lastCall = 0
|
||||
return function(...)
|
||||
local now = timer.systime()
|
||||
if now - lastCall >= delay then
|
||||
lastCall = now
|
||||
return func(...)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,8 +1,7 @@
|
||||
--@name koptilnya/mesh_loader/builder
|
||||
--@include sv_builder.txt
|
||||
--@include cl_builder.txt
|
||||
--@include /koptilnya/libs/perma.txt
|
||||
--@shared
|
||||
-- @name koptilnya/mesh_loader/builder
|
||||
-- @include sv_builder.txt
|
||||
-- @include cl_builder.txt
|
||||
-- @include /koptilnya/libs/perma.txt
|
||||
|
||||
require("/koptilnya/libs/perma.txt")
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
--@name koptilnya/mesh_loader/cl_builder
|
||||
--@client
|
||||
--@include /koptilnya/libs/table.txt
|
||||
--@include obj_parser.txt
|
||||
--@include /koptilnya/libs/utils.txt
|
||||
--@include /koptilnya/libs/constants.txt
|
||||
-- @name koptilnya/mesh_loader/cl_builder
|
||||
-- @client
|
||||
-- @include /koptilnya/libs/table.txt
|
||||
-- @include obj_parser.txt
|
||||
-- @include /koptilnya/libs/utils.txt
|
||||
-- @include /koptilnya/libs/constants.txt
|
||||
require("/koptilnya/libs/table.txt")
|
||||
require("obj_parser.txt")
|
||||
require("/koptilnya/libs/utils.txt")
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
--@name koptilnya/mesh_loader/obj_parser
|
||||
--@client
|
||||
--@include /koptilnya/libs/workers.txt
|
||||
-- @name koptilnya/mesh_loader/obj_parser
|
||||
-- @client
|
||||
-- @include /koptilnya/libs/workers.txt
|
||||
require("/koptilnya/libs/workers.txt")
|
||||
|
||||
ObjParser = class("ObjParser")
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
--@name koptilnya/mesh_loader/sv_builder
|
||||
--@server
|
||||
--@include /koptilnya/libs/workers.txt
|
||||
-- @name koptilnya/mesh_loader/sv_builder
|
||||
-- @server
|
||||
-- @include /koptilnya/libs/workers.txt
|
||||
require("/koptilnya/libs/workers.txt")
|
||||
|
||||
local TIMEOUT = 4
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
--@name Torque editor
|
||||
--@author Opti1337
|
||||
--@shared
|
||||
--@include /koptilnya/libs/render.txt
|
||||
--@include /koptilnya/gui/render_devices/hud.txt
|
||||
--@include /koptilnya/gui/gui.txt
|
||||
--@include /koptilnya/gui/elements/panel.txt
|
||||
--@include /koptilnya/gui/elements/label.txt
|
||||
--@include /koptilnya/gui/elements/shape.txt
|
||||
--@include /koptilnya/gui/elements/button.txt
|
||||
--@include /koptilnya/gui/segoe_mdl2_assets_icons.txt
|
||||
-- @name Torque editor
|
||||
-- @author Opti1337
|
||||
-- @shared
|
||||
-- @include /koptilnya/libs/render.txt
|
||||
-- @include /koptilnya/gui/render_devices/hud.txt
|
||||
-- @include /koptilnya/gui/gui.txt
|
||||
-- @include /koptilnya/gui/elements/panel.txt
|
||||
-- @include /koptilnya/gui/elements/label.txt
|
||||
-- @include /koptilnya/gui/elements/shape.txt
|
||||
-- @include /koptilnya/gui/elements/button.txt
|
||||
-- @include /koptilnya/gui/segoe_mdl2_assets_icons.txt
|
||||
local points = {
|
||||
Vector(0, 0),
|
||||
Vector(100, 0)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user