Releases: BOLL7708/desbot
v6.562 Setup & Reward Fixes
Fixes
- Install script fixed so it adjusts the presets import path.
- Fixed database retrieval so it doesn't return prepopulated default classes, but nothing, if the post did not exist.
- Fix database migration always asking to migrate if latest migration version did not match widget version.
- Updated readme with some details, hid links to outdated wikis for now.
- Fixed accumulating reward messing up titles and failing to update,
- Made it only cost the remainder at the end of the run.
- Stopped price from going negative on final redemption.
- Fix new counters getting the base class instead of their specific classes when saved to the database.
Known Issues
- Users can get randomized an empty voice, I don't know why this happens and have not been able to replicate it off stream yet.
- Some users don't get the Twitch authentication after installing the widget, could not replicate, yet.
v6.554 Here you go Jeppe, a Database!
Database Settings
This has been a month in the works, now all settings (as a first step, as outlined in the prior release) are now stored in a MariaDB database.
When you load the widget now, it will open the editor, which is not yet an editor, but it will let you set up the database and import your old settings, as well as login with your Twitch accounts. This comes with some steps in preparation though.
- You need a newer XAMPP with Maria DB 10.2 or later, for JSON support, and I'll recommend going for PHP 8.1 or higher as that is what I am running, and might use the features of in the future.
- For your configs, you will have to redo most imports, because I did a bunch of refactoring during this transition to database settings. This also means you need to delete the whole
dist
folder and rebuild it.
Then you just load the existing widget page and it will go through the setup, which hopefully will be explanatory enough to "just work", as it were. If not, make sure to tell me exactly where you got stuck, so I can improve the experience for future users.
On the last page of the setup you will see a link to the actual widget page. Yes, the default index is now the editor, and the widget URL/link is something you will have to update on your browser sources in OBS.
After that, you might also need to change references to label-files in OBS, text files with contents from the label action, as they have moved from the now defunct _settings
into the new _data
folder.
Other stuff?!?
- Fix quotes ignoring entries with only one word.
- Make redemption clearing delete redemptions that no longer exists on Twitch, instead of leaving them in the database forever.
- Screenshots are now converted to 85% quality JPEGs before being sent to Discord, to avoid hitting the upload size limit.
v5.511 Reward Merging, Game Event Triggering & Plans
(this was a draft that was mistakenly never published, the release was made, but the release notes were forgotten as a draft for more than a year, no wonder nobody read about my plans...)
Updates
Event Options
Added rewardMergeUpdateConfigWithFirst
to event options, this means reward properties when doing incrementing, accumulating or multi-tier events can use the first reward setup as a base, and merge the other setups on top of that.
Game Specific Events
The triggering of action entries should be fixed, I don't really know why the old code stopped working, but now it by default tries to merge the base event with the game specific event and should trigger all of that. It has only been briefly tested, so report any issues if you bump into them.
Fixes
A range of fixes, one was to try and prevent caching of the page to allow .js
files to load fresh, hopefully that works. It became a necessity after switching to JS modules.
Plans
With time it has become apparent that it is not sustainable to keep the widget in this state and gain more users, as there is only one of me, and eventually there will only be helping, no more coding.
When even the software developers I know are users of the widget are hesitant to update due to config changes, that's a good sign things have to change. I've already started working on database support, and will start off with moving all settings into that, which means TTS settings, trophy registrations, achievements, etc.
Eventually this means the config should also go into the database, but that is a huge system-wide change, and it will take a lot of planning, time and effort to make it happen, much as it also requires a config editor to be able to use it. This means new features have been pushed into the future, as most if not all time working on this will go towards this user friendly experience.
As how it is expected to work, when things are in a database, I can supply releases with .sql
files that are automatically run to migrate the user to the next release upon launching the widget. This is the plan anyhow, and I'm hopeful this will work out, eventually. Oh and if anyone wants to help with things like the config editor, don't hesitate to reach out, I'm mainly a backend developer after all.
v5.508 Imports & Help
Updates
Modules
A major change now is something to thank @jeppevinkel for, he didn't do it, but he tipped me off this existed. Most of the widget is now dynamically loaded by import/export modules supported by modern browsers. This means most files include import lines for whatever classes are used, like many other programming languages.
Imports can be easily auto-generated for any class that miss them by following the below instructions.
In Visual Studio Code
- Open
Settings
and change these two values:
TypeScript > Preferences
Import Module Specifier: relative
Import Module Specifier Ending: js
- On anything that needs to be imported, press
CTRL + .
and the import should have been added at the top of the file.
In IntelliJ
- Open
Settings
and change these two values:
Editor > Codestyle > TypeScript > Imports
[x]: Use paths relative to tsconfig.json
Use file extension: always ".js"
Use path mappings from tsconfig.json: Never
- On anything that needs to be imported, press
CTRL + ENTER
and the import should have been added at the top of the file.
Twitch Category
- Some games will not have a Steam title that match the Twitch Game registry, so there is a mismatch or no match at all. A table for overriding what is matched has been added.
- I also renamed the default game category and moved it from
Config.controller
toConfig.twitch
.
Config.twitch = {
defaultGameCategory: 'Games + Demos',
gameTitleToCategoryOverride: {
'Vermillion - VR Painting': 'Vermillion'
}
}
Help
Commands can now include help properties.
Config.events = {
'': {
triggers: {
entries: ['Hello'],
helpTitle: 'Title that is used if posting the help to Discord to break up sections.',
helpInput: ['first param', 'second param'],
helpText: 'This is a description about how a command is supposed to be used.'
}
}
}
There are two new commands that can be used with the above, copy them from the template.
!posthelp
- Will post all commands with help properties to the Discord webhook with the same key, from the template:HelpToDiscord
!help [command]
- Will post help for the command to chat, uses the key:HelpToChat
Quote
If the user tag is left out when using !quote
the configured channel name will be used instead, which is usually the streamer account, for convenience.
Dictionary
It is now possible to append and reduce a list of substitute words for a dictionary entry with the !word
command.
!word test hello
- will replace the current entry fortest
.!word +test world
- will add another word to the existing entry fortest
, replacement will be random.!word -test world
- will remove a word from the existing entry fortest
if a match was found.
Text Tags
- Added
eventLevelMaxShort
which can be used for accumulating rewards for a shortened goal number.
Entries
- Audio action
srcEntries
now has proper entries handling, meaning things like.userRandom()
should now work.
Actions
User
The user
object that is used in actions now contains inputWords
, a complement to input
, and it's simply input
split on space. This is mostly used for development and the custom
action.
System
The events
action and rewardStates
action has been consolidated into a common system
action.
Config.events = {
actionEntries: {
system: {
triggerCommandEntries: ['command'],
triggerEventEntries: ['OneKey', 'OtherKey'],
triggerInterval: 20,
toggleRewardStates: { 'OneKey': { state: false } }
}
}
}
Event Options
Added a new option to ignore automatically posting of reward redemptions to key-referenced Discord Webhook.
rewardIgnoreAutomaticDiscordPosting
v5.493 Keys
This is a small big update. That means the release notes will be short, but it's a huge change, big enough to up the main version number again. Yep, shake in fear, dear end users.
Update
Keys
What was a class with static properties is now a type. This means you need to update !keys.ts
and most of your configs. The templates have been updated accordingly. The install script has not been tested yet.
This change was done to make it easier to add new keys, to remove the need to both make a key name and a key value. Now they are both one and the same.
!keys.ts
What was this:
class Keys {
static readonly A_KEY = 'KeyValue'
static readonly ANOTHER_KEY = 'OtherKeyValue'
}
Is now this:
type TKeys =
'Unknown'
| 'KeyValue'
| 'OtherKeyValue'
Configs
What does this mean for the rest of the configs? It means any place where a Keys.A_KEY
was referenced, it should now be just 'KeyValue'
instead. See example below.
What was this:
Config.events = {
[Keys.A_KEY]: {}
}
Is now this:
Configs.events = {
'KeyValue': {}
}
In short, you remove the square brackets and the Keys
reference, then put the string value there instead.
Note: When using the array extensions, like .useRandom()
, on an array of keys, the result loses the TKeys
type, so we need to cast it to TKeys
with <TKeys[]>
in front, or with as TKeys[]
behind. I will try to make this easier to use in the future.
Config.events = {
'KeyValue': {
actionsEntries: {
events: {
keyEntries: <TKeys[]> ['OtherKeyValue', 'AnotherKeyValue'].useRandom()
}
}
}
}
v4.491 Reward States & Events Action
Fixes
Reward Toggling
If a reward is now in the main profiles or games profiles, it will not be overridden by a reward-per-game setting unless it is explicitly set. This has now changed twice.
- Original: Rewards-per-game overrode anything if it was set in either on/off list, would set the flipped state the game didn't match.
- Update to fix issue Doc had: Rewards-per-game only overrides profiles if the reward is in any of the lists, and only then.
- Final: A mix, we still override with rewards-per-game on a match, but if a profile has set a state, we don't override it with the flipped value.
Updates
RewardStates Action
The action for changing the state of rewards on Twitch has been updated. It can now take an optional state, if not included it will toggle, and a value for if the state should override things like the profiles used for games.
[Keys.EXAMPLE]: {
actionsEntries: {
rewardStates: {
[Keys.YOUR_REWARD]: {
state: true, // Leave this out to toggle the current state
override: true // Will store the state in the always on/off lists in the config
}
}
}
}
Commands Action renamed to Events Action
The ability to trigger other commands have been expanded to also be able to trigger other events on their key, as such the action has been renamed.
[Keys.EXAMPLE]: {
actionsEntries: {
events: {
commandEntries: ['one_command', 'another_command'],
keyEntries: [Keys.ONE_KEY, Keys.ANTHER_KEY],
interval: 20
}
}
}
Text Tags
These were added as I thought I needed them, but right now I'm not using them myself, so tell me if you find that they are not doing what you expect.
- userMessage - The message provided by the user regardless if it was a command or prompted reward.
- userInputWord1 - The first word from the user input
- userInputWord2 - The second word from the user input
- userInputWord3 - The third word from the user input
- userInputWord4 - The fourth word from the user input
- userInputWord5 - The fifth word from the user input
v4.486 Multi-Tier Behavior, Event Options Profiles & User Cooldowns
Fixes
- Fixed TTS changes not being applied to actions in the same event.
- Added missing accumulating reward settings load on init.
- Fixed example audio configs in the template to have
srcEntries
.
New Stuff
User based cooldowns for commands
Commands had optional cooldowns, they were always global though, now you can set one cooldown for global and one for user. This means a single user has their own cooldown, so others can still trigger the command during that time.
If there is a global cooldown and a user cooldown, both are used. Meaning a user can not use the command if the global cooldown is still running, or, if they have their own personal cooldown running.
[Keys.EXAMPLE]: {
triggers: {
command: { // or remoteCommand
entries: 'example',
globalCooldown: 10,
userCooldown: 5*60
}
}
}
Multi-Tier Event Behavior
This enables events that when triggered levels up, and if triggered again before a timeout will level up again, to the set maximum level. This will affect the index used, and it relies on .useSpecific()
on your entries.
In any entries, index 0 will be what is called if the event is reset, when it times out, leave it as an empty object {}
if it should do nothing. Then the one after that will be level 1, 2, 3 etc. The final level will be reused if there are no more.
[Keys.EXAMPLE]: {
options: {
behavior: EBehavior.MultiTier, // The new behavior
multiTierTimeout: 30, // Number of seconds before it resets
multiTierMaxLevel: 3, // The maximum level it can reach, if not set it will use the count of reward configs.
multiTierDoResetActions: true, // Set this to trigger the first actions in the set when resetting.
multiTierDisableWhenMaxed: true // Set this to hide the reward when it has reached maximum level.
}
}
Event Option Overrides
It is now possible to configure overrides to values in Config.events.options
, this is done in Config.twitch.eventOptionsDefault
and eventOptionsPerGame
, which are now default properties for Config.twitch
and needs to be added. See the template for sample input for them.
Text Tags
With multi-tier events comes a number of new text tags associated with them.
- eventLevel - Current level of the event
- eventLevelNext - The next level of the event
- eventLevelMax - The maximum level of the event
- eventLevelProgress - A progress value for the event: x/y
- eventLevelNextProgress - A progress value for the event using the next level: x+1/y
Cooldown Renamed
In the command
and remoteCommand
actions, cooldown
has been renamed to globalCooldown
.
This as we now have a secondary option, mentioned earlier: userCooldown
.
Specific Index Option
This is an option in Config.events.options
, set specificIndex
to have .useSpecific()
use that index if the event has no behavior set. This means you can make a custom action to modify what is in the config to have a reward act differently.
[Keys.EXAMPLE]: {
options: {
specificIndex: 1
},
actionsEntities: [
{ speech: { entries: 'one' } },
{ speech: { entries: 'two' } }, // Only this will be used now
{ speech: { entries: 'three' } }
].useSpecific()
}
v4.479 Relay & Move Space
I will try to do smaller and more frequent updates, as well, it melts my brain to save up too much and write release notes for all of it. Some features are just too big for that not to happen though! This time it's a small update.
This update requires at least version v1.43 of OpenVR2WS if you want to use the new features: Relay and Move Space.
New Features
Actions
Move Space
This new action will move your calibrated VR space. It can take properties for X, Y and Z, a boolean for if the Chaperone should be offset in the opposite direction, and a duration before it resets. All values are optional, with offsets , x
, y
, z
defaulting to 0
, the moveChaperone
flag to true
and if duration is not supplied there will be no reset.
[Keys.EXAMPLE]: {
actionsEntries: {
vrMoveSpace: {
y: 0.5,
duration: 1
}
}
}
Triggers
Relay
It is now possible to remote control the widget by using OpenVR2WS as a relay station. You can as an example install a Websocket plugin in your Stream Deck software and use that to activate triggers in the widget.
[Keys.EXAMPLE]: {
triggers: {
relay: 'your_key'
}
}
And this is a sample payload to send to OpenVR2WS to activate this relay trigger.
{
"key":"Relay",
"value":"your_password",
"value2":"a_twitch_username_to_act_as",
"value3":"your_key"
}
See where to set the password in the next section.
Config Changes
Relay
For relays to work we use a common password, just so we can filter incoming messages if we want multiple channels of communication. The password is sent to every connect client so it would probably be better to call it channel
, but this is it for now.
Config.credentials = {
OpenVR2WSRelayPassword: 'your_password'
}
Commands, etc
Remote commands now use entries instead of the event key, just like standard commands:
{
triggers: {
remoteCommand: { entries: 'the_command' }
}
}
An addition to this, is that the triggers for commands, remote commands and relay now all can be set to %eventKey
to again use the event key (Keys.YOUR_KEY
) as its value.
Action Rename
The action openVR2WS
has been renamed to vrSetting
, as that is what it was used for.
Another change is that world scale values are no longer handled as a decimal value but integers, meaning 0.5 is now 50.
v4.475 Entries & Accumulating Events
Version 4.x?
What is this, a new major version? This concludes something I sketched out back in May, so three months ago. The way events are triggered to activate a bunch of actions have been updated, now there's a handler in the middle that can handle weird behaviors, like incrementing, accumulating and random events.
A whole lot happened in this release, and I might have missed something. If you bump into any issues, please tell me and I might have to append these release notes. Thanks!
Note: This release moves files around a bit, so after pulling the changes, you should delete your dist
folder and regenerate all files.
Config Changes
Commands no longer using keys as triggers
Due to commands now sharing their actions with rewards (and other triggers), it ended up becoming an issue to have the strings be used for both the key and the trigger for commands. Because of this, commands now need to list their triggers in the trigger setup.
[Keys.EXAMPLE]: {
triggers: {
command: {
// These are entries so can take an array,
// will always use all though as nothing else makes sense.
entries: 'example'
}
}
Note: This might beak some uses of keys, like in the end stream command, so keep an eye out for that.
Entries
A bunch of action configs contain fields that end in entries
or are just that. These should all be handled in a specific way, as they can all be arrays and arrays have now been extended with a bunch of possible treatment properties.
{
discord: {
// This additional call on the array will set its type,
// and in this case that means it will use a random value from the array.
entries: ['First string', 'Other string'].useRandom()
}
}
These are the available properties.
const arr1 = [].useAll() // The default, will use all of the entries
const arr2 = [].useRandom() // Will use one random entry from the array
const arr3 = [].useAllRandom() // Will use all entries but in a random order
const arr4 = [].useSpecific() // Will use one specific entry based on an index generated by special event behaviors.
Behaviors
Behaviors are special handling of event triggering, there are a few types available as you can see below:
/**
* Various types of special event behavior.
*/
enum EBehavior {
All, // This is the default, all entries will be used.
Random, // A random entry will be used.
Incrementing, // An index will increment for each triggering, and the entry for that index will be used.
Accumulating, // A count is accumulating,
// the first entry is triggered every time until we meat the goal,
// the second entry will be used when the goal has been reached.
Multitier// TODO: Not implemented yet.
}
The above enum
is set in the Event.options.behavior
. See example below.
[Keys.EXAMPLE]: {
options: {
behavior: EBehavior.Incrementing
}
}
Note: If you are using the new Accumulating
behavior, you should also set the option accumulationGoal
in Event.options
.
Places that has changed to entries
Chat actions are now a proper config with an entries
field.
actionsEntries: { // This also changed, more about this below
chat: { entries: 'An entry' },
web: { entries: ['All entries can be an array too'] },
discord: { entries: ['And an array with', 'the type for behavior'].useRandom() },
remoteCommand: { entries: '!acommandentry' },
lights: { entries: {x: 1, y: 1} },
audio: { srcEntries: '_assets/asource.wav' },
pipe: {
imagePathEntries: ['Path1', 'Path2'],
imageDataEntries: 'imagedata'
}
}
Actions
Entries
As mentioned for other things, Event.actions
is now Event.actionsEntries
to adhere to the entries scheme. It can also take the use
calls to act with the event behavior. It is now simply a single IActions
object, or an array of them, and that array can use the behaviors.
[Keys.EXAMPLE]: {
actionsEntries: [
{ speech: { entries: 'One' } },
{ speech: { entries: 'One' } }
].useRandom()
}
Actions that no longer accept arrays of configs
This is a change due to actions themself being able to be handled in accordance with the event behavior, this reduces complexity. Basically, instead of having arrays of configs in one actions object, we have an array of actions objects.
- openVR2WS
- obs
- pipe
- lights
- chat
Timelines are no more
While timelines were nice, they were also limited in usability. For one they only supported absolute timestamps, not relative delays. This is now changed, and these values are now additional properties for the IAction
interface.
These will run in the order they are listed if using _delayMs
, or in the order of their absolute _timeMs
value. If there is a mix, any time a _timeMs
value is used, it will reset whichever time _delayMs
had set prior, and the next _delayMs
will then add to that time.
[Keys.EXAMPLE]: {
actionsEntries: [
{
_timeMs: 1000, // Will happen after one second
chat: { entries: 'Hello' }
},
{
_delayMs: 2000, // Will happen two seconds after the previous action that set a time (or 0 if none)
chat: { entries: 'Bye' }
}
]
}
The exec action has been split up
The exec
action would do both key presses in application windows and execute custom URIs. This have now been split up in two other actions.
[Keys.EXAMPLE]: {
keys: {}, // see IPressKeysAction
uri: { entries: 'custom://something' }
}
SpeechReferences
With a new command we should add a few speech references for it.
Check for Config.controller.speechReferences
in the config.template.ts
file, and copy that speech reference to your config.
Subscription announcements
This is a bit work in progress as I don't know how to get all values yet, will see how this works out.
Config.twitch.announceSubs = [
// Check the config.template.ts file for a full list of these.
{ tier: 0, gift: false, multi: false, message: '%userTag subbed with Prime' }
]
Text Tags
To support accumulating events, a few additional text tags were added.
eventKey
// The key from Keys associated with this event.eventCost
// If it was a reward, what it cost.eventCount
// The current accumulating value for this event.eventCountPercent
// The current accumulating progress in percent.eventGoal
// The goal for accumulation, if set.
Keys
Refactor: COMMAND_RESET_INCREWARD
into COMMAND_RESET_INCREMENTING_EVENTS
Add: COMMAND_RESET_ACCUMULATING_EVENTS
Settings
The file for counters for incrementing rewards have changed. It was twitch_reward_counters.csv
, but is now event_counters_incremental.csv
.
v3.465 Hotifx & Command Entries
The previous hotfix wasn't hot enough, so here's another.
It turns out combining rewards and commands with the same key used for both resulted in chaos, so now I've split things up so keys for commands are now just keys, and not used for the commands themselves.
Templates have been updated accordingly. This is a fairly major change in a tiny update, sorry! 😅
Config Changes
{
command: {
entries: ['hello', 'hi', 'yo'] // This can be either a single string, or an array of string.
}
}