diff --git a/.github/scripts/thunderstore_bundle.js b/.github/scripts/thunderstore_bundle.js index aa2a1cac7..b7b4e2f92 100644 --- a/.github/scripts/thunderstore_bundle.js +++ b/.github/scripts/thunderstore_bundle.js @@ -135,7 +135,7 @@ function generateManifest() { function generateApiManifest() { const manifest = { name: apiPluginInfo.name, - description: "API for other mods to work with the Nebula Multiplayer Mod", + description: "API for other mods to work with the Nebula Multiplayer Mod. (Does NOT require Nebula)", version_number: apiPluginInfo.version, dependencies: [ BEPINEX_DEPENDENCY diff --git a/CHANGELOG.md b/CHANGELOG.md index 06eeb8775..becbee9f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ ## Changelog +0.6.0: + +- Fixed cases where a multiplayer session could hang on the player joining screen. +- Fixed issue where foundations built by clients would not sync to other clients. +- Fixed issue where the user would not be informed if they were kicked due to a mod mismatch. +- Enabled pausing in Multiplayer when no clients are connected. (thanks to @starfi5h) +- Now supports DSP version 0.8.21.8562+ (also thanks to @starfi5h!) +- Mecha color configuration has been removed from the options in favor of the new option in the Mecha panel + 0.5.0: - Added API that enables other mods to sync over multiplayer! (Big thanks to @kremnev8!) diff --git a/Directory.Build.props b/Directory.Build.props index e15a63ce0..c1b4ad590 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -46,12 +46,12 @@ - + + - - + diff --git a/Libs/Assembly-CSharp.dll b/Libs/Assembly-CSharp.dll deleted file mode 100644 index c0be65263..000000000 Binary files a/Libs/Assembly-CSharp.dll and /dev/null differ diff --git a/NebulaAPI/CHANGELOG.md b/NebulaAPI/CHANGELOG.md index 0a520df56..3dbe320e9 100644 --- a/NebulaAPI/CHANGELOG.md +++ b/NebulaAPI/CHANGELOG.md @@ -1,5 +1,10 @@ ## Changelog +1.1.0: + +- Float3 IPlayerData.MechaColor has been changed to Float4[] IPlayerData.MechaColors in line with changes introduced in DSP version 0.8.21.8562. +- Edited description. + 1.0.0: - initial release on thunderstore diff --git a/NebulaAPI/DataStructures/Float4.cs b/NebulaAPI/DataStructures/Float4.cs index e99753e33..8f9d865b2 100644 --- a/NebulaAPI/DataStructures/Float4.cs +++ b/NebulaAPI/DataStructures/Float4.cs @@ -26,6 +26,40 @@ public Float4(Quaternion value) w = value.w; } + public Color ToColor() + { + return new Color(x, y, z, w); + } + + public Color32 ToColor32() + { + return new Color32((byte)x, (byte)y, (byte)z, (byte)w); + } + + public static Color32[] ToColor32(Float4[] float4s) + { + Color32[] color32s = new Color32[float4s.Length]; + for (int i = 0; i < float4s.Length; i++) + { + color32s[i] = float4s[i].ToColor32(); + } + return color32s; + } + public static Float4 ToFloat4(Color32 color32) + { + return new Float4(color32.r, color32.g, color32.b, color32.a); + } + + public static Float4[] ToFloat4(Color32[] color32s) + { + Float4[] float4s = new Float4[color32s.Length]; + for (int i = 0; i < color32s.Length; i++) + { + float4s[i] = new Float4(color32s[i].r, color32s[i].g, color32s[i].b, color32s[i].a); + } + return float4s; + } + public void Serialize(INetDataWriter writer) { writer.Put(x); diff --git a/NebulaAPI/GameState/IPlayerData.cs b/NebulaAPI/GameState/IPlayerData.cs index 9941c60f4..bbba2cdc2 100644 --- a/NebulaAPI/GameState/IPlayerData.cs +++ b/NebulaAPI/GameState/IPlayerData.cs @@ -5,7 +5,7 @@ public interface IPlayerData : INetSerializable string Username { get; set; } ushort PlayerId { get; set; } int LocalPlanetId { get; set; } - Float3 MechaColor { get; set; } + Float4[] MechaColors { get; set; } Float3 LocalPlanetPosition { get; set; } Double3 UPosition { get; set; } Float3 Rotation { get; set; } diff --git a/NebulaAPI/version.json b/NebulaAPI/version.json index c2143a858..9f53ebb31 100644 --- a/NebulaAPI/version.json +++ b/NebulaAPI/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "1.0.0", + "version": "1.1.0", "assemblyVersion": { "precision": "build" }, diff --git a/NebulaModel/DataStructures/PlayerData.cs b/NebulaModel/DataStructures/PlayerData.cs index 6b7168f91..6b5e32b21 100644 --- a/NebulaModel/DataStructures/PlayerData.cs +++ b/NebulaModel/DataStructures/PlayerData.cs @@ -8,7 +8,7 @@ public class PlayerData : IPlayerData public string Username { get; set; } public ushort PlayerId { get; set; } public int LocalPlanetId { get; set; } - public Float3 MechaColor { get; set; } + public Float4[] MechaColors { get; set; } public Float3 LocalPlanetPosition { get; set; } public Double3 UPosition { get; set; } public Float3 Rotation { get; set; } @@ -17,13 +17,13 @@ public class PlayerData : IPlayerData public int LocalStarId { get; set; } public PlayerData() { } - public PlayerData(ushort playerId, int localPlanetId, Float3 mechaColor, string username = null, Float3 localPlanetPosition = new Float3(), Double3 position = new Double3(), Float3 rotation = new Float3(), Float3 bodyRotation = new Float3()) + public PlayerData(ushort playerId, int localPlanetId, Float4[] mechaColors, string username = null, Float3 localPlanetPosition = new Float3(), Double3 position = new Double3(), Float3 rotation = new Float3(), Float3 bodyRotation = new Float3()) { PlayerId = playerId; LocalPlanetId = localPlanetId; + MechaColors = mechaColors; Username = !string.IsNullOrWhiteSpace(username) ? username : $"Player {playerId}"; LocalPlanetPosition = localPlanetPosition; - MechaColor = mechaColor; UPosition = position; Rotation = rotation; BodyRotation = bodyRotation; @@ -35,7 +35,11 @@ public void Serialize(INetDataWriter writer) writer.Put(Username); writer.Put(PlayerId); writer.Put(LocalPlanetId); - MechaColor.Serialize(writer); + writer.Put(MechaColors?.Length ?? 0); + for (int i = 0; i < (MechaColors?.Length ?? 0); i++) + { + MechaColors[i].Serialize(writer); + } LocalPlanetPosition.Serialize(writer); UPosition.Serialize(writer); Rotation.Serialize(writer); @@ -48,7 +52,11 @@ public void Deserialize(INetDataReader reader) Username = reader.GetString(); PlayerId = reader.GetUShort(); LocalPlanetId = reader.GetInt(); - MechaColor = reader.GetFloat3(); + MechaColors = new Float4[reader.GetInt()]; + for (int i = 0; i < MechaColors.Length; i++) + { + MechaColors[i] = reader.GetFloat4(); + } LocalPlanetPosition = reader.GetFloat3(); UPosition = reader.GetDouble3(); Rotation = reader.GetFloat3(); @@ -59,7 +67,7 @@ public void Deserialize(INetDataReader reader) public IPlayerData CreateCopyWithoutMechaData() { - return new PlayerData(PlayerId, LocalPlanetId, MechaColor, Username, LocalPlanetPosition, UPosition, Rotation, BodyRotation); + return new PlayerData(PlayerId, LocalPlanetId, MechaColors, Username, LocalPlanetPosition, UPosition, Rotation, BodyRotation); } } } diff --git a/NebulaModel/MultiplayerOptions.cs b/NebulaModel/MultiplayerOptions.cs index 982438c32..ebf12662e 100644 --- a/NebulaModel/MultiplayerOptions.cs +++ b/NebulaModel/MultiplayerOptions.cs @@ -1,4 +1,5 @@ -using NebulaModel.Attributes; +using NebulaAPI; +using NebulaModel.Attributes; using System; using System.ComponentModel; @@ -10,18 +11,6 @@ public class MultiplayerOptions : ICloneable [DisplayName("Nickname")] public string Nickname { get; set; } = string.Empty; - [DisplayName("Mecha Color Red")] - [UIRange(0, 255, true)] - public float MechaColorR { get; set; } = 255; - - [DisplayName("Mecha Color Green")] - [UIRange(0, 255, true)] - public float MechaColorG { get; set; } = 174; - - [DisplayName("Mecha Color Blue")] - [UIRange(0, 255, true)] - public float MechaColorB { get; set; } = 61; - [DisplayName("Host Port")] [UIRange(1, ushort.MaxValue)] public ushort HostPort { get; set; } = 8469; @@ -31,6 +20,38 @@ public class MultiplayerOptions : ICloneable public string LastIP { get; set; } = string.Empty; + public string MechaColors { get; set; } = "209 151 76 255;184 90 72 255;94 92 92 255;123 234 255 255;229 155 94 255;255 243 235 255;255 248 245 255;255 255 255 255;"; + + public Float4[] GetMechaColors() + { + string[] colors = MechaColors.Split(';'); + Float4[] mechaColors = new Float4[colors.Length - 1]; + for (int i = 0; i < colors.Length - 1; i++) + { + string[] color = colors[i].Split(' '); + if (!float.TryParse(color[0], out mechaColors[i].x) || + !float.TryParse(color[1], out mechaColors[i].y) || + !float.TryParse(color[2], out mechaColors[i].z) || + !float.TryParse(color[3], out mechaColors[i].w)) + { + Logger.Log.Error($"Color {i} is invalid."); + } + } + return mechaColors; + } + + public void SetMechaColors() + { + UnityEngine.Color32[] mainColors = GameMain.mainPlayer.mecha.mainColors; + string mechaColors = string.Empty; + for (int i = 0; i < mainColors.Length; i++) + { + mechaColors += $"{(int)mainColors[i].r} {(int)mainColors[i].g} {(int)mainColors[i].b} {(int)mainColors[i].a};"; + } + MechaColors = mechaColors; + Config.SaveOptions(); + } + // Detail function group buttons public bool PowerGridEnabled { get; set; } = false; public bool VeinDistributionEnabled { get; set; } = false; @@ -41,7 +62,7 @@ public class MultiplayerOptions : ICloneable public object Clone() { - return this.MemberwiseClone(); + return MemberwiseClone(); } } } diff --git a/NebulaModel/Packets/Players/PlayerAnimationUpdate.cs b/NebulaModel/Packets/Players/PlayerAnimationUpdate.cs index ca34c1edb..28e116dbd 100644 --- a/NebulaModel/Packets/Players/PlayerAnimationUpdate.cs +++ b/NebulaModel/Packets/Players/PlayerAnimationUpdate.cs @@ -1,5 +1,7 @@ using NebulaAPI; using NebulaModel.DataStructures; +using Unity; +using UnityEngine; namespace NebulaModel.Packets.Players { @@ -7,23 +9,41 @@ namespace NebulaModel.Packets.Players public class PlayerAnimationUpdate { public ushort PlayerId { get; set; } + public float JumpWeight { get; set; } + public float JumpNormalizedTime { get; set; } + public int IdleAnimIndex { get; set; } + public int SailAnimIndex { get; set; } + public float MiningWeight { get; set; } + public int MiningAnimIndex { get; set; } - // TODO: They don't use a finite state machine for there animation. But we need to find a way to optimized this packet. - // maybe we could only send the variables that are used to changed the animation state. - // See: (Game: PlayerAnimator class) - public NebulaAnimationState Idle { get; set; } - public NebulaAnimationState RunSlow { get; set; } - public NebulaAnimationState RunFast { get; set; } - public NebulaAnimationState Drift { get; set; } - public NebulaAnimationState DriftF { get; set; } - public NebulaAnimationState DriftL { get; set; } - public NebulaAnimationState DriftR { get; set; } - public NebulaAnimationState Fly { get; set; } - public NebulaAnimationState Sail { get; set; } - public NebulaAnimationState Mining0 { get; set; } - // some extra values to compute backpack flame size - // i put them here because i update the player fx together with the animation update - public float vertSpeed { get; set; } - public float horzSpeed { get; set; } + public EMovementState MovementState { get; set; } + public float HorzSpeed { get; set; } + public float VertSpeed { get; set; } + public float Turning { get; set; } + public float Altitude { get; set; } + + public PlayerAnimationUpdate() { } + + public PlayerAnimationUpdate(ushort playerId, PlayerAnimator animator) + { + PlayerId = playerId; + + JumpWeight = animator.jumpWeight; + JumpNormalizedTime = animator.jumpNormalizedTime; + IdleAnimIndex = animator.idleAnimIndex; + SailAnimIndex = animator.sailAnimIndex; + MiningWeight = animator.miningWeight; + MiningAnimIndex = animator.miningAnimIndex; + + MovementState = animator.movementState; + HorzSpeed = animator.controller.horzSpeed; + VertSpeed = animator.controller.vertSpeed; + Turning = animator.turning; + Altitude = 1f; + if (GameMain.localPlanet != null) + { + Altitude = Mathf.Clamp01((animator.player.position.magnitude - GameMain.localPlanet.realRadius - 7f) * 0.15f); + } + } } } diff --git a/NebulaModel/Packets/Players/PlayerColorChanged.cs b/NebulaModel/Packets/Players/PlayerColorChanged.cs index 91f66045d..3c26cfb67 100644 --- a/NebulaModel/Packets/Players/PlayerColorChanged.cs +++ b/NebulaModel/Packets/Players/PlayerColorChanged.cs @@ -5,13 +5,13 @@ namespace NebulaModel.Packets.Players public class PlayerColorChanged { public ushort PlayerId { get; set; } - public Float3 Color { get; set; } + public Float4[] Colors { get; set; } public PlayerColorChanged() { } - public PlayerColorChanged(ushort playerID, Float3 color) + public PlayerColorChanged(ushort playerID, Float4[] colors) { PlayerId = playerID; - Color = color; + Colors = colors; } } } diff --git a/NebulaModel/Packets/Session/HandshakeRequest.cs b/NebulaModel/Packets/Session/HandshakeRequest.cs index d69c24fd1..d7444b346 100644 --- a/NebulaModel/Packets/Session/HandshakeRequest.cs +++ b/NebulaModel/Packets/Session/HandshakeRequest.cs @@ -6,7 +6,7 @@ namespace NebulaModel.Packets.Session public class HandshakeRequest { public string Username { get; set; } - public Float3 MechaColor { get; set; } + public Float4[] MechaColors { get; set; } public byte[] ModsVersion { get; set; } public int ModsCount { get; set; } public int GameVersionSig { get; set; } @@ -14,15 +14,15 @@ public class HandshakeRequest public HandshakeRequest() { } - public HandshakeRequest(byte[] clientCert, string username, Float3 mechaColor) + public HandshakeRequest(byte[] clientCert, string username, Float4[] mechaColors) { Username = username; - MechaColor = mechaColor; + MechaColors = mechaColors; using (BinaryUtils.Writer writer = new BinaryUtils.Writer()) { int count = 0; - foreach (var pluginInfo in BepInEx.Bootstrap.Chainloader.PluginInfos) + foreach (System.Collections.Generic.KeyValuePair pluginInfo in BepInEx.Bootstrap.Chainloader.PluginInfos) { if (pluginInfo.Value.Instance is IMultiplayerMod mod) { diff --git a/NebulaNetwork/Client.cs b/NebulaNetwork/Client.cs index 1cce3f040..8b9df2481 100644 --- a/NebulaNetwork/Client.cs +++ b/NebulaNetwork/Client.cs @@ -161,7 +161,7 @@ private void ClientSocket_OnOpen(object sender, System.EventArgs e) SendPacket(new HandshakeRequest( CryptoUtils.GetPublicKey(CryptoUtils.GetOrCreateUserCert()), !string.IsNullOrWhiteSpace(Config.Options.Nickname) ? Config.Options.Nickname : GameMain.data.account.userName, - new Float3(Config.Options.MechaColorR / 255, Config.Options.MechaColorG / 255, Config.Options.MechaColorB / 255))); + Config.Options.GetMechaColors())); } private void ClientSocket_OnClose(object sender, CloseEventArgs e) diff --git a/NebulaNetwork/PacketProcessors/Players/PlayerColorChangedProcessor.cs b/NebulaNetwork/PacketProcessors/Players/PlayerColorChangedProcessor.cs index 9fa668a71..d49a18409 100644 --- a/NebulaNetwork/PacketProcessors/Players/PlayerColorChangedProcessor.cs +++ b/NebulaNetwork/PacketProcessors/Players/PlayerColorChangedProcessor.cs @@ -9,7 +9,7 @@ namespace NebulaNetwork.PacketProcessors.Players [RegisterPacketProcessor] public class PlayerColorChangedProcessor : PacketProcessor { - private IPlayerManager playerManager; + private readonly IPlayerManager playerManager; public PlayerColorChangedProcessor() { @@ -25,7 +25,7 @@ public override void ProcessPacket(PlayerColorChanged packet, NebulaConnection c INebulaPlayer player = playerManager.GetPlayer(conn); if (player != null) { - player.Data.MechaColor = packet.Color; + player.Data.MechaColors = packet.Colors; playerManager.SendPacketToOtherPlayers(packet, player); } else @@ -36,7 +36,7 @@ public override void ProcessPacket(PlayerColorChanged packet, NebulaConnection c if (valid) { - Multiplayer.Session.World.UpdatePlayerColor(packet.PlayerId, packet.Color); + Multiplayer.Session.World.UpdatePlayerColor(packet.PlayerId, packet.Colors); } } } diff --git a/NebulaNetwork/PacketProcessors/Session/HandshakeRequestProcessor.cs b/NebulaNetwork/PacketProcessors/Session/HandshakeRequestProcessor.cs index 5fd2d2ee5..6b0492b70 100644 --- a/NebulaNetwork/PacketProcessors/Session/HandshakeRequestProcessor.cs +++ b/NebulaNetwork/PacketProcessors/Session/HandshakeRequestProcessor.cs @@ -112,7 +112,7 @@ public override void ProcessPacket(HandshakeRequest packet, NebulaConnection con player.Data.Username = !string.IsNullOrWhiteSpace(packet.Username) ? packet.Username : $"Player {player.Id}"; // Add the Mecha Color to the player data - player.Data.MechaColor = packet.MechaColor; + player.Data.MechaColors = packet.MechaColors; // Make sure that each player that is currently in the game receives that a new player as join so they can create its RemotePlayerCharacter PlayerJoining pdata = new PlayerJoining((PlayerData)player.Data.CreateCopyWithoutMechaData()); // Remove inventory from mecha data diff --git a/NebulaNetwork/PlayerManager.cs b/NebulaNetwork/PlayerManager.cs index f19431910..6db92eeac 100644 --- a/NebulaNetwork/PlayerManager.cs +++ b/NebulaNetwork/PlayerManager.cs @@ -9,7 +9,6 @@ using NebulaWorld; using System.Collections.Generic; using System.Threading; -using Config = NebulaModel.Config; namespace NebulaNetwork { @@ -227,9 +226,8 @@ public INebulaPlayer PlayerConnected(INebulaConnection conn) // Generate new data for the player ushort playerId = GetNextAvailablePlayerId(); - Float3 playerColor = new Float3(Config.Options.MechaColorR / 255, Config.Options.MechaColorG / 255, Config.Options.MechaColorB / 255); PlanetData birthPlanet = GameMain.galaxy.PlanetById(GameMain.galaxy.birthPlanetId); - PlayerData playerData = new PlayerData(playerId, -1, playerColor, position: new Double3(birthPlanet.uPosition.x, birthPlanet.uPosition.y, birthPlanet.uPosition.z)); + PlayerData playerData = new PlayerData(playerId, -1, Config.Options.GetMechaColors(), position: new Double3(birthPlanet.uPosition.x, birthPlanet.uPosition.y, birthPlanet.uPosition.z)); INebulaPlayer newPlayer = new NebulaPlayer((NebulaConnection)conn, playerData); using (GetPendingPlayers(out Dictionary pendingPlayers)) diff --git a/NebulaNetwork/Server.cs b/NebulaNetwork/Server.cs index 0738c7279..1a91619ec 100644 --- a/NebulaNetwork/Server.cs +++ b/NebulaNetwork/Server.cs @@ -18,9 +18,9 @@ namespace NebulaNetwork { public class Server : NetworkProvider { - const float GAME_STATE_UPDATE_INTERVAL = 1; - const float GAME_RESEARCH_UPDATE_INTERVAL = 2; - const float STATISTICS_UPDATE_INTERVAL = 1; + private const float GAME_STATE_UPDATE_INTERVAL = 1; + private const float GAME_RESEARCH_UPDATE_INTERVAL = 2; + private const float STATISTICS_UPDATE_INTERVAL = 1; private float gameStateUpdateTimer = 0; private float gameResearchHashUpdateTimer = 0; @@ -69,7 +69,7 @@ public override void Start() ((LocalPlayer)Multiplayer.Session.LocalPlayer).SetPlayerData(new PlayerData( PlayerManager.GetNextAvailablePlayerId(), GameMain.localPlanet?.id ?? -1, - new Float3(Config.Options.MechaColorR / 255, Config.Options.MechaColorG / 255, Config.Options.MechaColorB / 255), + Config.Options.GetMechaColors(), !string.IsNullOrWhiteSpace(Config.Options.Nickname) ? Config.Options.Nickname : GameMain.data.account.userName), loadSaveFile); NebulaModAPI.OnMultiplayerGameStarted?.Invoke(); @@ -148,7 +148,7 @@ public override void Update() PacketProcessor.ProcessPacketQueue(); } - void DisableNagleAlgorithm(WebSocketServer socketServer) + private void DisableNagleAlgorithm(WebSocketServer socketServer) { TcpListener listener = AccessTools.FieldRefAccess("_listener")(socketServer); listener.Server.NoDelay = true; @@ -190,7 +190,9 @@ protected override void OnClose(CloseEventArgs e) // we don't need to inform the other clients since the disconnected client never // joined the game in the first place. if (e.Code == (short)DisconnectionReason.HostStillLoading) + { return; + } NebulaModel.Logger.Log.Info($"Client disconnected: {ID}, reason: {e.Reason}"); UnityDispatchQueue.RunOnMainThread(() => diff --git a/NebulaPatcher/Patches/Dynamic/UIMechaWindow_Patch.cs b/NebulaPatcher/Patches/Dynamic/UIMechaWindow_Patch.cs new file mode 100644 index 000000000..92271a7f6 --- /dev/null +++ b/NebulaPatcher/Patches/Dynamic/UIMechaWindow_Patch.cs @@ -0,0 +1,25 @@ +using HarmonyLib; +using NebulaAPI; +using NebulaModel; +using NebulaModel.Packets.Players; +using NebulaWorld; + +namespace NebulaPatcher.Patches.Dynamic +{ + [HarmonyPatch(typeof(UIMechaWindow))] + internal class UIMechaWindow_Patch + { + [HarmonyPostfix] + [HarmonyPatch(nameof(UIMechaWindow._OnClose))] + public static void _OnClose_Postfix() + { + if (!Multiplayer.IsActive) + { + return; + } + + Multiplayer.Session.Network.SendPacket(new PlayerColorChanged(Multiplayer.Session.LocalPlayer.Id, Float4.ToFloat4(GameMain.mainPlayer.mecha.mainColors))); + Config.Options.SetMechaColors(); + } + } +} diff --git a/NebulaPatcher/Patches/Transpilers/PowerSystem_Transpiler.cs b/NebulaPatcher/Patches/Transpilers/PowerSystem_Transpiler.cs index 99c413b28..cef6345eb 100644 --- a/NebulaPatcher/Patches/Transpilers/PowerSystem_Transpiler.cs +++ b/NebulaPatcher/Patches/Transpilers/PowerSystem_Transpiler.cs @@ -7,15 +7,15 @@ namespace NebulaPatcher.Patches.Transpilers { [HarmonyPatch(typeof(PowerSystem))] - class PowerSystem_Transpiler + internal class PowerSystem_Transpiler { - delegate void PlayerChargesAtTower(PowerSystem _this, int powerNodeId, int powerNetId); + private delegate void PlayerChargesAtTower(PowerSystem _this, int powerNodeId, int powerNetId); [HarmonyTranspiler] [HarmonyPatch(nameof(PowerSystem.GameTick))] public static IEnumerable PowerSystem_GameTick_Transpiler(IEnumerable instructions) { - instructions = new CodeMatcher(instructions) + CodeMatcher codeMatcher = new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PowerSystem), nameof(PowerSystem.nodePool))), @@ -26,10 +26,18 @@ public static IEnumerable PowerSystem_GameTick_Transpiler(IEnum new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldelema), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PowerNodeComponent), nameof(PowerNodeComponent.workEnergyPerTick))), - new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(PowerNodeComponent), nameof(PowerNodeComponent.requiredEnergy)))) + new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(PowerNodeComponent), nameof(PowerNodeComponent.requiredEnergy)))); + + if (codeMatcher.IsInvalid) + { + NebulaModel.Logger.Log.Error("PowerSystem_GameTick_Transpiler 1 failed. Mod version not compatible with game version."); + return instructions; + } + + codeMatcher = codeMatcher .Advance(1) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 58)) + .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 59)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 22)) .Insert(HarmonyLib.Transpilers.EmitDelegate((PowerSystem _this, int powerNodeId, int powerNetId) => { @@ -71,13 +79,21 @@ public static IEnumerable PowerSystem_GameTick_Transpiler(IEnum new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldelema), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PowerNodeComponent), nameof(PowerNodeComponent.idleEnergyPerTick))), - new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(PowerNodeComponent), nameof(PowerNodeComponent.requiredEnergy)))) + new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(PowerNodeComponent), nameof(PowerNodeComponent.requiredEnergy)))); + + if (codeMatcher.IsInvalid) + { + NebulaModel.Logger.Log.Error("PowerSystem_GameTick_Transpiler 2 failed. Mod version not compatible with game version."); + return codeMatcher.InstructionEnumeration(); + } + + return codeMatcher .Repeat(matcher => { matcher .Advance(1) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 58)) + .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 59)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 22)) .Insert(HarmonyLib.Transpilers.EmitDelegate((PowerSystem _this, int powerNodeId, int powerNetId) => { @@ -109,8 +125,6 @@ public static IEnumerable PowerSystem_GameTick_Transpiler(IEnum })); }) .InstructionEnumeration(); - - return instructions; } } } diff --git a/NebulaWorld/MonoBehaviours/Local/LocalPlayerAnimation.cs b/NebulaWorld/MonoBehaviours/Local/LocalPlayerAnimation.cs index db7eef289..f53833922 100644 --- a/NebulaWorld/MonoBehaviours/Local/LocalPlayerAnimation.cs +++ b/NebulaWorld/MonoBehaviours/Local/LocalPlayerAnimation.cs @@ -1,5 +1,4 @@ -using NebulaModel.DataStructures; -using NebulaModel.Packets.Players; +using NebulaModel.Packets.Players; using UnityEngine; namespace NebulaWorld.MonoBehaviours.Local @@ -24,28 +23,7 @@ void Update() if (time >= BROADCAST_INTERVAL) { time = 0; - - PlayerController controller = playerAnimator.player.controller; - float vertSpeed = Vector3.Dot(base.transform.up, controller.velocity); - Vector3 horzVel = controller.velocity - vertSpeed * base.transform.up; - float horzSpeed = horzVel.magnitude; - - Multiplayer.Session.Network.SendPacket(new PlayerAnimationUpdate() - { - PlayerId = Multiplayer.Session.LocalPlayer.Id, - Idle = playerAnimator.idle.ToNebula(), - RunSlow = playerAnimator.runSlow.ToNebula(), - RunFast = playerAnimator.runFast.ToNebula(), - Drift = playerAnimator.drift.ToNebula(), - DriftF = playerAnimator.driftF.ToNebula(), - DriftL = playerAnimator.driftL.ToNebula(), - DriftR = playerAnimator.driftR.ToNebula(), - Fly = playerAnimator.fly.ToNebula(), - Sail = playerAnimator.sail.ToNebula(), - Mining0 = playerAnimator.mining0.ToNebula(), - horzSpeed = horzSpeed, - vertSpeed = vertSpeed, - }); + Multiplayer.Session.Network.SendPacket(new PlayerAnimationUpdate(Multiplayer.Session.LocalPlayer.Id, playerAnimator)); } } } diff --git a/NebulaWorld/MonoBehaviours/Remote/RemotePlayerAnimation.cs b/NebulaWorld/MonoBehaviours/Remote/RemotePlayerAnimation.cs index ce1586bfc..92a29dbae 100644 --- a/NebulaWorld/MonoBehaviours/Remote/RemotePlayerAnimation.cs +++ b/NebulaWorld/MonoBehaviours/Remote/RemotePlayerAnimation.cs @@ -1,5 +1,4 @@ -using NebulaModel.DataStructures; -using NebulaModel.Packets.Players; +using NebulaModel.Packets.Players; using UnityEngine; namespace NebulaWorld.MonoBehaviours.Remote @@ -7,73 +6,119 @@ namespace NebulaWorld.MonoBehaviours.Remote // TODO: Missing client side interpolation public class RemotePlayerAnimation : MonoBehaviour { - private Animation anim; + public PlayerAnimator PlayerAnimator; - public AnimationState Idle { get; private set; } - public AnimationState RunSlow { get; private set; } - public AnimationState RunFast { get; private set; } - public AnimationState Drift { get; private set; } - public AnimationState DriftF { get; private set; } - public AnimationState DriftL { get; private set; } - public AnimationState DriftR { get; private set; } - public AnimationState Fly { get; private set; } - public AnimationState Sail { get; private set; } - public AnimationState Mining0 { get; private set; } + private float altitude; private void Awake() { - anim = GetComponentInChildren(); + PlayerAnimator = GetComponentInChildren(); + } + + public void UpdateState(PlayerAnimationUpdate packet) + { + if (PlayerAnimator == null) + { + return; + } + + PlayerAnimator.jumpWeight = packet.JumpWeight; + PlayerAnimator.jumpNormalizedTime = packet.JumpNormalizedTime; + PlayerAnimator.idleAnimIndex = packet.IdleAnimIndex; + PlayerAnimator.sailAnimIndex = packet.SailAnimIndex; + PlayerAnimator.miningWeight = packet.MiningWeight; + PlayerAnimator.miningAnimIndex = packet.MiningAnimIndex; + + PlayerAnimator.movementState = packet.MovementState; + PlayerAnimator.horzSpeed = packet.HorzSpeed; + PlayerAnimator.turning = packet.Turning; + altitude = packet.Altitude; + + float deltaTime = Time.deltaTime; + CalculateMovementStateWeights(PlayerAnimator, deltaTime); + CalculateDirectionWeights(PlayerAnimator, deltaTime); + + PlayerAnimator.AnimateIdleState(deltaTime); + PlayerAnimator.AnimateRunState(deltaTime); + PlayerAnimator.AnimateDriftState(deltaTime); + AnimateFlyState(PlayerAnimator); + AnimateSailState(PlayerAnimator); - Idle = anim["idle"]; - RunSlow = anim["run-slow"]; - RunFast = anim["run-fast"]; - Drift = anim["drift"]; - DriftF = anim["drift-f"]; - DriftL = anim["drift-l"]; - DriftR = anim["drift-r"]; - Fly = anim["fly"]; - Sail = anim["sail"]; - Mining0 = anim["mining-0"]; + PlayerAnimator.AnimateJumpState(deltaTime); + PlayerAnimator.AnimateSkills(deltaTime); + AnimateRenderers(PlayerAnimator); + } + + private void CalculateMovementStateWeights(PlayerAnimator animator, float dt) + { + float runTarget = (animator.horzSpeed > 0.15f) ? 1f : 0f; + float driftTarget = (animator.movementState >= EMovementState.Drift) ? 1f : 0f; + float flyTarget = (animator.movementState >= EMovementState.Fly) ? 1f : 0f; + float sailTarget = (animator.movementState >= EMovementState.Sail) ? 1f : 0f; + animator.runWeight = Mathf.MoveTowards(animator.runWeight, runTarget, dt / 0.22f); + animator.driftWeight = Mathf.MoveTowards(animator.driftWeight, driftTarget, dt / 0.2f); + animator.flyWeight = Mathf.MoveTowards(animator.flyWeight, flyTarget, dt / ((flyTarget > 0.5) ? 0.4f : 0.2f)); + animator.sailWeight = Mathf.MoveTowards(animator.sailWeight, sailTarget, dt / ((sailTarget > 0.5) ? 0.8f : 0.2f)); + for (int i = 0; i < animator.sails.Length; i++) + { + animator.sailAnimWeights[i] = Mathf.MoveTowards(animator.sailAnimWeights[i], (i == animator.sailAnimIndex) ? 1f : 0f, dt / 0.3f); + } + } + + private void CalculateDirectionWeights(PlayerAnimator animator, float dt) + { + animator.leftWeight = Mathf.InverseLerp(-animator.minTurningAngle, -animator.maxTurningAngle, animator.turning); + animator.rightWeight = Mathf.InverseLerp(animator.minTurningAngle, animator.maxTurningAngle, animator.turning); + animator.forwardWeight = Mathf.Clamp01(1f - animator.leftWeight - animator.rightWeight); + float num = Mathf.Clamp01((animator.horzSpeed - 0.01f) / ((animator.movementState == EMovementState.Drift) ? 5f : 12.5f)); + animator.forwardWeight *= num; + animator.leftWeight *= num; + animator.rightWeight *= num; + animator.zeroWeight = 1f - animator.forwardWeight - animator.leftWeight - animator.rightWeight; + } - Idle.layer = 0; - RunSlow.layer = 1; - RunFast.layer = 1; - Drift.layer = 2; - DriftF.layer = 2; - DriftL.layer = 2; - DriftR.layer = 2; - Fly.layer = 3; - Sail.layer = 3; - Mining0.layer = 4; - Idle.weight = 1f; - RunSlow.weight = 0.0f; - RunFast.weight = 0.0f; - Drift.weight = 0.0f; - Fly.weight = 0.0f; - Sail.weight = 0.0f; - Mining0.weight = 0.0f; - Mining0.speed = 0.8f; + public void AnimateFlyState(PlayerAnimator animator) + { + bool flag = animator.flyWeight > 0.001f; + animator.fly_0.enabled = flag; + animator.fly_f.enabled = flag; + animator.fly_l.enabled = flag; + animator.fly_r.enabled = flag; + animator.fly_0.weight = altitude * animator.flyWeight * animator.zeroWeight; + animator.fly_f.weight = altitude * animator.flyWeight * animator.forwardWeight; + animator.fly_l.weight = altitude * animator.flyWeight * animator.leftWeight; + animator.fly_r.weight = altitude * animator.flyWeight * animator.rightWeight; + animator.fly_0.speed = 0.44f; + animator.fly_f.speed = 0.44f; + animator.fly_l.speed = 0.44f; + animator.fly_r.speed = 0.44f; + if (!flag) + { + animator.fly_0.normalizedTime = 0f; + animator.fly_f.normalizedTime = 0f; + animator.fly_l.normalizedTime = 0f; + animator.fly_r.normalizedTime = 0f; + } } - public void UpdateState(PlayerAnimationUpdate packet) + public void AnimateSailState(PlayerAnimator animator) { - ApplyAnimationState(Idle, packet.Idle); - ApplyAnimationState(RunSlow, packet.RunSlow); - ApplyAnimationState(RunFast, packet.RunFast); - ApplyAnimationState(Drift, packet.Drift); - ApplyAnimationState(DriftF, packet.DriftF); - ApplyAnimationState(DriftL, packet.DriftL); - ApplyAnimationState(DriftR, packet.DriftR); - ApplyAnimationState(Fly, packet.Fly); - ApplyAnimationState(Sail, packet.Sail); - ApplyAnimationState(Mining0, packet.Mining0); + bool flag = animator.sailWeight > 0.001f; + for (int i = 0; i < animator.sails.Length; i++) + { + animator.sails[i].weight = altitude * animator.sailWeight * animator.sailAnimWeights[i]; + animator.sails[i].enabled = flag; + animator.sails[i].speed = 1f; + if (!flag) + { + animator.sails[i].normalizedTime = 0f; + } + } } - private void ApplyAnimationState(AnimationState animState, NebulaAnimationState newState) + public void AnimateRenderers(PlayerAnimator animator) { - animState.weight = newState.Weight; - animState.speed = newState.Speed; - animState.enabled = newState.Enabled; + animator.inst_armor_mat.SetVector("_InitPositionSet", transform.position); } } } diff --git a/NebulaWorld/MonoBehaviours/Remote/RemotePlayerEffects.cs b/NebulaWorld/MonoBehaviours/Remote/RemotePlayerEffects.cs index e3eadbe3a..a90590231 100644 --- a/NebulaWorld/MonoBehaviours/Remote/RemotePlayerEffects.cs +++ b/NebulaWorld/MonoBehaviours/Remote/RemotePlayerEffects.cs @@ -5,7 +5,7 @@ namespace NebulaWorld.MonoBehaviours.Remote { public class RemoteWarpEffect : MonoBehaviour - { + { private Transform rootTransform; private VFWarpEffect warpEffect = null; @@ -39,11 +39,11 @@ public class RemoteWarpEffect : MonoBehaviour Vector4[] warpRotations; Vector3 velocity; - RemotePlayerAnimation rootAnimation = null; + PlayerAnimator rootAnimation = null; public void Awake() { rootTransform = GetComponent(); - rootAnimation = GetComponent(); + rootAnimation = GetComponent(); warpEffect = Instantiate(Configs.builtin.warpEffectPrefab, GetComponent()); warpEffect.enabled = false; @@ -124,7 +124,7 @@ private void ToggleEffect(bool toggle) public void StartWarp() { - if (!rootAnimation.Sail.enabled || isWarping) + if (rootAnimation.sailWeight <= 0.001f || isWarping) { return; } @@ -134,7 +134,7 @@ public void StartWarp() public void StopWarp() { - if (!rootAnimation.Sail.enabled || !isWarping) + if (rootAnimation.sailWeight <= 0.001f || !isWarping) { return; } @@ -205,16 +205,17 @@ public void Update() astrosMat.SetFloat("_Multiplier", astrosMul * num2); nebulasMat.SetFloat("_Multiplier", nebulasMul * num2); } + } + public class RemotePlayerEffects : MonoBehaviour { - private RemotePlayerAnimation rootAnimation; + private PlayerAnimator rootAnimation; private Transform rootTransform; private Transform rootModelTransform; private RemoteWarpEffect rootWarp; private ParticleSystem[] WaterEffect; - private ParticleSystem[][] FootSmokeEffect; private ParticleSystem[] FootSmallSmoke; private ParticleSystem[] FootLargeSmoke; private ParticleSystem[] FootEffect; @@ -238,7 +239,7 @@ public class RemotePlayerEffects : MonoBehaviour public void Awake() { - rootAnimation = GetComponent(); + rootAnimation = GetComponentInChildren(); rootTransform = GetComponent(); rootModelTransform = rootTransform.Find("Model"); @@ -247,13 +248,11 @@ public void Awake() torchEffect = rootModelTransform.Find("bip/pelvis/spine-1/spine-2/spine-3/r-clavicle/r-upper-arm/r-forearm/r-torch/vfx-torch/blast").GetComponent(); FootEffect = new ParticleSystem[2]; WaterEffect = new ParticleSystem[2]; - FootSmokeEffect = new ParticleSystem[2][]; - FootSmokeEffect[0] = new ParticleSystem[2]; - FootSmokeEffect[1] = new ParticleSystem[2]; FootSmallSmoke = new ParticleSystem[2]; FootLargeSmoke = new ParticleSystem[2]; - Transform VFX = rootModelTransform.Find("bip/pelvis/spine-1/spine-2/spine-3/backpack/VFX").GetComponent(); + + Transform VFX = rootModelTransform.Find("bip/pelvis/spine-1/spine-2/spine-3/backpack/backpack_end/VFX").GetComponent(); psys[0] = VFX.GetChild(0).GetComponent(); psys[1] = VFX.GetChild(1).GetComponent(); @@ -261,18 +260,15 @@ public void Awake() psysr[0] = VFX.GetChild(0).Find("flames").GetComponent(); psysr[1] = VFX.GetChild(1).Find("flames").GetComponent(); - WaterEffect[0] = rootModelTransform.Find("bip/pelvis/l-thigh/l-calf/l-ankle/l-foot/vfx-footsteps/water").GetComponent(); - WaterEffect[1] = rootModelTransform.Find("bip/pelvis/r-thigh/r-calf/r-ankle/r-foot/vfx-footsteps/water").GetComponent(); - FootSmokeEffect[0][0] = rootModelTransform.Find("bip/pelvis/l-thigh/l-calf/l-ankle/l-foot/vfx-footsteps/smoke").GetComponent(); - FootSmokeEffect[0][1] = rootModelTransform.Find("bip/pelvis/l-thigh/l-calf/l-ankle/l-foot/vfx-footsteps/smoke-2").GetComponent(); - FootSmokeEffect[1][0] = rootModelTransform.Find("bip/pelvis/r-thigh/r-calf/r-ankle/r-foot/vfx-footsteps/smoke").GetComponent(); - FootSmokeEffect[1][1] = rootModelTransform.Find("bip/pelvis/r-thigh/r-calf/r-ankle/r-foot/vfx-footsteps/smoke-2").GetComponent(); - FootEffect[0] = rootModelTransform.Find("bip/pelvis/l-thigh/l-calf/l-ankle/l-foot/vfx-footsteps").GetComponent(); - FootEffect[1] = rootModelTransform.Find("bip/pelvis/r-thigh/r-calf/r-ankle/r-foot/vfx-footsteps").GetComponent(); - FootSmallSmoke[0] = rootModelTransform.Find("bip/pelvis/l-thigh/l-calf/l-ankle/l-foot/vfx-footsteps/smoke").GetComponent(); - FootSmallSmoke[1] = rootModelTransform.Find("bip/pelvis/r-thigh/r-calf/r-ankle/r-foot/vfx-footsteps/smoke").GetComponent(); - FootLargeSmoke[0] = rootModelTransform.Find("bip/pelvis/l-thigh/l-calf/l-ankle/l-foot/vfx-footsteps/smoke-2").GetComponent(); - FootLargeSmoke[1] = rootModelTransform.Find("bip/pelvis/r-thigh/r-calf/r-ankle/r-foot/vfx-footsteps/smoke-2").GetComponent(); + + WaterEffect[0] = rootModelTransform.Find("bip/pelvis/l-thigh/l-calf/l-ankle/l-foot/l-foot_end/vfx-footsteps/water").GetComponent(); + WaterEffect[1] = rootModelTransform.Find("bip/pelvis/r-thigh/r-calf/r-ankle/r-foot/r-foot_end/vfx-footsteps/water").GetComponent(); + FootEffect[0] = rootModelTransform.Find("bip/pelvis/l-thigh/l-calf/l-ankle/l-foot/l-foot_end/vfx-footsteps").GetComponent(); + FootEffect[1] = rootModelTransform.Find("bip/pelvis/r-thigh/r-calf/r-ankle/r-foot/r-foot_end/vfx-footsteps").GetComponent(); + FootSmallSmoke[0] = rootModelTransform.Find("bip/pelvis/l-thigh/l-calf/l-ankle/l-foot/l-foot_end/vfx-footsteps/smoke").GetComponent(); + FootSmallSmoke[1] = rootModelTransform.Find("bip/pelvis/r-thigh/r-calf/r-ankle/r-foot/r-foot_end/vfx-footsteps/smoke").GetComponent(); + FootLargeSmoke[0] = rootModelTransform.Find("bip/pelvis/l-thigh/l-calf/l-ankle/l-foot/l-foot_end/vfx-footsteps/smoke-2").GetComponent(); + FootLargeSmoke[1] = rootModelTransform.Find("bip/pelvis/r-thigh/r-calf/r-ankle/r-foot/r-foot_end/vfx-footsteps/smoke-2").GetComponent(); solidSoundEvents[0] = "footsteps-0"; solidSoundEvents[1] = "footsteps-1"; @@ -340,13 +336,13 @@ private bool IsGrounded() private void PlayFootsteps() { - float moveWeight = Mathf.Max(1f, Mathf.Pow(rootAnimation.RunSlow.weight + rootAnimation.RunFast.weight, 2f)); - bool trigger = (rootAnimation.RunSlow.enabled || rootAnimation.RunFast.enabled) && moveWeight > 0.15f; + float moveWeight = Mathf.Max(1f, Mathf.Pow(rootAnimation.run_slow.weight + rootAnimation.run_fast.weight, 2f)); + bool trigger = (rootAnimation.run_slow.enabled || rootAnimation.run_fast.enabled) && moveWeight > 0.15f; if (trigger) { - int normalizedTime = Mathf.FloorToInt(rootAnimation.RunFast.normalizedTime * 2f - 0.02f); - float normalizedTimeDiff = (rootAnimation.RunFast.normalizedTime * 2f - 0.02f) - (float)normalizedTime; + int normalizedTime = Mathf.FloorToInt(rootAnimation.run_fast.normalizedTime * 2f - 0.02f); + float normalizedTimeDiff = (rootAnimation.run_fast.normalizedTime * 2f - 0.02f) - (float)normalizedTime; bool timeIsEven = normalizedTime % 2 == 0; if (lastTriggeredFood != normalizedTime) @@ -439,7 +435,7 @@ private void PlayFootstepEffect(bool lr, float biomo, bool water) } ParticleSystem waterParticle = (!lr) ? WaterEffect[0] : WaterEffect[1]; - ParticleSystem[] smokeParticle = (!lr) ? FootSmokeEffect[0] : FootSmokeEffect[1]; + ParticleSystem[] smokeParticle = (!lr) ? FootSmallSmoke : FootLargeSmoke; ParticleSystem footEffect = (!lr) ? FootEffect[0] : FootEffect[1]; AmbientDesc ambientDesc = GameMain.galaxy.PlanetById(localPlanetId).ambientDesc; Color color = Color.clear; @@ -588,7 +584,7 @@ private void UpdateExtraSoundEffects(PlayerAnimationUpdate packet) tmpMaxAltitude = 1000f; } - if (rootAnimation.RunSlow.enabled || rootAnimation.RunFast.enabled || rootAnimation.Drift.enabled || rootAnimation.DriftF.enabled || rootAnimation.DriftR.enabled || rootAnimation.DriftL.enabled) + if (rootAnimation.runWeight > 0.001f || rootAnimation.driftWeight > 0.001f) { bool ground = IsGrounded(); @@ -622,7 +618,7 @@ private void UpdateExtraSoundEffects(PlayerAnimationUpdate packet) } // NOTE: the pPhys can only be loaded if the player trying to load it has the planet actually loaded (meaning he is on the same planet or near it) - if (pPhys != null && pFactory != null && packet.horzSpeed > 5f) + if (pPhys != null && pFactory != null && packet.HorzSpeed > 5f) { int number = Physics.OverlapSphereNonAlloc(base.transform.localPosition, 1.8f, collider, 1024, QueryTriggerInteraction.Collide); for (int i = 0; i < number; i++) @@ -655,8 +651,8 @@ private void UpdateExtraSoundEffects(PlayerAnimationUpdate packet) public void UpdateState(PlayerAnimationUpdate packet) { - bool anyMovingAnimationActive = rootAnimation.RunSlow.enabled || rootAnimation.RunFast.enabled || rootAnimation.Fly.enabled || rootAnimation.Sail.enabled || rootAnimation.Drift.enabled || rootAnimation.DriftF.enabled || rootAnimation.DriftL.enabled || rootAnimation.DriftR.enabled || !IsGrounded(); - bool anyDriftActive = rootAnimation.Drift.enabled || rootAnimation.DriftR.enabled || rootAnimation.DriftL.enabled || rootAnimation.DriftF.enabled; + bool anyMovingAnimationActive = rootAnimation.runWeight > 0.001f || rootAnimation.flyWeight > 0.001f || rootAnimation.sailWeight > 0.001f || rootAnimation.driftWeight > 0.001f || !IsGrounded(); + bool anyDriftActive = rootAnimation.driftWeight > 0.001f; bool fireParticleOkay = psys != null && psysr != null && (psys[0] != null && psys[1] != null && psysr[0] != null && psysr[1] != null); if (anyMovingAnimationActive) @@ -664,7 +660,7 @@ public void UpdateState(PlayerAnimationUpdate packet) UpdateExtraSoundEffects(packet); if (fireParticleOkay) { - if ((!rootAnimation.RunSlow.enabled && !rootAnimation.RunFast.enabled) || anyDriftActive || rootAnimation.Sail.enabled) + if ((!rootAnimation.run_slow.enabled && !rootAnimation.run_fast.enabled) || anyDriftActive || rootAnimation.sailWeight > 0.001f) { for (int i = 0; i < psys.Length; i++) { @@ -688,20 +684,20 @@ public void UpdateState(PlayerAnimationUpdate packet) } for (int i = 0; i < psysr.Length; i++) { - if (rootAnimation.RunSlow.enabled || rootAnimation.RunFast.enabled) + if (rootAnimation.run_slow.enabled || rootAnimation.run_fast.enabled) { - if (rootAnimation.RunFast.weight != 0) + if (rootAnimation.run_fast.weight != 0) { // when flying over the planet - psysr[i].lengthScale = Mathf.Lerp(-3.5f, -8f, Mathf.Max(packet.horzSpeed, packet.vertSpeed) * 0.04f); + psysr[i].lengthScale = Mathf.Lerp(-3.5f, -8f, Mathf.Max(packet.HorzSpeed, packet.VertSpeed) * 0.04f); } else { // when "walking" over water and moving in air without button press or while "walking" over water - psysr[i].lengthScale = Mathf.Lerp(-3.5f, -8f, Mathf.Max(packet.horzSpeed, packet.vertSpeed) * 0.03f); + psysr[i].lengthScale = Mathf.Lerp(-3.5f, -8f, Mathf.Max(packet.HorzSpeed, packet.VertSpeed) * 0.03f); } } - if (rootAnimation.Drift.enabled) + if (rootAnimation.drift_0.enabled) { // when in air without pressing spacebar psysr[i].lengthScale = -3.5f; @@ -719,10 +715,10 @@ public void UpdateState(PlayerAnimationUpdate packet) driftAudio = null; } } - if (rootAnimation.Fly.enabled) + if (rootAnimation.fly_0.enabled) { // when pressing spacebar but also when landing (Drift is disabled when landing) - psysr[i].lengthScale = Mathf.Lerp(-3.5f, -10f, Mathf.Max(packet.horzSpeed, packet.vertSpeed) * 0.03f); + psysr[i].lengthScale = Mathf.Lerp(-3.5f, -10f, Mathf.Max(packet.HorzSpeed, packet.VertSpeed) * 0.03f); if (flyAudio0 == null) { flyAudio0 = VFAudio.Create("fly-atmos", base.transform, Vector3.zero, false); @@ -737,9 +733,9 @@ public void UpdateState(PlayerAnimationUpdate packet) flyAudio0 = null; } } - if (rootAnimation.Sail.enabled) + if (rootAnimation.sailWeight > 0.001f) { - psysr[i].lengthScale = Mathf.Lerp(-3.5f, -10f, Mathf.Max(packet.horzSpeed, packet.vertSpeed) * 15f); + psysr[i].lengthScale = Mathf.Lerp(-3.5f, -10f, Mathf.Max(packet.HorzSpeed, packet.VertSpeed) * 15f); if (flyAudio1 == null) { flyAudio1 = VFAudio.Create("fly-space", base.transform, Vector3.zero, false); @@ -772,7 +768,7 @@ public void UpdateState(PlayerAnimationUpdate packet) } } - if (torchEffect != null && rootAnimation.Mining0.weight > 0.99f) + if (torchEffect != null && rootAnimation.miningWeight > 0.99f) { if (!torchEffect.isPlaying && miningAudio == null) { @@ -781,7 +777,7 @@ public void UpdateState(PlayerAnimationUpdate packet) miningAudio?.Play(); } } - else if (torchEffect != null && rootAnimation.Mining0.weight <= 0.99f) + else if (torchEffect != null && rootAnimation.miningWeight <= 0.99f) { if (torchEffect.isPlaying) { @@ -796,5 +792,6 @@ public void UpdatePlanet(int localPlanet) { localPlanetId = localPlanet; } + } } diff --git a/NebulaWorld/RemotePlayerModel.cs b/NebulaWorld/RemotePlayerModel.cs index a8d41482e..add1b9e31 100644 --- a/NebulaWorld/RemotePlayerModel.cs +++ b/NebulaWorld/RemotePlayerModel.cs @@ -35,7 +35,6 @@ public RemotePlayerModel(ushort playerId, string username) Object.Destroy(PlayerTransform.GetComponent()); Object.Destroy(PlayerTransform.GetComponent()); Object.Destroy(PlayerTransform.GetComponent()); - Object.Destroy(PlayerTransform.GetComponent()); Object.Destroy(PlayerTransform.GetComponent()); PlayerTransform.GetComponent().isKinematic = true; @@ -43,6 +42,9 @@ public RemotePlayerModel(ushort playerId, string username) Movement = PlayerTransform.gameObject.AddComponent(); Animator = PlayerTransform.gameObject.AddComponent(); Effects = PlayerTransform.gameObject.AddComponent(); + + PlayerTransform.GetComponent().Start(); + PlayerTransform.GetComponent().enabled = false; } PlayerTransform.gameObject.name = $"Remote Player ({playerId})"; diff --git a/NebulaWorld/SimulatedWorld.cs b/NebulaWorld/SimulatedWorld.cs index b1bb8f3d6..b8599d0ea 100644 --- a/NebulaWorld/SimulatedWorld.cs +++ b/NebulaWorld/SimulatedWorld.cs @@ -20,7 +20,7 @@ namespace NebulaWorld /// public class SimulatedWorld : IDisposable { - sealed class ThreadSafe + private sealed class ThreadSafe { internal readonly Dictionary RemotePlayersModels = new Dictionary(); } @@ -31,8 +31,10 @@ sealed class ThreadSafe private LocalPlayerMovement localPlayerMovement; private LocalPlayerAnimation localPlayerAnimation; - public Locker GetRemotePlayersModels(out Dictionary remotePlayersModels) => - threadSafe.RemotePlayersModels.GetLocked(out remotePlayersModels); + public Locker GetRemotePlayersModels(out Dictionary remotePlayersModels) + { + return threadSafe.RemotePlayersModels.GetLocked(out remotePlayersModels); + } public bool IsPlayerJoining { get; set; } @@ -43,9 +45,9 @@ public SimulatedWorld() public void Dispose() { - using (GetRemotePlayersModels(out var remotePlayersModels)) + using (GetRemotePlayersModels(out Dictionary remotePlayersModels)) { - foreach (var model in remotePlayersModels.Values) + foreach (RemotePlayerModel model in remotePlayersModels.Values) { model.Destroy(); } @@ -55,6 +57,7 @@ public void Dispose() UnityEngine.Object.Destroy(localPlayerMovement); UnityEngine.Object.Destroy(localPlayerAnimation); + SetPauseIndicator(true); } public void SetupInitialPlayerState() @@ -74,7 +77,7 @@ public void SetupInitialPlayerState() LocalPlayer player = Multiplayer.Session.LocalPlayer as LocalPlayer; // Assign our own color - UpdatePlayerColor(Multiplayer.Session.LocalPlayer.Id, player.Data.MechaColor); + UpdatePlayerColor(Multiplayer.Session.LocalPlayer.Id, player.Data.MechaColors); // If not a new client, we need to update the player position to put him where he was previously if (player.IsClient && !player.IsNewPlayer) @@ -154,7 +157,7 @@ public void OnAllPlayersSyncCompleted() public void SpawnRemotePlayerModel(IPlayerData playerData) { - using (GetRemotePlayersModels(out var remotePlayersModels)) + using (GetRemotePlayersModels(out Dictionary remotePlayersModels)) { if (!remotePlayersModels.ContainsKey(playerData.PlayerId)) { @@ -163,12 +166,12 @@ public void SpawnRemotePlayerModel(IPlayerData playerData) } } - UpdatePlayerColor(playerData.PlayerId, playerData.MechaColor); + UpdatePlayerColor(playerData.PlayerId, playerData.MechaColors); } public void DestroyRemotePlayerModel(ushort playerId) { - using (GetRemotePlayersModels(out var remotePlayersModels)) + using (GetRemotePlayersModels(out Dictionary remotePlayersModels)) { if (remotePlayersModels.TryGetValue(playerId, out RemotePlayerModel player)) { @@ -184,7 +187,7 @@ public void DestroyRemotePlayerModel(ushort playerId) public void UpdateRemotePlayerPosition(PlayerMovement packet) { - using (GetRemotePlayersModels(out var remotePlayersModels)) + using (GetRemotePlayersModels(out Dictionary remotePlayersModels)) { if (remotePlayersModels.TryGetValue(packet.PlayerId, out RemotePlayerModel player)) { @@ -195,11 +198,12 @@ public void UpdateRemotePlayerPosition(PlayerMovement packet) public void UpdateRemotePlayerAnimation(PlayerAnimationUpdate packet) { - using (GetRemotePlayersModels(out var remotePlayersModels)) + using (GetRemotePlayersModels(out Dictionary remotePlayersModels)) { if (remotePlayersModels.TryGetValue(packet.PlayerId, out RemotePlayerModel player)) { player.Animator.UpdateState(packet); + player.Effects.UpdateState(packet); } } @@ -207,9 +211,13 @@ public void UpdateRemotePlayerAnimation(PlayerAnimationUpdate packet) public void UpdateRemotePlayerWarpState(PlayerUseWarper packet) { - using (GetRemotePlayersModels(out var remotePlayersModels)) + using (GetRemotePlayersModels(out Dictionary remotePlayersModels)) { - if (packet.PlayerId == 0) packet.PlayerId = 1; // host sends himself as PlayerId 0 but clients see him as id 1 + if (packet.PlayerId == 0) + { + packet.PlayerId = 1; // host sends himself as PlayerId 0 but clients see him as id 1 + } + if (remotePlayersModels.TryGetValue(packet.PlayerId, out RemotePlayerModel player)) { if (packet.WarpCommand) @@ -226,14 +234,14 @@ public void UpdateRemotePlayerWarpState(PlayerUseWarper packet) public void UpdateRemotePlayerDrone(NewDroneOrderPacket packet) { - using (GetRemotePlayersModels(out var remotePlayersModels)) + using (GetRemotePlayersModels(out Dictionary remotePlayersModels)) { if (remotePlayersModels.TryGetValue(packet.PlayerId, out RemotePlayerModel player)) { //Setup drone of remote player based on the drone data ref MechaDrone drone = ref player.PlayerInstance.mecha.drones[packet.DroneId]; MechaDroneLogic droneLogic = player.PlayerInstance.mecha.droneLogic; - var tmpFactory = droneLogic.factory; + PlanetFactory tmpFactory = droneLogic.factory; droneLogic.factory = GameMain.galaxy.PlanetById(packet.PlanetId).factory; @@ -266,48 +274,61 @@ public void UpdateRemotePlayerDrone(NewDroneOrderPacket packet) } } - public void UpdatePlayerColor(ushort playerId, Float3 color) + public void UpdatePlayerColor(ushort playerId, Float4[] colors) { - using (GetRemotePlayersModels(out var remotePlayersModels)) + if (colors == null || colors.Length == 0) { - Transform transform; + return; + } + + using (GetRemotePlayersModels(out Dictionary remotePlayersModels)) + { + PlayerAnimator playerAnimator; if (playerId == Multiplayer.Session.LocalPlayer.Id) { - transform = GameMain.data.mainPlayer.transform; + playerAnimator = GameMain.data.mainPlayer.animator; } else if (remotePlayersModels.TryGetValue(playerId, out RemotePlayerModel remotePlayerModel)) { - transform = remotePlayerModel.PlayerTransform; + playerAnimator = remotePlayerModel.Animator.PlayerAnimator; } else { - Log.Error("Could not find the transform for player with ID " + playerId); + Log.Error("Could not find the playerAnimator for player with ID " + playerId); return; } - Log.Info($"Changing color of player {playerId} to {color}"); - - // Apply new color to each part of the mecha - SkinnedMeshRenderer[] componentsInChildren = transform.gameObject.GetComponentsInChildren(); - foreach (Renderer r in componentsInChildren) + Log.Info($"Changing color of player {playerId}"); + for (int i = 0; i < colors.Length; i++) { - if (r.material != null && r.material.name.StartsWith("icarus-armor", System.StringComparison.Ordinal)) - { - r.material.SetColor("_Color", color.ToColor()); - } + Log.Info($"Color {i}: {colors[i]}"); } + playerAnimator.inst_armor_mat.SetColor("_Color", colors[0].ToColor() / 255); + playerAnimator.inst_armor_mat.SetColor("_Color2", colors[1].ToColor() / 255); + playerAnimator.inst_armor_mat.SetColor("_Color3", colors[2].ToColor() / 255); + playerAnimator.inst_armor_mat.SetColor("_SpecularColor", colors[5].ToColor() / 255); + playerAnimator.inst_armor_mat.SetColor("_SpecularColor3", colors[6].ToColor() / 255); + playerAnimator.inst_skelt_mat.SetColor("_Color", colors[0].ToColor() / 255); + playerAnimator.inst_skelt_mat.SetColor("_Color2", colors[1].ToColor() / 255); + playerAnimator.inst_skelt_mat.SetColor("_Color3", colors[2].ToColor() / 255); + playerAnimator.inst_skelt_mat.SetColor("_SpecularColor", colors[5].ToColor() / 255); + playerAnimator.inst_skelt_mat.SetColor("_SpecularColor3", colors[6].ToColor() / 255); + playerAnimator.inst_armor_light_mat.SetColor("_EmissionMask", colors[3].ToColor() / 255); + playerAnimator.inst_skelt_light_mat.SetColor("_EmissionMask", colors[4].ToColor() / 255); + // We changed our own color, so we have to let others know if (Multiplayer.Session.LocalPlayer.Id == playerId) { - Multiplayer.Session.Network.SendPacket(new PlayerColorChanged(playerId, color)); + GameMain.mainPlayer.mecha.mainColors = Float4.ToColor32(colors); + Multiplayer.Session.Network.SendPacket(new PlayerColorChanged(playerId, colors)); } } } public int GenerateTrashOnPlayer(TrashSystemNewTrashCreatedPacket packet) { - using (GetRemotePlayersModels(out var remotePlayersModels)) + using (GetRemotePlayersModels(out Dictionary remotePlayersModels)) { if (remotePlayersModels.TryGetValue(packet.PlayerId, out RemotePlayerModel player)) { @@ -338,7 +359,7 @@ public int GenerateTrashOnPlayer(TrashSystemNewTrashCreatedPacket packet) public void OnDronesDraw() { - using (GetRemotePlayersModels(out var remotePlayersModels)) + using (GetRemotePlayersModels(out Dictionary remotePlayersModels)) { foreach (KeyValuePair remoteModel in remotePlayersModels) { @@ -356,17 +377,17 @@ public void OnDronesGameTick(float dt) double tmp = 1e10; //fake energy of remote player, needed to do the Update() double tmp2 = 1; - using (GetRemotePlayersModels(out var remotePlayersModels)) + using (GetRemotePlayersModels(out Dictionary remotePlayersModels)) { //Update drones positions based on their targets - var prebuildPool = GameMain.localPlanet?.factory?.prebuildPool; + PrebuildData[] prebuildPool = GameMain.localPlanet?.factory?.prebuildPool; foreach (KeyValuePair remoteModel in remotePlayersModels) { Mecha remoteMecha = remoteModel.Value.MechaInstance; MechaDrone[] drones = remoteMecha.drones; int droneCount = remoteMecha.droneCount; - var remotePosition = remoteModel.Value.Movement.GetLastPosition().LocalPlanetPosition.ToVector3(); + Vector3 remotePosition = remoteModel.Value.Movement.GetLastPosition().LocalPlanetPosition.ToVector3(); for (int i = 0; i < droneCount; i++) { @@ -393,9 +414,9 @@ public void RenderPlayerNameTagsOnStarmap(UIStarmap starmap) Text starmap_playerNameText = starmap.playerNameText; Transform starmap_playerTrack = starmap.playerTrack; - using (GetRemotePlayersModels(out var remotePlayersModels)) + using (GetRemotePlayersModels(out Dictionary remotePlayersModels)) { - foreach (var player in remotePlayersModels) + foreach (KeyValuePair player in remotePlayersModels) { RemotePlayerModel playerModel = player.Value; @@ -450,13 +471,13 @@ public void RenderPlayerNameTagsOnStarmap(UIStarmap starmap) if (playerModel.Movement.localPlanetId > 0) { PlanetData planet = GameMain.galaxy.PlanetById(playerModel.Movement.localPlanetId); - var rotation = planet.runtimeRotation * + Quaternion rotation = planet.runtimeRotation * Quaternion.LookRotation(playerModel.PlayerModelTransform.forward, playerModel.Movement.GetLastPosition().LocalPlanetPosition.ToVector3()); starmapTracker.rotation = rotation; } else { - var rotation = Quaternion.LookRotation(playerModel.PlayerModelTransform.forward, playerModel.PlayerTransform.localPosition); + Quaternion rotation = Quaternion.LookRotation(playerModel.PlayerModelTransform.forward, playerModel.PlayerTransform.localPosition); starmapTracker.rotation = rotation; } @@ -472,9 +493,9 @@ public void RenderPlayerNameTagsOnStarmap(UIStarmap starmap) public void ClearPlayerNameTagsOnStarmap() { - using (GetRemotePlayersModels(out var remotePlayersModels)) + using (GetRemotePlayersModels(out Dictionary remotePlayersModels)) { - foreach (var player in remotePlayersModels) + foreach (KeyValuePair player in remotePlayersModels) { // Destroy the marker and name so they don't linger and cause problems GameObject.Destroy(player.Value.StarmapNameText.gameObject); @@ -491,9 +512,9 @@ public void RenderPlayerNameTagsInGame() { TextMesh uiSailIndicator_targetText = null; - using (GetRemotePlayersModels(out var remotePlayersModels)) + using (GetRemotePlayersModels(out Dictionary remotePlayersModels)) { - foreach (var player in remotePlayersModels) + foreach (KeyValuePair player in remotePlayersModels) { RemotePlayerModel playerModel = player.Value; @@ -543,8 +564,8 @@ public void RenderPlayerNameTagsInGame() playerNameText.transform.rotation = GameCamera.main.transform.rotation; // Resizes the text based on distance from camera for better visual quality - var distanceFromCamera = Vector3.Distance(playerNameText.transform.position, GameCamera.main.transform.position); - var nameTextMesh = playerNameText.GetComponent(); + float distanceFromCamera = Vector3.Distance(playerNameText.transform.position, GameCamera.main.transform.position); + TextMesh nameTextMesh = playerNameText.GetComponent(); if (distanceFromCamera > 100f) { @@ -608,9 +629,9 @@ public void UpdatePingIndicator(string text) public void SetPauseIndicator(bool canPause) { //Tell the user if the game is paused or not - var targetObject = GameObject.Find("UI Root/Overlay Canvas/In Game/Esc Menu/pause-text"); - var pauseText = targetObject?.GetComponent(); - var pauseLocalizer = targetObject?.GetComponent(); + GameObject targetObject = GameObject.Find("UI Root/Overlay Canvas/In Game/Esc Menu/pause-text"); + Text pauseText = targetObject?.GetComponent(); + Localizer pauseLocalizer = targetObject?.GetComponent(); if (pauseText && pauseLocalizer) { if (!canPause) @@ -624,7 +645,7 @@ public void SetPauseIndicator(bool canPause) pauseLocalizer.stringKey = "游戏已暂停".Translate(); } } - + } } } diff --git a/nuget.config b/nuget.config index 4b1385e40..1864ded52 100644 --- a/nuget.config +++ b/nuget.config @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/version.json b/version.json index ff6748a6d..9c966362d 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "0.5.0", + "version": "0.6.0", "assemblyVersion": { "precision": "build" },