Announcement

Collapse
No announcement yet.

Looking for a video tutorial on vehicles

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    #76
    Originally posted by Mad Maxx
    Wow, you are making some really good progress there exo. I have a city map with nothing but flat roads in it. I would like to try the truck you made so far to see it does on the GTA stile map. Could you send me it so I can test it out as is?
    Sure, but firstly I need to clean it (as I said earlier I made a trailer out of vehicle - so it has code for driving, plus some of my custom stuff like exhaust smoke, headlights, braking sounds etc).

    Meanwhile you'll need to reproduce static mesh import on your end (as I've imported these into my own packages that are too large to share; besides it makes a good practice for you).

    Start with removal of trailer wheels. Then (in 3d app) place trailer so its center is located at grid origin (this point will become trailer's center of mass - for best result CoM should be located somwhere in the middle of trailer's underbelly - not too high or low, and not too close to the hitch or rear end). As Karma vehicle use (for some reason) inverted facing, lastly you'll need to rotate your trailer 180 degrees about Z axis. After that do regular export to ASE format (3ds max could do it via File>Export - no need for ActorX - and I think you could figure out what export options you need) and see if you could import that in Editor ("Static meshes" tab). If that works fine, you could save it as your own static mesh package (USX file).

    After that you'll need another static mesh - this time for trailer wheels. Take some of wheels from your trailer (or from the truck - rear ones). Make it so its pivot point located at the very center of wheel, and finally place (if not already) the wheel at grid origin as well. Export to ASE, import into your static mesh package.

    I think it's new for you, so don't be afraid to be mistaken - ask questions if something doesn't work as expected.
    - got sig? -

    Comment


      #77
      Originally posted by Mad Maxx
      Ok, import trailer and wheels as static meshes. How do you link the wheels to the trailer as static mesh?
      What is a Karma vehicle? Does it matter what the .USX file name is? So just import one wheel not eight?
      Karma vehicles is like UT2004s alternative vehicle evolution branch - it's a pure physical car which I believe was introduced in UT2003 (and I suspect it don't work well over network).

      For that type of car we use separate physical parts - body and its wheels. So static mesh for a trailer will become our "body part", and wheel static mesh will be used for a wheel class (and trailer indeed will be spawning each of four its wheels separately). That's why we only need one wheel (I'm talking about dual wheels, so trailer technically has only four - dual - not eight ones) mesh.

      You could name your package as you wish, just be sure to choose distinctive name related to your work (so it would be easier for you to browse and reference that package).
      - got sig? -

      Comment


        #78
        I'm not too sure how to attach pictures to posts so I will try my best to explain. There can be a lot of trial and error

        1. In the animation browser turn on the collision view: View->Collision (you may not see any change yet if you have not yet created any boxes). This will allow you to see the boxes as you adjust them.

        2. Go to the 'Mesh' tab on the right hand side of the Animation Browser, and then unroll/open the 'Collision' section. You should see 'Collision Boxes', Collision Spheres, Collision Static Mesh etc. Click on the Collision Boxes section and click the 'Add' button.

        3. First type in the bone name that you want your first box to be attached to. I usually make the first box(es) the simple Karma collision ones, so I typically list the root bone first.

        4. Now start filling in the Radii X, Y, and Z variables. You should see a purple colored box appear on your mesh. Adjust the Radii values until it is the correct size you want. Adjust the Offset vector to move the box around with respect the the bone. IMPORTANT Note: If you made your vehicle model's bones align to the world orientation (e.g. all bones have their X axis point forwards, Z axis up) then it is easier to adjust the box radii and offset values since they have the same alignment. If you don't world align the bones then you have to manually play around with figuring out which axis for a given box correlates to which direction with respect to the model.

        5. For the basic Karma/World geometry collision boxes set the bBlockKarma value to 1, and if you want pawns and weapons to be able to go through this box (because they will be standing or colliding with other boxes inside this one) set the bBlockNonZeroExtent and bBlockZeroExtent values to 0 (the box should now turn 'Red').

        6. Repeat the above steps for any other collision boxes. For the boxes that are supposed to be floors and walls, set the bBlockNonZeroExtent and bBlockZeroExtent values to 1, and the bBlockKarma value to 0. The boxes should turn blue.

        7. For slanted boxes (non-orthogonally aligned), you HAVE to include a bone that is rotated so that that its axes (it doesn't really matter which one) match the direction/orientation of the slanted surface you want. The rotation should be sort of shallow, less than 45 degrees, in order to allow for pawns to walk up even with the vehicle on a slope.

        These pictures below are some examples of an old test helicopter (poor quality Chinook model) and a raft. On the copter model you can see the large Red box (and the two smaller purple boxes) that collided with the world geometry and other karma objects (like other vehicles), and the blue boxes that stopped pawns (players & bots) and other actors that use trace checks for physics collision (weapon fire, projectiles etc.). For the Raft model, I wanted angled collision boxes at the front so I actually created two bones (centered in the "airtube" sections on the right and left) that were angled inward whose only purpose was to be the center location of the collision box.



        Here are some notional ideas of how I would arrange the collision boxes. You could have all of the boxes (except the angled ramp) based off of the root bone (if all of the mesh vertices were assigned to the root bone for instance) and then just adjust the offset vector to move them into place, OR you could place extra bones (with orientation aligned to the world axis) where you want the center of the boxes to be to make it easier to create the boxes:


        On a very tangential side note: You can add collision boxes to custom player models (there was a Dinosaur Invasion mod, Dinotopia, that did just that) for slightly more accurate collision detection. However, as I understand it, the movement collision would then be more finicky since, rather than calculating collision against a nice smooth and very simple to calculate mathematical cylinder, the native code would use the maximum extents of the model's entire list of collision boxes, create a world Axis Aligned Bounding Box (AABB), which is likely to be larger than the collision cylinder, and then try to maneuver that through the world geometry.
        Attached Files
        Last edited by meowcatbuf; 11-19-2016, 06:37 PM.

        Comment


          #79
          Maxx, it's too early for wheel attachin' yet

          Great, you've imported your meshes. Next you'll need to setup their collision (similar to what you do for a regular vehicle - but a bit different).

          First, on static meshes tab ensure you got these option checked (they're off by default):


          Next select your wheel mesh (we'll deal with trailer itself a bit later), and use standard tool that fits (here we'll need a Karma primitive option) primitive in a mesh:


          You could use either sphere or cylinder - both variants work (although sphere is suggested because of lower collision calc load).

          Here's how my work look with cylinder applied:


          Finally save the package. We're ready for scripting now.

          Here's three scripts that are 2 joints and a wheel class, you'll need them all before you move to trailer and truck:

          Name this one SemiBSJoint.uc:
          Code:
          class SemiBSJoint extends KBSJoint;
          
          
          defaultproperties
          {
               bNoDelete=False
          }
          ...this one - SemiJoint.uc:
          Code:
          class SemiJoint extends KConeLimit;
          
          
          defaultproperties
          {
               KHalfAngle=17000.000000
               KStiffness=50000.000000
               bNoDelete=False
          }

          and finally - a wheel (name is SemiWheel.uc - also note you'll have to update that script with your own texture and mesh references):
          Code:
          class SemiWheel extends KTire;
          
          
          var ShadowProjector TireShadow;
          
          
          simulated function PostBeginPlay()
          {
          	Super.PostBeginPlay();
          
          
          	if (Level.NetMode != NM_DedicatedServer)
          	{
          		TireShadow = Spawn(class'ShadowProjector', self, '', Location);
          		TireShadow.ShadowActor = self;
          		TireShadow.bBlobShadow = false;
          		TireShadow.LightDirection = Normal(vect(1,1,6));
          		TireShadow.LightDistance = 1200;
          		TireShadow.MaxTraceDistance = 350;
          		TireShadow.InitShadow();
          	}
          }
          
          
          simulated function Destroyed()
          {
          	if (TireShadow != None) TireShadow.Destroy();
          
          
          	Super.Destroyed();
          }
          
          
          defaultproperties
          {
               Skins(0)=Texture'MegaForceTX_semi.Simi.Tires'
               StaticMesh=StaticMesh'carma_sm.cars.semi_wheel'
               CollisionRadius=40.400000
               CollisionHeight=23.450000
               Mass=0.010000
               Begin Object Class=KarmaParamsRBFull Name=KParams0
                   KInertiaTensor(0)=0.907500
                   KInertiaTensor(3)=0.453750
                   KInertiaTensor(5)=0.453750
                   KLinearDamping=0.000000
                   KAngularDamping=0.500000
                   KBuoyancy=2.000000
                   KMaxSpeed=150000.000000
                   KMaxAngularSpeed=5000000.000000
                   bHighDetailOnly=False
                   bClientOnly=False
                   bKDoubleTickRate=True
               End Object
               KParams=KarmaParamsRBFull'MegaForce.SemiWheel.KParams0'
          }
          After that try to compile and see if there any problems. I hope it would work fine - after that I'll share the rest of scripts and steps for trailer mesh work.
          Attached Files
          - got sig? -

          Comment


            #80
            Hi Maxx. The green-blue outline is a collision staticmesh that I assigned to these models' StaticMeshCollsion variable. You have to already have imported the StaticMesh you want to use into UnrealEd and saved it in a staticmesh .ukx file. The collision static mesh, at this time, is basically only used by the Bioglob and the ONS Grenade Projectile (both of these classes have their bUseCollisionStaticMesh=true). The "easy" way to create the collision mesh is to just export your skeletal mesh from your modelling program as a .ase or .lwo, and import it into UEd in a staticmesh package. In my opinion, since the staticmesh does not really need a lot of the finer model detail to still work properly for these projectile collisions, I usually save my final skeletal mesh as a separate file (I typically append a "_COLMESH" to the file name) then delete a lot of the little details on the mesh (the helicopter blades for instance, handles etc.) before exporting.

            Optimizing the collision staticmesh in this way is probably not required so much anymore (since most computers are pretty fast), but by doing so you would be speeding up collision calculations for those weapons, and more importantly saving memory (again not a big detail these days, but apparently a real big deal on the older game consoles that had UEngine games on them and were very memory constrained).

            Don't forget to rigidize your vehicle's skeletal mesh once imported.

            For the Doors: I'd recommend using animations if possible. I used animations on the back door/ramp of my MH53 Copter and the code was reasonably simple. The door-ramp goes up when the copter is moving at a faster speed, lowers to level when the copter is hovering, and lowers down to about ground level when the back of the copter is just above some sort of surface (via a trace check below the ramp). Collision boxes will move with the bone that they are attached too.... BUT the karma collision won't. If I recall correctly, Epic changed/removed the karma collision with animated bones because people were using one of the vehicle (Leviathan?) to launch other vehicles really far, it was kind of game breaking on certain maps.

            On another side note, here is the Psyonix Vehicle Importing Tutorial link from a long time ago (still squirreled away on their website). If I recall correctly they basically invented Onslaught as a demo for UT2k3 (using UScript for the vehicle coding), and then Epic had them build it out as the full fledged gamemode for UT2k4.
            Last edited by meowcatbuf; 11-19-2016, 06:30 PM.

            Comment


              #81
              Meanwhile, I've tried articulation concept with that Landmaster... It uses the same principle as with trailer - but this time trailer is just a reskinned tank (and since it doesn't have wheels it's much easier to drag around - although it still a passive thing that doesn't adds to propulsion). I think joint also needs to be constrained (and also I'd like to try to make its motorized version). Sorry for the acidic textures btw

              - got sig? -

              Comment


                #82
                @ exo7341: That is very cool! It looks very smooth too. I'd love to see the basic code if you cared to share at some point (I've been kicking around a few trailer ideas for a while now and would love to try them out). Have you experimented with trailer-detach/re-attach code (think backing up to trailer to connect later after having dropped it off). It might be cool to see that one staticmesh gas trailer-truck vehicle actually in game as driveable (see DM-Metallurgy for the broken version and AS-Convoy, inside the main "train" cargo bay, for the clean version). It could be whole new "escort the truck" game type for ONS maps.....

                @ Mad Maxx: Those are looking great! Glad they've turned out so well! For testing your modded Levi, summon some bots to "cover you" via the order commands, after they get on board trade spots with one, then hop off and walk back on in the bay. If you use a vehicle swapping mutator you can force them to have no other choice but to use your Levi. It looks like you may need to add one more blue collision box to the front of your Levi to prevent pawns from being able to walk into it.

                Have you assigned the triangles of your V-22 model to smoothing groups yet? It looks like they all have hard edges/are faceted. Its not a big deal at the prototyping stage.
                Last edited by meowcatbuf; 11-20-2016, 08:22 PM.

                Comment


                  #83
                  Maxx, your apc and copter turning out being really nice! That's great!

                  Next step for the trailer is trailer itself.
                  Firstly its static mesh also needs a collision (otherwise game will crash whenever you try to spawn the trailer). So navigate to static meshes tab again, select there your trailer mesh (and don't forget to enable collision visibility via menu - like in previous step). For the wheel we were adding karma primitive, but for the trailer we'll need actual collision box. I used lazy approach and just fit regular box with tools menu:



                  after that my result looked like so (notice collision box is simple bounding box, and takes too much space on the bottom of trailer - you might consider importing separate ASE mesh as a more precise collision):



                  Then again - save your package.

                  Now, here's most bulky part - trailer's code. Although I encourage you trying to read that, I'm doubt it would be easy for you . So just don't try going too deep - mostly that code is from old UTs vehicle named Bulldog. Your main points of interest located in the beggining of defaultproperties section:

                  http://pastebin.com/mYgCqKVv

                  FrontTireClass and RearTireClass needs to be your wheel class (that one you're already did). Next few lines dictate location of wheels on trailer (separate settings for different axis and front/rear wheels). Also don't forget to correct last line with KParams - it should point to correct class (btw script's name is SemiTrailer_maxx.uc).

                  Once again, try to compile. If all done well, we'll hop to the last part - updated truck code, that allows trailer spawning and joining.

                  ----

                  meowcat,
                  Sure, I'll share that code here (although I have some doubts about it being usable over network... - we still have to see how its replication will work). Also I don't think there could be some problems with attaching/detaching - I made my trailer spawning "of nowhere" just for quickness and simplicity.
                  Attached Files
                  - got sig? -

                  Comment


                    #84
                    Originally posted by Mad Maxx
                    It compiled with some warnings but that probably not too important, I am guessing.
                    I am read for the next step.
                    OK then. Here's final part of that adventure - truck modifications. We simply use karma joints to connect two karma objects (truck and your trailer).

                    This is new code for your script (you could place it just after #exec's section in your script):
                    Code:
                    var actor myTail;
                    var SemiJoint myJoint;
                    var SemiBSJoint myBSJoint;
                    
                    
                    function Fire(optional float F)
                    {
                        local vector X,Y,Z;
                    
                    
                        if (Role != ROLE_Authority) return;
                    
                    
                        if (myTail != None) return;
                    
                    
                        GetAxes(Rotation,X,Y,Z);
                    
                    
                        // spawn trailer behind and higher
                        myTail = Spawn(class'SemiTrailer_maxx',,,Location + X*(-300) + 100*Z,Rotation);
                        if (myTail != None)
                        {
                            // simple ball-socket joint
                            myBSJoint = Spawn(class'SemiBSJoint',self,,Location + X*(-150),Rotation);
                            if (myBSJoint != None)
                            {
                                myBSJoint.KPos1 = vect(-4,0,1.7);     // connection point on truck - karma scale, 1:50
                                myBSJoint.KPos2 = vect(4,0,0);        // connection point on trailer
                                myBSJoint.KConstraintActor1 = self;
                                myBSJoint.KConstraintActor2 = myTail;
                                myBSJoint.KUpdateConstraintParams();
                                myBSJoint.SetPhysics(PHYS_Karma);
                            }
                        }
                    }
                    
                    
                    function AltFire(optional float F)
                    {
                        local vector X,Y,Z;
                    
                    
                        if (Role != ROLE_Authority) return;
                    
                    
                        if (myTail != None) return;
                    
                    
                        GetAxes(Rotation,X,Y,Z);
                    
                    
                        myTail = Spawn(class'SemiTrailer_maxx',,,Location + X*(-300) + 100*Z,Rotation);
                        if (myTail != None)
                        {
                            // cone-limited constraint
                            myJoint = Spawn(class'SemiJoint',self,,Location + X*(-150),rotator(Z));
                            if (myJoint != None)
                            {
                                myBSJoint.KPos1 = vect(-4,0,1.7);
                                myBSJoint.KPos2 = vect(4,0,0);
                                myJoint.KConstraintActor1 = self;
                                myJoint.KConstraintActor2 = myTail;
                                myJoint.KPriAxis1 = vect(0,0,-1);    // important!
                                //myJoint.KSecAxis1 = vect(0,0,1);
                                myJoint.KUpdateConstraintParams();
                                myJoint.SetPhysics(PHYS_Karma);
                            }
                    
                    
                            // same ball-socket joint
                            myBSJoint = Spawn(class'SemiBSJoint',self,,Location + X*(-150),Rotation);
                            if (myBSJoint != None)
                            {
                                myBSJoint.KPos1 = vect(-4,0,1.7);
                                myBSJoint.KPos2 = vect(4,0,0);
                                myBSJoint.KConstraintActor1 = self;
                                myBSJoint.KConstraintActor2 = myTail;
                                myBSJoint.KUpdateConstraintParams();
                                myBSJoint.SetPhysics(PHYS_Karma);
                            }
                        }
                    }
                    
                    
                    function Destroyed()
                    {
                        if (myTail != None)
                            myTail.Destroy();
                    
                    
                        if (myJoint != None)
                            myJoint.Destroy();
                    
                    
                        if (myBSJoint != None)
                            myBSJoint.Destroy();
                    
                    
                        Super.Destroyed();
                    }
                    So with that code truck spawns and connects a trailer (if trailer is already present it does nothing). Primary fire makes unrestricted ball-socket joint, alt - cone-restricted one. Also, @meowcatbuf - above is essence of what you were asking for

                    Note, I didn't make connection point locations too precise - so you could correct these to more proper values (you can obtain coords from 3d app and divide it by 50 to get karma scale - same with trailer wheels coords).

                    Almost forgot one small thing - truck needs to be much more massive. To achieve this, find VehicleMass in default properties and make it something 10+ (truck in my videos was at 13.5 units - for comparison Goliath's mass is 12).
                    Last edited by exo7341; 11-22-2016, 03:12 AM.
                    - got sig? -

                    Comment


                      #85
                      Thank you for sharing exo7341! I'm gonna have to give this code a try this next weekend!

                      Its so nice to see this forum becoming as useful as the previous (now permanently lost?) forum.

                      Comment


                        #86
                        Further testing of constraints. This time it's hinge - that limits its freedom to just one axis, but allows controlling its angle (which is unique among other joints). Through 0:40 to 0:50 I was just pressing forward - twisted state was due to joint keeping its angle (which makes handling a little weird btw):



                        Back in the day (around 2008 I believe) I was also experimenting with Warthog-like antenna physics. I didn't succeeded back then. But these recent experiments with joints had opened some new possibilities for me, so I was able to somewhat implement antenna too

                        [MENTION=30139]meowcatbuf[/MENTION], you're welcome! I hope you could battle its replication problem (to make it really useful).
                        - got sig? -

                        Comment


                          #87
                          exo7341: That looks really, really nice! With that code you could actually realistic articulated construction equipment! Once I get around to making a test vehicle I will see about making testing the replication code. Have you tried adding some code to spawn the hinge (in reality a duplicate hinge) clientside between the truck and trailer? You could replicate a reference to the trailer in your truck class' replication block, then in the simulated function 'PostNetReceive' (as long as bNetNotify=true) do a check if the truck is on a client (Role<ROLE_Authority), see if the trailer reference exists yet (trailer!=none), and duplicate your hinge spawning and setup code from you 'fire' function.

                          Seeing the work you guys have been doing has actually motivated me to work on my own vehicle pack again and some new vehicle types (or at least some experimental stuff). I've got a super-rough AT-AT Walker test vehicle (basically a really high in the air hovercraft subclass), I'm probably going to go the route that T-Shinzon and Xyx did for their XS vehicle pack's mecha, which was to just animate the legs and not worry about the exact foot placement (though the rough model is all setup to be able to later use IK for foot placement if I bother to code it). I've also been working on my own version of the "Elephant" vehicle from Halo 3. Its a super large "support" tank vehicle that will spawn small vehicles on it (I'm going to test it with my ATV four-wheeler vehicle first). I'm going to eventually test some features like an automated vehicle repair capability (drive your damaged vehicle up next to it and it will be healed like using the link gun), Info Status Screen Command Center (in VCTF and ONS modes display some added useful info about your team mates, status of flags, vehicles etc.), and maybe a health/weapons/ammo locker feature ("use" a specific console on the vehicle and your weapons/ammo will be loaded similar to a Weapon Locker in ONS/VCTF).

                          Comment


                            #88
                            @meowcatbuf, that's great you got some motivation from us!

                            I think I could learn more from you on replication topic. As I never been releasing my mods, I never had a need for replication - but anyway I just couldn't wrap my head around that stuff It doesn't seem so complicated, but at the same time I'm still not getting it right

                            So, you mean there could be two versions of trailer - server and client (independent of each other)? How that would work with towing vehicle? I thought client vehicles are near-precise imprint of server ones (due to replication; so physics only "works" on a server, and clients just gets final result - location/rotation/veloctiy/acceleration etc)?

                            p.s. it seems dedicated server doesn't obeys to "log" function (I mean I don't see any of my custom logs in dedicated server's log file). Is there a way to overcome this?
                            Last edited by exo7341; 11-28-2016, 06:30 AM.
                            - got sig? -

                            Comment


                              #89
                              Not sure why the log statements aren't working in the Server.log file, do you have the log open in real time? (I think that can screw up writing the statements to the dedicated Server.log file, though I remember having both logs open at once before...) Could you post a sample function that includes once of the calls to 'log'?

                              As some background info here is a link to the old UDN 2 Sitemap (good reference stuff) and their replication pages for Roles, Variables and Functions. Other good references on the UnrealWiki for replication. I'm not sure how much longer the UDN2 sites will be up so you might want to to do what I've done: access every page on that site and save a copy to your harddrive for reference.

                              Here's a quick brief of replication stuff from hard experience (if you already know this info feel free to skip it). There are lots of caveats and obscure details so the reference links above should be reviewed if what I've said below is not working/making sense. The easiest way to think about Network replication is that the Server has the authoritative copies of all actors, clients only have subset of locally simulated copies that get fed info from the server to make the simulation match up. The only actors that clients have complete control over (and that the server will know nothing about) are those that are spawned clientside (by code executed on the client's computer). Replication from the Server to Clients can be via Function calls from Server to Client, or by replication of variables. The Clients can only replicate info to the Server by function calls (with variables as parameters), and only for actors that are in their 'ownership chain' (e.g. a pawn can send the server a replicated function call from their own weapon's third person version of the weapon (WeaponAttachment) but not from another client's replicated pawn's WeaponAttachment).

                              The server only tells client's (replicates) about actors that are relevant to them, and then only replicates information to them based on what is in that particular actor class's replication block. An Actor's RemoteRole property determines whether clients will ever be sent info on it. There is a lot more involved in the topic of Roles, especially related to PlayerController and Pawn control, so I won't go any further here on that. When the Server determines that an actor is relevant to a given client, the Server essentially tells the Client machine to 'spawn' an actor of the class, and then updates that copy on the client with all of the pertinent replicated info (per the Replication block rules). After that the Server updates the Client's copy of the actor with new (replicated) information only when a replicated variable changes (there are also some timing variables like NetUpdateTime and NetUpdateFrequency that affect how often this occurs). These relevancy checks are done by the server for every Actor in the level, with a RemoteRole greater than ROLE_None, for every client! (I think NetFrequency may affect how often these relevancy checks are done though... it definitely effects how often data is sent once relevancy is determined for any given client).

                              When the Server determines that an actor is no longer relevant to a client (its is visually blocked by BSP geometry, also known as Network Occluded, or behind the Client's viewing camera location out of view, or some other checks) then the server actually commands the client to 'Destroy' its copy of the actor after a few moments (I've verified this with log statements in my mod's custom pawn class). When the server determines that the actor is relevant to the client again, it tells the client computer to spawn a new copy of the actor, and then proceeds to replicate the NetInitial variables and function calls to "set it up" on the client. The only actors that are always relevant on the client are bStatic actors (stuff placed in the level while building it in UEd like StaticMeshes), and those with 'bAlwaysRelevant' set to true. Some actor classes, like certain projectiles, are initially replicated to clients that can see them, but are then 'tornoff' which allows the client to take over simulation of the actor after that and destroy it on its own since it behavior is easy to predict (the RL rockets are an example since they travel in a straight line after launch), without taking up any more network bandwidth.

                              Client's copies of actors can only execute code ('functions') locally on the client if their RemoteRole is SimulatedProxy, AutonomousProxy or Authority. DumbProxy can only receive variable updates (if I recall correctly). SimProxies can only execute functions if they are declared 'simulated' (also applies to 'simulated states'/state code).

                              While the Server can iterate over all of the actors in a level with ForEach "AllActors" iterator, Clients only have access to the "DynamicActors" iterator made up of stuff that is relevant to them (as told by the server), or spawned locally. Other useful iterators like the ControllerList (which allows faster access to all pawns) also only exist on the server.

                              Now to the vehicles: I think your understanding is correct with respect to vehicles, though I think there might be one small difference. I believe the client's also crunch the karma collision calculations, but the Server essentially overwrites everything the client calculates/updates (which you can see as the slight jitteriness). For normal player/bot pawn movement code, the non-owning clients run physics on all of the pawns (those replicated to them) based on the last information provided by the server, so if no more updates are received the pawns will just keep moving in whichever direction they were going, colliding with walls etc. until the server updates them again. What I've encountered as problems with vehicles, is that if no-one is driving the vehicle (e.g. some Controller, either AI/Bot/MonsterController or PlayerController) and you tried to do something non-standard with it (like attaching one vehicle to another vehicle, or turning the karma physics on and off), then its replication priority seems to be dropped -or- whatever checks the Server does for relevancy seem to get messed up (or maybe it just ends up destroying the vehicle?). Also, UnPossessed vehicles also have a much lower update frequency (either 4 or 8 times a second max) and the lowest NetPriority (1, as opposed to 3 while being driven, pawns and projectiles have priorities of 2 (3 when controlled) and 2.5 respectively for comparison).

                              Logging on both the client and server might be the only way to really figure out what the engine is doing at the native code (C++) level when behavior of the vehicles is 'funny'.

                              For towing a vehicle, I think that as long as you spawned the hinge clientside too (in a simulated function) it should just work as the RemoteRole for the KActor parent class of KHinge is ROLE_None (so the server will never tell the client about the existence of the hinge). The NetPriority and NetUpdateFrequency for the trailer should also be updated when the Truck/tractor vehicle is being driven so that its updates will more closely match the truck's from the server (and also slowed down when not driven).

                              Here is some sample (untested) code based on the stuff you posted above to update the net variables, and create the hinge clientside:
                              Code:
                              class Truck extends ONSWheeledVehicle;
                              ...
                              var actor MyTrailer;
                              
                              replication
                              {
                                  unreliable if(Role==ROLE_Authority )
                                      MyTrailer;
                              }
                              
                              ....
                              
                              // This code assumes you already spawned the trailer, on the Server
                              // via the 'fire' function, and set it to the 'MyTrailer' variable, AND that 
                              // the Trailer's RemoteRole=ROLE_SimulatedProxy... which should already
                              // be the case for a subclass of KVehicle or SVehicle.
                              // It also assumes that the Server already created its own KHinge (as listed 
                              // in your sample code above) for the trailer.
                              
                              simulated event PostNetReceive(){
                                  // the below code should trigger every time that the myTrailer variable is 
                                  // newly replicated to a client.
                                  //  NOTE!!! may also need/want to add this to 'PostNetBeginPlay' to spawn the 
                                  // hinge the first time that the Truck and its trailer are replicated to the client!!!
                                  if (myTrailer != None && myBSJoint==none)
                                  {
                                      // simple ball-socket joint
                                      myBSJoint = Spawn(class'SemiBSJoint',self,,Location + X*(-150),Rotation);
                                      if (myBSJoint != None)
                                      {
                                          myBSJoint.KPos1 = vect(-4,0,1.7);     // connection point on truck - karma scale, 1:50
                                          myBSJoint.KPos2 = vect(4,0,0);        // connection point on trailer
                                          myBSJoint.KConstraintActor1 = self;
                                          myBSJoint.KConstraintActor2 = myTrailer;
                                          myBSJoint.KUpdateConstraintParams();
                                          myBSJoint.SetPhysics(PHYS_Karma);
                                      }
                                  }
                                  bNetNotify=true; // ensure that this is still true.
                              }
                              ....
                              
                              function PossessedBy(Controller C)
                              {
                                  super.PossessedBy(C);// the truck's net variables are updated in the 'super' version of this in the 'Vehicle' parent class
                                  // update the trailer's Net variables for smoother updates on clients
                                  if(myTrailer != none){
                                       myTrailer.NetPriority = 3;
                                       myTrailer.NetUpdateFrequency = 100;
                                  }
                              }
                              
                              function UnPossessed()
                              {
                                  super.UnPossessed(); // the truck's net variables are updated in the 'super' version of this in the 'Vehicle' parent class
                                  // No longer being driven so let's lower the trailer's net frequency and priority too.
                                  if(myTrailer != none){
                                       myTrailer.NetPriority = myTrailer.Default.NetPriority;            // restore original netpriority changed when possessing;
                                       myTrailer.NetUpdateFrequency = myTrailer.Default.NetUpdateFrequency;
                                       myTrailer.NetUpdateTime = Level.TimeSeconds - 1;
                                  }
                              
                              }
                              
                              DefaultProperties{
                              ....
                              bNetNotify=true
                              
                              }
                              Last edited by meowcatbuf; 11-29-2016, 12:39 AM.

                              Comment


                                #90
                                Wow, meowcat! Thanks a LOT for that writeup! There's a lot of useful tips (and links)!

                                Before I go into deep testing, I have some minor questions though...

                                1) I could easely trace function calls and actors behaviour if only "log" worked properly...
                                Instead, that's all I got in my ded. server's log between my connect/play/disconnect:

                                Code:
                                ScriptLog: New Player bla-bla-bla id=50215410a14df913601e478371eeee6c
                                ScriptLog: START MATCH
                                NetComeGo: Close TcpipConnection 192.168.0.104:64017 bla-bla-bla time
                                NetComeGo: Open myLevel 11/29/16 10:03:10 192.168.0.104:64017
                                NetComeGo: Close TcpipConnection 192.168.0.104:64017 bla-bla-bla time
                                For stand-alone or listen server I got my custom logs after "START MATCH"... like "ScriptLog: Heeeey!!! Fire pressed!"


                                UPDATE
                                OK, I think I could do even without logs - I could just use projectile spawning to indicate calls and various events. For example, I've tried PostNetReceive. It wasn't firing (literally - with rockets) at all until I set bNetNotify to true in defaultproperties for my truck. But I'm still couldn't spawn trailer class client-side though


                                UPDATE_2
                                I did some testing with spawning. My test trailer initially was a modified Goliath, so I went up the parent chain (so, firstly I made a trailer as a child of SVehicle, then Vehicle etc). Closest parent that I was able to spawn is just Pawn. Thus, there's something that starts on Vehicle class, that prevents (or ignores?) its spawning on a client?


                                UPDATE_3
                                I've also checked another thing. I made my trailer to be a child to Vehicle class AND wrote some stuff for Destroyed() event - and it worked! It turned out that trailer is actually spawning initially, but immediately destroyed after that...
                                Last edited by exo7341; 11-29-2016, 02:50 AM.
                                - got sig? -

                                Comment

                                Working...
                                X