Compare commits

..

1 Commits

Author SHA1 Message Date
d140c785e1 adds dice to queue
All checks were successful
CI / deploy (push) Successful in 5m59s
2025-04-07 21:20:00 +02:00
7 changed files with 79 additions and 57 deletions

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>de.arindy</groupId> <groupId>de.arindy</groupId>
<artifactId>dice-tower</artifactId> <artifactId>dice-tower</artifactId>
<version>1.2.8-SNAPSHOT</version> <version>1.2.7-SNAPSHOT</version>
<properties> <properties>
<compiler-plugin.version>3.13.0</compiler-plugin.version> <compiler-plugin.version>3.13.0</compiler-plugin.version>

View File

@ -21,16 +21,14 @@ class ChatOverlayResource {
@QueryParam("modsAllowed") modsAllowed: Boolean = false, @QueryParam("modsAllowed") modsAllowed: Boolean = false,
@QueryParam("vipAllowed") vipAllowed: Boolean = false, @QueryParam("vipAllowed") vipAllowed: Boolean = false,
@QueryParam("subsAllowed") subsAllowed: Boolean = false, @QueryParam("subsAllowed") subsAllowed: Boolean = false,
@QueryParam("allAllowed") allAllowed: Boolean = false,
@QueryParam("cmd") cmd: String? = "roll", @QueryParam("cmd") cmd: String? = "roll",
@QueryParam("theme") theme: String? = "default", @QueryParam("theme") theme: String? = "default",
@QueryParam("faceColor") faceColor: String? = "#ff0202", @QueryParam("faceColor") faceColor: String? = "#ff0202",
@QueryParam("numberColor") numberColor: String? = "#ffffff", @QueryParam("numberColor") numberColor: String? = "#ffffff",
@QueryParam("clearAfter") clearAfter: Long? = -1, @QueryParam("clearAfter") clearAfter: Long? = -1,
@QueryParam("timeout") timeout: Long? = -1, @QueryParam("timeout") timeout: Long? = -1
@QueryParam("showResults") showResults: Boolean = true
): TemplateInstance { ): TemplateInstance {
return Templates.chatoverlay(channel, scale ?: 7, maxDice ?: 20, modsAllowed, vipAllowed, subsAllowed, allAllowed, cmd ?: "roll", theme ?: "default", faceColor ?: "#ff0202", numberColor ?: "#ffffff", clearAfter ?: 10, timeout ?: 60, showResults) return Templates.chatoverlay(channel, scale ?: 7, maxDice ?: 20, modsAllowed, vipAllowed, subsAllowed, cmd ?: "roll", theme ?: "default", faceColor ?: "#ff0202", numberColor ?: "#ffffff", clearAfter ?: 10, timeout ?: 60)
} }
@GET @GET

View File

@ -25,13 +25,11 @@ object Templates {
modsAllowed: Boolean, modsAllowed: Boolean,
vipAllowed: Boolean, vipAllowed: Boolean,
subsAllowed: Boolean, subsAllowed: Boolean,
allAllowed: Boolean,
cmd: String?, cmd: String?,
theme: String?, theme: String?,
faceColor: String?, faceColor: String?,
numberColor: String?, numberColor: String?,
clearAfter: Long?, clearAfter: Long?,
timeout: Long?, timeout: Long?
showResults: Boolean?
): TemplateInstance ): TemplateInstance
} }

View File

@ -123,15 +123,15 @@ class ColorPicker extends HTMLElement {
<div class="bg-cover" id="controls"> <div class="bg-cover" id="controls">
<label for="hue"> <label for="hue">
<abbr title="Hue: The color tint.">H</abbr> <abbr title="Hue: The color tint.">H</abbr>
<input type="range" id="hue" min="0" max="360" value="0" step="0.01"> <input type="range" id="hue" min="0" max="360" value="0">
</label> </label>
<label for="saturation"> <label for="saturation">
<abbr title="Saturation: The amount of gray in the color.">S</abbr> <abbr title="Saturation: The amount of gray in the color.">S</abbr>
<input type="range" id="saturation" min="0" max="100" value="0" step="0.01"> <input type="range" id="saturation" min="0" max="100" value="0">
</label> </label>
<label for="lightness"> <label for="lightness">
<abbr title="Lightness: How light or dark the color is.">L</abbr> <abbr title="Lightness: How light or dark the color is.">L</abbr>
<input type="range" id="lightness" min="0" max="100" value="0" step="0.01"> <input type="range" id="lightness" min="0" max="100" value="0">
</label> </label>
</div> </div>
</div>`; </div>`;
@ -251,9 +251,9 @@ class ColorPicker extends HTMLElement {
*/ */
updateColor() { updateColor() {
const hue = parseFloat( this.hueInput.value ); const hue = Math.round( this.hueInput.value );
const saturation = parseFloat( this.saturationInput.value ); const saturation = Math.round( this.saturationInput.value );
const lightness = parseFloat( this.lightnessInput.value ); const lightness = Math.round( this.lightnessInput.value );
const hsla = [ hue, saturation, lightness ]; const hsla = [ hue, saturation, lightness ];
const rgba = this.HSLAToRGBA( hsla ); const rgba = this.HSLAToRGBA( hsla );
@ -324,10 +324,6 @@ class ColorPicker extends HTMLElement {
*/ */
setColor( color = 'hsla(60, 100%, 50%, 0.5)' ) { setColor( color = 'hsla(60, 100%, 50%, 0.5)' ) {
if ( /^[0-9A-F]{3,6}$/i.test( color ) ) {
color = '#' + color;
}
const rgba = this.colorToRGBA( color ); const rgba = this.colorToRGBA( color );
const hsla = this.rgbToHSLA( rgba ); const hsla = this.rgbToHSLA( rgba );
@ -488,15 +484,13 @@ class ColorPicker extends HTMLElement {
} }
// Calculate hue // Calculate hue
let hue = 0; let hue;
if ( max !== min ) { if ( max === normalizedR ) {
if ( max === normalizedR ) { hue = ( ( normalizedG - normalizedB ) / ( max - min ) ) % 6;
hue = ( ( normalizedG - normalizedB ) / ( max - min ) ) % 6; } else if ( max === normalizedG ) {
} else if ( max === normalizedG ) { hue = ( ( normalizedB - normalizedR ) / ( max - min ) + 2 );
hue = ( ( normalizedB - normalizedR ) / ( max - min ) + 2 ); } else {
} else { hue = ( ( normalizedR - normalizedG ) / ( max - min ) + 4 );
hue = ( ( normalizedR - normalizedG ) / ( max - min ) + 4 );
}
} }
// Convert hue to degrees // Convert hue to degrees
@ -506,7 +500,7 @@ class ColorPicker extends HTMLElement {
hue += 360; hue += 360;
} }
return [ parseFloat(hue.toFixed(2)), parseFloat((saturation * 100).toFixed(2)), parseFloat((lightness * 100).toFixed(2)), a ]; return [ Math.round( hue ), Math.round( saturation * 100 ), Math.round( lightness * 100 ), a ];
} }

View File

@ -31,7 +31,9 @@
//maxDice //maxDice
ComfyJS.onCommand = async (user, command, message, flags) => { ComfyJS.onCommand = async (user, command, message, flags) => {
if ((flags.broadcaster || {allAllowed} || ({modsAllowed} && flags.mod) || ({vipAllowed} && flags.vip) || ({subsAllowed} && flags.subscriber)) && '{cmd}' === command && !shouldWait() && message.match(/^\d+d(4|6|8|10|12|20|100)$/) && (+message.split('d')[0] <= {maxDice}) if ((
flags.broadcaster || ({modsAllowed} && flags.mod) || ({vipAllowed} && flags.vip) || ({subsAllowed} && flags.subscriber
)) && '{cmd}' === command && !shouldWait() && message.match(/^\d+d(4|6|8|10|12|20|100)$/) && (+message.split('d')[0] <= {maxDice})
) { ) {
toggleWait(true); toggleWait(true);
@ -43,9 +45,7 @@
}) })
document.getElementById('results').innerHTML = '<strong>' + user + '</strong> rolls <strong>' + message + '</strong>:<br/> [' + values.map(value => value === 1 ? '<strong style="text-shadow: 2px 2px 10px red">' + value + '</strong>' : value === result.sides ? '<strong style="text-shadow: 2px 2px 10px green">' + value + '</strong>' : value).join(' + ') + '] = <strong>' + result.total + '</strong> ' document.getElementById('results').innerHTML = '<strong>' + user + '</strong> rolls <strong>' + message + '</strong>:<br/> [' + values.map(value => value === 1 ? '<strong style="text-shadow: 2px 2px 10px red">' + value + '</strong>' : value === result.sides ? '<strong style="text-shadow: 2px 2px 10px green">' + value + '</strong>' : value).join(' + ') + '] = <strong>' + result.total + '</strong> '
}) })
if({showResults}) { document.getElementById('results').showPopover()
document.getElementById('results').showPopover()
}
setTimeout(() => { setTimeout(() => {
diceBox.clearDice(); diceBox.clearDice();
document.getElementById('results').hidePopover() document.getElementById('results').hidePopover()

View File

@ -52,10 +52,6 @@
<input type="checkbox" id="subsAllowed"> <input type="checkbox" id="subsAllowed">
<span class="checkmark"></span> <span class="checkmark"></span>
</label> </label>
<label class="checkbox" id="allAllowed-container">Allow everyone to roll (yes, everyone!!)
<input type="checkbox" id="allAllowed">
<span class="checkmark"></span>
</label>
</div> </div>
<div> <div>
<label for="scale">Dice-Scale </label> <label for="scale">Dice-Scale </label>
@ -68,10 +64,6 @@
<input type="number" id="clearAfter" style="width: 50px; margin-top: 20px" value="10"/> <input type="number" id="clearAfter" style="width: 50px; margin-top: 20px" value="10"/>
<label for="timeout">Command-timeout (in seconds)</label> <label for="timeout">Command-timeout (in seconds)</label>
<input type="number" id="timeout" style="width: 50px; margin-top: 20px" value="60"/> <input type="number" id="timeout" style="width: 50px; margin-top: 20px" value="60"/>
<label class="checkbox" id="showResults-container">Show Results Overlay
<input type="checkbox" id="showResults" checked>
<span class="checkmark"></span>
</label>
</div> </div>
<div id="dice-box" style="width: 850px; height: 400px"> <div id="dice-box" style="width: 850px; height: 400px">
@ -252,9 +244,7 @@
"&timeout=" + document.getElementById('timeout').value + "&timeout=" + document.getElementById('timeout').value +
"&modsAllowed=" + document.getElementById('modsAllowed').checked + "&modsAllowed=" + document.getElementById('modsAllowed').checked +
"&vipAllowed=" + document.getElementById('vipAllowed').checked + "&vipAllowed=" + document.getElementById('vipAllowed').checked +
"&subsAllowed=" + document.getElementById('subsAllowed').checked + "&subsAllowed=" + document.getElementById('subsAllowed').checked
"&allAllowed=" + document.getElementById('allAllowed').checked +
"&showResults=" + document.getElementById('showResults').checked
} }
}) })
</script> </script>

View File

@ -9,13 +9,14 @@
<body> <body>
<div id="dice-box"></div> <div id="dice-box"></div>
<script type="module"> <script type="module">
import DiceBox from "/vendor/dice-box/dice-box-threejs.es.js";
function url() { function url() {
return window.location.protocol + '//' + window.location.hostname + (window.location.port?.length > 0 ? ':' + window.location.port : ''); return window.location.protocol + '//' + window.location.hostname + (window.location.port?.length > 0 ? ':' + window.location.port : '');
} }
import DiceBox from "/vendor/dice-box/dice-box-threejs.es.js";
const evtSource = new EventSource(url() + "/dice/{diceid??}/stream"); const evtSource = new EventSource(url() + "/dice/{diceid??}/stream");
const diceBox = new DiceBox("#dice-box", { const diceBox = new DiceBox("#dice-box", {
assetPath: "/vendor/dice-box/", assetPath: "/vendor/dice-box/",
light_intensity: 2, light_intensity: 2,
@ -23,26 +24,67 @@
baseScale: {scale} * 10, baseScale: {scale} * 10,
strength: Math.floor(Math.random() * 4), strength: Math.floor(Math.random() * 4),
}); });
diceBox.initialize(); diceBox.initialize();
let timeout = 0;
evtSource.addEventListener("message", function (event) { let rollQueue = [];
clearInterval(timeout); let rolling = false;
let data = JSON.parse(event.data); let clearTimeoutId = null;
diceBox.onRollComplete = () => { let lastRollTime = Date.now();
if ({clearAfter} > 0) {
timeout = setTimeout(() => diceBox.clearDice(), {clearAfter} * 1000) function scheduleClear() {
if (clearTimeoutId) clearTimeout(clearTimeoutId);
clearTimeoutId = setTimeout(() => {
const now = Date.now();
if (now - lastRollTime >= ({clearAfter} * 1000)) {
diceBox.clearDice();
rolling = false;
processQueue();
} else {
scheduleClear(); // try again later
} }
}, {clearAfter} * 1000);
}
async function processQueue() {
if (rolling || rollQueue.length === 0) return;
rolling = true;
const data = rollQueue.shift();
const rollString = data.roll
.filter(it => it.split('@')[0].split('d')[1] !== "2")
.join('&');
if (!rollString) {
rolling = false;
return;
} }
diceBox.updateConfig({
lastRollTime = Date.now();
await diceBox.updateConfig({
theme_customColorset: { theme_customColorset: {
texture: data.theme, texture: data.theme,
background: data.faceColor, background: data.faceColor,
foreground: data.numberColor foreground: data.numberColor
} }
}).then(() => { });
diceBox.roll(data.roll.filter(it => it.split('@')[0].split('d')[1] !== "2").join('&'));
}) await diceBox.add(rollString);
}) scheduleClear();
rolling = false;
void processQueue();
}
evtSource.addEventListener("message", function (event) {
const data = JSON.parse(event.data);
rollQueue.push(data);
processQueue();
});
</script> </script>
</body> </body>
</html> </html>