What are the Do's and Don'ts for Multiplayer?

I searched the net for a simple list of coding practices when scripting a game that has both SP and MP. Please share if you are knowledgeable on the topic. I also have some specific questions that I’d really appreciate if someone answered.

  1. How does static work in MP?
  2. How do events work in MP? I’ve only been using static events so far, how would a public non-static event behave in a MP game? Does the delegate behind it have to be static, if it doesn’t do I have to reference the public non-static event to subscribe to it? (It doesn’t have much to do with MP I’m just a bit confused on their behavior and usages).
  3. Should I use Serialized private fields backing public properties or is it safe to go with publics?
  4. It is my understanding that Singletons create many problems in MP, is that true?
  5. How do PlayerPrefs behave in MP? Are they even usable?

And a few off-topic questions just popped into my head, wouldn’t mind someone helping me understand them.
6.When exactly would I need to use the NEW keyword? It seems like Instantiating a prefab is always the better way to go. And having non-behavior scripts are almost all the time attached to a game object that’s not destroyed on load.
7. Whats the point of Interfaces? I mean I see them essentially as adding another TYPE to an object. What are the uses of that? I know its useful for iterating over them and making collections, but when would they be applicable? Seems to me that TAG and LAYER are giving me enough flexibility to distinguish objects, so I’d like to hear whats the general use for Interfaces.

Thanks in advance.

  1. static works the same way. Multiplayer doesn’t change the syntax of the language… Just remember if you’re using some static to make code easier to access and it’s say something like “player health” or another thing specific to the player. Well now there is more than one player, and the static only allows 1.

  2. non-static events are the most common… I’m surprised you haven’t used them yet. As for the static thing. Same as (1), anything that is specific to the player and made static, well can’t be static, as you’ll need more than 1 representation for each player.

  3. This has nothing to do with multiplayer. And it’s a personal preference. Personally I’m a private fields with public getters/setters, but I come from a business software engineering background.

  4. Singleton has the same issue as I brought up about statics. If the Singleton is intended to represent the player… well you need more than one now, which is not a Singleton.

  5. Sure, PlayerPrefs aren’t the “players” prefs, they’re the system’s configuration (the name is sort of arbitrary really). If you need prefs for each specific player, just index the id. Instead of “Player.SomeSetting”, name it “Player1.SomeSetting”.

  1. new is for creating an instance of a class. Components/MonoBehaviours don’t get constructed that way though as they’re a special kind of class, they get created by calling ‘AddComponent’. You’d use new for creating things like Lists, Arrays, custom classes your wrote that aren’t scripts on a GameObject, things like that.

  2. Interfaces are a fairly complex topic. And you seem to be a beginner from the look of your questions. So I’ll give a short overview.

First off the ‘interface’ construct is NOT a Unity thing, and is really a ‘.Net/Mono’ thing that was adopted from other languages like Java (not javascript, javascript and Java aren’t the same thing).

Next thing is there are 2 general uses of the word ‘interface’. There is the interface as a coding construct (the interface you’re talking about), and then there is the interface as a concept. The interface as a concept comes from the basic principals of the Object Oriented Paradigm. One of the major principles is ‘encapsulation’. Encapsulation is about wrapping your code up into an encapsulated thing, in oop this is the class. This encapsulation has two primary sides to it. There is the “interface” and the “implementation”. The interface being the publicly outward facing shape of the class. This is the properties, methods, and what not that you can access the class through. The implementation is the actual code inside the class that those methods are allowing you access to. The interface as a concept, not as the construct, is what controls the access to that code. I like to think of it like an old VCR… there are buttons to play, pause, fastforward, rewind, and stop the video, as well as video outputs to display the video that is played back. This grants you access to the guts of the VCR that actually do the work, but in a controlled manner. The guts do the complex stuff, all encapsulated inside the VCR.

What’s interesting is you can take the interface of the VCR and emulate it a new device with completely different internals. Take the DVD player… it has an identical interface! Play, pause, stop, fastforward, and rewind, as well as the same video outputs. It also adds a couple new buttons… track forward, track backward, and menu, etc. BUT the core interface from the VCR is still there. Thing is the internals are COMPLETELY different… but you still interact with it in the same general way. If you know how to use a VCR, you know how to use a DVD player, and this extends again to Blu-Ray.

You might have this in code as well. Various classes that you interact with in the same manner, but the guts of which do the work differently. Think for instance the various ‘Collections’ that exist like List, Queue, Stack, Dictionary, Array, etc. But they all are a collection with very similar interfaces!

So now what if we could programmatically describe that interface. That is what the construct of an ‘interface’ is. It’s used to define a contract that a class will implement. We’re saying that we guarantee these methods/functions of these names with these inputs and outputs exist and do SOMETHING. There’s no guarantee of how it will be done, just that it will exist.

Like the collections, there is an ‘ICollection’ interface that they all implement that guarantee they have methods like:
Count
Contains
Add
Remove
CopyTo
GetEnumerator
etc

They relates all those classes together. So now say you go and write a function that expects a collection as in input, and loop over the collection removing the entries that meet some criteria. Well instead of writing a function for EVERY collection type, you just take ‘ICollection’ as the input parameter, and you can deal with all collections, as long as it implements ICollection.

Thanks for the answer lordofduct. They are really in depth, but I am at fault for not structuring one of my questions properly.

at 6) I meant to say, eerm, lemme just give an example: If I have Class A written (doesn’t inherit MonoBehavior), and then write in Class B(derived from Mono)

Class A Asdf = new Class A();

Where will this constructed class reside? Also, is there any benefit from making some custom class that doesn’t derive from Mono, have all the functionality there, and then just construct it in another class and use it, as opposed to just writing all the methods in a MonoBehavior inherited class?

And about 7) Dude thanks so much for that answer, I somehow thought that interfaces are only worth the iterations, it never occurred to me to use them for parameters. Very nice analogy by the way, makes it very clear. I’m having some trouble figuring out how to do that though. If you have a method that takes a parameter inside a class with an interface, how would you write the method that passes it in? I mean:

public interface IRetardable
{void Brick(float fl);}
public class One : IRetardable
void Brick(float fl)
{
      Debug.Log ("First One:" + fl);
}
public void GetRetarded (IRetardable retarded)
{
        retarded.Brick (15);
}

Is this a correct way?

P.S: At 3) I also like it that way, my only problem is that properties don’t show up in the inspector, so I always wrestle with myself if it’s worth the bother typing up a full property and serializing the backing field or just going public.

6*)

“Where” is a really indeterminate term when it comes to managed code. There’s where in all of known available memory you might be… which honestly, you don’t need to know that. That’s some bare metal coding to know that. You technically CAN get that information if you really really wanted it, but you probably won’t need to. This though is honestly stuff you won’t really ever need, and you can go look into in more depth on your own time just for knowledge sake.

What you may want to know is the “general” where of in memory .Net/mono places things in managed memory (managed memory meaning .net/mono deals with the WHERE things are in memory for you so you don’t have to really care about it…). It splits the memory it allocates for itself into two parts.

The ‘stack’ and the ‘heap’.

When you call ‘new’ on a class, because it’s a class, a chunk of the ‘heap’ is allocated for that specific object. That’s where the actual object will exist. Whenever you need to access this object you need a “reference” to the object in the heap. Quite literally it’s an integer that represents a index (sort of…) within the heap. You honestly NEVER see this value, and the way it is organized is dependent on .net/mono and is subject to change in any update of the runtime. What you do know is that this ‘reference’ is represented as the ‘variable’ you’ve made for it.

MyClass obj; //<- this is a variable with a null reference right now, it points at nothing
obj = new MyClass(); //you just created an instance of MyClass and a reference to it is assigned to 'obj'
var obj2 = obj; //the same reference that obj is, is now set to obj2. obj and obj2 point to the same object on the heap

References may exist as members of an object as fields (the variables that are members directly of the class), or in operating code on the stack as parameters or variables scoped to a function.

The stack is the chunk of memory that handles all the memory that is currently being operated on directly. Think of it like if you were cooking and while cooking you had the recipe right there in front of you. You don’t really store the entire recipe all in your active thinking memory in your head, you let it rest there on the paper until you get to that step of the recipe. Only then you read the information you need and operate on that. 1 cup sugar, pour in bowl. 2 cups water, pour in bowl. etc etc.

Here’s more information about the stack and heap.

I didn’t really read this, just grabbed the first article I saw that looked reasonable when I googled it.

I will add this… you will hear people say that ‘value types’ (structures: int, float, Vector3) ALWAYS exist on the stack, unless otherwise boxed and placed on the 'heap. There is a lot of misconception about what constitutes boxing. I will say… no…

Value types exist directly where you place them, and aren’t referenced (unless otherwise explicitly stated as referenced with the ‘ref’ keyword). So that variable you create, instead of storing an integer that points to where on the ‘heap’ you’re value is, it’s just that value instead. If that variable is scoped to a function (like a parameter), then yes, it’s on the stack. But if that variable is a field on a class, then the value exists on the heap as a member of the object it is a field on. Of course when you go and access that variable in operating code, a copy is brought to the stack to be operated on. This is why a lot of the time when dealing with ‘structs’ you have copy a value out very explicitly and copy it back in. This is why you have to do things like this:

//doesn't work
someGameObject.transform.position.y += 5f;

//does work
var pos = someGameObject.transform.position;
pos.y += 5f;
someGameObject.transform.position = pos;

You inherit from MonoBehaviour if you want your class to be a component that gets attached to a GameObject. You ONLY inherit from MonoBehaviour if you are writing a script that gets attached to a GameObject. You NEVER call ‘new’ on a class that inherits from MonoBehaviour (or any Component, which is in MonoBehaviours parent class chain).

You will want something to be a script if it describes the GameObject directly. A MovementMotor for instance will most certainly be a MonoBehaviour. You need to do this if you’re expecting to receive game messages like ‘update’ and ‘start’ and the sort.

Any classes that aren’t supposed to be part of GameObjects inherit from whatever it is you want to inherit from (often ‘object’). You don’t use ‘start’ then, and you don’t receive any messages.

I’ll give you examples… here is the open version of my framework of code that I use when making games (its a slimmed down version of my full framework as I’m not allowed to share the entire thing).
https://code.google.com/p/spacepuppy-unity-framework/source/browse/#svn/trunk/SpacepuppyUnityFramework

Lets take a class that is a MonoBehaviour like ‘MultiTag’:
https://code.google.com/p/spacepuppy-unity-framework/source/browse/trunk/SpacepuppyUnityFramework/MultiTag.cs

This class is used to allow you to put multiple tags on a single GameObject, as opposed to just one. This is specific to a GameObject. I want to give a GameObject this ability, so I have a component to attach to a GameObject.

You may notice it inherits from ‘SPComponent’, this is because all my components inherit from SPComponent which inherits from MonoBehaviour:
https://code.google.com/p/spacepuppy-unity-framework/source/browse/trunk/SpacepuppyUnityFramework/SPComponent.cs

This is because I have a few things I want ALL my components to do, so I put that code here. This is because all my components aught to be an ‘INotificationDispatcher’, as well as implement my ‘IComponent’ interface, as well as some other stuff.

Now here is a class that is not a MonoBehaviour, it is ‘RadicalCoroutine’:
https://code.google.com/p/spacepuppy-unity-framework/source/browse/trunk/SpacepuppyUnityFramework/RadicalCoroutine.cs

This class is not part of a GameObject. It instead is a more advanced version of the built in Unity Coroutine. Not only can I store a reference to the Coroutine (which unity allows), but I can manually tick the coroutine, I can cancel the coroutine, and I can write my own custom yield instruction for the coroutines.

This is just a general object that is never attached to a GameObject, and I could have several of them at any given time inside a single script on a single GameObject. So thusly it’s not a MonoBehaviour.

Here’s another that is not a MonoBehaviour, WeakList:
https://code.google.com/p/spacepuppy-unity-framework/source/browse/trunk/SpacepuppyUnityFramework/Collections/UniqueList.cs

It’s a list of weak references. Again, not a gameobjct thing.

‘Capsule’

This here isn’t even a class, it’s a struct, and is used to ‘represent’ a Capsule… but not as a piece of physics geom. I can use this to copy the shape and position of a CapsuleCollider at any moment in game, and that capsule will go onto move and reshape, but I care about what it looked like at a specific moment.

Take a look around, you’ll notice a lot of stuff doesn’t inherit from MonoBehaviour (or SPComponent in my case). While other stuff does.

1 Like

Put the ‘SerializeField’ attribute on any private fields you want to show up in the inspector.

That’s how I do all my components:
https://code.google.com/p/spacepuppy-unity-framework/source/browse/trunk/SpacepuppyUnityFramework/Scenario/TriggerComponent.cs

1 Like

Holy smokes man, what an essay :smile: Thank you for the time you allocated to writing all this stuff. I finally know why I can’t directly manipulate a transform.

So basically only inherit from mono when I want it to be physically in the game, and don’t inherit when I want a background system that doesn’t interact with the game. I didn’t read all your code, you have a lot of it, but that’s the general idea I got.

I’m currently using SerializeField as well, but it gets annoying typing it 10 times if I have 10 private fields. I do try to steer clear from publics, but sometimes I just can’t be arsed :smile:

Anyway, I’m very grateful for your explanation, helped me out in figuring out how to go about my game. Good luck with your projects :slight_smile:

I think this the TL;DR of this thread is that the ultimate DO of multiplayer is just DON’T.

I’m sorry, how is this the TLDR? Why not do MP?