Skip to content

Commit 287e37c

Browse files
committed
Compiles, and small error fixes
1 parent 794ee92 commit 287e37c

File tree

48 files changed

+261
-210
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+261
-210
lines changed

Nitrox.Test/Model/Helper/NetHelperTest.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Net;
33
using System.Net.Sockets;
44
using FluentAssertions;

Nitrox.Test/Patcher/Patches/Dynamic/FootstepSounds_OnStep_PatchTest.cs

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//TODO: Fix with steps patch
2+
#if SUBNAUTICA
13
using System.Collections.Generic;
24
using System.Linq;
35
using HarmonyLib;
@@ -18,3 +20,4 @@ public void InjectionSanity()
1820
Assert.AreEqual(beforeInstructions.Count() + 4, result.Count());
1921
}
2022
}
23+
#endif

NitroxClient/ClientAutoFacRegistrar.cs

+2
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ private void RegisterCoreDependencies(ContainerBuilder containerBuilder)
116116
containerBuilder.RegisterType<NitroxConsole>().InstancePerLifetimeScope();
117117
containerBuilder.RegisterType<Terrain>().InstancePerLifetimeScope();
118118
containerBuilder.RegisterType<ExosuitModuleEvent>().InstancePerLifetimeScope();
119+
#if SUBNAUTICA
119120
containerBuilder.RegisterType<SeamothModulesEvent>().InstancePerLifetimeScope();
121+
#endif
120122
containerBuilder.RegisterType<Fires>().InstancePerLifetimeScope();
121123
containerBuilder.Register(_ => new FMODWhitelist(GameInfo.Subnautica)).InstancePerLifetimeScope();
122124
containerBuilder.RegisterType<FMODSystem>().InstancePerLifetimeScope();

NitroxClient/GameLogic/HUD/NitroxPDATabManager.cs

+17-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
using System.Collections.Generic;
2+
#if BELOWZERO
23
using UnityEngine;
4+
#endif
35

46
namespace NitroxClient.GameLogic.HUD;
57

68
public class NitroxPDATabManager
79
{
810
public readonly Dictionary<PDATab, NitroxPDATab> CustomTabs = new();
9-
11+
#if SUBNAUTICA
12+
private readonly Dictionary<string, Atlas.Sprite> tabSpritesByName = new();
13+
#elif BELOWZERO
1014
private readonly Dictionary<string, Sprite> tabSpritesByName = new();
15+
#endif
1116
private readonly Dictionary<string, TabSpriteLoadedEvent> spriteLoadedCallbackByName = new();
1217

1318
public NitroxPDATabManager()
@@ -19,8 +24,11 @@ void RegisterTab(NitroxPDATab nitroxTab)
1924

2025
RegisterTab(new PlayerListTab());
2126
}
22-
27+
#if SUBNAUTICA
28+
public void AddTabSprite(string spriteName, Atlas.Sprite sprite)
29+
#elif BELOWZERO
2330
public void AddTabSprite(string spriteName, Sprite sprite)
31+
#endif
2432
{
2533
tabSpritesByName.Add(spriteName, sprite);
2634
if (spriteLoadedCallbackByName.TryGetValue(spriteName, out TabSpriteLoadedEvent spriteLoadedEvent))
@@ -29,11 +37,16 @@ public void AddTabSprite(string spriteName, Sprite sprite)
2937
spriteLoadedCallbackByName.Remove(spriteName);
3038
}
3139
}
32-
40+
#if SUBNAUTICA
41+
public bool TryGetTabSprite(string spriteName, out Atlas.Sprite sprite) => tabSpritesByName.TryGetValue(spriteName, out sprite);
42+
43+
public delegate void TabSpriteLoadedEvent(Atlas.Sprite sprite);
44+
#elif BELOWZERO
3345
public bool TryGetTabSprite(string spriteName, out Sprite sprite) => tabSpritesByName.TryGetValue(spriteName, out sprite);
3446

3547
public delegate void TabSpriteLoadedEvent(Sprite sprite);
36-
48+
#endif
49+
3750
public void SetSpriteLoadedCallback(string tabName, TabSpriteLoadedEvent callback)
3851
{
3952
if (!spriteLoadedCallbackByName.ContainsKey(tabName))

NitroxClient/GameLogic/HUD/PdaTabs/uGUI_PlayerListTab.cs

+4
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,11 @@ public IEnumerator Start()
7575
{
7676
if (asset.name.Equals("player_list_tab@3x"))
7777
{
78+
#if SUBNAUTICA
79+
nitroxPDATabManager.AddTabSprite(asset.name, new Atlas.Sprite(sprite));
80+
#elif BELOWZERO
7881
nitroxPDATabManager.AddTabSprite(asset.name, Sprite.Create(sprite.texture, sprite.rect, sprite.pivot, sprite.pixelsPerUnit));
82+
#endif
7983
}
8084
assets.Add(asset.name, sprite);
8185
}

NitroxClient/GameLogic/InitialSync/PdaInitialSyncProcessor.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ private static IEnumerator RestoreEncyclopediaEntries(InitialPlayerSync packet)
6666
foreach (string entry in entries)
6767
{
6868
#if SUBNAUTICA
69-
PDAEncyclopedia.Add(entry, false);
69+
PDAEncyclopedia.Add(entry, false);
7070
#elif BELOWZERO
7171
PDAEncyclopedia.Add(entry, false, false);
7272
#endif

NitroxClient/GameLogic/LocalPlayer.cs

+2
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ public void BroadcastSubrootChange(Optional<NitroxId> subrootId)
116116
packetSender.Send(new SubRootChanged(PlayerId.Value, subrootId));
117117
}
118118
}
119+
119120
#if SUBNAUTICA
120121
public void BroadcastEscapePodChange(Optional<NitroxId> escapePodId)
121122
{
@@ -141,6 +142,7 @@ public void BroadcastHeldItemChanged(NitroxId itemId, PlayerHeldItemChanged.Chan
141142
private GameObject CreateBodyPrototype()
142143
{
143144
GameObject prototype = Body;
145+
144146
// Cheap fix for showing head, much easier since male_geo contains many different heads
145147
#if SUBNAUTICA
146148
prototype.GetComponentInParent<Player>().head.shadowCastingMode = ShadowCastingMode.On;

NitroxClient/GameLogic/PlayerLogic/PlayerModel/ColorSwap/ReinforcedSuitColorSwapManager.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using NitroxClient.GameLogic.PlayerLogic.PlayerModel.Abstract;
44
using NitroxClient.GameLogic.PlayerLogic.PlayerModel.ColorSwap.Strategy;

NitroxClient/GameLogic/PlayerLogic/PlayerModel/Equipment/ReinforcedSuitVisibilityHandler.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Collections.ObjectModel;
1+
using System.Collections.ObjectModel;
22
using NitroxClient.GameLogic.PlayerLogic.PlayerModel.Equipment.Abstract;
33
using UnityEngine;
44

NitroxClient/GameLogic/PlayerLogic/PlayerModel/PlayerModelManager.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ public void RegisterEquipmentVisibilityHandler(GameObject playerModel)
3333
{
3434
new DiveSuitVisibilityHandler(playerModel),
3535
new FinsVisibilityHandler(playerModel),
36-
new StillSuitVisibilityHandler(playerModel),
3736
new ReinforcedSuitVisibilityHandler(playerModel),
37+
new StillSuitVisibilityHandler(playerModel),
3838
#if SUBNAUTICA
39-
new RadiationSuitVisibilityHandler(playerModel),
40-
new ScubaSuitVisibilityHandler(playerModel)
39+
new ScubaSuitVisibilityHandler(playerModel),
40+
new RadiationSuitVisibilityHandler(playerModel)
4141
#elif BELOWZERO
42-
new ColdProtectiveSuitVisibilityHandler(playerModel),
43-
new BaseVisibilityHandler(playerModel)
42+
new BaseVisibilityHandler(playerModel),
43+
new ColdProtectiveSuitVisibilityHandler(playerModel)
4444
#endif
4545
};
4646
}

NitroxClient/GameLogic/RemotePlayer.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System.Collections.Generic;
22
using System.Collections.ObjectModel;
3+
#if BELOWZERO
34
using FMODUnity;
5+
#endif
46
using NitroxClient.GameLogic.HUD;
57
using NitroxClient.GameLogic.PlayerLogic;
68
using NitroxClient.GameLogic.PlayerLogic.PlayerModel;
@@ -70,7 +72,6 @@ public void InitializeGameObject(GameObject playerBody)
7072
NitroxEntity.SetNewId(Body, PlayerContext.PlayerNitroxId);
7173

7274
// Get player
73-
PlayerModel = Body.RequireGameObject("player_view");
7475
#if SUBNAUTICA
7576
PlayerModel = Body.RequireGameObject("player_view");
7677
#elif BELOWZERO

NitroxClient/GameLogic/SeamothModulesEvent.cs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#if SUBNAUTICA
12
using NitroxClient.Communication.Abstract;
23
using NitroxModel.DataStructures;
34
using NitroxModel.Packets;
@@ -58,3 +59,4 @@ public void BroadcastElectricalDefense(TechType techType, int slotID, SeaMoth in
5859
}
5960
}
6061
}
62+
#endif

NitroxClient/GameLogic/Spawning/Metadata/Extractor/ExosuitMetadataExtractor.cs

+4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
#if BELOWZERO
12
using System.Linq;
3+
#endif
24
using NitroxClient.GameLogic.Spawning.Metadata.Extractor.Abstract;
35
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
6+
#if BELOWZERO
47
using NitroxModel_Subnautica.DataStructures;
8+
#endif
59

610
namespace NitroxClient.GameLogic.Spawning.Metadata.Extractor;
711

NitroxClient/GameLogic/Spawning/Metadata/Processor/ExosuitMetadataProcessor.cs

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public override void ProcessMetadata(GameObject gameObject, ExosuitMetadata meta
1717
Log.ErrorOnce($"[{nameof(ExosuitMetadataProcessor)}] Could not find {nameof(Exosuit)} on {gameObject}");
1818
return;
1919
}
20+
//TODO: Check login here for subNameInput
2021
#if SUBNAUTICA
2122
if (!gameObject.TryGetComponent(out SubName subName))
2223
{

NitroxClient/GameLogic/Spawning/Metadata/Processor/SubNameInputMetadataProcessor.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
using NitroxModel.Packets;
88
using NitroxModel_Subnautica.DataStructures;
99
using UnityEngine;
10-
using static GameInput;
1110

1211
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
1312

@@ -20,6 +19,7 @@ public override void ProcessMetadata(GameObject gameObject, SubNameInputMetadata
2019
Log.ErrorOnce($"[{nameof(SubNameInputMetadataProcessor)}] Could not find {nameof(SubNameInput)} on {gameObject}");
2120
return;
2221
}
22+
//TODO: Check the naming logic here
2323
#if SUBNAUTICA
2424
SubName subName = subNameInput.target;
2525
if (!subName && !subNameInput.TryGetComponent(out subName))

NitroxClient/MonoBehaviours/CinematicController/RemotePlayerCinematicController.cs

+1
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ public void ManagedLateUpdate()
378378
{
379379
transform = player.Body.GetComponent<Transform>();
380380
}
381+
381382
#if SUBNAUTICA
382383
bool isVrAnimationMode = !GameOptions.GetVrAnimationMode();
383384
#elif BELOWZERO

NitroxClient/MonoBehaviours/FMODEmitterController.cs

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public void LateRegisterEmitter()
4444
}
4545
}
4646
}
47+
4748
#if SUBNAUTICA
4849
public void AddEmitter(string path, FMOD_CustomEmitter customEmitter, float maxDistance)
4950
{

NitroxClient/MonoBehaviours/Multiplayer.cs

-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,6 @@ private static void SetLoadingComplete()
193193
#elif BELOWZERO
194194
WaitScreen.main.Hide();
195195
#endif
196-
197196
WaitScreen.main.items.Clear();
198197

199198
PlayerManager remotePlayerManager = NitroxServiceLocator.LocateService<PlayerManager>();

NitroxClient/MonoBehaviours/MultiplayerExosuit.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using NitroxClient.GameLogic.FMOD;
1+
using NitroxClient.GameLogic.FMOD;
22
using NitroxClient.Unity.Smoothing;
33
using NitroxModel.GameLogic.FMOD;
44
using UnityEngine;
@@ -20,6 +20,7 @@ protected override void Awake()
2020
WheelPitchSetter = value => exosuit.steeringWheelPitch = value;
2121
base.Awake();
2222
SmoothRotation = new ExosuitSmoothRotation(gameObject.transform.rotation);
23+
2324
#if SUBNAUTICA
2425
this.Resolve<FMODWhitelist>().TryGetSoundData(exosuit.loopingJetSound.asset.path, out SoundData jetSoundData);
2526
#elif BELOWZERO

NitroxClient/MonoBehaviours/MultiplayerSeaMoth.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using FMOD.Studio;
1+
using FMOD.Studio;
22
using NitroxModel.GameLogic.FMOD;
33
using UnityEngine;
44

NitroxClient/MonoBehaviours/PlayerStatsBroadcaster.cs

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using NitroxClient.GameLogic;
22
using NitroxClient.Unity.Helper;
3-
using NitroxModel.Core;
43
using UnityEngine;
54

65
namespace NitroxClient.MonoBehaviours;

NitroxLauncher/LauncherConfig.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.ComponentModel;
1+
using System.ComponentModel;
22
using System.Runtime.CompilerServices;
33
using NitroxLauncher.Properties;
44
using NitroxModel.Helper;

NitroxLauncher/LauncherLogic.cs

+17-18
Original file line numberDiff line numberDiff line change
@@ -248,46 +248,45 @@ internal async Task StartMultiplayerAsync()
248248

249249
gameProcess = await StartSubnauticaAsync();
250250
}
251-
#if BELOWZERO
251+
#if SUBNAUTICA
252252
private async Task<ProcessEx> StartSubnauticaAsync()
253253
{
254254
string subnauticaPath = Config.SubnauticaPath;
255255
string subnauticaLaunchArguments = Config.SubnauticaLaunchArguments;
256-
string subnauticaExe = Path.Combine(subnauticaPath, GameInfo.SubnauticaBelowZero.ExeName);
256+
string subnauticaExe = Path.Combine(subnauticaPath, GameInfo.Subnautica.ExeName);
257257
IGamePlatform platform = GamePlatforms.GetPlatformByGameDir(subnauticaPath);
258258

259259
// Start game & gaming platform if needed.
260260
using ProcessEx game = platform switch
261261
{
262-
Steam s => await s.StartGameAsync(subnauticaExe, GameInfo.SubnauticaBelowZero.SteamAppId, subnauticaLaunchArguments),
262+
Steam s => await s.StartGameAsync(subnauticaExe, GameInfo.Subnautica.SteamAppId, subnauticaLaunchArguments),
263263
EpicGames e => await e.StartGameAsync(subnauticaExe, subnauticaLaunchArguments),
264264
MSStore m => await m.StartGameAsync(subnauticaExe),
265265
DiscordStore d => await d.StartGameAsync(subnauticaExe, subnauticaLaunchArguments),
266-
_ => throw new Exception($"Directory '{subnauticaPath}' is not a valid {GameInfo.SubnauticaBelowZero.Name} game installation or the game's platform is unsupported by Nitrox.")
266+
_ => throw new Exception($"Directory '{subnauticaPath}' is not a valid {GameInfo.Subnautica.Name} game installation or the game's platform is unsupported by Nitrox.")
267267
};
268268

269-
return game ?? throw new Exception($"Unable to start game through {platform.Name}");
269+
return game ?? throw new Exception($"Game failed to start through {platform.Name}");
270270
}
271-
#endif
272-
#if SUBNAUTICA
271+
#elif BELOWZERO
273272
private async Task<ProcessEx> StartSubnauticaAsync()
274273
{
275-
string subnauticaPath = Config.SubnauticaPath;
276-
string subnauticaLaunchArguments = Config.SubnauticaLaunchArguments;
277-
string subnauticaExe = Path.Combine(subnauticaPath, GameInfo.Subnautica.ExeName);
278-
IGamePlatform platform = GamePlatforms.GetPlatformByGameDir(subnauticaPath);
279-
274+
string subnauticaBelowZeroPath = Config.SubnauticaPath;
275+
string subnauticaBelowZeroLaunchArguments = Config.SubnauticaLaunchArguments;
276+
string subnauticaBelowZeroExe = Path.Combine(subnauticaBelowZeroPath, GameInfo.SubnauticaBelowZero.ExeName);
277+
IGamePlatform platform = GamePlatforms.GetPlatformByGameDir(subnauticaBelowZeroPath);
278+
280279
// Start game & gaming platform if needed.
281280
using ProcessEx game = platform switch
282281
{
283-
Steam s => await s.StartGameAsync(subnauticaExe, GameInfo.Subnautica.SteamAppId, subnauticaLaunchArguments),
284-
EpicGames e => await e.StartGameAsync(subnauticaExe, subnauticaLaunchArguments),
285-
MSStore m => await m.StartGameAsync(subnauticaExe),
286-
DiscordStore d => await d.StartGameAsync(subnauticaExe, subnauticaLaunchArguments),
287-
_ => throw new Exception($"Directory '{subnauticaPath}' is not a valid {GameInfo.Subnautica.Name} game installation or the game's platform is unsupported by Nitrox.")
282+
Steam s => await s.StartGameAsync(subnauticaBelowZeroExe, GameInfo.SubnauticaBelowZero.SteamAppId, subnauticaBelowZeroLaunchArguments),
283+
EpicGames e => await e.StartGameAsync(subnauticaBelowZeroExe, subnauticaBelowZeroLaunchArguments),
284+
MSStore m => await m.StartGameAsync(subnauticaBelowZeroExe),
285+
DiscordStore d => await d.StartGameAsync(subnauticaBelowZeroExe, subnauticaBelowZeroLaunchArguments),
286+
_ => throw new Exception($"Directory '{subnauticaBelowZeroPath}' is not a valid {GameInfo.SubnauticaBelowZero.Name} game installation or the game's platform is unsupported by Nitrox.")
288287
};
289288

290-
return game ?? throw new Exception($"Game failed to start through {platform.Name}");
289+
return game ?? throw new Exception($"Unable to start game through {platform.Name}");
291290
}
292291
#endif
293292

NitroxModel-Subnautica/DataStructures/DataExtensions.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,10 @@ public static StoryGoalExecuted.EventType ToDto(this Story.GoalType goalType)
140140
Story.GoalType.Radio => StoryGoalExecuted.EventType.RADIO,
141141
Story.GoalType.Encyclopedia => StoryGoalExecuted.EventType.ENCYCLOPEDIA,
142142
Story.GoalType.Story => StoryGoalExecuted.EventType.STORY,
143-
_ => throw new ArgumentException("The provided Story.GoalType doesn't correspond to a StoryEventSend.EventType"),
143+
#if BELOWZERO
144+
Story.GoalType.Call => StoryGoalExecuted.EventType.CALL,
145+
#endif
146+
_ => throw new ArgumentException($"The provided Story.GoalType ({goalType}) doesn't correspond to a StoryEventSend.EventType"),
144147
};
145148
}
146149

@@ -152,7 +155,10 @@ public static Story.GoalType ToUnity(this StoryGoalExecuted.EventType eventType)
152155
StoryGoalExecuted.EventType.RADIO => Story.GoalType.Radio,
153156
StoryGoalExecuted.EventType.ENCYCLOPEDIA => Story.GoalType.Encyclopedia,
154157
StoryGoalExecuted.EventType.STORY => Story.GoalType.Story,
155-
_ => throw new ArgumentException("The provided StoryEventSend.EventType doesn't correspond to a Story.GoalType")
158+
#if BELOWZERO
159+
StoryGoalExecuted.EventType.CALL => Story.GoalType.Call,
160+
#endif
161+
_ => throw new ArgumentException($"The provided StoryEventSend.EventType ({eventType}) doesn't correspond to a Story.GoalType")
156162
};
157163
}
158164

NitroxModel-Subnautica/Helper/SubnauticaMap.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Collections.Generic;
1+
using System.Collections.Generic;
22
using NitroxModel.DataStructures;
33
using NitroxModel.DataStructures.GameLogic;
44
using NitroxModel.Helper;
@@ -24,7 +24,9 @@ public class SubnauticaMap : IMap
2424
new NitroxTechType(nameof(TechType.Gravsphere)),
2525
new NitroxTechType(nameof(TechType.PipeSurfaceFloater)),
2626
new NitroxTechType(nameof(TechType.SmallStorage)),
27+
#if SUBNAUTICA
2728
new NitroxTechType(nameof(TechType.CyclopsDecoy)),
29+
#endif
2830
new NitroxTechType(nameof(TechType.LEDLight)),
2931
new NitroxTechType(nameof(TechType.Beacon))
3032
};

NitroxModel/DataStructures/GameLogic/PlayerStatsData.cs

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ protected PlayerStatsData()
3232
{
3333
// Constructor for serialization. Has to be "protected" for json serialization.
3434
}
35+
3536
#if SUBNAUTICA
3637
public PlayerStatsData(float oxygen, float maxOxygen, float health, float food, float water, float infectionAmount)
3738
#elif BELOWZERO

NitroxModel/Helper/NetHelper.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ public static class NetHelper
3737
public static IEnumerable<NetworkInterface> GetInternetInterfaces()
3838
{
3939
return NetworkInterface.GetAllNetworkInterfaces()
40-
.Where(n => n.Name is "Ethernet" or "Wi-Fi" && n.OperationalStatus is OperationalStatus.Up && n.NetworkInterfaceType is NetworkInterfaceType.Wireless80211 or NetworkInterfaceType.Ethernet)
41-
.OrderBy(n => n.Name == "Ethernet" ? 1 : 0)
40+
.Where(n => n.Name.Contains("Ethernet") || n.Name.Contains("Wi-Fi") && n.OperationalStatus is OperationalStatus.Up && n.NetworkInterfaceType is NetworkInterfaceType.Wireless80211 or NetworkInterfaceType.Ethernet)
41+
.OrderBy(n => n.Name.Contains("Ethernet") ? 1 : 0)
4242
.ThenBy(n => n.Name);
4343
}
4444

0 commit comments

Comments
 (0)