mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
feat: added coalition selection for audio manager
This commit is contained in:
parent
cde33fdd76
commit
d31aa30da8
@ -1,4 +1,4 @@
|
||||
import { AudioMessageType, OlympusState } from "../constants/constants";
|
||||
import { AudioMessageType, BLUE_COMMANDER, GAME_MASTER, OlympusState, RED_COMMANDER } from "../constants/constants";
|
||||
import { MicrophoneSource } from "./microphonesource";
|
||||
import { RadioSink } from "./radiosink";
|
||||
import { getApp } from "../olympusapp";
|
||||
@ -11,17 +11,20 @@ import { Unit } from "../unit/unit";
|
||||
import { UnitSink } from "./unitsink";
|
||||
import { AudioPacket, MessageType } from "./audiopacket";
|
||||
import {
|
||||
AudioManagerCoalitionChangedEvent,
|
||||
AudioManagerDevicesChangedEvent,
|
||||
AudioManagerInputChangedEvent,
|
||||
AudioManagerOutputChangedEvent,
|
||||
AudioManagerStateChangedEvent,
|
||||
AudioSinksChangedEvent,
|
||||
AudioSourcesChangedEvent,
|
||||
CommandModeOptionsChangedEvent,
|
||||
ConfigLoadedEvent,
|
||||
SRSClientsChangedEvent,
|
||||
} from "../events";
|
||||
import { OlympusConfig } from "../interfaces";
|
||||
import { CommandModeOptions, OlympusConfig } from "../interfaces";
|
||||
import { TextToSpeechSource } from "./texttospeechsource";
|
||||
import { Coalition } from "../types/types";
|
||||
|
||||
export class AudioManager {
|
||||
#audioContext: AudioContext;
|
||||
@ -46,12 +49,23 @@ export class AudioManager {
|
||||
#syncInterval: number;
|
||||
#speechRecognition: boolean = true;
|
||||
#internalTextToSpeechSource: TextToSpeechSource;
|
||||
#coalition: Coalition = "blue";
|
||||
#commandMode: string = BLUE_COMMANDER;
|
||||
|
||||
constructor() {
|
||||
ConfigLoadedEvent.on((config: OlympusConfig) => {
|
||||
config.audio.WSPort ? this.setPort(config.audio.WSPort) : this.setEndpoint(config.audio.WSEndpoint);
|
||||
});
|
||||
|
||||
CommandModeOptionsChangedEvent.on((options: CommandModeOptions) => {
|
||||
if (options.commandMode === BLUE_COMMANDER) {
|
||||
this.setCoalition("blue");
|
||||
} else if (options.commandMode === RED_COMMANDER) {
|
||||
this.setCoalition("red");
|
||||
}
|
||||
this.#commandMode = options.commandMode;
|
||||
});
|
||||
|
||||
let PTTKeys = ["KeyZ", "KeyX", "KeyC", "KeyV", "KeyB", "KeyN", "KeyM", "KeyComma", "KeyDot"];
|
||||
PTTKeys.forEach((key, idx) => {
|
||||
getApp()
|
||||
@ -117,7 +131,7 @@ export class AudioManager {
|
||||
if (sink.getFrequency() === frequencyInfo.frequency && sink.getModulation() === frequencyInfo.modulation && sink.getTuned()) {
|
||||
sink.setReceiving(true);
|
||||
|
||||
sink.setTransmittingUnit(getApp().getUnitsManager().getUnitByID(audioPacket.getUnitID()) ?? undefined)
|
||||
sink.setTransmittingUnit(getApp().getUnitsManager().getUnitByID(audioPacket.getUnitID()) ?? undefined);
|
||||
|
||||
/* Make a copy of the array buffer for the playback pipeline to use */
|
||||
var dst = new ArrayBuffer(audioPacket.getAudioData().buffer.byteLength);
|
||||
@ -150,7 +164,7 @@ export class AudioManager {
|
||||
let newRadio = this.addRadio();
|
||||
newRadio?.setFrequency(options.frequency);
|
||||
newRadio?.setModulation(options.modulation);
|
||||
newRadio?.setPan(options.pan)
|
||||
newRadio?.setPan(options.pan);
|
||||
});
|
||||
} else {
|
||||
/* Add two default radios and connect to the microphone*/
|
||||
@ -346,12 +360,23 @@ export class AudioManager {
|
||||
return this.#internalTextToSpeechSource;
|
||||
}
|
||||
|
||||
setCoalition(coalition: Coalition) {
|
||||
if (this.#commandMode === GAME_MASTER) {
|
||||
this.#coalition = coalition;
|
||||
AudioManagerCoalitionChangedEvent.dispatch(coalition);
|
||||
}
|
||||
}
|
||||
|
||||
getCoalition() {
|
||||
return this.#coalition;
|
||||
}
|
||||
|
||||
#syncRadioSettings() {
|
||||
/* Send the radio settings of each radio to the SRS backend */
|
||||
let message = {
|
||||
type: "Settings update",
|
||||
guid: this.#guid,
|
||||
coalition: 2, // TODO
|
||||
coalition: this.#coalition,
|
||||
settings: this.#sinks
|
||||
.filter((sink) => sink instanceof RadioSink)
|
||||
.map((radio) => {
|
||||
|
||||
@ -7,7 +7,7 @@ import { CoalitionPolygon } from "./map/coalitionarea/coalitionpolygon";
|
||||
import { Airbase } from "./mission/airbase";
|
||||
import { Bullseye } from "./mission/bullseye";
|
||||
import { Shortcut } from "./shortcut/shortcut";
|
||||
import { MapHiddenTypes, MapOptions } from "./types/types";
|
||||
import { Coalition, MapHiddenTypes, MapOptions } from "./types/types";
|
||||
import { ContextAction } from "./unit/contextaction";
|
||||
import { ContextActionSet } from "./unit/contextactionset";
|
||||
import { Unit } from "./unit/unit";
|
||||
@ -749,6 +749,23 @@ export class AudioManagerOutputChangedEvent {
|
||||
}
|
||||
}
|
||||
|
||||
export class AudioManagerCoalitionChangedEvent {
|
||||
static on(callback: (coalition: Coalition) => void, singleShot = false) {
|
||||
document.addEventListener(
|
||||
this.name,
|
||||
(ev: CustomEventInit) => {
|
||||
callback(ev.detail.coalition);
|
||||
},
|
||||
{ once: singleShot }
|
||||
);
|
||||
}
|
||||
|
||||
static dispatch(coalition: Coalition) {
|
||||
document.dispatchEvent(new CustomEvent(this.name, { detail: { coalition } }));
|
||||
console.log(`Event ${this.name} dispatched`);
|
||||
}
|
||||
}
|
||||
|
||||
/************** Mission data events ***************/
|
||||
export class BullseyesDataChangedEvent {
|
||||
static on(callback: (bullseyes: { [name: string]: Bullseye }) => void, singleShot = false) {
|
||||
|
||||
@ -6,7 +6,7 @@ import { BLUE_COMMANDER, GAME_MASTER, NONE, RED_COMMANDER } from "../constants/c
|
||||
import { AirbasesData, BullseyesData, CommandModeOptions, DateAndTime, MissionData } from "../interfaces";
|
||||
import { Coalition } from "../types/types";
|
||||
import { Carrier } from "./carrier";
|
||||
import { AirbaseSelectedEvent, AppStateChangedEvent, BullseyesDataChangedEvent, CommandModeOptionsChangedEvent, InfoPopupEvent, MissionDataChangedEvent } from "../events";
|
||||
import { AirbaseSelectedEvent, AppStateChangedEvent, BullseyesDataChangedEvent, CommandModeOptionsChangedEvent, MissionDataChangedEvent } from "../events";
|
||||
|
||||
/** The MissionManager */
|
||||
export class MissionManager {
|
||||
|
||||
@ -28,7 +28,6 @@ import { OlDropdownItem } from "../components/oldropdown";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { OlCoalitionToggle } from "../components/olcoalitiontoggle";
|
||||
import { Coalition } from "../../types/types";
|
||||
import { CompactEffectSpawnMenu } from "../panels/compacteffectspawnmenu";
|
||||
|
||||
enum CategoryGroup {
|
||||
NONE,
|
||||
|
||||
@ -12,15 +12,20 @@ import { UnitSink } from "../../audio/unitsink";
|
||||
import { FaMinus, FaVolumeHigh } from "react-icons/fa6";
|
||||
import { getRandomColor } from "../../other/utils";
|
||||
import {
|
||||
AudioManagerCoalitionChangedEvent,
|
||||
AudioManagerDevicesChangedEvent,
|
||||
AudioManagerInputChangedEvent,
|
||||
AudioManagerOutputChangedEvent,
|
||||
AudioManagerStateChangedEvent,
|
||||
AudioSinksChangedEvent,
|
||||
AudioSourcesChangedEvent,
|
||||
CommandModeOptionsChangedEvent,
|
||||
ShortcutsChangedEvent,
|
||||
} from "../../events";
|
||||
import { OlDropdown, OlDropdownItem } from "../components/oldropdown";
|
||||
import { OlCoalitionToggle } from "../components/olcoalitiontoggle";
|
||||
import { Coalition } from "../../types/types";
|
||||
import { GAME_MASTER, NONE } from "../../constants/constants";
|
||||
|
||||
export function AudioMenu(props: { open: boolean; onClose: () => void; children?: JSX.Element | JSX.Element[] }) {
|
||||
const [devices, setDevices] = useState([] as MediaDeviceInfo[]);
|
||||
@ -32,6 +37,8 @@ export function AudioMenu(props: { open: boolean; onClose: () => void; children?
|
||||
const [shortcuts, setShortcuts] = useState({});
|
||||
const [input, setInput] = useState(undefined as undefined | MediaDeviceInfo);
|
||||
const [output, setOutput] = useState(undefined as undefined | MediaDeviceInfo);
|
||||
const [coalition, setCoalition] = useState("blue" as Coalition);
|
||||
const [commandMode, setCommandMode] = useState(NONE as string);
|
||||
|
||||
/* Preallocate 128 references for the source and sink panels. If the number of references changes, React will give an error */
|
||||
const sourceRefs = Array(128)
|
||||
@ -77,6 +84,8 @@ export function AudioMenu(props: { open: boolean; onClose: () => void; children?
|
||||
AudioManagerDevicesChangedEvent.on((devices) => setDevices([...devices]));
|
||||
AudioManagerInputChangedEvent.on((input) => setInput(input));
|
||||
AudioManagerOutputChangedEvent.on((output) => setOutput(output));
|
||||
AudioManagerCoalitionChangedEvent.on((coalition) => setCoalition(coalition));
|
||||
CommandModeOptionsChangedEvent.on((options) => setCommandMode(options.commandMode));
|
||||
}, []);
|
||||
|
||||
/* When the sinks or sources change, use the count state to force a rerender to update the connection lines */
|
||||
@ -135,6 +144,7 @@ export function AudioMenu(props: { open: boolean; onClose: () => void; children?
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
<div className="flex flex-col gap-3">
|
||||
<div
|
||||
className={`
|
||||
@ -145,6 +155,24 @@ export function AudioMenu(props: { open: boolean; onClose: () => void; children?
|
||||
>
|
||||
{audioManagerEnabled && (
|
||||
<>
|
||||
{commandMode === GAME_MASTER && (
|
||||
<div className="flex justify-between">
|
||||
<div>Radio coalition </div>
|
||||
<OlCoalitionToggle
|
||||
coalition={coalition}
|
||||
onClick={() => {
|
||||
let newCoalition = "";
|
||||
if (coalition === "blue") newCoalition = "neutral";
|
||||
else if (coalition === "neutral") newCoalition = "red";
|
||||
else if (coalition === "red") newCoalition = "blue";
|
||||
getApp()
|
||||
.getAudioManager()
|
||||
.setCoalition(newCoalition as Coalition);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<span>Input</span>
|
||||
|
||||
<OlDropdown label={input ? input.label : "Default"}>
|
||||
|
||||
@ -21,7 +21,7 @@ export function CoordinatesPanel(props: {}) {
|
||||
|
||||
BullseyesDataChangedEvent.on((bullseyes) => setBullseyes(bullseyes));
|
||||
SelectedUnitsChangedEvent.on((selectedUnits) => setSelectedUnits(selectedUnits));
|
||||
SelectionClearedEvent.on(() => setSelectedUnits([]))
|
||||
SelectionClearedEvent.on(() => setSelectedUnits([]));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@ -41,28 +41,32 @@ export function CoordinatesPanel(props: {}) {
|
||||
gap-2
|
||||
`}
|
||||
>
|
||||
<div className="flex justify-start gap-2">
|
||||
<span
|
||||
className={`
|
||||
rounded-sm bg-blue-500 px-1 py-1 text-center font-bold
|
||||
text-olympus-700
|
||||
`}
|
||||
>
|
||||
<FaBullseye />
|
||||
</span>{" "}
|
||||
{computeBearingRangeString(bullseyes[2].getLatLng(), latlng)}
|
||||
</div>
|
||||
<div className="flex w-[50%] justify-start gap-2">
|
||||
<span
|
||||
className={`
|
||||
rounded-sm bg-red-500 px-1 py-1 text-center font-bold
|
||||
text-olympus-700
|
||||
`}
|
||||
>
|
||||
<FaBullseye />
|
||||
</span>
|
||||
{computeBearingRangeString(bullseyes[1].getLatLng(), latlng)}
|
||||
</div>
|
||||
{bullseyes[2] && (
|
||||
<div className="flex justify-start gap-2">
|
||||
<span
|
||||
className={`
|
||||
rounded-sm bg-blue-500 px-1 py-1 text-center font-bold
|
||||
text-olympus-700
|
||||
`}
|
||||
>
|
||||
<FaBullseye />
|
||||
</span>{" "}
|
||||
{computeBearingRangeString(bullseyes[2].getLatLng(), latlng)}
|
||||
</div>
|
||||
)}
|
||||
{bullseyes[1] && (
|
||||
<div className="flex w-[50%] justify-start gap-2">
|
||||
<span
|
||||
className={`
|
||||
rounded-sm bg-red-500 px-1 py-1 text-center font-bold
|
||||
text-olympus-700
|
||||
`}
|
||||
>
|
||||
<FaBullseye />
|
||||
</span>
|
||||
{computeBearingRangeString(bullseyes[1].getLatLng(), latlng)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{selectedUnits.length == 1 && (
|
||||
<div className="flex justify-start gap-2">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user