1
0
Fork 0

Compare commits

..

21 Commits

Author SHA1 Message Date
ivan tkachenko 3bb7a1b752 WIP: Add frontend web app player & editor in Vue 3 + Vite
TODO:
- implement viewing & editing.
- Add links to deployment, and CHANGELOG.

style.css

package.json

vite config

.vscode

eslint use --cache

.vscode

add vite-css-modules

editorconfig

tsconfig and updated vue-tsc (fixes most of the type checking bugs)

fix last type errors

audiowaveform

gitignore ESLint

ESLint: ignore autogenerated JSON

lint:fix tsconfig and vite config

migrate icon generating script to TS

eslint src/lib/

eslint stores

eslint src/*.ts

eslint audio

pnpm update

update icon

eslint ahh

import new tracks json

instructions on jq codenames

codenames.json

fix styles broken by import order

eslint audio

app

error screen

footer

copyright year

global header

loading screen

transition

search field

preview

track info

inspector

control

controls

controls range

controls impl

controls index

eslint no-console off

AudioTrack view inspector

cards and sliders

more controls

master volume slider

playhead

library page

player page

timeline markers

timeline markers

header tick

timestamp

timeline clip index

clip empty

clip lyrics

clip palette

clip fadeout

clip default

import order

timeline

timeline panel

timeline track header

timeline trackview

clip view

clip audio

audio waveform

scrollsync

easy lints

eslint store

eslint no mutating props off

pnpm catalog off

add unhead dep

use head

eslint inspector

eslint easy minor stuff

eslint audiowaveform

easy fix

eslint use :key with v-for

fix audio waveforms

inspector makes more sense

season

remove debug

inspector

Merge codenames into main json

bump pnpm

pnpm in particular

enabled

monospace Game Over
2026-01-23 15:48:24 +02:00
ivan tkachenko 8942b2ee37 Implement a better way to disable tracks while keeping them in JSON 2026-01-23 15:32:33 +02:00
ivan tkachenko f20a500992 Show Artist & Song metadata in config 2026-01-23 14:34:37 +02:00
ivan tkachenko 6a71ed578b Include Artist & Song metadata in the track info 2026-01-23 14:19:34 +02:00
ivan tkachenko 3490b1c2f3 Bump version 2026-01-23 14:01:00 +02:00
ivan tkachenko cbf1c14e01 Release v1337.9001.68 2026-01-23 05:29:16 +02:00
ivan tkachenko 5258b806d4 Add a new track Arcane 2026-01-23 05:23:53 +02:00
ivan tkachenko 4cc187b525 Split audio tracks metadata into a separate file 2026-01-23 01:52:23 +02:00
ivan tkachenko ecee2a25e2 Reorder [General] config section alphabetically
As a side-effect, this conveniently places the most important option
OverrideSpawnRates at the top.
2026-01-23 00:13:02 +02:00
ivan tkachenko af38056d11 Merge Config.DisplayLyrics and ReduceVFXIntensity
Both are responsible for some sort of VFX. Make the number of options
less overwhelming by merging the two into one.
2026-01-23 00:08:17 +02:00
ivan tkachenko 567597e353 Remove Config.ExtrapolateTime even from Debug build
Just always do it, there is no reason not to.

And maybe try dspTime to replace the whole extrapolation technique.
2026-01-22 23:47:00 +02:00
ivan tkachenko ee2b1574d0 Hide AudioOffset from Lethal Config
It is a niche option, and having two sliders next to each other might be
overwhelming for players.
2026-01-22 23:43:02 +02:00
ivan tkachenko 02903ba537 Adapt to WaterGun-V70PoweredLights_Fix-1.1.0
Don't replace the rest of the patches, because animators and audio would
be broken for reasons yet unknown.
2026-01-22 23:38:57 +02:00
ivan tkachenko b0d5922c3c Replace hotfix in code with a properly rebuilt asset bundle 2026-01-22 23:38:56 +02:00
ivan tkachenko 4e9ba0928f Disable track Yalgaar in release builds
Still will be available in a web player.
2026-01-22 23:38:56 +02:00
ivan tkachenko 6a5cc637ac Rewrite client-side vanilla-compat mode
Amends b8ef4d7937

Networking and playback are fixed, but client-side vanilla-compat mode
can never work as intended, because timers are actually client-side and
not synchronized at all. No matter what your local timer is set to, the
host gets to decide when to pop Jester at a completely random for your
client moment. There can be no meaningful prediction whatsoever.
2026-01-22 23:38:56 +02:00
ivan tkachenko a2cf66476c Deduplicate logs to avoid spamming console with errors each frame 2026-01-20 01:48:39 +02:00
ivan tkachenko a254188f0c Stop farAudio (popGoesTheWeaselTheme) in the only place where it matters 2026-01-17 19:40:42 +02:00
ivan tkachenko 3041d9f73c Merge EnemyAI.OnDestroy patch with cleanups into existing Behaviour
That Harmony patch predated MuzikaGromcheJesterNetworkBehaviour, but
there is no need to have as a separate class, especially not with the
subclass check hack.
2026-01-16 19:38:43 +02:00
ivan tkachenko 908ddeb862 editorconfig: do not suggest null propagation for Unity code 2026-01-16 18:04:07 +02:00
ivan tkachenko 3835e84450 Bump version 2026-01-16 18:04:06 +02:00
25 changed files with 3030 additions and 2734 deletions

View File

@ -6,3 +6,10 @@ csharp_style_prefer_primary_constructors = false
# IDE0305: Simplify collection initialization
dotnet_style_prefer_collection_expression = never
# IDE0031: Use null propagation
# Unity overrides equality operator, so gameObject == null also accounts for internal state of the backing C++ object
# Read more:
# - https://blog.lslabs.dev/posts/null_check_equality_unity
# - https://blog.lslabs.dev/posts/unity_script_duality
dotnet_style_null_propagation = false

BIN
Assets/ArcaneIntro.ogg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Assets/ArcaneLoop.ogg (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -1,5 +1,17 @@
# Changelog
## MuzikaGromche 1337.9001.69
- Show real Artist & Song info in the config.
## MuzikaGromche 1337.9001.68 - LocalHost hotfix
- Fixed occasionally broken playback of v1337.9001.67, sorry about that.
- Turns out, client-side vanilla-compat mode can never be perfectly timed, so don't expect much without a modded host.
- Removed an existing track Yalgaar.
- Merged two config options into one: Reduce Visual Effects & Display Lyrics.
- Added a new track Arcane.
## MuzikaGromche 1337.9001.67 - LocalHost Edition
- Added a new track TwoFastTuFurious (from the same artist as PickUpSticks), thematic to the upcoming Valentine's Day.

View File

@ -16,15 +16,7 @@ The look & feel is inspired by a certain popular NLE (Non-Linear video Editor) w
1. Add track declaration to Plugin.cs and fill in its properties.
2. Launch the game once, so that it generates a new JSON dump (in the Lethal Company save files directory) of all tracks.
3. Replace `public/MuzikaGromcheTracks.json` with the new JSON dump.
4. Run the following script to generate bare codenames file:
```sh
cat ./MuzikaGromcheTracks.json | jq '[.tracks[].Name | {(.): { "Artist": "", "Song": "" }}] | add' > MuzikaGromcheCodenamesBare.json
jq -s '.[0] * .[1]' MuzikaGromcheCodenamesBare.json MuzikaGromcheCodenames.json > tmp.json
rm MuzikaGromcheCodenames.json
rm MuzikaGromcheCodenamesBare.json
mv tmp.json MuzikaGromcheCodenames.json
```
5. Add new codenames from the generated file above to `public/MuzikaGromcheCodenames.json` file.
4. Discard lines with IP address and username or replace them with generic ones.
### Run & test

View File

@ -3,7 +3,7 @@
"type": "module",
"version": "0.0.0",
"private": true,
"packageManager": "pnpm@10.28.0+sha512.05df71d1421f21399e053fde567cea34d446fa02c76571441bfc1c7956e98e363088982d940465fd34480d4d90a0668bc12362f8aa88000a64e83d0b0e47be48",
"packageManager": "pnpm@10.28.1+sha512.7d7dbbca9e99447b7c3bf7a73286afaaf6be99251eb9498baefa7d406892f67b879adb3a1d7e687fc4ccc1a388c7175fbaae567a26ab44d1067b54fcb0d6a316",
"scripts": {
"dev": "vite",
"build": "run-p type-check prebuild \"build-only {@}\" --",
@ -24,39 +24,39 @@
"mitt": "^3.0.1",
"pinia": "^3.0.4",
"tailwindcss": "^4.1.18",
"vue": "^3.5.25",
"vue": "^3.5.27",
"vue-router": "^4.6.4"
},
"devDependencies": {
"@antfu/eslint-config": "^6.6.1",
"@tsconfig/node24": "^24.0.3",
"@antfu/eslint-config": "^6.7.3",
"@tsconfig/node24": "^24.0.4",
"@types/jsdom": "^27.0.0",
"@types/node": "^24.10.3",
"@vitejs/plugin-vue": "^6.0.2",
"@vitest/browser-playwright": "^4.0.15",
"@types/node": "^24.10.9",
"@vitejs/plugin-vue": "^6.0.3",
"@vitest/browser-playwright": "^4.0.18",
"@vitest/coverage-v8": "4.0.15",
"@vitest/eslint-plugin": "^1.5.2",
"@vitest/eslint-plugin": "^1.6.6",
"@vue/eslint-config-prettier": "^10.2.0",
"@vue/eslint-config-typescript": "^14.6.0",
"@vue/test-utils": "^2.4.6",
"@vue/tsconfig": "^0.8.1",
"eslint": "~9.39.1",
"eslint-plugin-format": "^1.1.0",
"eslint": "~9.39.2",
"eslint-plugin-format": "^1.3.1",
"eslint-plugin-vue": "~10.6.2",
"jiti": "^2.6.1",
"jsdom": "^27.3.0",
"jsdom": "^27.4.0",
"npm-run-all2": "^8.0.4",
"png-to-ico": "^3.0.1",
"prettier": "^3.7.4",
"prettier": "^3.8.1",
"sharp": "^0.33.5",
"tsx": "^4.21.0",
"typescript": "~5.9.3",
"vite": "npm:rolldown-vite@^7.2.11",
"vite": "npm:rolldown-vite@^7.3.1",
"vite-css-modules": "^1.12.0",
"vite-plugin-vue-devtools": "^8.0.5",
"vite-svg-loader": "^5.1.0",
"vitest": "^4.0.15",
"vitest-browser-vue": "^2.0.1",
"vue-tsc": "^3.1.8"
"vitest": "^4.0.18",
"vitest-browser-vue": "^2.0.2",
"vue-tsc": "^3.2.3"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,10 @@ catalogMode: manual
shellEmulator: true
trustPolicy: no-downgrade
trustPolicyExclude:
- semver@6.3.1
- undici-types@6.21.0
onlyBuiltDependencies:
- esbuild
- sharp

View File

@ -1,138 +0,0 @@
{
"AttentionPls1": {
"Artist": "Отпетые Мошенники",
"Song": "Обратите внимание"
},
"AttentionPls2": {
"Artist": "Отпетые Мошенники",
"Song": "Обратите внимание"
},
"BbIXODaHET": {
"Artist": "Сплин",
"Song": "Выхода нет"
},
"BeefLiver1": {
"Artist": "Imagine Dragons",
"Song": "Believer"
},
"BeefLiver3": {
"Artist": "Imagine Dragons",
"Song": "Believer"
},
"BeefLiver4": {
"Artist": "Imagine Dragons",
"Song": "Believer"
},
"Beha1": {
"Artist": "Жу-Жу",
"Song": "Ленинград ft. Глюк'oZа ft. ST"
},
"Beha2": {
"Artist": "Жу-Жу",
"Song": "Ленинград ft. Глюк'oZа ft. ST"
},
"Beha3": {
"Artist": "Жу-Жу",
"Song": "Ленинград ft. Глюк'oZа ft. ST"
},
"Chereshnya": {
"Artist": "Дискотека Авария",
"Song": "Малинки"
},
"DeployDestroy": {
"Artist": "Noize MC",
"Song": "Устрой дестрой"
},
"DiscoKapot": {
"Artist": "Дискотека Авария",
"Song": "Новогодняя"
},
"Durochka": {
"Artist": "Би-2",
"Song": "Дурочка"
},
"GodMode": {
"Artist": "Fall Out Boy",
"Song": "Immortals"
},
"Gorgorod": {
"Artist": "Город под подошвой",
"Song": "Oxxxymiron"
},
"HighLow": {
"Artist": "Nirvana",
"Song": "Smells Like Teen Spirit"
},
"IkWilJe": {
"Artist": "My Chemical Romance",
"Song": "All I Want for Christmas Is You"
},
"Kach": {
"Artist": "Black Eyed Peas",
"Song": "Pump It"
},
"MoyaZhittya": {
"Artist": "Bon Jovi",
"Song": "It's My Life"
},
"MuzikaGromche": {
"Artist": "Пошлая Молли",
"Song": "Нон стоп"
},
"OnePartiyaUdar": {
"Artist": "One-Punch Man",
"Song": "Opening"
},
"Paarden": {
"Artist": "Элизиум",
"Song": "Три белых коня"
},
"Peretasovka": {
"Artist": "LMFAO",
"Song": "Party Rock Anthem"
},
"PickUpSticks1": {
"Artist": "t.A.T.u.",
"Song": "Show Me Love"
},
"PickUpSticks2": {
"Artist": "t.A.T.u.",
"Song": "Show Me Love"
},
"PWNED": {
"Artist": "CYBEЯIA",
"Song": "Russian Hackers"
},
"ReelGoon": {
"Artist": "John Shanks and Sheryl Crow",
"Song": "Real Gone"
},
"RiseAndShine": {
"Artist": "Fall Out Boy",
"Song": "The Phoenix"
},
"Song2": {
"Artist": "Витас",
"Song": "Опера #2"
},
"TwoFastTuFurious": {
"Artist": "t.A.T.u.",
"Song": "Not Gonna Get Us / Нас не догонят"
},
"VseVZale": {
"Artist": "Дискотека Авария",
"Song": " Х.Х.Х.И.Р.Н.Р."
},
"Whistle": {
"Artist": "Flo Rida",
"Song": "Whistle"
},
"Yalgaar": {
"Artist": "Ajey Nagar and Wily Frenzy",
"Song": "Yalgaar"
},
"ZmeiGorynich": {
"Artist": "aespa",
"Song": "Black Mamba"
}
}

View File

@ -1,8 +1,135 @@
{
"version": "1337.9001.67",
"version": "1337.9001.69",
"tracks": [
{
"Enabled": true,
"Name": "Arcane",
"Artist": "Imagine Dragons & J.I.D",
"Song": "Enemy",
"IsExplicit": false,
"Season": null,
"Language": "English",
"WindUpTimer": 38.28,
"Bpm": 77.0002,
"Beats": 32,
"LoopOffset": 0,
"Ext": "ogg",
"FileDurationIntro": 41.366,
"FileDurationLoop": 24.935,
"FileNameIntro": "ArcaneIntro.ogg",
"FileNameLoop": "ArcaneLoop.ogg",
"BeatsOffset": 0.0,
"FadeOutBeat": -1.5,
"FadeOutDuration": 1.5,
"ColorTransitionIn": 0.2,
"ColorTransitionOut": 0.3,
"ColorTransitionEasing": "InOutExpo",
"FlickerLightsTimeSeries": [
-48.1,
-44.1,
-16.0,
15.9,
31.9
],
"Lyrics": [],
"DrunknessLoopOffsetTimeSeries": [
[
-48.0,
0.0
],
[
-47.75,
0.5
],
[
-44.0,
0.2
],
[
-43.75,
0.5
],
[
-36.0,
0.0
],
[
0.0,
0.0
],
[
0.25,
0.4
],
[
6.0,
0.0
],
[
8.0,
0.0
],
[
8.25,
0.4
],
[
14.0,
0.0
],
[
16.0,
0.0
],
[
16.25,
0.4
],
[
22.0,
0.0
],
[
24.0,
0.0
],
[
24.25,
0.4
],
[
30.0,
0.0
]
],
"CondensationLoopOffsetTimeSeries": [
[
24.0,
0.0
],
[
24.25,
0.5
],
[
30.0,
0.0
]
],
"Palette": [
"#F0FBFF",
"#0B95FF",
"#A8F5E2",
"#B79BF2",
"#FED2E1"
],
"GameOverText": "[LIFE SUPPORT: HEXTECH]"
},
{
"Enabled": true,
"Name": "AttentionPls1",
"Artist": "Отпетые Мошенники",
"Song": "Обратите внимание",
"IsExplicit": true,
"Season": null,
"Language": "Russian",
@ -67,7 +194,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "AttentionPls2",
"Artist": "Отпетые Мошенники",
"Song": "Обратите внимание",
"IsExplicit": true,
"Season": null,
"Language": "Russian",
@ -132,7 +262,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "BbIXODaHET",
"Artist": "Сплин",
"Song": "Выхода нет",
"IsExplicit": false,
"Season": null,
"Language": "Russian",
@ -187,7 +320,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "BeefLiver1",
"Artist": "Imagine Dragons",
"Song": "Believer",
"IsExplicit": false,
"Season": null,
"Language": "English",
@ -334,7 +470,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "BeefLiver3",
"Artist": "Imagine Dragons",
"Song": "Believer",
"IsExplicit": false,
"Season": null,
"Language": "English",
@ -481,7 +620,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "BeefLiver4",
"Artist": "Imagine Dragons",
"Song": "Believer",
"IsExplicit": false,
"Season": null,
"Language": "English",
@ -616,7 +758,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "Beha1",
"Artist": "Ленинград ft. Глюк'oZа ft. ST",
"Song": "Жу-Жу",
"IsExplicit": true,
"Season": null,
"Language": "Russian",
@ -653,7 +798,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "Beha2",
"Artist": "Ленинград ft. Глюк'oZа ft. ST",
"Song": "Жу-Жу",
"IsExplicit": true,
"Season": null,
"Language": "Russian",
@ -690,7 +838,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "Beha3",
"Artist": "Ленинград ft. Глюк'oZа ft. ST",
"Song": "Жу-Жу",
"IsExplicit": true,
"Season": null,
"Language": "Russian",
@ -727,7 +878,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "Chereshnya",
"Artist": "Дискотека Авария",
"Song": "Малинки",
"IsExplicit": false,
"Season": null,
"Language": "Russian",
@ -777,7 +931,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "DeployDestroy",
"Artist": "Noize MC",
"Song": "Устрой дестрой",
"IsExplicit": false,
"Season": null,
"Language": "Russian",
@ -940,7 +1097,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "DiscoKapot",
"Artist": "Дискотека Авария",
"Song": "Новогодняя",
"IsExplicit": false,
"Season": "New Year",
"Language": "Russian",
@ -993,7 +1153,10 @@
"GameOverText": "[NEXT YEAR -- DEFINITELY]"
},
{
"Enabled": true,
"Name": "Durochka",
"Artist": "Би-2",
"Song": "Дурочка",
"IsExplicit": false,
"Season": null,
"Language": "Russian",
@ -1031,7 +1194,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "GodMode",
"Artist": "Fall Out Boy",
"Song": "Immortals",
"IsExplicit": false,
"Season": null,
"Language": "English",
@ -1086,7 +1252,10 @@
"GameOverText": "[COULD'VE BEEN: IMMORTAL]"
},
{
"Enabled": true,
"Name": "Gorgorod",
"Artist": "Oxxxymiron",
"Song": "Город под подошвой",
"IsExplicit": false,
"Season": null,
"Language": "Russian",
@ -1124,7 +1293,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "HighLow",
"Artist": "Nirvana",
"Song": "Smells Like Teen Spirit",
"IsExplicit": false,
"Season": null,
"Language": "English",
@ -1189,7 +1361,10 @@
"GameOverText": "[LIFE SUPORT: NIRVANA]"
},
{
"Enabled": true,
"Name": "IkWilJe",
"Artist": "My Chemical Romance",
"Song": "All I Want for Christmas Is You",
"IsExplicit": false,
"Season": "New Year",
"Language": "English",
@ -1238,7 +1413,10 @@
"GameOverText": "[NEXT YEAR -- DEFINITELY]"
},
{
"Enabled": true,
"Name": "Kach",
"Artist": "Black Eyed Peas",
"Song": "Pump It",
"IsExplicit": false,
"Season": null,
"Language": "English",
@ -1285,7 +1463,10 @@
"GameOverText": "[DIDN'T PUMP IT: LOUDER]"
},
{
"Enabled": true,
"Name": "MoyaZhittya",
"Artist": "Bon Jovi",
"Song": "It's My Life",
"IsExplicit": false,
"Season": null,
"Language": "English",
@ -1476,7 +1657,10 @@
"GameOverText": "[LIFE IS: NOW OR NEVER]"
},
{
"Enabled": true,
"Name": "MuzikaGromche",
"Artist": "Пошлая Молли",
"Song": "Нон стоп",
"IsExplicit": false,
"Season": null,
"Language": "Russian",
@ -1640,7 +1824,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "OnePartiyaUdar",
"Artist": "One-Punch Man",
"Song": "Opening",
"IsExplicit": false,
"Season": null,
"Language": "Japanese",
@ -1678,7 +1865,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "Paarden",
"Artist": "Элизиум",
"Song": "Три белых коня",
"IsExplicit": false,
"Season": "New Year",
"Language": "Russian",
@ -1727,7 +1917,10 @@
"GameOverText": "[NEXT YEAR -- DEFINITELY]"
},
{
"Enabled": true,
"Name": "Peretasovka",
"Artist": "LMFAO",
"Song": "Party Rock Anthem",
"IsExplicit": false,
"Season": null,
"Language": "English",
@ -1766,7 +1959,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "PickUpSticks1",
"Artist": "t.A.T.u.",
"Song": "Show Me Love",
"IsExplicit": false,
"Season": null,
"Language": "English",
@ -1912,7 +2108,10 @@
"GameOverText": "[LOVE SUPPORT: OFFLINE]"
},
{
"Enabled": true,
"Name": "PickUpSticks2",
"Artist": "t.A.T.u.",
"Song": "Show Me Love",
"IsExplicit": false,
"Season": null,
"Language": "English",
@ -2058,7 +2257,10 @@
"GameOverText": "[LOVE SUPPORT: OFFLINE]"
},
{
"Enabled": true,
"Name": "PWNED",
"Artist": "CYBEЯIA",
"Song": "Russian Hackers",
"IsExplicit": true,
"Season": null,
"Language": "English",
@ -2425,7 +2627,10 @@
"GameOverText": "[HACK3D BY: RUSSI4NS]"
},
{
"Enabled": true,
"Name": "ReelGoon",
"Artist": "John Shanks and Sheryl Crow",
"Song": "Real Gone",
"IsExplicit": false,
"Season": null,
"Language": "English",
@ -2485,7 +2690,10 @@
"GameOverText": "[LIFE SUPPORT: REAL GONE]"
},
{
"Enabled": true,
"Name": "RiseAndShine",
"Artist": "Fall Out Boy",
"Song": "The Phoenix",
"IsExplicit": false,
"Season": null,
"Language": "English",
@ -2542,7 +2750,10 @@
"GameOverText": "[ HEY, YOUNG BLOOD ]"
},
{
"Enabled": true,
"Name": "Song2",
"Artist": "Витас",
"Song": "Опера #2",
"IsExplicit": false,
"Season": null,
"Language": "Russian",
@ -2580,7 +2791,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "TwoFastTuFurious",
"Artist": "t.A.T.u.",
"Song": "Not Gonna Get Us / Нас не догонят",
"IsExplicit": false,
"Season": null,
"Language": "English",
@ -2742,7 +2956,10 @@
"GameOverText": "[ O NOES, THEY GOT US ]"
},
{
"Enabled": true,
"Name": "VseVZale",
"Artist": "Дискотека Авария",
"Song": " Х.Х.Х.И.Р.Н.Р.",
"IsExplicit": false,
"Season": null,
"Language": "Russian",
@ -2887,7 +3104,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "Whistle",
"Artist": "Flo Rida",
"Song": "Whistle",
"IsExplicit": false,
"Season": null,
"Language": "English",
@ -3038,7 +3258,10 @@
"GameOverText": null
},
{
"Enabled": false,
"Name": "Yalgaar",
"Artist": "Ajey Nagar and Wily Frenzy",
"Song": "Yalgaar",
"IsExplicit": false,
"Season": null,
"Language": "Hindi",
@ -3076,7 +3299,10 @@
"GameOverText": null
},
{
"Enabled": true,
"Name": "ZmeiGorynich",
"Artist": "aespa",
"Song": "Black Mamba",
"IsExplicit": false,
"Season": null,
"Language": "Korean",

View File

@ -18,6 +18,7 @@ const {
:disabled="control.disabled"
:readonly="control.readonly"
class="tw:w-full tw:max-w-full"
:class="{ 'tw:font-mono': control.monospace }"
>
</div>
</BaseNamedControlView>

View File

@ -185,6 +185,7 @@ const controls = computed<Controls>(() => [
key: 'GameOverText',
name: 'Game Over',
ref: gameOverText,
monospace: true,
},
])
</script>

View File

@ -26,6 +26,9 @@ const hasEffects = computed<boolean>(() =>
|| timeSeriesIsEmpty(track.CondensationLoopOffsetTimeSeries),
)
// weird equality due to possible cache issues, and default being true
const classForDisabled = computed<string | null>(() => track.Enabled === false ? 'tw:line-through' : null)
const trackPalettePreview = computed<string[]>(() => track.Palette.slice(0, 6))
// preview color per track name (reactive map)
@ -62,7 +65,7 @@ function updatePreview(pos: number) {
<!-- info -->
<div style="grid-area: info;" class="tw:grid tw:grid-cols-1 tw:flex-col tw:gap-0 tw:items-end tw:justify-between">
<div class="tw:flex tw:flex-row tw:gap-1 tw:items-center">
<h3 class="tw:text-xl ellided" title="Song's codename as seen in game">
<h3 class="tw:text-xl ellided" :class="classForDisabled" title="Song's codename as seen in game">
{{ track.Name }}
</h3>
<TrackCardBadge v-if="track.IsExplicit" :icon="Explicit" title="Warning: Explicit Content" />
@ -72,10 +75,10 @@ function updatePreview(pos: number) {
<TrackCardBadge v-if="hasEffects" :icon="AutoAwesome" title="Contains Visual Effects" />
</div>
<CardSeparator />
<p class="ellided inactive-color" title="Artist">
<p class="ellided inactive-color" :class="classForDisabled" title="Artist">
{{ track.Artist }}
</p>
<p class="ellided inactive-color" title="Song">
<p class="ellided inactive-color" :class="classForDisabled" title="Song">
{{ track.Song }}
</p>
<CardSeparator />

View File

@ -37,7 +37,10 @@ export function ext(audioType: AudioType): string {
export interface AudioTrack {
// Propreties from JSON
Enabled: boolean
Name: string
Artist: string
Song: string
IsExplicit: boolean
Language: Language
Season: string | null
@ -66,10 +69,6 @@ export interface AudioTrack {
Palette: ColorString[]
GameOverText: string | null
// Added from Codenames.json
Artist: string
Song: string
// Properties added by the TrackStore
loadedIntro: AudioBuffer | null
loadedLoop: AudioBuffer | null
@ -77,7 +76,10 @@ export interface AudioTrack {
export function dummyAudioTrackForTesting(): AudioTrack {
return {
Enabled: true,
Name: 'Test Name',
Artist: 'Test Artist',
Song: 'Test Song',
IsExplicit: false,
Language: 'English',
Season: 'New Year',
@ -106,9 +108,6 @@ export function dummyAudioTrackForTesting(): AudioTrack {
Palette: ['#000000', '#FFFFFF'],
GameOverText: '',
Artist: 'Test Artist',
Song: 'Test Song',
loadedIntro: null,
loadedLoop: null,
}
@ -120,13 +119,6 @@ export function timeSeriesIsEmpty(timeSeries: TimeSeries<AnyTime>): boolean {
return timeSeries.length !== 0
}
export interface Codenames {
[key: string]: {
Artist: string
Song: string
}
}
/**
* Format timeline wall clock timestamp like [-]0:00.000 with configurable milliseconds precision.
*/

View File

@ -1,10 +1,9 @@
import type { AudioTrack, Codenames, Language } from '@/lib/AudioTrack'
import type { AudioTrack, Language } from '@/lib/AudioTrack'
import { useStorage } from '@vueuse/core'
import { defineStore } from 'pinia'
import { shallowRef } from 'vue'
import audioEngine, { VOLUME_MAX } from '@/audio/AudioEngine'
import { sleep } from '@/lib/sleep'
import codenamesJsonUrl from '/MuzikaGromcheCodenames.json?url'
import tracksJsonUrl from '/MuzikaGromcheTracks.json?url'
// Don't mark it as unused, it is needed for debugging
@ -80,12 +79,7 @@ export const useTrackStore = defineStore('track', {
)
this.version = jsonTracks.version
const tracks: Partial<AudioTrack>[] = jsonTracks.tracks
const codenames: Codenames = await fetch(codenamesJsonUrl, { signal })
.then(res => res.json())
for (const t of tracks) {
const codename = codenames[t.Name!]
t.Artist = codename?.Artist ?? ''
t.Song = codename?.Song ?? ''
t.loadedIntro = null
t.loadedLoop = null
}

View File

@ -0,0 +1,70 @@
using BepInEx.Logging;
namespace MuzikaGromche;
#if DEBUG
// A logger with an API similar to ManualLogSource.
// This logger caches last posted messagee and uses it to deduplicate subsequent messages.
// Use Clear() to forget deduplicated message.
internal class DedupManualLogSource
{
public ManualLogSource Source;
object? lastData = null;
public DedupManualLogSource(ManualLogSource source)
{
Source = source;
}
public void Log(LogLevel level, object data)
{
if (lastData != data)
{
lastData = data;
Source.Log(level, data);
}
}
public void LogFatal(object data)
{
Log(LogLevel.Fatal, data);
}
public void LogError(object data)
{
Log(LogLevel.Error, data);
}
public void LogWarning(object data)
{
Log(LogLevel.Warning, data);
}
public void LogMessage(object data)
{
Log(LogLevel.Message, data);
}
public void LogInfo(object data)
{
Log(LogLevel.Info, data);
}
public void LogDebug(object data)
{
Log(LogLevel.Debug, data);
}
public void Clear()
{
lastData = null;
}
public void Dispose()
{
}
}
#endif

View File

@ -50,37 +50,10 @@ namespace MuzikaGromche
];
Patches = [.. patchDescriptors.Select(d =>
new TilePatch(d.TileName, HotFixPrefab(d.PrefabPath, assetBundle.LoadAsset<GameObject>(d.PrefabPath)))
new TilePatch(d.TileName, assetBundle.LoadAsset<GameObject>(d.PrefabPath))
)];
}
static GameObject HotFixPrefab(string PrefabPath, GameObject gameObject)
{
// beacause I can't be bothered to reassemble the asset bundle
if (PrefabPath == "Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerFactory.prefab")
{
void RemoveGameObject(string gameObjectPath)
{
var transform = gameObject.transform.Find(gameObjectPath);
if (transform != null)
{
UnityEngine.Object.Destroy(transform.gameObject);
}
}
RemoveGameObject("DiscoBallProp1");
RemoveGameObject("DiscoBallProp2");
var discoBall = gameObject.transform.Find("DiscoBallProp3");
if (discoBall != null)
{
var position = discoBall.position;
position.y -= 5f;
discoBall.position = position;
}
}
return gameObject;
}
internal static void Patch(Tile tile)
{
var query = from patch in Patches

View File

@ -54,7 +54,10 @@ namespace MuzikaGromche
{
var obj = new Dictionary<string, object?>
{
["Enabled"] = selectableTrack.Enabled,
["Name"] = audioTrack.Name, // may be different from selectableTrack.Name, if selectable track is a group
["Artist"] = selectableTrack.Artist,
["Song"] = selectableTrack.Song,
["IsExplicit"] = selectableTrack.IsExplicit,
["Season"] = selectableTrack.Season?.Name,
["Language"] = selectableTrack.Language.Full,

1122
MuzikaGromche/Library.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@
<AssemblyName>Ratijas.MuzikaGromche</AssemblyName>
<Product>Muzika Gromche</Product>
<Description>Add some content to your inverse teleporter experience on Titan!</Description>
<Version>1337.9001.67</Version>
<Version>1337.9001.69</Version>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>

File diff suppressed because it is too large Load Diff

View File

@ -115,9 +115,10 @@ namespace MuzikaGromche
]),
new("GarageTile", [
new("HangingLEDBarLight (3)", LEDHangingLight),
new("HangingLEDBarLight (4)", LEDHangingLight,
new("HangingLEDBarLight (4)", LEDHangingLight),
// This HangingLEDBarLight's IndirectLight is wrongly named, so animator couldn't find it
ManualPatch: RenameGameObjectPatch("IndirectLight (1)", "IndirectLight")),
// renamed by WaterGun-V70PoweredLights_Fix-1.1.0
// ManualPatch: RenameGameObjectPatch("IndirectLight (1)", "IndirectLight")),
]),
new("PoolTile", [
new("PoolLights/HangingLEDBarLight", LEDHangingLight),

View File

@ -19,7 +19,7 @@ All tracks are available on the web player: [ratijas.me/muzika-gromche](https://
Muzika Gromche is compatible with *Almost Vanilla™* gameplay and [*High Quota Mindset*](https://youtu.be/18RUCgQldGg?t=2553). It slightly changes Jester's wind-up timers to pop up on the drop, so won't be compatible with leaderboards. If you are a streamer™, be aware that it does play *copyrighted content.*
- **Modded host is compatible** with vanilla clients, but if a selected track's wind-up timer differs significantly from the vanilla value, vanilla clients may observe Jester pop early or hear its theme restart from the beginning.
- **Modded client is compatible** with vanilla host: the client will locally select the track whose wind-up timer most closely matches vanilla value, but it will never play tracks whose timer fall far outside of vanilla range.
- **Modded client is compatible** with vanilla host: the client will locally select the track whose wind-up timer most closely matches vanilla value, but it will never play tracks whose timer fall far outside of vanilla range. It is impossible to time the drop perfectly, because clients don't know timer values of host.
Muzika Gromche v1337.9001.0 has been updated to work with Lethal Company v73. Previous versions of Muzika Gromche work with all Lethal Company versions from all the way back to v40 and up to v72.
@ -32,7 +32,7 @@ English playlist features artists such as **Imagine Dragons, Fall Out Boy, Bon J
Russian playlist includes **Би-2, Витас, ГлюкoZa** (Глюкоза) & **Ленинград, Дискотека Авария, Noize MC, Oxxxymiron, Сплин, Пошлая Молли.**
There are also a K-pop track by **aespa**, an anime opening from **One Punch Man,** and an Indian banger by **CarryMinati & Wily Frenzy.**
There are also a K-pop track by **aespa**, and an anime opening from **One Punch Man.**
Seasonal New Year's songs:
@ -46,7 +46,7 @@ Configuration integrates with [`LethalConfig`] mod.
Consider leaving the **Override Spawn Rates** config entry ON: it makes Jester progressively more likely to spawn afternoon.
Music track names are codenamed, and by default have equal chance of being selected. In the Lethal Config menu tracks are **grouped by language**, where the whole **group can be quickly toggled** ON or OFF at once. For example, you might want to toggle Russian or Hindi tracks OFF if you don't speak those languages.
Music track names are codenamed, and by default have equal chance of being selected. In the Lethal Config menu tracks are **grouped by language**, where the whole **group can be quickly toggled** ON or OFF at once. For example, you might want to toggle Russian or Japanese tracks OFF if you don't speak those languages.
Track selection options are only configurable by the host player.

View File

@ -1,6 +1,6 @@
{
"name": "MuzikaGromche",
"version_number": "1337.9001.67",
"version_number": "1337.9001.69",
"author": "Ratijas",
"description": "Add some content to your inverse teleporter experience on Titan!",
"website_url": "https://git.vilunov.me/ratijas/muzika-gromche",