Announcement

Collapse

The Infinity Blade Forums Have Moved

We've launched brand new Infinity Blade forums with improved features and revamped layout. We've also included a complete archive of the previous posts. Come check out the new Infinity Blade forums.
See more
See less

[VIDEO][CODE] Proof of Concept: A Multiplayer Level Editor

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

    [VIDEO][CODE] Proof of Concept: A Multiplayer Level Editor

    In this tutorial I am demoing my very own Multiplayer Level Editor.

    Below I am providing you with the core code that you need to do what I am doing in this video, which is to create new world objects with proper collision during a multiplayer game and replicate the dynamic setting of materials and meshes of the new objects.

    In this tutorial is the core understanding and code you need to make worlds with your friends!

    Developers can use this technology I am presenting to reduce development time by working on a level together at same time.

    In this video I demonstrate that multiplayer levels made by 2+ people at same time can also be saved to hard disk and reloaded later. It doesnt matter who loads/saves the level, both players will end up with the same core files.



    ~~~

    Network Optimizations used in my Multiplayer Editor

    -Very little data is being sent across the network for object creation, really only a few strings to tell the server what material and mesh with which the client wants to create an object.

    -The saving of the level to hard disk is not passed across the network, each client generates the save file independently.

    -As players/editors move objects their rotation and location and drawscale are deliberately updated slowly to avoid clogging the network, but the final positions are always recorded exactly so both editors are seeing the exact same changes.


    ~~~

    Demonstrated In the Video

    1. Multiplayer Level Editing

    2. Being able to edit level in realtime / top speed on client side, and have the other client receive the exact same edits even after network delays.

    3. Multiplayer Level Saving after exiting unreal and reloading the server and clients

    4. Having one player load the level, get disconnected, and having the other player still able to make changes and save the level.

    5. Asymmetric scaling of objects and collision working correctly


    ~~~

    Code For You

    With this Code below I am showing you how to:

    1. How to Create new World Objects with proper collision during Multiplayer Game

    2. Set and Replicate Changing of the Mesh and Material for new World Objects

    3. Get the Path of Materials for Actors (Static Mesh Actors and Dynamic SMAS)

    4. Get the Path of Mesh for Actors (Static Mesh Actors and Dynamic SMAS)


    ~~~

    World Object Class for Spawning

    Here's the core class code I use for spawned objects created on the server.

    In the initialization function below I set their materials and meshes and have the clients update to match.

    Code:
    class WorldOBJ extends StaticMeshActor placeable;
    
    //cur mesh
    var repnotify string r_curMeshType;
    
    //cur mat
    var repnotify string r_curMaterialType;
    
    replication
    {
    	if ( bNetDirty )
    		r_curMeshType,
    		r_curMaterialType;
    }
    //=============== REPLICATION EVENT ============
    simulated event ReplicatedEvent( name VarName )
    {
    	//very important line
    	super.ReplicatedEvent( VarName );
    	
    	if (varname == 'r_curMeshType') {
    		updateCurMesh();
    	}
    	else if (varname == 'r_curMaterialType') {
    		updateCurMaterial();
    	}
    }
    
    //server init
    reliable server function joyInit_SERVER(string meshtypei, string materialtypei) {
    	
    	//******************************************************
    	// clients will not update without the r_ repnotify vars
    	//******************************************************
    	//mesh
    	StaticMeshComponent.SetStaticMesh(StaticMesh(
               DynamicLoadObject(meshtypei, class'StaticMesh')));
    
    	r_curMeshType 		= meshtypei;
    	
    	//Material
    	StaticMeshComponent.SetMaterial(0, Material(
               DynamicLoadObject(materialtypei, class'Material')));
    
    	r_curMaterialType 	= materialtypei;
    	
    }
    //mesh
    simulated function updateCurMesh() {
    	
    	StaticMeshComponent.SetStaticMesh(
    		StaticMesh(
    			DynamicLoadObject(
    				r_curMeshType, class'StaticMesh')));
    }
    
    //material
    simulated function updateCurMaterial() {
    	
    	StaticMeshComponent.SetMaterial(0, 
    		Material(
    			DynamicLoadObject(
    				r_curMaterialType, class'Material')));
    				
    	updateCoreStruct();
    }
    
    DefaultProperties
    {
    	//to ensure spawned object has proper light environment
           Begin Object class=DynamicLightEnvironmentComponent Name=joyLightEnv
    		bEnabled = true
    		bCastShadows = false 					//false
    	End Object
    	
        Components.Add(joyLightEnv)
    	
    	Begin Object Name=StaticMeshComponent0
    		LightEnvironment=joyLightEnv
    		CastShadow = false						//false
    		bUsePrecomputedShadows=false
    		
    		BlockRigidBody=true
    		BlockZeroExtent=true
    		
    		//RB Collision
    		bNotifyRigidBodyCollision = true
    		ScriptRigidBodyCollisionThreshold = 1
    
    		StaticMesh=StaticMesh'yourstaticmesh'
    		RBCollideWithChannels=(Default=true)
    		
    		bAllowAmbientOcclusion=false
    	End Object
    	CollisionComponent=StaticMeshComponent0
    	
    	bStatic=false
    	bMovable=true
    	
    	bCollideActors = true
    	
    	//Multiplayer
    	RemoteRole=ROLE_SimulatedProxy
    	
    	bOnlyDirtyReplication 	= true
    	
    	//****************************
    	// 	  ABSOLUTELY ESSENTIAL
    	bAlwaysRelevant			= true
    	//****************************
    	
    	//can vary, 3 is quite high
    	NetUpdateFrequency 		= 1
    }
    ~~~

    Spawning the World Objects

    Here is my class code for spawning the world objects on the server

    I also wrote two functions for you to get the pathnames for staticmeshes and materials so you can use the core function I am providing to spawn new objects and set mesh/material using string paths.

    //In Your Player Controller Class
    Code:
    //spawn on server so collision works correctly
    
    	//server
    	//because this runs this way on server
    	//with location/rotation pulled from pc side
    	//there's no need for any delays to guarantee
    	//location updates and such.
    	
    	//lesson: create stuff on server, FROM client variable info 
    	//which will ALWAYS be up-to-date
    	//with what that player is seeing
    	
    	//**********************************************************
    	//implementation: pass variables from client to server a lot
    	//**********************************************************
    	
    	//calling: this is in the player controller class so you must decide
    	//how to call this function and pass it the parameters you've chosen
    reliable server function VOID_manifestYay_SERVER(
    	vector theLocation, 
    	rotator theRotation, 
    	string meshPath,
    	string materialPath
    ) {
    	local WorldOBJ newWall;
    	
    	newWall=Spawn(class'WorldOBJ',,,theLocation,theRotation);
    	newWall.joyInit_SERVER(meshPath, materialPath);
    }
    
    //support function for you to get the path of materials
    function string getPath_Material(Actor a, optional int index) {
    	
    	if (a.isa('StaticMeshActor'))
    		return PathName(StaticMeshActor(a).StaticMeshComponent.GetMaterial(index));
    	if(a.isa('DynamicSMActor'))
    		return PathName(DynamicSMActor(a).StaticMeshComponent.GetMaterial(index));
    	
    	return "";
    }
    
    //support function for you to get the path of meshes
    function string getPath_StaticMesh(Actor a) {
    	if (a.isa('StaticMeshActor'))
    		return PathName(StaticMeshActor(a).StaticMeshComponent.staticmesh);
    	if(a.isa('DynamicSMActor'))
    		return PathName(DynamicSMActor(a).StaticMeshComponent.staticmesh);
    		
    	return "";
    }
    ~~~

    Summary

    With this code you now have the starting point to write your own multiplayer level editor, or spawn world objects in your multiplayer game any time you want!

    I am showing in the video that Multiplayer Level Editing is a valid concept that could help developers cut down on the time to make levels as two+ artists work on level simultaneously.

    Enjoy!

    Rama

    #2
    while it's an awesome achievement and resource I thought I'd jump in to state some not-so-obvious downsides:
    1. you can't modify terrain/foliage - if your level is outdoors-based, you still need a terrain+foliage base already done.
    2. you can't open the saved level in the editor - this essentially "splits" your levels into one of the following two categories: editor-editable levels, and run-time-only levels.
    3. you can only place dynamic lights and so you can't re-build lighting.
    4. you can't re-build paths so anything you place won't affect pathfinding (ie. your bots can easily become dumb)

    however I'm not just barging in with negative comments, I do have an idea for problem no. 2. if you take some extra time to add some more functionality you could turn all of your levels into editor-editable levels.

    the idea behind it is simple:
    the UDK editor allows you to copy-paste objects as any other software, the difference is that the copied objects go into the clipboard as a very human-readable format.
    to make my point clear I just opened the editor, placed a static mesh and hit Ctrl+C. then opened Notepad and hit Ctrl+V. this is the outcome:
    Code:
    Begin Map
       Begin Level
          Begin Actor Class=StaticMeshActor Name=StaticMeshActor_0 Archetype=StaticMeshActor'Engine.Default__StaticMeshActor'
             Begin Object Class=StaticMeshComponent Name=StaticMeshComponent0 ObjName=StaticMeshComponent_2 Archetype=StaticMeshComponent'Engine.Default__StaticMeshActor:StaticMeshComponent0'
                StaticMesh=StaticMesh'Equipment.Cube'
                ReplacementPrimitive=None
                bAllowApproximateOcclusion=True
                bForceDirectLightMap=True
                bUsePrecomputedShadows=True
                LightingChannels=(bInitialized=True,Static=True)
                Name="StaticMeshComponent_2"
                ObjectArchetype=StaticMeshComponent'Engine.Default__StaticMeshActor:StaticMeshComponent0'
             End Object
             StaticMeshComponent=StaticMeshComponent'StaticMeshComponent_2'
             Components(0)=StaticMeshComponent'StaticMeshComponent_2'
             Location=(X=-680.000000,Y=55.000000,Z=448.000000)
             CreationTime=49.524918
             Tag="StaticMeshActor"
             CollisionComponent=StaticMeshComponent'StaticMeshComponent_2'
             Name="StaticMeshActor_0"
             ObjectArchetype=StaticMeshActor'Engine.Default__StaticMeshActor'
          End Actor
       End Level
    Begin Surface
    End Surface
    End Map
    In notepad I then changed the Location var to (X=0,Y=0,Z=0), selected all the text, pressed Ctrl+C, and then in the editor I pressed Ctrl+V. The result was a copy of my cube but placed at location (0,0,0)

    so now the tricky part:
    you would need to write a custom 'exporter' from within your game, such an exporter should output all of the objects you've placed in your "Multiplayer editing session", into a .txt with the same format as above. Not sure if BasicSaveObject would be customizable enough to allow this, if your existing level savegame system would, or if it would need an entirely different solution (something involving DLLBind or maybe TCPLink).
    if you're able to write such an exporter, you'd only need to open the generated .txt file, select all, Ctrl+C, open the editor, open the "base" map, Ctrl+V, and now you'd have your runtime-placed objects in the editor

    it would be awesome if you could get this done

    Comment


      #3
      Dear Chosker,

      1. Yea I been thinking about how to handle terrains, and I not sure of way to do it without native code access because I cant writeout heightmap changes to file.

      2. oooh wow, thanks for sharing!

      I could just compile all the results into a single string in a config file and open the config file and copy into the editor!

      Great idea!



      If anyone reading this has any idea how to do dynamic terrain creation in-game let me know

      I presume there has to be the ability to edit the heightmap image and so I cant see anyway to do this with non-license only.


      Rama

      Comment


        #4
        1. you can't. it's not just a heightmap, and there's no way to edit or save a terrain/landscape if you're not in the editor. let's just say it's "editor-native", just like importing assets or saving packages.
        there is no way to do dynamic terrain creation/editing unless you programmed your own terrain system, which would most likely be too slow to use (due to it being written in UnrealScript)

        2. glad you like the idea

        Comment


          #5
          My multiplayer editor that I am showing in this video is really being tailored toward my own game, where I want people to be able to make their own levels even if they dont have the UDK.

          Basically a game that ships with its own in-game editor for super easy further content creation.

          I decided replay value of a game is infinite if people can easily (note *easily*) make their own levels!


          So I'd already sort of resigned myself to needing to provide a set of prefab terrains in my maps for people to use.

          That's the only real limitation I've encountered with my plans for people to be able to make their own worlds using my in-game editor.


          Again if anyone has any ideas for dynamic terrain generation of a feasible sort let me know!


          In the meantime this video is demoing that you can indeed make a multiplayer editor for your game, especially if you are writing the editor yourself as I am

          Chosker's #2 idea is still fabulous anytime I want to create a cross-over from my in-game editor to the UDK, thanks again Chosker for sharing

          Rama

          Comment


            #6
            Originally posted by evernewjoy View Post
            That's the only real limitation I've encountered with my plans for people to be able to make their own worlds using my in-game editor.
            there's a few other limitations:
            - you're forced to do pure dynamic lighting and shadowing (something I've proved doable myself, but it's best if some optimizations are done)
            - you can't use navmeshes or pathnodes, so you'll be forced to write your own pathfinding system for AI (something I've also done myself, but not as powerful or fast as using native pathfinding)

            anyway, keep it up

            Comment


              #7
              Navmesh-Free AI

              I've already written my own navmesh and pathnode free aI

              I actually find it performs better than AI I've seen in most games because my AI can easily jump over objects and can be placed in totally dynamic environments and give quite the challenge for the player

              It's one of my greatest achievements with coding in unrealscript, which I only started with my level editor and built-in editor in mind

              I will be doing tutorial on how to make your own navmesh-free AI soon!



              Rama


              PS: regarding dynamic lighting, yes that's true, but my game does not require perfect lighting so it is not a concern for my current project.

              If you know any optimizations I can use for people playing my game with lower-end pc's I'd be very happy to hear them

              Comment


                #8
                Neat Level Tweaker .....

                Comment


                  #9
                  Wow, great job. I love all of your tutorials!!!

                  Comment


                    #10
                    Originally posted by evernewjoy View Post
                    I actually find it performs better than AI I've seen in most games because my AI can easily jump over objects and can be placed in totally dynamic environments and give quite the challenge for the player
                    with performance I meant it's most likely slower than tha native solutions. I'd guess your solution is based on traces like mine, so the more complex it might be then the slower it could go.
                    I'm interested in watching your tutorial, it would be nice to see someone else's implementation

                    Originally posted by evernewjoy View Post
                    If you know any optimizations I can use for people playing my game with lower-end pc's I'd be very happy to hear them
                    inspired by the way Oblivion handled lights, I have a custom light that extends spotlight. this custom light does distance checks between its location and the local player's location, and as the distance increases it degrades into worse-quality shadowmaps, disabling shadows, and even turning the light off.
                    this is tied to a custom 'view distance' system setting you can change in my game's options menu. at the minimum distance it becomes visible and obvious but it still allows a low-end PC to run a level with hundreds of pure dynamic lights (since only a few are turned on at any given time). at the maximum distance, I could have a really large open area and the player will never notice any fading.
                    to make the effect a little less visible, there's a pure black heightfog (also tied to the view distance setting)
                    of course this all works quite good because my level is a dark dungeon with lots of corners and very little open areas. but eventually I'll translate it into an outdoors game and I'll need to adapt this whole system. and I'm sure I can make it work in outdoors too

                    Comment


                      #11
                      Originally posted by Chosker View Post
                      inspired by the way Oblivion handled lights, I have a custom light that extends spotlight. this custom light does distance checks between its location and the local player's location, and as the distance increases it degrades into worse-quality shadowmaps, disabling shadows, and even turning the light off.
                      this is tied to a custom 'view distance' system setting you can change in my game's options menu. at the minimum distance it becomes visible and obvious but it still allows a low-end PC to run a level with hundreds of pure dynamic lights (since only a few are turned on at any given time). at the maximum distance, I could have a really large open area and the player will never notice any fading.
                      to make the effect a little less visible, there's a pure black heightfog (also tied to the view distance setting)
                      of course this all works quite good because my level is a dark dungeon with lots of corners and very little open areas. but eventually I'll translate it into an outdoors game and I'll need to adapt this whole system. and I'm sure I can make it work in outdoors too
                      This is extremely awesome info, I always wondered why I could use dynamic lights so freely in my skyrim levels

                      Thanks so much for sharing Chosker!



                      Rama

                      Comment


                        #12
                        interesting stuff!
                        thanks for sharing

                        the experiments ive done with dynamic levels is limited by the amount of meshes, after so many are used the framerate suffers.
                        Chosker's ideas with the lights makes me think of doing the same with meshes,
                        but rather that turning them on and off, draw them from a pool and set their location, collision and visibility when needed.
                        since you (evernewjoy) are giving the player pre-made meshes this would work beautifully.
                        im yet to come up with a concrete idea how to handle it all, some kind of template, perhaps even a huge string in an .ini with locations ect..
                        then use the location of the player to trigger what is where

                        ive never been able to do a decent dynamic terrain or landscape alternative, the native ones are just native and we are stuck with it like that unfortunately.

                        Comment


                          #13
                          Originally posted by tegleg View Post
                          interesting stuff!
                          thanks for sharing

                          the experiments ive done with dynamic levels is limited by the amount of meshes, after so many are used the framerate suffers.
                          Chosker's ideas with the lights makes me think of doing the same with meshes,
                          but rather that turning them on and off, draw them from a pool and set their location, collision and visibility when needed.
                          since you (evernewjoy) are giving the player pre-made meshes this would work beautifully.
                          im yet to come up with a concrete idea how to handle it all, some kind of template, perhaps even a huge string in an .ini with locations ect..
                          then use the location of the player to trigger what is where

                          ive never been able to do a decent dynamic terrain or landscape alternative, the native ones are just native and we are stuck with it like that unfortunately.

                          Great to hear from you Tegleg!

                          Well in my game having a ton of tiny meshes in close proximity is not something my game is designed for, and therefore, so far, I can simply do this code below and it seems to keep everything under control / easily relatively optimized

                          Code:
                          //in the class of the staticmeshactor or dynamicSMA that you want to set cull distance for
                          //adjust the number as needed, can make into property and can change this value any time
                          staticmeshcomponent.SetCullDistance(30000);
                          For those not familiar with this code:

                          This causes the unreal engine to automatically hide objects greater than 30000 units from the player camera, freeing you from the need to calculate distances and hide/show objects manually

                          Unreal engine also shows the object again when it is closer than 30000 units




                          ~~~

                          Further Optimization

                          Ideally you can set the cull distance to a number based on the drawscale of the mesh, smaller objects can be culled a lot closer than 30000, very large objects might need 70000 before player cant really make it out any more



                          Rama

                          Comment


                            #14
                            Hey this is great tut ! so usefule can't wait to recon the code : ) .

                            Comment


                              #15
                              Originally posted by Neongho View Post
                              Hey this is great tut ! so usefule can't wait to recon the code : ) .
                              Glad you like!

                              Let me know how it goes for you!

                              Rama

                              Comment

                              Working...
                              X