v1.5.2_pre

This commit is contained in:
Cristian Deenen
2023-10-05 23:17:56 +02:00
parent 2cfa8c3ac9
commit 9242cf4978
13 changed files with 269 additions and 299 deletions

1
.gitignore vendored
View File

@@ -1 +0,0 @@
MaterialDeck.zip

View File

@@ -8,9 +8,38 @@ import { SoundboardControl } from "./src/actions/soundboard.js";
import { OtherControls } from "./src/actions/othercontrols.js";
import { ExternalModules } from "./src/actions/external.js";
import { SceneControl } from "./src/actions/scene.js";
import { downloadUtility, compareVersions, compatibleCore } from "./src/misc.js";
import { downloadUtility, compareVersions } from "./src/misc.js";
import { TokenHelper } from "./src/systems/tokenHelper.js";
export const releaseURLs = {
module: {
api: "https://api.github.com/repos/MaterialFoundry/MaterialDeck/releases",
url: "https://github.com/MaterialFoundry/MaterialDeck/releases"
},
plugin: {
api: "https://api.github.com/repos/MaterialFoundry/MaterialDeck_SD/releases",
url: "https://github.com/MaterialFoundry/MaterialDeck_SD/releases"
},
materialCompanion: {
api: "https://api.github.com/repos/MaterialFoundry/MaterialCompanion/releases",
url: "https://github.com/MaterialFoundry/MaterialCompanion/releases"
}
}
export let versions = {
materialCompanion: {
current: 'Unknown',
minimum: 'Unknown'
},
plugin: {
current: 'Unknown',
minimum: 'Unknown'
},
module: {
current: 'Unknown'
}
}
export var streamDeck;
export var tokenControl;
export var macroControl;
@@ -25,14 +54,9 @@ export const moduleName = "MaterialDeck";
export let gamingSystem = "dnd5e";
export let hotbarUses = false;
export let calculateHotbarUses;
export let sdVersion;
export let msVersion;
let ready = false;
let controlTokenTimer;
let updateDialog;
export let minimumMSversion;
export let minimumSDversion;
export var enableModule;
@@ -54,20 +78,24 @@ async function analyzeWSmessage(msg){
if (enableModule == false) return;
const data = JSON.parse(msg);
//console.log("Received",data);
if (data.type == 'connected') {
console.log('rec',data)
}
if ((data.type == "connected" || data.type == "version") && data.data == "SD"){
transmitInitData();
if (data.type == "connected" && data.source == "MaterialCompanion"){
//console.log('data',data)
//transmitInitData();
let sdNok = false;
let msNok = false;
if (data.MSversion) {
msVersion = data.MSversion;
if (!compareVersions(minimumMSversion,msVersion)) {
if (data.materialCompanionVersion) {
versions.materialCompanion.current = data.materialCompanionVersion;
if (!compareVersions(versions.materialCompanion.minimum, versions.materialCompanion.current)) {
msNok = true;
}
}
if (data.SDversion) {
sdVersion = data.SDversion;
if (!compareVersions(minimumSDversion,sdVersion)) {
if (data.pluginVersion) {
versions.plugin.current = data.pluginVersion;
if (!compareVersions(versions.plugin.minimum, versions.plugin.current)) {
sdNok = true;
}
}
@@ -75,15 +103,15 @@ async function analyzeWSmessage(msg){
let content = '';
if (sdNok && msNok) content += `${game.i18n.localize("MaterialDeck.UpdateRequired.Both")}<br><br>`;
else if (sdNok) content += `${game.i18n.localize("MaterialDeck.UpdateRequired.SD")}<br><br>`;
else if (msNok) content += `${game.i18n.localize("MaterialDeck.UpdateRequired.MS")}<br><br>`;
else if (msNok) content += `${game.i18n.localize("MaterialDeck.UpdateRequired.MC")}<br><br>`;
content += `${game.i18n.localize("MaterialDeck.UpdateRequired.Update")}<br><br>`;
if (sdNok) content += `<a href="https://github.com/CDeenen/MaterialDeck_SD/releases">${game.i18n.localize("MaterialDeck.UpdateRequired.SDdownload")}</a><br>`;
if (msNok) content += `<a href="https://github.com/CDeenen/MaterialServer/releases">Material Server</a><br>`;
if (sdNok) content += `<a href="${releaseURLs.plugin.url}">${game.i18n.localize("MaterialDeck.UpdateRequired.SDdownload")}</a><br>`;
if (msNok) content += `<a href="${releaseURLs.materialCompanion.url}">Material Companion</a><br>`;
content += "<br>"
const myDialog = new Dialog({
new Dialog({
title: game.i18n.localize("MaterialDeck.UpdateRequired.Title"),
content,
buttons: {
@@ -101,7 +129,7 @@ async function analyzeWSmessage(msg){
}).render(true);
}
console.log("streamdeck connected to server", msVersion);
console.log("streamdeck connected to server", versions.materialCompanion.current);
streamDeck.resetImageBuffer();
}
@@ -128,8 +156,6 @@ async function analyzeWSmessage(msg){
streamDeck.setScreen(action);
await streamDeck.setContext(device,data.size,data.deviceIteration,action,context,coordinates,settings,name,type);
if (game.settings.get(moduleName, 'devices')?.[device]?.enable == false) return;
if (action == 'token'){
tokenControl.active = true;
tokenControl.pushData(canvas.tokens.controlled[0]?.id,settings,context,device);
@@ -156,7 +182,6 @@ async function analyzeWSmessage(msg){
}
else if (event == 'keyDown'){
if (game.settings.get(moduleName, 'devices')?.[device]?.enable == false) return;
if (action == 'token')
tokenControl.keyPress(settings);
@@ -177,7 +202,6 @@ async function analyzeWSmessage(msg){
}
else if (event == 'keyUp'){
if (game.settings.get(moduleName, 'devices')?.[device]?.enable == false) return;
if (action == 'soundboard'){
soundboard.keyPressUp(settings);
@@ -211,8 +235,13 @@ function startWebsocket() {
ui.notifications.info("Material Deck "+game.i18n.localize("MaterialDeck.Notifications.Connected") +": "+address);
wsOpen = true;
const msg = {
target: "server",
module: "MD"
target: "MaterialCompanion",
source: "MaterialDeck_Foundry",
sourceTarget: "MaterialDeck_Device",
type: "connected",
userId: game.userId,
userName: game.user.name,
version: game.modules.get(moduleName).version
}
ws.send(JSON.stringify(msg));
transmitInitData();
@@ -228,8 +257,9 @@ let messageCount = 0;
function transmitInitData() {
const msg = {
target: "SD",
target: "MaterialDeck_Device",
type: "init",
userId: game.userId,
system: getGamingSystem(),
systemData: {
conditions: tokenHelper.getConditionList(),
@@ -343,8 +373,9 @@ Hooks.once('ready', async()=>{
enableModule = (game.settings.get(moduleName,'Enable')) ? true : false;
getGamingSystem();
minimumMSversion = game.modules.get(moduleName).flags.minimumMSVersion;
minimumSDversion = game.modules.get(moduleName).flags.minimumPluginVersion;
versions.module.current = game.modules.get('MaterialDeck').version;
versions.materialCompanion.minimum = game.modules.get(moduleName).flags.minimumMaterialCompanionVersion;
versions.plugin.minimum = game.modules.get(moduleName).flags.minimumPluginVersion;
soundboard = new SoundboardControl();
streamDeck = new StreamDeck();
@@ -447,7 +478,8 @@ Hooks.once('ready', async()=>{
});
function updateActor(id) {
const token = tokenHelper.getTokenFromActorId(id)
const token = tokenHelper.getTokenFromActorId(id);
if (token == undefined) return;
tokenControl.update(token.id);
}
@@ -704,4 +736,21 @@ Hooks.on('globalAmbientVolumeChanged', () => {
Hooks.on('globalInterfaceVolumeChanged', () => {
if (enableModule == false || ready == false || otherControls == undefined) return;
otherControls.updateAll();
})
})
Hooks.on('MaterialDeck', (data) => {
if (data.type == 'setButton') {
//Get the buttonContext and device from streamDeck.buttonContext using data.buttonId
const buttonContext = streamDeck.buttonContext[0]?.buttons[data.button]?.context;
const device = streamDeck.buttonContext[0]?.device;
//Set icon on SD
streamDeck.setIcon(buttonContext, device, data.icon, data.options);
//Set text on SD
streamDeck.setTitle(data.text, buttonContext);
}
else {
//reserved for future MD hooks
}
});

View File

@@ -1,4 +1,18 @@
# Changelog Material Deck Module
### v1.5.2 - xx-xx-2023
<b>Starting from this version you have to use <a href="https://github.com/MaterialFoundry/MaterialCompanion">Material Companion</a> instead of Material Server.</b>
Fixes:
<ul>
<li>(PF2e) Token Action => Toggle Condition: Condition icons work again</li>
</ul>
Other:
<ul>
<li>Material Deck is no longer compatible with Material Server, you now have to use Material Companion</li>
<li>Removed 'Device Config' because this is now handled by Material Companion</li>
</ul>
### v1.5.1 - 28-06-2023
Fixes:
<ul>

View File

@@ -1,6 +1,6 @@
{
"MaterialDeck.Notifications.Disconnected": "Disconnected from Material Server, attempting to reconnect",
"MaterialDeck.Notifications.ConnectFail": "Can't connect to Material Server, retrying",
"MaterialDeck.Notifications.Disconnected": "Disconnected from Material Companion, attempting to reconnect",
"MaterialDeck.Notifications.ConnectFail": "Can't connect to Material Companion, retrying",
"MaterialDeck.Notifications.Connected": "Connected",
"MaterialDeck.Notifications.Soundboard.NoPermission": "You do not have permission to configure the soundboard",
"MaterialDeck.Notifications.Macroboard.NoPermission": "You do not have permission to configure the macroboard",
@@ -12,9 +12,9 @@
"MaterialDeck.EnableDialog.No": "No",
"MaterialDeck.UpdateRequired.Title": "Material Deck: Update Required",
"MaterialDeck.UpdateRequired.MS": "The Material Server version you are using is incompatible with this version of Material Deck.",
"MaterialDeck.UpdateRequired.MC": "The Material Companion version you are using is incompatible with this version of Material Deck.",
"MaterialDeck.UpdateRequired.SD": "The Stream Deck plugin you are using is incompatible with this version of Material Deck.",
"MaterialDeck.UpdateRequired.Both": "The Stream Deck plugin and Material Server you are using are incompatible with this version of Material Deck.",
"MaterialDeck.UpdateRequired.Both": "The Stream Deck plugin and Material Companion you are using are incompatible with this version of Material Deck.",
"MaterialDeck.UpdateRequired.Update": "Please update using the Download Utility or click the link below.",
"MaterialDeck.UpdateRequired.SDdownload": "Stream Deck Plugin",
@@ -22,18 +22,17 @@
"MaterialDeck.Sett.EnableHint": "Enabling the module for this client is required if you want to use Material Deck on your computer. If you do not have a Stream Deck connected or don't want to use it for Material Deck, disable the module here.",
"MaterialDeck.Sett.Help": "Help",
"MaterialDeck.Sett.Permission": "User Permission Configuration",
"MaterialDeck.DeviceConfig.Title": "Device Configuration",
"MaterialDeck.Sett.PlaylistConfig": "Playlist Configuration",
"MaterialDeck.Sett.MacroConfig": "Macro Configuration",
"MaterialDeck.Sett.SoundboardConfig": "Soundboard Configuration",
"MaterialDeck.Sett.ServerAddr": "Material Server Address",
"MaterialDeck.Sett.ServerAddrHint": "The IP address and port of Material Server. The default value will work for 99% of people, only change this if you know what you're doing. Must follow the format [ip_address]:[port], for example: 'localhost:3001' or '192.168.1.1:4000'.",
"MaterialDeck.Sett.ServerAddr": "Material Companion Address",
"MaterialDeck.Sett.ServerAddrHint": "The IP address and port of Material Companion. The default value will work for 99% of people, only change this if you know what you're doing. Must follow the format [ip_address]:[port], for example: 'localhost:3001' or '192.168.1.1:4000'.",
"MaterialDeck.Sett.ImageBuffer": "Image Cache Size",
"MaterialDeck.Sett.ImageBufferHint": "Sets the amount of images to store in the image cache. The image cache will locally store all images sent to the Stream Deck. This improves the update speed, but increases memory usage.",
"MaterialDeck.Sett.ImageBrightness": "Image Brightness",
"MaterialDeck.Sett.ImageBrightnessHint": "Sets the brightness of the default white images. If the Image Cache Size is bigger than 0, perform a refresh for instant results.",
"MaterialDeck.Sett.NrOfConnMessages": "Number of Connection Warnings",
"MaterialDeck.Sett.NrOfConnMessagesHint": "Sets the number of times a connection warning is displayed if Material Deck cannot connect to Material Server. If set to 0, it will give not be limited.",
"MaterialDeck.Sett.NrOfConnMessagesHint": "Sets the number of times a connection warning is displayed if Material Deck cannot connect to Material Companion. If set to 0, it will give not be limited.",
"MaterialDeck.Sett.SystemOverride": "System Override",
"MaterialDeck.Sett.SystemOverrideHint": "Overrides the automatic gaming system detection. Unsupported systems default to dnd5e, but if an unsupported system is similar to a different system you can specify that system here.",
@@ -210,7 +209,7 @@
"MaterialDeck.SimpleCalendar.Of": "of",
"MaterialDeck.DownloadUtility.Title": "Download Utility",
"MaterialDeck.DownloadUtility.Plugin": "Module, Stream Deck Plugin & Material Server",
"MaterialDeck.DownloadUtility.Plugin": "Module, Stream Deck Plugin & Material Companion",
"MaterialDeck.DownloadUtility.Minimum": "Minimum",
"MaterialDeck.DownloadUtility.Current": "Current",
"MaterialDeck.DownloadUtility.Latest": "Latest",
@@ -218,7 +217,7 @@
"MaterialDeck.DownloadUtility.Download": "Download",
"MaterialDeck.DownloadUtility.module": "Module",
"MaterialDeck.DownloadUtility.SDplugin": "SD Plugin",
"MaterialDeck.DownloadUtility.MSserver": "Material Server",
"MaterialDeck.DownloadUtility.MSserver": "Material Companion",
"MaterialDeck.DownloadUtility.Windows": "Windows",
"MaterialDeck.DownloadUtility.MacosM1": "MacOS (M1)",
"MaterialDeck.DownloadUtility.MacosIntel": "MacOS (Intel)",

View File

@@ -3,7 +3,7 @@
"id": "MaterialDeck",
"title": "Material Deck",
"description": "Material Deck allows you to control Foundry using an Elgato Stream Deck",
"version": "1.5.1",
"version": "1.5.2_pre",
"author": "CDeenen",
"authors": [
{
@@ -28,8 +28,8 @@
"verified": "11"
},
"flags": {
"minimumMSVersion": "1.1.0",
"minimumPluginVersion": "1.5.0"
"minimumMaterialCompanionVersion": "1.0.2",
"minimumPluginVersion": "1.5.2"
},
"languages": [
{

View File

@@ -916,8 +916,10 @@ export class ExternalModules{
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
updateMonksActiveTiles(settings,context,device) {
const id = settings.monksActiveTilesId;
if (id == undefined || id == '') return;
let tile = canvas.tiles.placeables.find(t => t.id == id);
if (tile == undefined) return;
const tileData = tile.document.flags?.['monks-active-tiles'];
if (tileData == undefined) return;
@@ -929,7 +931,7 @@ export class ExternalModules{
ring = 2;
ringColor = '#00ff00'
}
let src = tile.document.texture.sr;
let src = tile.document.texture.src;
streamDeck.setTitle('',context);
if (settings.iconOverride != '' && settings.iconOverride != undefined) src = settings.iconOverride;
@@ -946,6 +948,7 @@ export class ExternalModules{
if (tileData == undefined) return;
if (mode == 'toggle') tile.document.setFlag('monks-active-tiles','active',!tileData.active);
else tile.document.setFlag('monks-active-tiles','active',mode == 'enable');
}
}

View File

@@ -1,4 +1,4 @@
import { sdVersion, msVersion, moduleName, getPermission, enableModule, streamDeck, macroControl,soundboard,playlistControl, minimumMSversion, minimumSDversion } from "../MaterialDeck.js";
import { moduleName, getPermission, enableModule, macroControl, soundboard, playlistControl, releaseURLs, versions } from "../MaterialDeck.js";
export function compareVersions(checkedVersion, requiredVersion) {
requiredVersion = requiredVersion.split(".");
@@ -1041,21 +1041,7 @@ export class importConfigForm extends FormApplication {
export class downloadUtility extends FormApplication {
constructor(data, options) {
super(data, options);
this.localSDversion = sdVersion;
this.masterSDversion;
this.localMSversion = msVersion;
this.masterMSversion;
this.masterModuleVersion;
this.releaseAssets = [];
this.profiles = [];
let parent = this;
setTimeout(function(){
parent.checkForUpdate('SD');
parent.checkForUpdate('MS');
parent.checkForUpdate('Module');
parent.getReleaseData();
},100)
this.releases = {}
}
/**
@@ -1074,33 +1060,20 @@ export class downloadUtility extends FormApplication {
/**
* Provide data to the template
*/
getData() {
async getData() {
let dlDisabled = true;
this.profiles = [];
let iteration = 0;
for (let asset of this.releaseAssets) {
let split = asset.name.split('.');
if (split[split.length-1] == 'streamDeckProfile') {
this.profiles.push({id: iteration, label:split[0], url:asset.browser_download_url});
iteration++;
dlDisabled = false;
}
this.releases = {
module: await this.checkForUpdate('module'),
plugin: await this.checkForUpdate('plugin'),
materialCompanion: await this.checkForUpdate('materialCompanion')
}
if (this.localMSversion == undefined) this.localMSversion = 'unknown';
return {
minimumSdVersion: minimumSDversion,
localSdVersion: this.localSDversion,
masterSdVersion: this.masterSDversion,
sdDlDisable: this.masterSDversion == undefined,
minimumMsVersion: minimumMSversion,
localMsVersion: this.localMSversion,
masterMsVersion: this.masterMSversion,
msDlDisable: this.masterMSversion == undefined,
localModuleVersion: game.modules.get('MaterialDeck').version,
masterModuleVersion: this.masterModuleVersion,
profiles: this.profiles,
releases: this.releases,
versions,
sdDlDisable: this.releases.plugin == undefined,
msDlDisable: this.releases.materialCompanion == undefined,
profileDlDisable: dlDisabled
}
}
@@ -1118,38 +1091,22 @@ export class downloadUtility extends FormApplication {
super.activateListeners(html);
const downloadSd = html.find("button[id='materialDeck_dlUtil_downloadSd']");
const downloadMs = html.find("button[id='materialDeck_dlUtil_downloadMs']");
const downloadMc = html.find("button[id='materialDeck_dlUtil_downloadMc']");
const downloadProfile = html.find("button[name='downloadProfile']")
const refresh = html.find("button[id='materialDeck_dlUtil_refresh']");
//releaseURLs
downloadSd.on('click', () => {
const version = document.getElementById('materialDeck_dlUtil_masterSdVersion').innerHTML;
if (version == '' || version == undefined || version == 'Error') return;
const url = `https://github.com/CDeenen/MaterialDeck_SD/releases/download/v${version}/com.cdeenen.materialdeck.streamDeckPlugin`;
this.downloadURI(url,'com.cdeenen.materialdeck.streamDeckPlugin')
this.downloadURI(this.releases.plugin.url)
})
downloadMs.on('click', () => {
const version = document.getElementById('materialDeck_dlUtil_masterMsVersion').innerHTML;
downloadMc.on('click', () => {
const os = document.getElementById('materialDeck_dlUtil_os').value;
if (version == '' || version == undefined || version == 'Error') return;
let name = `MaterialServer-${os}.zip`;
let url;
if (os == 'source') url = `https://github.com/CDeenen/MaterialServer/archive/refs/tags/v${version}.zip`;
else url = `https://github.com/CDeenen/MaterialServer/releases/download/v${version}/${name}`;
this.downloadURI(url,name)
this.downloadURI(this.releases.materialCompanion.variants.find(v => v.name.includes(os)).url)
})
downloadProfile.on('click',(event) => {
let id = event.currentTarget.id.replace('materialDeck_dlUtil_dlProfile-','');
this.downloadURI(this.profiles[id].url,`${this.profiles[id].label}.streamDeckProfile`);
})
refresh.on('click', () => {
document.getElementById('materialDeck_dlUtil_masterSdVersion').value = 'Getting data';
this.checkForUpdate('SD');
document.getElementById('materialDeck_dlUtil_masterMsVersion').value = 'Getting data';
this.checkForUpdate('MS');
document.getElementById('materialDeck_dlUtil_masterModuleVersion').value = 'Getting data';
this.checkForUpdate('Module');
this.getReleaseData();
let name = event.currentTarget.id.replace('materialDeck_dlUtil_dlProfile-','');
this.downloadURI(this.releases.plugin.profiles.find(p => p.name.includes(name)).url);
})
}
@@ -1181,8 +1138,53 @@ export class downloadUtility extends FormApplication {
}
checkForUpdate(reqType) {
let parent = this;
let url;
return new Promise((resolve) => {
const url = releaseURLs?.[reqType].api;
if (url == undefined) return;
$.getJSON(url).done(function(releases) {
const release = releases[0];
if (reqType == 'plugin') {
const url = release.assets.find(a => a.name.includes('streamDeckPlugin'))?.browser_download_url;
let profiles = [];
for (let profile of release.assets.filter(a => a.name.includes('streamDeckProfile'))) {
profiles.push({
name: profile.name.replace('.streamDeckProfile', ''),
url: profile.browser_download_url
})
}
resolve({
release: releases[0],
version: release.tag_name,
url,
profiles
});
}
else if (reqType == 'materialCompanion') {
let variants = [];
for (let variant of release.assets) {
variants.push({
name: variant.name,
url: variant.browser_download_url
})
}
resolve({
release: releases[0],
version: release.tag_name,
url,
variants
});
}
else if (reqType == 'module') {
resolve({
release: releases[0],
version: release.tag_name
});
}
});
});
/*
let elementId;
if (reqType == 'SD') {
elementId = 'materialDeck_dlUtil_masterSdVersion';
@@ -1194,7 +1196,7 @@ export class downloadUtility extends FormApplication {
}
else if (reqType == 'Module') {
elementId = 'materialDeck_dlUtil_masterModuleVersion';
url = 'https://raw.githubusercontent.com/CDeenen/MaterialDeck/Master/module.json';
url = game.modules.get('MaterialDeck').manifest;
}
var request = new XMLHttpRequest();
@@ -1215,92 +1217,6 @@ export class downloadUtility extends FormApplication {
request.onerror = function () {
document.getElementById(elementId).innerHTML = 'Error';
}
*/
}
}
export class deviceConfig extends FormApplication {
constructor(data, options) {
super(data, options);
this.devices = [];
}
/**
* Default Options for this FormApplication
*/
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
id: "materialDeck_deviceConfig",
title: "Material Deck: " + game.i18n.localize("MaterialDeck.DeviceConfig.Title"),
template: "./modules/MaterialDeck/templates/deviceConfig.html",
width: 500,
height: "auto"
});
}
/**
* Provide data to the template
*/
getData() {
this.devices = [];
let dConfig = game.settings.get(moduleName, 'devices');
if (Object.prototype.toString.call(game.settings.get('MaterialDeck', 'devices')) === "[object String]") {
dConfig = {};
game.settings.set(moduleName, 'devices', dConfig);
}
for (let d of streamDeck.buttonContext) {
if (d == undefined) continue;
let type;
if (d.type == 0) type = 'Stream Deck';
else if (d.type == 1) type = 'Stream Deck Mini';
else if (d.type == 2) type = 'Stream Deck XL';
else if (d.type == 3) type = 'Stream Deck Mobile';
else if (d.type == 4) type = 'Corsair G Keys';
const name = d.name;
const id = d.device;
let enable;
if (dConfig?.[id] == undefined) enable = true;
else enable = dConfig?.[id].enable;
const device = {
id,
name,
type,
en: enable
}
this.devices.push(device);
}
return {
devices: this.devices
}
}
/**
* Update on form submit
* @param {*} event
* @param {*} formData
*/
async _updateObject(event, formData) {
}
activateListeners(html) {
super.activateListeners(html);
html.find("input[name='enable']").on('change', (event) => {
const id = event.currentTarget.id.replace('materialDeck_devConf_','');;
for (let d of this.devices) {
if (d.id == id) {
let dConfig = game.settings.get(moduleName, 'devices');
delete dConfig[id];
dConfig[id] = {enable: event.currentTarget.checked}
game.settings.set(moduleName, 'devices', dConfig);
}
}
})
}
}

View File

@@ -1,5 +1,5 @@
import { moduleName, isEmpty } from "../MaterialDeck.js";
import { playlistConfigForm, macroConfigForm, soundboardConfigForm, downloadUtility, deviceConfig } from "./misc.js";
import { playlistConfigForm, macroConfigForm, soundboardConfigForm, downloadUtility } from "./misc.js";
let userPermissions = {};
const defaultEnable = [true,true,true,true];
@@ -173,21 +173,6 @@ export const registerSettings = async function() {
restricted: false
});
game.settings.registerMenu(moduleName, 'deviceConfig',{
name: "MaterialDeck.DeviceConfig.Title",
label: "MaterialDeck.DeviceConfig.Title",
type: deviceConfig,
restricted: false
});
game.settings.register(moduleName, 'devices', {
name: "devices",
scope: "client",
type: Object,
config: false,
default: {}
});
game.settings.registerMenu(moduleName, 'permissionConfig',{
name: "MaterialDeck.Sett.Permission",
label: "MaterialDeck.Sett.Permission",

View File

@@ -205,16 +205,20 @@ export class StreamDeck{
setTitle(txt,context){
if (txt == null || txt == undefined) txt = '';
txt = this.formatTitle(txt);
let thisDevice;
for (let device of this.buttonContext) {
if (device == undefined) continue;
const btn = device.buttons.find(b => b?.context == context);
if (btn == undefined) continue;
btn.txt = txt;
thisDevice = device;
}
let msg = {
target: "SD",
target: "MaterialDeck_Device",
source: "MaterialDeck_Foundry",
userId: game.userId,
device: thisDevice,
event: 'setTitle',
context: context,
payload: {
@@ -226,8 +230,16 @@ export class StreamDeck{
}
setColor(context,color = '#000000'){
let thisDevice;
for (let device of this.buttonContext) {
if (device == undefined) continue;
thisDevice = device.buttons.find(b => b?.context == context);
}
let msg = {
target: "SD",
target: "MaterialDeck_Device",
source: "MaterialDeck_Foundry",
userId: game.userId,
device: thisDevice,
event: 'setIcon',
context: context,
url: '',
@@ -239,7 +251,9 @@ export class StreamDeck{
setImage(image,context,device,nr,id){
var json = {
target: "SD",
target: "MaterialDeck_Device",
source: "MaterialDeck_Foundry",
userId: game.userId,
event: "setImage",
context: context,
device: device,
@@ -255,7 +269,9 @@ export class StreamDeck{
setBufferImage(context,device,nr,id){
var json = {
target: "SD",
target: "MaterialDeck_Device",
source: "MaterialDeck_Foundry",
userId: game.userId,
event: "setBufferImage",
context: context,
device: device,
@@ -322,7 +338,9 @@ export class StreamDeck{
let split2 = split[0].split('-');
if (split2[0] == 'fa') format = 'icon';
let msg = {
target: "SD",
target: "MaterialDeck_Device",
source: "MaterialDeck_Foundry",
userId: game.userId,
event: 'setIcon',
context: context,
device: device,
@@ -339,9 +357,17 @@ export class StreamDeck{
}
setState(state,context,action){
let thisDevice;
for (let device of this.buttonContext) {
if (device == undefined) continue;
thisDevice = device.buttons.find(b => b?.context == context);
}
let msg = {
target: "SD",
target: "MaterialDeck_Device",
source: "MaterialDeck_Foundry",
userId: game.userId,
event: 'setStateCustom',
device: thisDevice,
context: context,
action: action,
state: state
@@ -354,8 +380,9 @@ export class StreamDeck{
if (action == 'playlistcontrol')
profile = 'MaterialDeck-Playlist'
var json = {
target: "SD",
source: 1,
target: "MaterialDeck_Device",
source: "MaterialDeck_Foundry",
userId: game.userId,
event: "switchToProfile",
context: this.pluginId,
device: device,

View File

@@ -239,7 +239,7 @@ export class pf2e{
getConditionIcon(condition) {
if (condition == undefined) condition = 'removeAll';
if (condition == 'removeAll') return window.CONFIG.controlIcons.effects;
else return `${CONFIG.PF2E.statusEffects.effectsIconFolder}${condition}.webp`;
else return `${CONFIG.PF2E.statusEffects.iconDir}${condition}.webp`;
}
getConditionActive(token,condition) {
@@ -281,6 +281,7 @@ export class pf2e{
}
async toggleCondition(token,condition) {
console.log(token,condition)
if (condition == undefined) condition = 'removeAll';
if (condition == 'removeAll'){
for( let effect of token.actor.items.filter(i => i.type == 'condition'))
@@ -288,6 +289,7 @@ export class pf2e{
}
else {
const effect = this.getCondition(token,condition);
console.log('eff',effect)
if (effect == undefined) {
const newEffect = game.pf2e.ConditionManager.conditions.get(condition).toObject();
await token.actor?.createEmbeddedDocuments("Item", [newEffect]);

View File

@@ -1,18 +0,0 @@
<form autocomplete="off" onsubmit="event.preventDefault()">
<table style="width:100%; min-width:400px">
<tr>
<th class='materialDeck_devConf_columnLabel'>{{localize "MaterialDeck.Name"}}</th>
<th class='materialDeck_devConf_columnLabel'>{{localize "MaterialDeck.Type"}}</th>
<th class='materialDeck_devConf_columnId'>{{localize "MaterialDeck.Id"}}</th>
<th class='materialDeck_devConf_columnCB'>{{localize "MaterialDeck.Perm.ENABLE.ENABLE.label"}}</th>
</tr>
{{#each devices as |d|}}
<tr>
<td class='materialDeck_devConf_columnLabel'>{{d.name}}</td>
<td class='materialDeck_devConf_columnLabel'>{{d.type}}</td>
<td class='materialDeck_devConf_columnId'><input type="text" value={{d.id}} disabled></td>
<td class='materialDeck_devConf_columnCB'><input type="checkbox" name="enable" id="materialDeck_devConf_{{d.id}}" {{checked d.en}}></td>
</tr>
{{/each}}
</table>
</form>

View File

@@ -13,9 +13,9 @@
<tr>
<td class='materialDeck_dlUtil_columnLabel'>{{localize "MaterialDeck.DownloadUtility.module"}}</td>
<td class='materialDeck_dlUtil_columnVersion'>{{localModuleVersion}}</td>
<td class='materialDeck_dlUtil_columnVersion'>v{{versions.module.current}}</td>
<td class='materialDeck_dlUtil_columnVersion'></td>
<td class='materialDeck_dlUtil_columnVersion' id='materialDeck_dlUtil_masterModuleVersion'>{{masterModuleVersion}}</td>
<td class='materialDeck_dlUtil_columnVersion'>{{releases.module.version}}</td>
<td class='materialDeck_dlUtil_columnOS'></td>
<td class='materialDeck_dlUtil_columnButton'><button type="button" class='materialDeck_dlUtil_button' style="visibility:hidden">
<i class="fas fa-download"></i>
@@ -25,9 +25,9 @@
<tr>
<td class='materialDeck_dlUtil_columnLabel'>{{localize "MaterialDeck.DownloadUtility.SDplugin"}}</td>
<td class='materialDeck_dlUtil_columnVersion'>{{localSdVersion}}</td>
<td class='materialDeck_dlUtil_columnVersion'>{{minimumSdVersion}}</td>
<td class='materialDeck_dlUtil_columnVersion' id='materialDeck_dlUtil_masterSdVersion'>{{masterSdVersion}}</td>
<td class='materialDeck_dlUtil_columnVersion'>v{{versions.plugin.current}}</td>
<td class='materialDeck_dlUtil_columnVersion'>v{{versions.plugin.minimum}}</td>
<td class='materialDeck_dlUtil_columnVersion'>{{releases.plugin.version}}</td>
<td class='materialDeck_dlUtil_columnOS'></td>
<td class='materialDeck_dlUtil_columnButton'>
<button type="button" class='materialDeck_dlUtil_button' id='materialDeck_dlUtil_downloadSd' {{#if sdDlDisable}}disabled{{/if}}>
@@ -38,20 +38,22 @@
<tr>
<td class='materialDeck_dlUtil_columnLabel'>{{localize "MaterialDeck.DownloadUtility.MSserver"}}</td>
<td class='materialDeck_dlUtil_columnVersion'>{{localMsVersion}}</td>
<td class='materialDeck_dlUtil_columnVersion'>{{minimumMsVersion}}</td>
<td class='materialDeck_dlUtil_columnVersion' id='materialDeck_dlUtil_masterMsVersion'>{{masterMsVersion}}</td>
<td class='materialDeck_dlUtil_columnVersion'>v{{versions.materialCompanion.current}}</td>
<td class='materialDeck_dlUtil_columnVersion'>v{{versions.materialCompanion.minimum}}</td>
<td class='materialDeck_dlUtil_columnVersion'>{{releases.materialCompanion.version}}</td>
<td class='materialDeck_dlUtil_columnOS'>
<select id="materialDeck_dlUtil_os" default="" {{#if msDlDisable}}disabled{{/if}}>
<option value="win32-x64">{{localize "MaterialDeck.DownloadUtility.Windows"}}</option>
<option value="macos-x64">{{localize "MaterialDeck.DownloadUtility.MacosIntel"}}</option>
<option value="macos-arm64">{{localize "MaterialDeck.DownloadUtility.MacosM1"}}</option>
<option value="macos-x64.dmg">{{localize "MaterialDeck.DownloadUtility.MacosIntel"}} - dmg</option>
<option value="macos-x64.zip">{{localize "MaterialDeck.DownloadUtility.MacosIntel"}} - zip</option>
<option value="macos-arm64.dmg">{{localize "MaterialDeck.DownloadUtility.MacosM1"}} - dmg</option>
<option value="macos-arm64.zip">{{localize "MaterialDeck.DownloadUtility.MacosM1"}} - zip</option>
<option value="linux-x64">{{localize "MaterialDeck.DownloadUtility.Linux"}}</option>
<option value="source">{{localize "MaterialDeck.DownloadUtility.Source"}}</option>
</select>
</td>
<td class='materialDeck_dlUtil_columnButton'>
<button type="button" class='materialDeck_dlUtil_button' id='materialDeck_dlUtil_downloadMs' {{#if msDlDisable}}disabled{{/if}}>
<button type="button" class='materialDeck_dlUtil_button' id='materialDeck_dlUtil_downloadMc' {{#if msDlDisable}}disabled{{/if}}>
<i class="fas fa-download"></i>
</button>
</td>
@@ -66,11 +68,11 @@
<th class='materialDeck_dlUtil_columnButton'>{{localize "MaterialDeck.DownloadUtility.Download"}}</th>
</tr>
<div id='profileContents'>
{{#each profiles as |p|}}
{{#each releases.plugin.profiles as |p|}}
<tr>
<td>{{p.label}}</td>
<td>{{p.name}}</td>
<td class='materialDeck_dlUtil_columnButton'>
<button type="button" class='materialDeck_dlUtil_button' id='materialDeck_dlUtil_dlProfile-{{p.id}}' name='downloadProfile' {{#if ../profileDlDisable}}disabled{{/if}}>
<button type="button" class='materialDeck_dlUtil_button' id='materialDeck_dlUtil_dlProfile-{{p.name}}' name='downloadProfile'>
<i class="fas fa-download"></i>
</button>
</td>
@@ -78,10 +80,4 @@
{{/each}}
</div>
</table>
<button type="button" id='materialDeck_dlUtil_refresh'>
<i class="fas fa-redo"></i>
{{localize "MaterialDeck.DownloadUtility.Refresh"}}
</button>
</form>

View File

@@ -12,7 +12,7 @@
}
</script>
<div style="width:1200px">
<div style="width:1200px; height:700px">
<h1 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/down.png" class="materialDeck_helpMenu_expandableIcon" style="width:20px">Introduction</h1>
<div class="">
@@ -24,15 +24,15 @@
between the combat tracker, soundboard, or any other (custom) configuration.<br>
<br>
Material Deck is a very large module with tons of features and ways of customizing your experience. This menu will only cover the basics to get you started,
the full documentation can be found on <a href="https://github.com/CDeenen/MaterialDeck/wiki">Github</a>. Please also check the <a href="https://github.com/CDeenen/MaterialDeck/wiki/FAQ">FAQ</a> which answers some common questions, including some basic troubleshooting.<br>
the full documentation can be found on <a href="https://github.com/MaterialFoundry/MaterialDeck/wiki">Github</a>. Please also check the <a href="https://github.com/MaterialFoundry/MaterialDeck/wiki/FAQ">FAQ</a> which answers some common questions, including some basic troubleshooting.<br>
</div>
<h1 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:20px">Latest Releases</h1>
<div class="materialDeck_helpMenu_collapsed">
<a href="https://github.com/CDeenen/MaterialDeck/releases">Module</a><br>
<a href="https://github.com/CDeenen/MaterialDeck_SD/releases">Stream Deck</a><br>
<a href="https://github.com/CDeenen/MaterialServer/releases">Server</a><br>
You can use the download utility in the module settings to download the Stream Deck plugin, Stream Deck profiles and Material Server.
<a href="https://github.com/MaterialFoundry/MaterialDeck/releases">Module</a><br>
<a href="https://github.com/MaterialFoundry/MaterialDeck_SD/releases">Stream Deck</a><br>
<a href="https://github.com/MaterialFoundry/MaterialCompanion/releases">Material Companion</a><br>
You can use the download utility in the module settings to download the Stream Deck plugin, Stream Deck profiles and Material Companion.
</div>
<h1 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:20px">Getting Started</h1>
@@ -57,7 +57,7 @@
<h3>Manually</h3>
<ol>
<li>Download the latest plugin file using the download utility in the module settings, or download it (com.cdeenen.materialdeck.streamDeckPlugin) from <a href="https://github.com/CDeenen/MaterialDeck_SD/releases">here</a></li>
<li>Download the latest plugin file using the download utility in the module settings, or download it (com.cdeenen.materialdeck.streamDeckPlugin) from <a href="https://github.com/MaterialFoundry/MaterialDeck_SD/releases">here</a></li>
<li>Double-click the file, this should open the Stream Deck software</li>
<li>Press 'Install' in the pop-up</li>
</ol>
@@ -67,22 +67,22 @@
<div class="materialDeck_helpMenu_collapsed">
You can create your own profile, but it is recommended to start with one of the pre-made profiles. Currently, there is a profile for the normal and XL Stream Deck variants.
<ol>
<li>Download the latest plugin file using the download utility in the module settings, or download one (ending with .streamDeckProfile) from <a href="https://github.com/CDeenen/MaterialDeck_SD/releases">here</a></li>
<li>Download the latest plugin file using the download utility in the module settings, or download one (ending with .streamDeckProfile) from <a href="https://github.com/MaterialFoundry/MaterialDeck_SD/releases">here</a></li>
<li>Double-click the file, this should load the profile into the Stream Deck software</li>
</ol>
</div>
<h2 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:15px">Downloading and Starting Material Server</h2>
<h2 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:15px">Downloading and Starting Material Companion</h2>
<div class="materialDeck_helpMenu_collapsed">
Material Server acts as a bridge application, bridging the communication between the Stream Deck and Material Deck.
Material Companion acts as a bridge application, bridging the communication between the Stream Deck and Material Deck.
<ol>
<li>Download the latest version for your operating system <a href="https://github.com/CDeenen/MaterialServer/releases">here</a> or through the download utility</li>
<li>Download the latest version for your operating system <a href="https://github.com/MaterialFoundry/MaterialCompanion/releases">here</a> or through the download utility</li>
<li>Extract the archive</li>
<li>Run 'materialserver.exe' (Windows) or 'materialserver' (MacOS and Linux)</li>
<li>Run 'MaterialCompanion.exe' (Windows) or 'MaterialCompanion' (MacOS and Linux)</li>
</ol>
<b>You need to always have Material Server running when you want to use Material Deck</b><br>
<b>You need to always have Material Companion running when you want to use Material Deck</b><br>
<br>
<a href="https://github.com/CDeenen/MaterialServer/wiki">Material Server documentation</a>
<a href="https://github.com/MaterialFoundry/MaterialCompanion/wiki">Material Companion documentation</a>
</div>
</div>
@@ -103,15 +103,15 @@
Below the buttons you will find the following settings:
<ul>
<li><b>Enable Module</b> - Ticking this box enabled the module for the client</li>
<li><b>Material Server Address</b> - Fill in the address of Material Server (usually if you run it on the same computer as
<li><b>Material Companion Address</b> - Fill in the address of Material Companion (usually if you run it on the same computer as
you're using for Foundry, this can be localhost:3001). This is not necessarily the IP address of Foundry! It is the IP
address of the computer that's running Material Server. The default value will work for 99% of people, only change it if
you know what you're doing. More info on Material Server can be found <a href="https://github.com/CDeenen/MaterialServer/blob/master/README.md">here</a></li>
address of the computer that's running Material Companion. The default value will work for 99% of people, only change it if
you know what you're doing. More info on Material Companion can be found <a href="https://github.com/MaterialFoundry/MaterialCompanion/blob/master/README.md">here</a></li>
<li><b>Image Cache Size</b> - Sets the amount of images to store in the image cache. The image cache will locally store all images sent to the Stream Deck.
This improves the update speed, but increases memory usage.</li>
<li><b>Image Brightness</b> - Sets the brightness of the default white images for better readibility of the text. If Image Cache Size is large, it'll take a while for
the new brightness setting to be applied. A refresh will give instantaneous results.</li>
<li><b>Number of Connection Warnings</b> - Sets the number of times you will get a warning when Material Deck cannot connect to Material Server. Will be unlimited if set to 0.</li>
<li><b>Number of Connection Warnings</b> - Sets the number of times you will get a warning when Material Deck cannot connect to Material Companion. Will be unlimited if set to 0.</li>
</ul>
<BR CLEAR="right" />
@@ -131,12 +131,10 @@
<h2 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:15px">Download Utility</h2>
<div class="materialDeck_helpMenu_collapsed">
<img src="modules/MaterialDeck/wiki/img/DownloadUtility.png" align="right" HSPACE="5" width="350">
The download utility allows you to easily check the current version of the Stream Deck plugin and Material Server, and gives you the option to download the latest version.<br>
Please note that the current version of Material Server is at the moment not supported.<br>
The download utility allows you to easily check the current version of the Stream Deck plugin and Material Companion, and gives you the option to download the latest version.<br>
Please note that the current version of Material Companion is at the moment not supported.<br>
<br>
At the bottom you can also download the default profiles from <a href="https://github.com/CDeenen/MaterialDeck_SD/releases">Github</a><div class=""></div><br>
<br>
The refresh button at the bottom refreshes the page in case there was a connection issue.
At the bottom you can also download the default profiles from <a href="https://github.com/MaterialFoundry/MaterialDeck_SD/releases">Github</a>.<div class=""></div><br>
<BR CLEAR="right" />
</div>
@@ -144,7 +142,7 @@
<h2 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:15px">Playlist Configuration</h2>
<div class="materialDeck_helpMenu_collapsed">
<img src="modules/MaterialDeck/wiki/img/PlaylistConfig.png" align="right" HSPACE="5" width="350">
The playlist configuration screen configures the playlists that you control using the <a href="https://github.com/CDeenen/MaterialDeck/wiki/Playlist-Action">Playlist action</a>.<br>
The playlist configuration screen configures the playlists that you control using the <a href="https://github.com/MaterialFoundry/MaterialDeck/wiki/Playlist-Action">Playlist action</a>.<br>
There are 2 sections: 'Settings', and 'Playlists'.
<h3><b>Settings</b></h3>
@@ -174,7 +172,7 @@
<h2 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:15px">Macro Configuration</h2>
<div class="materialDeck_helpMenu_collapsed">
The Macro Configuration screen is to configure the macroboard for the <a href="https://github.com/CDeenen/MaterialDeck/wiki/Macro-Action">Macro action</a>.<br>
The Macro Configuration screen is to configure the macroboard for the <a href="https://github.com/MaterialFoundry/MaterialDeck/wiki/Macro-Action">Macro action</a>.<br>
<br>
The screen is divided into 32 boxes, each labeled 'Macro #', where each represents a single macro and its settings. This screen will be refered to as a page.
By pressing the arrows at the top right and top left, you can go to the next or previous page. There is no limit to the amount of pages you can add, but if you
@@ -206,7 +204,7 @@
<h2 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:15px">Soundboard Configuration</h2>
<div class="materialDeck_helpMenu_collapsed">
The Soundboard Configuration screen is used to configure the soundboard for the <a href="https://github.com/CDeenen/MaterialDeck/wiki/Soundboard-Action">Soundboard action</a>.<br>
The Soundboard Configuration screen is used to configure the soundboard for the <a href="https://github.com/MaterialFoundry/MaterialDeck/wiki/Soundboard-Action">Soundboard action</a>.<br>
<br>
Similar to the Macro Configuration screen, the screen is divided into boxes, each labeled 'Sound #', where each represents a single sound and its settings. This screen will be refered to as a page.
By pressing the arrows at the top right and top left, you can go to the next or previous page. There is no limit to the amount of pages you can add, but if you
@@ -223,7 +221,7 @@
For example, if you have the sounds 'Thunder.wav', 'Thunder2.wav' and 'Thunder3.wav' in the folder 'Assets', you could fill in the following: 'Assets/Thunder*', which
will play one of the three sounds randomly when you press the button on the Stream Deck.</li>
<li><b>Icon</b> - Here you can select an icon that will be displayed on the SD button if 'Display Icon' is selected in the property inspector.
Please read <a href="https://github.com/CDeenen/MaterialDeck/wiki/Getting-Started#important-notes-on-foundry-assigned-text-and-icons">these</a> notes on rules regarding icon selection.</li>
Please read <a href="https://github.com/MaterialFoundry/MaterialDeck/wiki/Getting-Started#important-notes-on-foundry-assigned-text-and-icons">these</a> notes on rules regarding icon selection.</li>
<li><b>On</b> - Clicking the colored box you'll be presented with a color picker. This sets the color of the ring that's shown on the button when the sound is playing.</li>
<li><b>Off</b> - Clicking the colored box you'll be presented with a color picker. This sets the color of the ring that's shown on the button when the sound is not playing.</li>
<li><b>Playback</b> - This sets the playback mode, you can select from:
@@ -254,31 +252,31 @@
<h1 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:20px">Customization</h1>
<div class="materialDeck_helpMenu_collapsed">
Material Deck is extremely flexible, but most of this flexibility must be performed in the Stream Deck software.<br>
Some basic instructions on using the software can be found <a href="https://github.com/CDeenen/MaterialDeck/wiki/Getting-Started#basic-stream-deck-setup-instructions">here</a>.<br>
Some basic instructions on using the software can be found <a href="https://github.com/MaterialFoundry/MaterialDeck/wiki/Getting-Started#basic-stream-deck-setup-instructions">here</a>.<br>
<br>
Some of the things you can change are:
<ul>
<li><b>Button location</b> - You can drag buttons around into any order you want</li>
<li><b>Changing button text and icon</b> - All the text and icons on the Stream Deck can be customized, see <a href="https://github.com/CDeenen/MaterialDeck/wiki/Getting-Started#changing-the-button-text-and-icon">here</a></li>
<li><b>Changing button text and icon</b> - All the text and icons on the Stream Deck can be customized, see <a href="https://github.com/MaterialFoundry/MaterialDeck/wiki/Getting-Started#changing-the-button-text-and-icon">here</a></li>
<li><b>Customize the behavior of buttons</b> - See below</li>
</ul>
All the buttons have many settings to fine-tune your experience. Due to the large amount of things you can change, they will not be discussed here, instead you can read about it at the following links:
<ul>
<li><a href="https://github.com/CDeenen/MaterialDeck/wiki/Combat-Tracker-Action">Combat Tracker Action</a></li>
<li><a href="https://github.com/CDeenen/MaterialDeck/wiki/External-Modules">External Modules</a></li>
<li><a href="https://github.com/CDeenen/MaterialDeck/wiki/Macro-Action">Macro Action</a></li>
<li><a href="https://github.com/CDeenen/MaterialDeck/wiki/Other-Actions">Other Actions</a></li>
<li><a href="https://github.com/CDeenen/MaterialDeck/wiki/Playlist-Action">Playlist Action</a></li>
<li><a href="https://github.com/CDeenen/MaterialDeck/wiki/Scene-Action">Scene Action</a></li>
<li><a href="https://github.com/CDeenen/MaterialDeck/wiki/Soundboard-Action">Soundboard Action</a></li>
<li><a href="https://github.com/CDeenen/MaterialDeck/wiki/Token-Action">Token Action</a></li>
<li><a href="https://github.com/MaterialFoundry/MaterialDeck/wiki/Combat-Tracker-Action">Combat Tracker Action</a></li>
<li><a href="https://github.com/MaterialFoundry/MaterialDeck/wiki/External-Modules">External Modules</a></li>
<li><a href="https://github.com/MaterialFoundry/MaterialDeck/wiki/Macro-Action">Macro Action</a></li>
<li><a href="https://github.com/MaterialFoundry/MaterialDeck/wiki/Other-Actions">Other Actions</a></li>
<li><a href="https://github.com/MaterialFoundry/MaterialDeck/wiki/Playlist-Action">Playlist Action</a></li>
<li><a href="https://github.com/MaterialFoundry/MaterialDeck/wiki/Scene-Action">Scene Action</a></li>
<li><a href="https://github.com/MaterialFoundry/MaterialDeck/wiki/Soundboard-Action">Soundboard Action</a></li>
<li><a href="https://github.com/MaterialFoundry/MaterialDeck/wiki/Token-Action">Token Action</a></li>
</ul>
</div>
<h1 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:20px">Feedback & Credits</h1>
<div class="materialDeck_helpMenu_collapsed">
If you have any suggestions or bugs to report, feel free to create an issue, contact me on Discord (Cris#6864), or send me an email: cdeenen@outlook.com.<br>
If you have any suggestions or bugs to report, feel free to create an issue, contact me on Discord (Cris#6864), or send me an email: info@materialfoundry.nl.<br>
<br>
<b>Author:</b> Cristian Deenen (Cris#6864 on Discord)<br>
<br>