Bullet Trails

SeconalSeconal Join Date: 2012-02-24 Member: 147354Members
<div class="IPBDescription">Simulate trails for hitscan weapons</div>Here's a visual...

Without the bullet tracer:
<img src="http://img.gistifi.com/ns2-bullettrail2.jpg" border="0" class="linked-image" />
With the bullet tracer:
<img src="http://img.gistifi.com/ns2-bullettrail3.jpg" border="0" class="linked-image" />

Comments

  • twilitebluetwiliteblue bug stalker Join Date: 2003-02-04 Member: 13116Members, NS2 Playtester, Squad Five Blue
    edited February 2012
    I'm pretty sure guns used to fire tracers. I wonder if and why they were removed. Perhaps they disappeared after the tracer network messages were removed?
  • FragmagnetFragmagnet Join Date: 2010-07-26 Member: 72873Members
    I know for a fact that the rifle still fires tracers. But for me it seems like they are only shown when facing in a certain direction.
    (and they obviously arn't shown every shot, because they shouldn't be on every bullet anyway.)
  • RobBRobB TUBES OF THE INTERWEB Join Date: 2003-08-11 Member: 19423Members, Constellation, Reinforced - Shadow
    <!--quoteo--><div class='quotetop'>QUOTE </div><div class='quotemain'><!--quotec-->But for me it seems like they are only shown when facing in a certain direction.<!--QuoteEnd--></div><!--QuoteEEnd-->
    sounds like a bug in the calculations, any lua fluent scripter looking at that right now?
  • SeconalSeconal Join Date: 2012-02-24 Member: 147354Members
    edited February 2012
    I actually used decoda to breakpoint the calls to the tracers functions. and they seem to be getting called when the rifle and pistol was being fired. Funny thing is that I couldn't see the cinematic object getting rendered. I tried the fx_stats command to see if the tracer cinematic object was actually listed when I fired, but it seems to not be present in the list when I fire the rifle/pistol several times?

    Edit: Unfortunately, I'm only fluent in C/C++ and some Java and Python. Hopefully, I will spend a bit of time enough learning Lua to take a further in-depth look into this non-issue.
  • SeconalSeconal Join Date: 2012-02-24 Member: 147354Members
    edited February 2012
    Well, I did a bit of digging around in the Lua code and found out that nothing was broken, so I turned my attention to the "tracer.cinematic" file. I opened that up in the cinematic editor and created a default emitter and copied a bit of the defaults over to the tracer particle emitter then adjusted it until it rendered a tracer 100% with the pistol.

    By default the tracer has a 30% chance to draw with a set limit:

    <i>TracerMixin.lua:</i>
    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// Limiting the number of tracers fired will decrease the amount of network traffic required.
    local kTracerNumberWrapAround = 250<!--c2--></div><!--ec2-->


    <i>Pistol.lua:</i>
    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function Pistol:OnCreate()

        ClipWeapon.OnCreate(self)
        
        InitMixin(self, TracerMixin, { kTracerPercentage = 0.3 }) // Changed this to 1 for 100%
        InitMixin(self, PickupableWeaponMixin)
        InitMixin(self, LaserMixin)
        
        self.altMode = false
        self.emptyPoseParam = 0
        self.timeLastShot = 0

    end<!--c2--></div><!--ec2-->

    It seem as though making a slight change to the cinematic file has fixed the tracers:
    <img src="http://img.gistifi.com/FixedTracer.png" border="0" class="linked-image" />

    The following file: <a href="http://tmp.gistifi.com/tracer.zip" target="_blank"><i>Tracer.zip</i></a> can be unzipped into the following directory:
    <i>C:\[Program Files (x86) or Program Files]\Steam\steamapps\common\natural selection 2\ns2\cinematics\marine</i>
  • KalabalanaKalabalana Join Date: 2003-11-14 Member: 22859Members
    edited February 2012
    Why would this affect network traffic? Can't tracers be done exclusively client side? Things like this scare me.
  • RobBRobB TUBES OF THE INTERWEB Join Date: 2003-08-11 Member: 19423Members, Constellation, Reinforced - Shadow
    maybe it's because it's an attack and synched. also, the enemy should see it, too.
  • SeconalSeconal Join Date: 2012-02-24 Member: 147354Members
    edited February 2012
    Client tracer drawing:

    This is how the client defines the tracer along with the pistol clip-weapon weapon:
    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->Client.lua <- Tracer_Client.lua
        ^
         |
    Shared.lua <- Pistol.lua <- TracerMixin.lua
                  ^
                  |
              ClipWeapon.lua <- Weapon.lua<!--c2--></div><!--ec2-->

    From the ClipWeapon.lua:
    <b>ClipWeapon</b> which is a parent of <b>Pistol</b> handles a state in which a weapon can fire and calls
    the <b>FireBullets</b> function. In this function, it checks if the Tracer Mixin is defined within it's child <b>Pistol</b> and then calls TriggerTracer():

    <i>ClipWeapon.lua</i>
    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->        if Server and HasMixin(self, "Tracer") then
                self:TriggerTracer(trace.endPoint)
            end<!--c2--></div><!--ec2-->


    From the TracerMixin.lua:
    The TracerMixin.lua holds of number of tracers to be fired based on a percentage.

    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function TracerMixin:TriggerTracer(endPoint)

        assert(Client == nil)
        
        local randomProvider = self:GetMixinConstants().kRandomProvider
        local randomNumber = (randomProvider and randomProvider()) or math.random()
        if randomNumber < self:GetMixinConstants().kTracerPercentage then
        
            self.tracerEndPoint = endPoint
            self.numberTracersFired = self.numberTracersFired + 1
            if self.numberTracersFired > kTracerNumberWrapAround then
                self.numberTracersFired = 0
            end
            
        end
        
    end
    AddFunctionContract(TracerMixin.TriggerTracer, { Arguments = { "Entity", "Vector" }, Returns = { } })<!--c2--></div><!--ec2-->

    Then calls the <b>CreateTracer</b> function <b>onUpdateRender</b> time:
    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function TracerMixin:OnUpdateRender()

        assert(Server == nil)
        
        if self.oldNumberTracersFired ~= self.numberTracersFired then
        
            local tracerStart = self:GetBarrelPoint()
            local tracerVelocity = GetNormalizedVector(self.tracerEndPoint - tracerStart) * kTracerSpeed
            CreateTracer(tracerStart, self.tracerEndPoint, tracerVelocity)
            
            self.oldNumberTracersFired = self.numberTracersFired
            
        end
        
    end
    AddFunctionContract(TracerMixin.OnUpdateRender, { Arguments = { "Entity" }, Returns = { } })<!--c2--></div><!--ec2-->

    This function then calls <b>CreateTracer</b> defined in Client.lua.

    From Client.lua:
    The client initializes a single tracer and stores that in the tracersList table defined in Client.lua:
    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function CreateTracer(startPoint, endPoint, velocity)

        if not Shared.GetIsRunningPrediction() then

            local tracer = BuildTracer(startPoint, endPoint, velocity)
            table.insert(Client.tracersList, tracer)
            
        end
        
    end<!--c2--></div><!--ec2-->

    The <b>BuildTracers</b> function that was called is defined in Tracer_Client.lua.

    From Tracer_Client.lua:
    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function BuildTracer(startPoint, endPoint, velocity)

        local tracer = Tracer()
        
        tracer.tracerEffect = Client.CreateCinematic(RenderScene.Zone_Default)
        tracer.tracerEffect:SetCinematic(Tracer.kTracerEffect)
        tracer.tracerEffect:SetRepeatStyle(Cinematic.Repeat_Endless)
        
        tracer.velocity = Vector(0, 0, 0)
        VectorCopy(velocity, tracer.velocity)
        
        tracer.startPoint = Vector(0, 0, 0)
        VectorCopy(startPoint, tracer.startPoint)
        
        // Calculate how long we should live so we can animate to that target
        tracer.lifetime = (endPoint - startPoint):GetLength() / velocity:GetLength()
        tracer.timePassed = 0
        
        return tracer
        
    end<!--c2--></div><!--ec2-->

    This is the beautiful part, the class <b>'Tracer'</b> is defined in this file, which precaches the "<b>tracer.cinematic</b>" emitter:
    <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->class 'Tracer'

    Tracer.kMapName             = "tracer"
    Tracer.kTracerEffect        = PrecacheAsset("cinematics/marine/tracer.cinematic")<!--c2--></div><!--ec2-->

    The Client_Tracer.lua also handles the how the cinematic is played.

    The client handles the drawing of this tracer and the list of tracers. As defined in TracerMixin.lua, the server just knows what the rate each client is shooting out tracers based on a percentage, which then stores each tracer in the clients tracer list. This is done per-weapon so that you should see each weapon that has TracerMixin should store tracers into your clients tracerlist and render them on screen (client-sided).
Sign In or Register to comment.