What is the proper way for one client to get a specific object on all other clients to do something

I am attempting to use Photon Bolt for Unity and I feel like I am missing something colossal. I am new to multiplayer code so it is very likely that there is a better way to do what I am doing. What I am attempting to do is have the player set a projectile's team when it is fired (I haven't even gotten to dealing damage yet). This is used to determine which players it should deal damage to as well as auto coloring the projectile depending on which client is viewing it so you can tell if its a friendly or enemy projectile. The problem is, there doesn't seem to be any way to send that information to the correct instances of the projectile on remote clients.

Based on the way BOLT events work. According to the documentation ( https://doc.photonengine.com/en-us/bolt/current/getting-started/bolt-103-events ) Global events are sent reliably but EntityEvents cannot be sent reliably. It is not an option, just cannot be done. But if I make the command a global event, and set up the projectiles to listen for it, all projectiles regardless of who fired them, receive the set team event, thus making every projectile that has ever been fired, the team of the last player to fire a projectile. Not optimal. If I make it a entity event, the event works locally but for some reason is never received by any of the other clients. Which itself seems like I am either doing something wrong or there is a bug, since even unreliably it should not be lost 100% of the time on a LAN network.

What I don't understand is, even if I fix whatever I am doing wrong, if entity events are unreliable and shouldn't be trusted with core game functionality, and global events cannot be made to target specific entities but must effect literally everything that hears them, how can any player effect any other specific player at all? For example: I can't deal damage with a global message, since that would hurt everyone. I shouldn't deal damage as a entity event because if it fails to go through I could get mismatching health values across multiple clients. I assume I am missing something yes?

Comments

  • You could use a token, instantiate the projectile locally and modify the state, send an event to the host to do the same thing, etc.
  • I don't think I understand. Is this what you are talking about with tokens? https://doc.photonengine.com/en/bolt/current/in-depth/protocol-tokens

    If I am understanding it right I would need a token on the projectile that ignores global messages not sent with the correct token? That looks like I would need to create an additional token class for every class in my game that needs to receive global events but only respond to ones targeted to them. Every player, every projectile, every door, etc... Seems like that's probably overkill for what I need..? If that's the way it works I am thinking I could just include the network id of the target object in the global event, and if check if it matches. Either way it still means every projectile in the game at any given point would have to run this logic when it revives the global event. Even if it does a simple if check and bails early, I am concerned about the performance of hundred of projectiles having to do if checks every time a new projectile is spawned. The example here seems to show that is exactly how a token would be used too https://doc.photonengine.com/en/bolt/current/reference/iprotocoltoken

    Again I am super new to networking and to bolt specifically so maybe I am asking the question poorly, but ultimately what I want to do is send a message to a specific instance of an object. For example projectile #12 spawned from player 1, on all remote clients. This is presumably similar to the logic I would use to say Projectile #12 just hit player 2, player 2 should lose x health. Or, Player 3 just opened door 25.
  • CiberX15
    CiberX15
    edited July 2017
    I still don't get it. I have spent all day trying to figure this out. If its something to do with commands? Simulate controller? Bolt makes it unbelievably easy for a client to replicate its state to remote players but as far as I can find it is completely impossible for a remote player to tell my client anything, much less get it to do anything.

    I know this cannot be true. I know I am missing something but none of the tutorials seem to go far enough to explain how to do it!

    The advanced tutorial goes just far enough to show me how to make weapons that fire but never finish the logic to show how damage is transferred to another player https://doc.photonengine.com/en-us/bolt/current/advanced-tutorials/chapter-5

    The Basic tutorial https://doc.photonengine.com/en-us/bolt/current/getting-started/bolt-103-events talks about events an how the can only be reliably sent to everyone.

    Does anyone have an example of how data or commands can be sent to anything that is not owned by the client?

    At this point I am getting ready to give up on bolt. I am so tired of running into brick walls trying to get what should be the most basic of concepts to work.

    Lets try this. Projectile is fired from Player A on client A. Projectile hits Player B still on client A. Projectile on client A needs to tell client B that player B has been hit and it should take damage. How should that be done?
  • "Lets try this. Projectile is fired from Player A on client A. Projectile hits Player B still on client A. Projectile on client A needs to tell client B that player B has been hit and it should take damage. How should that be done?"
    You can use an event to send the event to that client.
  • stanchion said:

    "
    You can use an event to send the event to that client.

    OK but events sent to a specific entity on that client have to be entityevents yes? Which cannot be made reliable. Global events can be reliable but can't be sent to one entity on a client. Correct me if I am wrong but I am assuming an unreliable means the event will not be guaranteed to make it to all clients.

    So if Client A sends an Entity Event to Player B on Client B, and there is a bunch of other traffic going on, or the network is a bit slow there is a reasonable chance that Client B won't get the event. If Client B never gets the event then health is never decreased on B or any other client (assuming it was Client B's job to replicate that information to all the other clients since its the one that has Ownership of Player B's game object).

    If I target Client B with a Global Message from Client A saying take damage (I can't specify the specific Player B because global messages are global and thus are received by every player object), every player on player B's client would take damage, including the player who fired because they all receive the message. Of course in this instance Player B's health _is_ replicated since it has ownership, but Player B would now see every player as having less health, but on every other client they are unharmed.

    To be clear in the examples I am using Player A and B to represent the players' game objects, not the people sitting at the keyboard. Clients being the instanced game-worlds on each machine.

    I don't understand why EntityEvents are forced to unreliable. I assume that it was done for security purposes, but being able to send events to specific entities seems like it would be a critical part of any multiplayer game design. I don't know how one could make a game without it. That's why I am so confused. It feels like I am just trying to find big looping work-arounds for a missing method, rather then using a "correct" method.

    I was assuming I shouldn't be using events because they can't do what I need. I am assuming I am just inexperienced and don't know the right method to use instead. But if events _are_ the correct method then it seems like they are missing a massive piece of functionality.

    Can you point me to an example of an FPS like game working using BOLT? It may be easier for me to just reverse engineer a working example then trying to dig through the tutorials.
  • "OK but events sent to a specific entity on that client have to be entityevents yes? Which cannot be made reliable. Global events can be reliable but can't be sent to one entity on a client. Correct me if I am wrong but I am assuming an unreliable means the event will not be guaranteed to make it to all clients. "
    Global events can be sent to specific clients.

    You can use Global Events with an entity property to make "reliable" entity events.

    A complete shooter game is included with the package, "Advanced Tutorial"
  • CiberX15
    CiberX15
    edited July 2017
    Oh! That sounds like exactly what I need. But how do I do that? According to the events tutorial:

    "The way you send an entity event is almost identical to a global event, except for one detail: You pass the entity you want to send the event on into the Create method."

    Code from the tutorial:
    var flash = FlashColorEvent.Create(entity);
    flash.FlashColor = Color.red;
    flash.Send();

    (~2/3 through https://doc.photonengine.com/en-us/bolt/current/getting-started/bolt-103-events)

    So doesn't the act of providing an entity make it an entity event?
  • You make a global event normally and as one of the properties have the entity. The overrides for create give more options for receivers.