Event cache options

Options
Hi,

I would like to use event cache in my turn-based game and I would like to cache all moves in a round of the game.
I still don't really get it after I read the documents.

1. What is the difference between ADD_TO_ROOM_CACHE & ADD_TO_ROOM_CACHE_GLOBAL?
2. What is the difference between REMOVE_CACHE & REMOVE_FROM_ROOM_CACHE? How to use it if I wanna raise an event and also clear all other events cached before.
3. What is the SLICE mechanism?
4. Are events included in the data of webhooks (State)?

BTW, any use cases to describe how to choose EVENTs or GAME PROPERTIES for turn-based game?

Thanks a lot!
Jo

Best Answer

Answers

  • Kaiserludi
    Kaiserludi admin
    edited September 2015
    Options
    Hi JoH.
    
    DO_NOT_CACHE  // Default value (not sent).
    MERGE_CACHE // Obsolete - Merges this event's keys with those already cached.
    REPLACE_CACHE // Obsolete - Replaces the event cache for this eventCode with this event's content.
    REMOVE_CACHE // Obsolete - Removes this event (by eventCode) from the cache.
    ADD_TO_ROOM_CACHE // Adds this event to the room's cache
    ADD_TO_ROOM_CACHE_GLOBAL // Adds this event to the cache for actor 0 (becoming a "globally owned" event in the cache).
    REMOVE_FROM_ROOM_CACHE // Removes fitting events from the room's cache.
    REMOVE_FROM_ROOM_CACHE_FOR_ACTORS_LEFT // Removes events of players who already left the room (cleaning up).
    SLICE_INC_INDEX // Increments the slice index.
    SLICE_SET_INDEX // Sets the slice index to the specified value.
    SLICE_PURGE_INDEX // Deletes or purges the specified slice index.
    SLICE_PURGE_UP_TO_INDEX // Purges all cache slices up to the specified index (inclusive).
    
    1.
    See comments from above.

    2.
    REMOVE_CACHE is deprecated.
    Please use REMOVE_FROM_ROOM_CACHE instead.

    3.
    Slices are a grouping mechanism for cached events.
    Imagine you can send around a lot of cached events with slice 1 and then at some point something game specific happens which causes that none of the are needed to be cached anymore. You now can just purge them from the cache all at once.
    For example when a game uses some type of levels, then a player that joins the room, while the players inside have already pushed the game to level 25, then the cached events from room 1-24 may not be relevant at all anymore for the new player, that joins the game in level 25, so there is no need to let the serve send all those outdated events to him.
    This can be critical for long running games that cache lots of events.
    Depending on the amount and average size of cached events the initial load of data that gets sent to late joiners may become that huge, that those new clients connections get struck dead by the pure massive amount of data that comes in at once.
    Being able to group event in slices give you a tool to prevent this scenario by limiting the amount of data.

    4.
    Webhooks are unrelated to event caching.
    Client::opRaiseEvent() has an optional bool parameter 'forwardToWebhook'. Its default value is 'false'. If you pass 'true', then the event that gets raised by that call to the function gets forwarded to webhooks (provided, you have set up webhooks for that appId in your dashboard, of course).
  • JoH
    Options

    I would like to confirm the order of events which are sent with ADD_TO_ROOM_CACHE or ADD_TO_ROOM_CACHE_GLOBAL.
    In Ordered delivery section in the link "https://doc.photonengine.com/en/realtime/current/reference/cached-events" , it says the order depends on event code and merge if it's a hashtable.
    Is that the deprecated part?

    I would like to make sure the order is exactly the same as Photon Cloud received in my game.

    Ex:
    1. Event code = 0, ADD_TO_ROOM_CACHE
    2. Event code = 1, ADD_TO_ROOM_CACHE
    3. Event code = 1, ADD_TO_ROOM_CACHE
    4. Event code = 1, ADD_TO_ROOM_CACHE_GLOBAL
    5. Event code = 2, ADD_TO_ROOM_CACHE
    6. Event code = 1, ADD_TO_ROOM_CACHE

    Can I assume that the order never change?
    Thanks for your help!

    Jo
  • Kaiserludi
    Options
    Hi JoH.

    Photon has two EventCache implementations.
    The original and now deprecated variant used the event codes MERGE_CACHE, REPLACE_CACHE and REMOVE_CACHE and determined the order based on eventCodes like described in the doc that you have linked.

    The new variant for which we have added the other codes uses the same order like when the events get originally sent.

    So, yes, with those new codes you can assume that the order never changes, but only when you either choose TCP as protocol (which implicitly makes everything reliable) or mark all events as reliable.

    When events are marked unreliable and UDP gets used, then for both, the raiseEvent operations sent to the server as well as the events sent from the server to the other clients, some might get lost completely and some might just outrun others and arrive earlier. This is true independently from the question if the event is coming from a cache or not.



    Some more background info on you original question 1:
    When a player leaves a room (not, when he just becomes inactive, but when he leaves the room entirely), then on events that are cached for his player number get deleted from the cache.
    If this is desired, then ADD_TO_ROOM_CACHE is the appropriate choice. If this is not desired, then ADD_TO_ROOM_CACHE_GLOBAL is more appropriate, as that means, the event only gets removed from the cache, when either a client explicitly requests this or when the whole room gets deleted.



    Unfortunately the new EventCache implementation isn't covered very well in the documentation, yet.
    We will work on improving this in the future.
  • JoH
    Options
    Hi
    thanks for your detail explanation.

    Let describe my needs and my understanding to confirm it again.

    1. Event code = 0, ADD_TO_ROOM_CACHE , player 1
    2. Event code = 1, ADD_TO_ROOM_CACHE , player 1
    3. Event code = 1, ADD_TO_ROOM_CACHE , player 2
    4. Event code = 1, ADD_TO_ROOM_CACHE_GLOBAL, , player 3
    5. Event code = 2, ADD_TO_ROOM_CACHE , player 1
    6. Event code = 1, ADD_TO_ROOM_CACHE , player 2


    a) If player 2 and player 3 left rooms, player 4 join the room, he will get the event 1,2,4,5 ?
    my game is kind of card game, so even player 2 left completely , his moves are still important to the game.
    So I should use ADD_TO_ROOM_CACHE_GLOBAL for all moves, right?

    b) Leaving the room entirely means calling Client::opLeaveRoom(false) ?

    c) REMOVE_FROM_ROOM_CACHE clears both ADD_TO_ROOM_CACHE_GLOBAL & ADD_TO_ROOM_CACHE ?

    d) I would like to save the all moves via webhooks, but there is no cache event. What I wanted is to save all moves once when a hand ended. But since there is no cache event, I need to use the event webhook to accumulate all moves so there are more requests. Should I use game properties instead of Cache? Any suggestion is helpful.

    Thanks a lot!
    Jo
  • Kaiserludi
    Options
    Hi JoH.

    a)
    If player 4 joins after player 2 and 3 have left, then yes, player 4 will get events 1, 2, 4 and 5.

    b)
    Either that or if he leaves with Client::opLeaveRoom(true) or disconnects and additionally does not come back within the time specified as playerTtl (ttl stands for time to live) on room creation, which determines, how long players stay inactive, until Photon considers them left.

    c)
    It removes whatever event you specify to remove in the other parameters of opRaiseEvent (eventCode, targetActors and filters specified as a Hashtable in parameters).

    d)
    Sorry, but I don't get what you mean. Would you like to eleborate please, what exactly you are doing, what you expect to happen and what actually happens? Thanks.
    Aside from that: Yes, game properties might be a simpler way to achieve this. You might want to take a look at demo_memory, which uses game properties to implement a turn based memory game, which state is stored even when none of the players is online.
  • JoH
    Options
    d) When maybe 10 moves occurred, a round finished. Then I would like to record it to other server by web hooks and clear the Cache in the room.

    1. If I use "events" to send moves, my webhooks endpoint need to record all moves by GaemEvent web hook which is 10 TIMES in this case. There is no backup if any network trouble or computing resource issue accidentally happened. And I cannot recover game when recreate the game because I save nothing in Game properties.

    2. if I use "game properties" to send moves (also as cache for rejoin) , my webhooks could save only ONCE for the round by raising a end round event or detect some flag in game properties. But there might be some race condition for writing to the game properties. (If someone no response, a master client may send moves for the idle user)

    I would like to use 1. for the exact order of every move, but the concern is that there is no event cached in the POST content.

    Any suggestions for this? Or should I mix up it?

    Thanks a lot!
  • JohnTube
    JohnTube ✭✭✭✭✭
    edited September 2015
    Options
    Hey @JoH !

    Although what you are asking is not very clear I will try to make a suggestion:
    From what I understood, you want to send multiple events during a round of your game. Then once the round ends you want those events to be saved.

    You should raise events with the ADD_TO_ROOM_CACHE_GLOBAL flag.

    Now the question is how do you want to load or access those events:

    - ONLY when rejoining the game:
    If you want to receive the events in order every time you rejoin the game, you should only save the Room state in GameClose Type=='Save' webhook endpoint. Make sure IsPersistent is set to true for your application.
    Optionally, after each round send another event to increase room cache slice so you will have a slice per round. Then later, you can delete each event from cache separately or even delete whole round events at the same time. You can also remove events until a specific round.
    - Anytime:
    If you want to access the events data anytime and from outside Photon then you should save each event independently in its respective GameEvent webhook call.

    HL
  • Kaiserludi
    Options
    Hi @JoH.

    1.
    If you send the events marked as reliable or if you use TCP then it is guaranteed by Photon that either all events arrive at the server or that a disconnect will occur for a client which connection is that bad that it just can't get the message through, but in that disconnect case the event will also never reach the other players, so that players move basically never happens and therefor it should not be stored in the webhooks.

    2.
    Same as opRaiseEvent() all game property setting functions have a parameter called 'forwardToWebhook'. When you set that to true, the server will send that game property change to the webhooks, so there is no need for a special end of round event.

    Also you race condition issue should be a non-issue as the same is true for game properties as for events: If the clients already ask for forwarding the change to the webhooks when the change occurs, then if the change does not reach the server, then the server not only can't send it to the webhooks, but also not to the other clients, so that that change basically never happened in the first place and therefor should not be stored in the webhooks anyway.



    Also, what @JohnTube has mentioned, is true:
    You do not need to store your events or game properties in the webhooks at all, if you just want to reload the game later on: Just set the game state to persistent in the webhooks and cached events and game properties will survive and exist as long as the room itself gets stored in the webhooks.

    However, the option to also store cached events and game properties additionally separately from the game state exists not only to be able to access them from external services, but also so that you can use Client::opWebRpc() and Listener::WebRpcReturn() to retrieve this info from the Client even when the client is not inside that room.

    That way if a player has for example 20 unfinished games going on, you can present him up to date info about all those games (for example: "it's your turn now in room 15", or "player d in room 12 has made his move") without the need for the Client to always first enter and leave all those rooms all the time.
  • JoH
    Options
    Hi, @JohnTube , @Kaiserludi

    Really thanks for your help.
    I think I didn't explain well in the previous comments.

    1. According to Kaiserludi's first answer "Webhooks are unrelated to event caching." , even "GameClose Type=='Save'" webhooks occurs, there is no event related data to save, isn't there?
    But Kaiserludi said "Just set the game state to persistent in the webhooks and cached events and game properties will survive and exist as long as the room itself gets stored in the webhooks." in the last comment. I got a little bit confused.
    Do cached events still exist after setting the game state to persistent in the webhooks?

    2. What I asked is about saving all moves via webhooks so I can access "from outside Photon". So I reconsidered if I should use a)Events OR b)Game properties.

    a) If I use Events, I have to save each events via webhooks. If any webhooks of event (move) failed, the move may be lost forever. Ex: Assuming there are 10 moves in a round, the webhook endpoint need to save moves 10 TIMES. If one of the 10 webhook requests failed (due to network issue or endpoint computing resource issue or whatever), the history of the round is not completed.
    Any suggestion to handle this kind of error?

    b) if I use GameProperties ({"move1":"someMove","move2":"someMove2"}..etc. All moves are saved in Properties, so it also can be treated as cache) , when the round ended, the webhook endpoint can save all moves ONLY ONCE.
    But there might be a race condition (which is not related to webhooks). That is: The Master Client may raise an event (folding cards) for the player who is disconnected, so the Master client and the player (maybe re-join anytime) may write to the same key of game properties, so the later move overrides the previous one and that is unwanted. In this case, using event cache can prevent it because moves are in order.

    Sorry for unclear questions before, I tried my best to explain my thought here.

    Thanks a lot.
  • JohnTube
    JohnTube ✭✭✭✭✭
    Options
    @JoH

    First, please take some time to read about webhooks and their FAQs.

    Now let's try answering your questions:

    1. "Events caching", "webhook forwarding" and "IsPersistent" are three different things.
    - Events caching: events sent with caching flag enabled will have its data added to room state cache. Cached events' main purpose is to send or resend those events to joining actors.
    - "IsPersistent": webhook setting to enable triggering a webhook when the room is about to be removed from Photon servers in order to save its state. That state will include the events cache among other things.
    - Webhook forwarding: option available with OpSetProperties and OpRaiseEvent to trigger a respective webhook. Webhooks' main purpose is to be able to save games' data.

    Yes. If you take care of saving the state in your GameClose's web service endpoint then all cached events will be saved.

    2. a) Please stop worrying about network failure. As @Kaiserludi already explained to you: if a GameEvent webhook fails then the OpRaiseEvent should fail.

    If you are still worried about events not being transmitted or saved, you can add an "ACK event" per "event". Optionally you can remove the respective event from cache by setting the "ACK event" caching flag to REMOVE_FROM_ROOM_CACHE. If you need more details about this approach let me know as I'm using it in my game.

    2. b) For your case you should not use custom properties in my opinion. I don't know if you are aware of this but: "the webhook endpoint can save all moves ONLY ONCE." means that you are calling OpSetProperties with webForward==true exactly ONLY ONCE. I don't consider the issue you are raising as "race condition" but rather a design problem in your game.