Skip to content

Commit

Permalink
Factor out TeamLayout
Browse files Browse the repository at this point in the history
  • Loading branch information
bcopy committed Oct 12, 2024
1 parent d5112cd commit 7ea0354
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 159 deletions.
62 changes: 62 additions & 0 deletions src/homie-lit-components/TeamLayout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { html, render } from 'lit-html';

class TeamLayout {
constructor(parentElement){
this.parentElement = parentElement;
}

createTeamLayouts() {
const teamLayouts = html`
<a-entity id="team-1" position="-9.5 0 0" rotation="0 90 0" arc-layout="radius: 10; startAngle: -40; endAngle: 40; itemSelector: .arc-item"></a-entity>
<a-entity id="team-2" position="9.5 0 0" rotation="0 90 0" arc-layout="radius: 10; startAngle: -40; endAngle: 40; itemSelector: .arc-item"></a-entity>
`;
render(teamLayouts, this.parentElement);
}


renderPlayers(players) {
const playerTemplate = (player) => html`
<a-entity class="arc-item" look-towards="#camera"
animation-mixer="${player.properties['animation-mixer'] || 'clip: Idle; loop:repeat'}"
id="${player.nodeId}"
gltf-model="#player-model"
texture-map="src: assets/players/skins/${player.properties.skin || 'alienA'}.png"
scale="${player.properties.scale || '1 1 1'}">
<a-text
color="black"
opacity="0.8"
value="${player.properties.nickname || '...'}"
width="1" align="center" position="0 0 2" label="overwrite:true"></a-text>
</a-entity>
`;

const team1Players = Array.from(players.values())
.filter(player => player.properties.active === 'true' && player.properties['team-id'] === 'team-1');

const team2Players = Array.from(players.values())
.filter(player => player.properties.active === 'true' && player.properties['team-id'] === 'team-2');

const team1Template = html`
${team1Players.map(player => playerTemplate(player))}
`;

const team2Template = html`
${team2Players.map(player => playerTemplate(player))}
`;

const team1Element = this.parentElement.querySelector('#team-1');
const team2Element = this.parentElement.querySelector('#team-2');

if (team1Element) {
render(team1Template, team1Element);
team1Element.components['arc-layout'].update();
}

if (team2Element) {
render(team2Template, team2Element);
team2Element.components['arc-layout'].update();
}
}
}

export default TeamLayout;
94 changes: 0 additions & 94 deletions src/quizz/QuizzSceneController.js

This file was deleted.

136 changes: 136 additions & 0 deletions src/scene-quizz/QuizzSceneController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { createMqttHomieObserver, HomiePropertyBuffer, logger as homieLogger } from '@cmcrobotics/homie-lit';
import PropertyUpdate from '../homie-lit-components/PropertyUpdate';
import TeamLayout from '../homie-lit-components/TeamLayout';
import * as nools from 'nools';
import log from 'loglevel';

class PlayerNode {
constructor(deviceId, nodeId, properties) {
this.deviceId = deviceId;
this.nodeId = nodeId;
this.properties = properties;
}
}

class QuizzSceneController {
constructor(brokerUrl, parentElementId, mqttOptions = {}) {
this.setupLogging();
this.homieObserver = createMqttHomieObserver(brokerUrl, mqttOptions);
// this.homieObserver.subscribe("gateway/#");
// this.homieObserver.subscribe("terminal-+/#");
this.homieObserver.subscribe("#");
this.parentElement = document.getElementById(parentElementId);
this.propertyBuffer = new HomiePropertyBuffer(this.homieObserver, 300);
this.players = new Map();
this.terminalToPlayerMap = new Map();
this.teamLayout = new TeamLayout(this.parentElement);

this.flow = this.initNoolsFlow();
this.session = this.flow.getSession();

this.setupObservers();
this.teamLayout.createTeamLayouts();

}

setupLogging() {
log.setLevel("debug");
homieLogger.setLevel("info");
}

initNoolsFlow() {
const flow = nools.compile(`
rule ProcessPlayerUpdate {
when {
update: PropertyUpdate update.deviceId == 'gateway' && update.nodeId.startsWith('player-')
}
then {
handlePropertyUpdate(update);
}
}
`,{
define:{
PropertyUpdate : PropertyUpdate,
PlayerNode: PlayerNode
},
scope: {
handlePropertyUpdate: this.handlePropertyUpdate.bind(this),
logger: console
},
name: "quizz"
});

return flow;
}

setupObservers() {
this.propertyBuffer.getBufferedUpdates().subscribe(updates => {
const filteredUpdates = updates.filter(update => !this.isMetaProperty(update.propertyId));

filteredUpdates.forEach(update => {
this.session.assert(new PropertyUpdate(update.deviceId, update.nodeId, update.propertyId, update.value));
});

if (filteredUpdates.length > 0) {
this.session.match();
}
});
}

isMetaProperty(propertyId) {
return propertyId.startsWith('$');
}

handlePropertyUpdate(update) {
if (this.isMetaProperty(update.propertyId)) {
return; // Ignore meta properties
}

let player = this.players.get(update.nodeId);

if (!player) {
player = new PlayerNode(update.deviceId, update.nodeId, {});
this.players.set(update.nodeId, player);
}

player.properties[update.propertyId] = update.value;

log.debug(`Updating player property: ${update.nodeId}/${update.propertyId} = ${update.value}`);

if (update.propertyId === 'terminal-id') {
this.updateTerminalToPlayerMap(player, update.value);
}

if (update.propertyId === 'active' || update.propertyId === 'team-id' || !player.properties['active']) {
this.teamLayout.renderPlayers(this.players);
} else if (update.propertyId === 'animation-mixer') {
this.updatePlayerAnimation(player);
}
}



updatePlayerAnimation(player) {
const playerEntity = this.parentElement.querySelector(`#${player.nodeId}`);
if (playerEntity) {
playerEntity.setAttribute('animation-mixer', player.properties['animation-mixer']);
log.debug(`Updated animation for player ${player.nodeId}: ${player.properties['animation-mixer']}`);
}
}

updateTerminalToPlayerMap(player, terminalId) {
// Remove old mapping if exists
for (let [key, value] of this.terminalToPlayerMap) {
if (value === player.nodeId) {
this.terminalToPlayerMap.delete(key);
break;
}
}
// Add new mapping
this.terminalToPlayerMap.set(terminalId, player.nodeId);
log.debug(`Updated terminal-to-player mapping: Terminal ${terminalId} -> Player ${player.nodeId}`);
}

}

export default QuizzSceneController;
Loading

0 comments on commit 7ea0354

Please sign in to comment.