Difference between revisions of "AI War 2:Custom Text Messages To The Player"
X4000Chris (talk | contribs) (→Hey!) |
X4000Chris (talk | contribs) |
||
(2 intermediate revisions by the same user not shown) | |||
Line 4: | Line 4: | ||
What is presented below is an older form of "journal entry," which is just embedded in the chat log. It can be useful to do that sort of thing at various points as well, but those are... less robust. The journal entries that we're referring to at the above link is instead like uncovering little wiki entries, almost, that show up in a dedicated tab in your sidebar as you play. | What is presented below is an older form of "journal entry," which is just embedded in the chat log. It can be useful to do that sort of thing at various points as well, but those are... less robust. The journal entries that we're referring to at the above link is instead like uncovering little wiki entries, almost, that show up in a dedicated tab in your sidebar as you play. | ||
− | = | + | = Revised Q&A = |
'''Q:''' Do you have sample code for how to emit different journal entries? For example, I'd like a permanent journal entry at game start when you have allied marauders that basically explain how marauders work, and that they can build Raiders if they have their own planets. | '''Q:''' Do you have sample code for how to emit different journal entries? For example, I'd like a permanent journal entry at game start when you have allied marauders that basically explain how marauders work, and that they can build Raiders if they have their own planets. | ||
− | '''A:''' | + | '''A:''' This has changed a LOT! |
− | + | === Where Do Do That Sort Of Permanent Logging === | |
− | + | Now you will find the new instructions for that in the [[AI_War_2:_Journal_Entries#Q.26A_On_How_To_Log_Journal_Entries_From_Custom_Code|Q&A On How To Log Journal Entries From Custom Code]]. | |
− | + | === Why We'd Use This Instead === | |
− | + | So we've established at this point that nothing we do here is actually permanent, correct? | |
− | + | Okay. So, our purpose here is just to write to the chat log. This means a little popup on the right side of the screen for 10 seconds, and then it's visible in the chat window until 50 more messages are logged. Only the last 50 chat log messages are kept, whereas all journal entries are kept forever. | |
− | + | The goal of using something like this is probably to tell people about something that is happening right now ("hey, marauders are back for the 80th time, just thought you should know") in a conversational way that really makes them notice it, but without logging it forever (seriously, a journal full of 80 marauder attacks would be so overstuffed as to be incomprehensible. | |
− | + | One thing you should NOT do is use this AND a journal entry call for permanent logging. Why? Journal entries have chat_text built right in as a field on them, and they will already send a message to the chat log when they arrive, if the journal entry author feels that is warranted. Trust the journal entry author. If you do both, probably players will get double messages. | |
− | + | So here are some use cases for this sort of thing: | |
− | + | ==== Local-Only ==== | |
− | + | 1. First off, to have something show up in the sidebar log for a second and then NOT go to the chat log -- and while we're at it, only go to the local player: | |
− | + | World_AIW2.Instance.QueueChatMessageOrCommand( "Not enough energy to place " + typeToPlace.DisplayName, ChatType.ShowLocallyOnly, "CannotDoThatThing", context ); | |
− | + | There are several overloads, but it's the new ChatType.ShowLocallyOnly that matters. | |
− | World_AIW2.Instance. | + | ==== Main Chat For Everyone ==== |
+ | |||
+ | 2. Taking a step up from that, let's tell everyone and dump that in the general chat log: | ||
+ | |||
+ | World_AIW2.Instance.QueueChatMessageOrCommand( "Human Resistance Fighters arriving to reinforce " + targetPlanet.Name, ChatType.LogToCentralChat, "HumanResistanceFightersWarpInNeutralPlanet", Context ); | ||
+ | |||
+ | = The Various Method Overloads And How To Use Them = | ||
+ | |||
+ | There are several different overloads to World_AIW2.Instance.QueueChatMessageOrCommand(), and all of them are safe to be called from any thread on any machine. Please DO bear in mind that these will generate a GameCommand that then gets executed on everyone's machine... UNLESS you have it set to ChatType.ShowLocallyOnly. So if you are in sim code that happens for everybody in multiplayer, you really want to wrapper it like this: | ||
+ | |||
+ | if ( Engine_Universal.GetIsHostMode() ) | ||
+ | { | ||
+ | //your code in here | ||
+ | } | ||
+ | |||
+ | You have no idea how many clients there are, but there is always one host. In single player there is one host and no clients. And all code definitely runs on the host, but not all code runs on clients (some code, like the long-term planning threads, is host-only). If you DON'T wrapper it in this way, then you'll get multiple copies of the journal entry -- one per player in the game at the moment. | ||
+ | |||
+ | ==Using This For GUI Feedback == | ||
+ | |||
+ | This example from above typifies it: | ||
+ | |||
+ | World_AIW2.Instance.QueueChatMessageOrCommand( "Not enough energy to place " + typeToPlace.DisplayName, ChatType.ShowLocallyOnly, "CannotDoThatThing", context ); | ||
+ | |||
+ | Essentially, you want to show the current player that they are not allowed to do the thing that they just did, and play a little buzzer sound. None of this should go to other players, and it should not be in the chat log even locally. It just needs to pop up on the side of the screen there so that players know why their click just failed. | ||
+ | |||
+ | These types of calls to QueueChatMessageOrCommand are VERY specific to the local machine, and you should never be wrappering them in GetIsHostMode() or similar. If you do, then only the host would get notice of why their clicks fail, etc. That sort of limitation to just being on the host is for something that happens from all the machines and needs to be broadcast to everyone else. | ||
+ | |||
+ | ==Using This For Multiplayer Communication == | ||
+ | |||
+ | It is possible that you could also do something like this in response to a GUI click: | ||
+ | |||
+ | World_AIW2.Instance.QueueChatMessageOrCommand( localPlayerName + " would like to bring your attention to " + ship.Typedata.DisplayName + " on " + ship.Planet.Name + ". Click here to view it.", ChatType.LogToCentralChat, string.Empty, ship, Context ); | ||
+ | |||
+ | This would then broadcast to all players and the chat log that you've just indicated some specific ship on a given planet, as an example. They could then click on the message from you, either while it is popped-up or when it is in the longer-term chat log (only the last 50 messages, still, but this is plenty of time) to see what you were indicating. | ||
+ | |||
+ | ==Overrides include== | ||
+ | |||
+ | * void QueueChatMessageOrCommand( string Message, ChatType Type, ArcenSimContextBase ContextCanBeNull ) | ||
+ | ** Message | ||
+ | *** The literal text of the message to show. If you want special colorization or similar, use [http://digitalnativestudios.com/textmeshpro/docs/rich-text/ rich text tags from TextMeshPro]. | ||
+ | ** Type | ||
+ | *** ChatType.ShowLocallyOnly | ||
+ | **** This is for local UI feedback only. It goes to no other players and no chat logs, here or otherwise. No GameCommands are generated. | ||
+ | *** ChatType.ShowToEveryone | ||
+ | **** This is for showing everybody, but just for 10 seconds for some reason. It goes to all players (on the right side of the screen), but no chat logs. It generates a GameCommand to do so. Is there really a use for this? Eh, whatever, it's here in the interest of completeness. | ||
+ | *** ChatType.LogToCentralChat | ||
+ | **** This is for showing everybody, and having it go to the ongoing chat log. It goes to all players (on the right side of the screen) for 10 seconds at first. It generates a GameCommand to do so. This is useful for inter-player communication along the lines of what we described above. | ||
+ | ** ContextCanBeNull | ||
+ | *** You can pass in a null, but it's better if you pass in an ArcenSimContext. | ||
+ | *** In the event that maybe you are on some sort of background thread, passing in an ArcenSimContext will ensure that your command gets properly queued. | ||
+ | *** Worst case, you pass in a null and are on a background thread, and potentially your main-thread sim queue gets a little scrambled or even throws an error. | ||
+ | |||
+ | * void QueueChatMessageOrCommand( string Message, ChatType Type, ArcenSimContext ContextCanBeNull ) | ||
+ | ** This is identical to the method above, but uses ArcenSimContext rather than ArcenSimContextBase. If you're reading this and not in the core codebase (ArcenUniversal), then you'll automatically wind up using this version. But it really doesn't matter. | ||
+ | ** The purpose of having two methods is so that some of our stuff that is game-agnostic in ArcenUniversal can still send chat messages to the sidebar, like voice clips. It's actually a LOT more common for a voice clip to do this than logging to the journal. | ||
+ | |||
+ | * void QueueChatMessageOrCommand( string Message, ChatType Type, string SFXItemInternalName, ArcenSimContext Context) | ||
+ | ** SFXItemInternalName | ||
+ | *** This string is the name of a sound clip, which can be a sound or a voice clip. It will play on the appropriate audio bus as defined by the sound clip, and it will avoid playing if the rules of playing it say not to. | ||
+ | *** In most cases this would just be string.Empty, unless you want it to buzz in a "you can't do that" sort of way and use "CannotDoThatThing", or use some sort of happy sound for confirming an action. In other cases, like one of the examples above, you might have it play a voice clip for everyone. | ||
+ | *** Please do be careful with playing voice clips via these, as in some cases the voice clips will themselves also write a text message to the chat log, stating the subtitles for whatever the voice clip says. | ||
+ | |||
+ | * void QueueChatMessageOrCommand( string Message, ChatType Type, string SFXItemInternalName, GameEntity_Squad RelatedEntityOrNull, ArcenSimContext Context) | ||
+ | ** RelatedEntityOrNull | ||
+ | *** If this is present, then clicking this chat message will take you to that entity, if it is still alive when the players click on it. |
Latest revision as of 15:19, 7 May 2020
Contents
Hey!
Do you really mean " Journal Entries", in the sense of those things that are defined in xml and new in version 2.040 of the game and further? If so, click that link. Those are what you should be using for long-term, detailed journal entries. And as a bonus, they don't require any custom code from you.
What is presented below is an older form of "journal entry," which is just embedded in the chat log. It can be useful to do that sort of thing at various points as well, but those are... less robust. The journal entries that we're referring to at the above link is instead like uncovering little wiki entries, almost, that show up in a dedicated tab in your sidebar as you play.
Revised Q&A
Q: Do you have sample code for how to emit different journal entries? For example, I'd like a permanent journal entry at game start when you have allied marauders that basically explain how marauders work, and that they can build Raiders if they have their own planets.
A: This has changed a LOT!
Where Do Do That Sort Of Permanent Logging
Now you will find the new instructions for that in the Q&A On How To Log Journal Entries From Custom Code.
Why We'd Use This Instead
So we've established at this point that nothing we do here is actually permanent, correct?
Okay. So, our purpose here is just to write to the chat log. This means a little popup on the right side of the screen for 10 seconds, and then it's visible in the chat window until 50 more messages are logged. Only the last 50 chat log messages are kept, whereas all journal entries are kept forever.
The goal of using something like this is probably to tell people about something that is happening right now ("hey, marauders are back for the 80th time, just thought you should know") in a conversational way that really makes them notice it, but without logging it forever (seriously, a journal full of 80 marauder attacks would be so overstuffed as to be incomprehensible.
One thing you should NOT do is use this AND a journal entry call for permanent logging. Why? Journal entries have chat_text built right in as a field on them, and they will already send a message to the chat log when they arrive, if the journal entry author feels that is warranted. Trust the journal entry author. If you do both, probably players will get double messages.
So here are some use cases for this sort of thing:
Local-Only
1. First off, to have something show up in the sidebar log for a second and then NOT go to the chat log -- and while we're at it, only go to the local player:
World_AIW2.Instance.QueueChatMessageOrCommand( "Not enough energy to place " + typeToPlace.DisplayName, ChatType.ShowLocallyOnly, "CannotDoThatThing", context );
There are several overloads, but it's the new ChatType.ShowLocallyOnly that matters.
Main Chat For Everyone
2. Taking a step up from that, let's tell everyone and dump that in the general chat log:
World_AIW2.Instance.QueueChatMessageOrCommand( "Human Resistance Fighters arriving to reinforce " + targetPlanet.Name, ChatType.LogToCentralChat, "HumanResistanceFightersWarpInNeutralPlanet", Context );
The Various Method Overloads And How To Use Them
There are several different overloads to World_AIW2.Instance.QueueChatMessageOrCommand(), and all of them are safe to be called from any thread on any machine. Please DO bear in mind that these will generate a GameCommand that then gets executed on everyone's machine... UNLESS you have it set to ChatType.ShowLocallyOnly. So if you are in sim code that happens for everybody in multiplayer, you really want to wrapper it like this:
if ( Engine_Universal.GetIsHostMode() ) { //your code in here }
You have no idea how many clients there are, but there is always one host. In single player there is one host and no clients. And all code definitely runs on the host, but not all code runs on clients (some code, like the long-term planning threads, is host-only). If you DON'T wrapper it in this way, then you'll get multiple copies of the journal entry -- one per player in the game at the moment.
Using This For GUI Feedback
This example from above typifies it:
World_AIW2.Instance.QueueChatMessageOrCommand( "Not enough energy to place " + typeToPlace.DisplayName, ChatType.ShowLocallyOnly, "CannotDoThatThing", context );
Essentially, you want to show the current player that they are not allowed to do the thing that they just did, and play a little buzzer sound. None of this should go to other players, and it should not be in the chat log even locally. It just needs to pop up on the side of the screen there so that players know why their click just failed.
These types of calls to QueueChatMessageOrCommand are VERY specific to the local machine, and you should never be wrappering them in GetIsHostMode() or similar. If you do, then only the host would get notice of why their clicks fail, etc. That sort of limitation to just being on the host is for something that happens from all the machines and needs to be broadcast to everyone else.
Using This For Multiplayer Communication
It is possible that you could also do something like this in response to a GUI click:
World_AIW2.Instance.QueueChatMessageOrCommand( localPlayerName + " would like to bring your attention to " + ship.Typedata.DisplayName + " on " + ship.Planet.Name + ". Click here to view it.", ChatType.LogToCentralChat, string.Empty, ship, Context );
This would then broadcast to all players and the chat log that you've just indicated some specific ship on a given planet, as an example. They could then click on the message from you, either while it is popped-up or when it is in the longer-term chat log (only the last 50 messages, still, but this is plenty of time) to see what you were indicating.
Overrides include
- void QueueChatMessageOrCommand( string Message, ChatType Type, ArcenSimContextBase ContextCanBeNull )
- Message
- The literal text of the message to show. If you want special colorization or similar, use rich text tags from TextMeshPro.
- Type
- ChatType.ShowLocallyOnly
- This is for local UI feedback only. It goes to no other players and no chat logs, here or otherwise. No GameCommands are generated.
- ChatType.ShowToEveryone
- This is for showing everybody, but just for 10 seconds for some reason. It goes to all players (on the right side of the screen), but no chat logs. It generates a GameCommand to do so. Is there really a use for this? Eh, whatever, it's here in the interest of completeness.
- ChatType.LogToCentralChat
- This is for showing everybody, and having it go to the ongoing chat log. It goes to all players (on the right side of the screen) for 10 seconds at first. It generates a GameCommand to do so. This is useful for inter-player communication along the lines of what we described above.
- ChatType.ShowLocallyOnly
- ContextCanBeNull
- You can pass in a null, but it's better if you pass in an ArcenSimContext.
- In the event that maybe you are on some sort of background thread, passing in an ArcenSimContext will ensure that your command gets properly queued.
- Worst case, you pass in a null and are on a background thread, and potentially your main-thread sim queue gets a little scrambled or even throws an error.
- Message
- void QueueChatMessageOrCommand( string Message, ChatType Type, ArcenSimContext ContextCanBeNull )
- This is identical to the method above, but uses ArcenSimContext rather than ArcenSimContextBase. If you're reading this and not in the core codebase (ArcenUniversal), then you'll automatically wind up using this version. But it really doesn't matter.
- The purpose of having two methods is so that some of our stuff that is game-agnostic in ArcenUniversal can still send chat messages to the sidebar, like voice clips. It's actually a LOT more common for a voice clip to do this than logging to the journal.
- void QueueChatMessageOrCommand( string Message, ChatType Type, string SFXItemInternalName, ArcenSimContext Context)
- SFXItemInternalName
- This string is the name of a sound clip, which can be a sound or a voice clip. It will play on the appropriate audio bus as defined by the sound clip, and it will avoid playing if the rules of playing it say not to.
- In most cases this would just be string.Empty, unless you want it to buzz in a "you can't do that" sort of way and use "CannotDoThatThing", or use some sort of happy sound for confirming an action. In other cases, like one of the examples above, you might have it play a voice clip for everyone.
- Please do be careful with playing voice clips via these, as in some cases the voice clips will themselves also write a text message to the chat log, stating the subtitles for whatever the voice clip says.
- SFXItemInternalName
- void QueueChatMessageOrCommand( string Message, ChatType Type, string SFXItemInternalName, GameEntity_Squad RelatedEntityOrNull, ArcenSimContext Context)
- RelatedEntityOrNull
- If this is present, then clicking this chat message will take you to that entity, if it is still alive when the players click on it.
- RelatedEntityOrNull