@adatechnology/game-weather 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -771,6 +771,177 @@ function createTimeline(options) {
771
771
  };
772
772
  }
773
773
 
774
+ // src/audio/recipes.ts
775
+ import { sceneNoise, sceneTone } from "@adatechnology/game-audio";
776
+ var RAIN_LOOP = {
777
+ id: "rain_loop",
778
+ bus: "weather",
779
+ order: "chain_loop",
780
+ source: { kind: "noise", loop: true },
781
+ filters: {
782
+ mode: "serial",
783
+ bank: [
784
+ { type: "highpass", frequency: { set: 600 } },
785
+ { type: "lowpass", frequency: { set: 6e3 } }
786
+ ]
787
+ },
788
+ sources: ["cena:L1314"]
789
+ };
790
+ var WIND_LOOP = {
791
+ id: "wind_loop",
792
+ bus: "weather",
793
+ order: "chain_loop",
794
+ source: { kind: "noise", loop: true },
795
+ filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: 320 } }] },
796
+ modulators: [{ target: "gain", rate: 0.07, depth: 0.035 }],
797
+ sources: ["cena:L1315"]
798
+ };
799
+ var RAIN_HISS_GAME = {
800
+ id: "rain_hiss_game",
801
+ bus: "weather",
802
+ order: "game_loop",
803
+ source: { kind: "noise", loop: true },
804
+ filters: { mode: "serial", bank: [{ type: "highpass", frequency: { set: 2500 } }] },
805
+ sources: ["jogo:L62116 chuva"]
806
+ };
807
+ var THUNDER = {
808
+ id: "thunder",
809
+ bus: "weather",
810
+ pan: true,
811
+ layers: [sceneTone({ f: 70, f2: 28, d: 1.2, vol: 1 }), sceneNoise({ f: 260, f2: 50, d: 3.2, vol: 0.9, wet: 0.8 })],
812
+ falloff: { model: "inverse_square", k: 1e-5, scale: 1.4 },
813
+ sources: ["jogo:L68278-68285 boom", "sdk: rumble and falloff"]
814
+ };
815
+ var WEATHER_BANK = { id: "weather", sounds: [THUNDER], loops: [RAIN_LOOP, WIND_LOOP, RAIN_HISS_GAME] };
816
+ var WEATHER_SOUNDS = WEATHER_BANK.sounds ?? [];
817
+ var WEATHER_LOOPS = WEATHER_BANK.loops ?? [];
818
+
819
+ // src/audio/sound.ts
820
+ var DEFAULT_RAIN_SOUND = { light: 0.035, heavy: 0.06, lightAt: 2.5, heavyAt: 15 };
821
+ var DEFAULT_WIND_SOUND = { base: 0.05, referenceSpeed: 3.8, max: 0.12 };
822
+ function rainVolume(rain, options = {}) {
823
+ if (!(rain > 0)) return 0;
824
+ const { light, heavy, lightAt, heavyAt } = { ...DEFAULT_RAIN_SOUND, ...options };
825
+ if (heavyAt <= lightAt) return rain >= heavyAt ? heavy : light;
826
+ const t = Math.min(1, Math.max(0, (rain - lightAt) / (heavyAt - lightAt)));
827
+ return light + (heavy - light) * t;
828
+ }
829
+ function windVolume(speed, options = {}) {
830
+ const { base, referenceSpeed, max } = { ...DEFAULT_WIND_SOUND, ...options };
831
+ return Math.min(max, base * Math.max(0, speed) / referenceSpeed);
832
+ }
833
+ function strikePosition(strike, origin = [0, 0, 0]) {
834
+ const angle = strike.bearing * Math.PI / 180;
835
+ return [origin[0] + Math.sin(angle) * strike.distance, origin[1], origin[2] - Math.cos(angle) * strike.distance];
836
+ }
837
+ function createWeatherSound(sink, options = {}) {
838
+ if (sink && options.register !== false) sink.register?.(WEATHER_BANK);
839
+ const rainSound = options.style === "game" ? "rain_hiss_game" : "rain_loop";
840
+ const loops = /* @__PURE__ */ new Map();
841
+ const set = (id, volume) => {
842
+ let loop = loops.get(id);
843
+ if (!loop) {
844
+ if (!(volume > 0) || !sink?.loop) return;
845
+ loop = sink.loop(id);
846
+ loops.set(id, loop);
847
+ }
848
+ loop.set({ volume });
849
+ };
850
+ return {
851
+ update(sample) {
852
+ set(rainSound, rainVolume(sample.rain, options.rain));
853
+ set("wind_loop", windVolume(sample.windSpeed, options.wind));
854
+ },
855
+ thunder(strike) {
856
+ sink?.play({ sound: "thunder", position: strikePosition(strike, options.listener?.()), ...options.thunderVolume === void 0 ? {} : { volume: options.thunderVolume } });
857
+ },
858
+ dispose() {
859
+ for (const loop of loops.values()) loop.stop();
860
+ loops.clear();
861
+ }
862
+ };
863
+ }
864
+
865
+ // src/bridges.ts
866
+ var DEFAULT_BRIDGE_RULES = { filmRainFullAt: 2.5, washFrom: 15, washBelow: 0.5, washEvery: 1, windFull: 20 };
867
+ function environmentOf(sample) {
868
+ return {
869
+ rain: sample.rain,
870
+ windX: sample.windX,
871
+ windZ: sample.windZ,
872
+ windSpeed: sample.windSpeed,
873
+ gust: sample.gust,
874
+ fogFar: sample.fogFar,
875
+ visibility: sample.effects.visibility,
876
+ nightFactor: sample.nightFactor,
877
+ temperatureC: sample.temperatureC,
878
+ wetness: sample.groundWetness
879
+ };
880
+ }
881
+ function createWeatherBridges(targets, options = {}) {
882
+ const rules = { ...DEFAULT_BRIDGE_RULES, ...options };
883
+ const sound = options.sound === false || !targets.audio ? void 0 : createWeatherSound(targets.audio, options.sound ?? {});
884
+ let weather;
885
+ let offThunder;
886
+ let sinceWash = 0;
887
+ let last = {};
888
+ const push = () => {
889
+ if (!weather) return;
890
+ const sample = weather.sample();
891
+ const { film, interactables, vegetation, vfx, environment } = targets;
892
+ environment?.set(environmentOf(sample));
893
+ if (film) {
894
+ const rain = Math.min(1, Math.max(0, sample.rain / rules.filmRainFullAt));
895
+ const drying = sample.effects.dryingScale;
896
+ if (rain !== last.filmRain || drying !== last.drying) film.setWeather({ rain, drying });
897
+ last.filmRain = rain;
898
+ last.drying = drying;
899
+ }
900
+ if (interactables && sample.rain !== last.rain) interactables.water.setRain(sample.rain);
901
+ const windChanged = sample.windX !== last.windX || sample.windZ !== last.windZ;
902
+ if (windChanged) {
903
+ interactables?.setWind(sample.windX, sample.windZ);
904
+ vfx?.setWind([sample.windX, 0, sample.windZ]);
905
+ if (vegetation) {
906
+ const wind = { strength: Math.min(1, sample.windSpeed / rules.windFull), gust: Math.min(1, sample.gust / rules.windFull) };
907
+ vegetation.setWind(sample.windSpeed > 1e-6 ? { direction: [sample.windX, sample.windZ], ...wind } : wind);
908
+ }
909
+ }
910
+ last = { ...last, rain: sample.rain, windX: sample.windX, windZ: sample.windZ };
911
+ sound?.update(sample);
912
+ };
913
+ const onThunder = (strike) => sound?.thunder(strike);
914
+ return {
915
+ bind(next) {
916
+ offThunder?.();
917
+ weather = next;
918
+ offThunder = next.on("thunder", onThunder);
919
+ last = {};
920
+ sinceWash = 0;
921
+ push();
922
+ },
923
+ update(dt) {
924
+ push();
925
+ if (!weather || !targets.film?.wash) return;
926
+ if (weather.sample().rain < rules.washFrom) {
927
+ sinceWash = 0;
928
+ return;
929
+ }
930
+ sinceWash += dt;
931
+ if (sinceWash >= rules.washEvery) {
932
+ sinceWash = 0;
933
+ targets.film.wash(rules.washBelow);
934
+ }
935
+ },
936
+ dispose() {
937
+ offThunder?.();
938
+ offThunder = void 0;
939
+ weather = void 0;
940
+ sound?.dispose();
941
+ }
942
+ };
943
+ }
944
+
774
945
  // src/bench/locale.ts
775
946
  var EN = {
776
947
  group: "Weather",
@@ -873,9 +1044,12 @@ var FOG_NEAR = 1;
873
1044
  function createWeatherTestModule(options = {}) {
874
1045
  const locale = options.locale ?? "pt-BR";
875
1046
  const text = weatherBenchTextOf(locale);
876
- const { locale: _locale, translate, weather: given, fog: _fog, ...weatherOptions } = options;
1047
+ const { locale: _locale, translate, weather: given, fog: _fog, targets: _targets, sound: _sound, visual: _visual, ...weatherOptions } = options;
877
1048
  void _locale;
878
1049
  void _fog;
1050
+ void _targets;
1051
+ void _sound;
1052
+ void _visual;
879
1053
  const state = {
880
1054
  seed: options.seed ?? 1,
881
1055
  hour: options.startHour ?? 8,
@@ -887,6 +1061,8 @@ function createWeatherTestModule(options = {}) {
887
1061
  let host = null;
888
1062
  let strikes = 0;
889
1063
  let offStrike;
1064
+ let bridges;
1065
+ let visual;
890
1066
  let weather = given ?? createWeather({ ...weatherOptions, autoSchedule: state.auto, ...state.auto ? { timeScale: FAST_SCALE } : {} });
891
1067
  const watch = () => {
892
1068
  offStrike?.();
@@ -899,19 +1075,8 @@ function createWeatherTestModule(options = {}) {
899
1075
  weather = createWeather({ ...weatherOptions, seed: state.seed, start: current, startHour: state.hour, autoSchedule: state.auto, timeScale: state.auto ? FAST_SCALE : NORMAL_SCALE });
900
1076
  strikes = 0;
901
1077
  watch();
1078
+ bridges?.bind(weather);
902
1079
  };
903
- const toEnvironment = (sample) => ({
904
- rain: sample.rain,
905
- windX: sample.windX,
906
- windZ: sample.windZ,
907
- windSpeed: sample.windSpeed,
908
- gust: sample.gust,
909
- fogFar: sample.fogFar,
910
- visibility: sample.effects.visibility,
911
- nightFactor: sample.nightFactor,
912
- temperatureC: sample.temperatureC,
913
- wetness: sample.groundWetness
914
- });
915
1080
  const applyFog = (far) => {
916
1081
  const scene = host?.scene;
917
1082
  const Fog = host?.THREE?.Fog;
@@ -922,12 +1087,13 @@ function createWeatherTestModule(options = {}) {
922
1087
  };
923
1088
  const publish = () => {
924
1089
  const sample = weather.sample();
925
- if (state.environment) host?.environment?.set(toEnvironment(sample));
926
- if (state.fog) applyFog(sample.fogFar);
1090
+ if (state.environment) host?.environment?.set(environmentOf(sample));
1091
+ if (state.fog && !visual) applyFog(sample.fogFar);
927
1092
  };
928
1093
  const onChange = (change) => {
929
1094
  if (change.kind === "layer") {
930
1095
  if (change.id === "environment" || change.id === "fog") state[change.id] = change.on;
1096
+ visual?.setLayer(change.id, change.on);
931
1097
  return;
932
1098
  }
933
1099
  if (change.kind === "action") return;
@@ -965,7 +1131,8 @@ function createWeatherTestModule(options = {}) {
965
1131
  ];
966
1132
  const layers = () => [
967
1133
  { id: "environment", name: text.layers.environment },
968
- { id: "fog", name: text.layers.fog, default: state.fog }
1134
+ { id: "fog", name: text.layers.fog, default: state.fog },
1135
+ ...options.visual?.layers(locale) ?? []
969
1136
  ];
970
1137
  const metrics = () => [
971
1138
  { id: "current_state", name: text.metrics.state, read: () => nameOf(weather.state()) },
@@ -1054,14 +1221,24 @@ function createWeatherTestModule(options = {}) {
1054
1221
  attach(lent) {
1055
1222
  host = lent;
1056
1223
  const off = lent.bench?.onChange(onChange);
1224
+ bridges = createWeatherBridges({ ...options.targets, ...lent.audio ? { audio: lent.audio } : {} }, { sound: options.sound ?? {} });
1225
+ bridges.bind(weather);
1226
+ visual = options.visual?.create({ host: lent, locale, weather: { sample: () => weather.sample() } });
1227
+ if (visual && !state.fog) visual.setLayer("fog", false);
1057
1228
  publish();
1058
1229
  const offFrame = lent.onFrame((dt) => {
1059
1230
  weather.advance(dt);
1060
1231
  publish();
1232
+ bridges?.update(dt);
1233
+ visual?.update(dt);
1061
1234
  });
1062
1235
  return () => {
1236
+ visual?.dispose();
1237
+ visual = void 0;
1063
1238
  off?.();
1064
1239
  offFrame();
1240
+ bridges?.dispose();
1241
+ bridges = void 0;
1065
1242
  host = null;
1066
1243
  };
1067
1244
  }
@@ -1071,17 +1248,27 @@ function createWeatherTestModule(options = {}) {
1071
1248
  export {
1072
1249
  CLIMATES,
1073
1250
  DAY_REAL_SECONDS,
1251
+ DEFAULT_BRIDGE_RULES,
1074
1252
  DEFAULT_DRY_OUT_SECONDS,
1253
+ DEFAULT_RAIN_SOUND,
1075
1254
  DEFAULT_START_HOUR,
1076
1255
  DEFAULT_TIME_SCALE,
1077
1256
  DEFAULT_WET_RISE_SECONDS,
1257
+ DEFAULT_WIND_SOUND,
1078
1258
  DRY_VISIBILITY_METERS,
1079
1259
  FLASH_END_SECONDS,
1080
1260
  GAME_DAY_SECONDS,
1081
1261
  NIGHT_SIGHT_LOSS,
1262
+ RAIN_HISS_GAME,
1263
+ RAIN_LOOP,
1082
1264
  SPEED_OF_SOUND,
1083
1265
  STATE_VALUE_KEYS,
1266
+ THUNDER,
1267
+ WEATHER_BANK,
1268
+ WEATHER_LOOPS,
1269
+ WEATHER_SOUNDS,
1084
1270
  WEATHER_STATES,
1271
+ WIND_LOOP,
1085
1272
  blendValues,
1086
1273
  createLightningStream,
1087
1274
  createRng,
@@ -1089,18 +1276,24 @@ export {
1089
1276
  createStream,
1090
1277
  createTimeline,
1091
1278
  createWeather,
1279
+ createWeatherBridges,
1092
1280
  createWeatherRegistry,
1281
+ createWeatherSound,
1093
1282
  createWeatherTestModule,
1094
1283
  createWetness,
1095
1284
  dayFractionAt,
1096
1285
  daylight,
1097
1286
  deriveEffects,
1287
+ environmentOf,
1098
1288
  flashIntensity,
1099
1289
  heatIndexC,
1100
1290
  heatStress,
1291
+ rainVolume,
1101
1292
  streamSeed,
1293
+ strikePosition,
1102
1294
  thunderDelay,
1103
1295
  valuesOf,
1104
- weatherBenchTextOf
1296
+ weatherBenchTextOf,
1297
+ windVolume
1105
1298
  };
1106
1299
  //# sourceMappingURL=index.js.map