Added more console feed back and fixed the TP command when used on a a player other than the current one. Prepped the animations for modularization. Moved version to 1510.

This commit is contained in:
Twirlbug 2023-07-05 21:02:05 -05:00
parent 1d86b05a62
commit 84419debcf
7 changed files with 242 additions and 117 deletions

View file

@ -1,17 +1,17 @@
# srmp-public
This is the code for the Slime Rancher MultiPlayer Mod (SRMP).
Currently working on going through the code, adding notes and fixing some of the bugs in my free time.
I adore this mod and want to give both credit and a huge thank you to Saty for the origional creation of the mod.
The suer manual can be found [here](/manual.md).
I am slowly working my way through the list of bugs as seen below.
## Bug Status
# Bug Status
Notes: Bug list compiled from last known bug list of version 1488
FIXED:
- Multiplayer window doesn't show up on resolutions < 1920x1080
IN PROGRESS (NEEDS MORE TESTING):
- Exchange sometimes skips rewards if multiple players put items in at the same time
- Exchange chest disappears without rewards
@ -30,20 +30,14 @@ Known Bugs:
- Upgrades sometimes does not get applied to All players
##Current Status
@Twirlbug
- Currently working on going through the code, adding notes and fixing some of the bugs in my free time.
- I adore this mod and want to give both credit and a huge thank you to Saty for the origional creation of the mod.
I am slowly working my way through the list of bugs as seen above.
###Notation Status
Files in the following folders still need more notation:
#Notes Status
Files in the following folders still need notes:
- Networking
- Packets
- Patches
---------------------------------------------------------------------------------
##Origional File From SatyPardus
Origional File From SatyPardus
It's bad. It's really really bad.

View file

@ -290,6 +290,7 @@ namespace SRMultiplayer
//mark target transform location
PacketPlayerPosition packet = null;
string destSummary = "";
//first check distination
switch (destination.ToLower())
@ -304,7 +305,7 @@ namespace SRMultiplayer
RegionSet = (byte)home.GetRegionSetId()
};
destSummary = "Home";
break;
default: //check for a player name
var play = Globals.Players.Values.FirstOrDefault(p => p.Username.Equals(destination, StringComparison.CurrentCultureIgnoreCase));
@ -320,7 +321,7 @@ namespace SRMultiplayer
Rotation = play.transform.eulerAngles.y,
RegionSet = (byte)play.CurrentRegionSet
};
destSummary = play.Username;
break;
}
@ -346,10 +347,12 @@ namespace SRMultiplayer
return;
}
ConsoleLog("Teleporting " + targetPlayer.Username + " to " + destSummary);
if (!targetPlayer.IsLocal)
{
//if a target is located and is not the local player send the teleport command
packet.ID = targetPlayer.ID;
packet.WeaponY = targetPlayer.GetWeaponLocation();
packet.Send();
return;
@ -361,6 +364,8 @@ namespace SRMultiplayer
SRSingleton<SceneContext>.Instance.player.transform.position = packet.Position;
SRSingleton<SceneContext>.Instance.player.transform.eulerAngles = new Vector3(0, packet.Rotation, 0);
SRSingleton<SceneContext>.Instance.PlayerState.model.SetCurrRegionSet((RegionRegistry.RegionSetId)packet.RegionSet);
// play the teleport animation
SRSingleton<Overlay>.Instance.PlayTeleport();
}
}

View file

@ -1,15 +1,12 @@
using DG.Tweening;
using Lidgren.Network;
using MonomiPark.SlimeRancher.DataModel;
using MonomiPark.SlimeRancher.Persist;
using MonomiPark.SlimeRancher.Regions;
using SRMultiplayer.Packets;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace SRMultiplayer.Networking
@ -30,7 +27,7 @@ namespace SRMultiplayer.Networking
case PacketType.PlayerJoined: OnPlayerJoined(new PacketPlayerJoined(im)); break;
case PacketType.PlayerLeft: OnPlayerLeft(new PacketPlayerLeft(im)); break;
case PacketType.PlayerLoaded: OnPlayerLoaded(new PacketPlayerLoaded(im)); break;
case PacketType.PlayerPosition: OnPlayerPosition(new PacketPlayerPosition(im)); break;
case PacketType.PlayerPosition: OnPlayerPosition(new PacketPlayerPosition(im)); break;
case PacketType.PlayerFX: OnPlayerFX(new PacketPlayerFX(im)); break;
case PacketType.PlayerCurrency: OnPlayerCurrency(new PacketPlayerCurrency(im)); break;
case PacketType.PlayerCurrencyDisplay: OnPlayerCurrencyDisplay(new PacketPlayerCurrencyDisplay(im)); break;
@ -151,7 +148,7 @@ namespace SRMultiplayer.Networking
// Race
case PacketType.RaceActivate: OnRaceActivate(new PacketRaceActivate(im)); break;
case PacketType.RaceEnd: OnRaceEnd(new PacketRaceEnd(im)); break;
case PacketType.RaceTime: OnRaceTime(new PacketRaceTime(im)); break;
case PacketType.RaceTime: OnRaceTime(new PacketRaceTime(im)); break;
case PacketType.RaceTrigger: OnRaceTrigger(new PacketRaceTrigger(im)); break;
default:
SRMP.Log($"Got unhandled packet: {type} " + Enum.GetName(typeof(PacketType), type));
@ -372,7 +369,7 @@ namespace SRMultiplayer.Networking
//send off fireworks
SRBehaviour.InstantiateDynamic(eject.awardFX, eject.awardAt.position, eject.awardAt.rotation);
}
//dont clear out the offer yet, we arent done with it
//SRSingleton<SceneContext>.Instance.ExchangeDirector.ClearOffer(type);
}
@ -383,7 +380,7 @@ namespace SRMultiplayer.Networking
}
}
}
private static void OnExchangePrepareDaily(PacketExchangePrepareDaily packet)
private static void OnExchangePrepareDaily(PacketExchangePrepareDaily packet)
{
SRSingleton<SceneContext>.Instance.ExchangeDirector.worldModel.pendingOfferRancherIds = packet.pendingOfferRancherIds;
SRSingleton<SceneContext>.Instance.ExchangeDirector.OfferDidChange();
@ -1940,7 +1937,9 @@ namespace SRMultiplayer.Networking
if(type == PacketPlayerAnimation.AnimationType.Speed)
player.ReadAnimatorSpeed(packet.internalData);
else if (type == PacketPlayerAnimation.AnimationType.Parameters)
{
player.ReadParameters(packet.internalData);
}
else
player.ReadAnimatorLayer(packet.internalData);
}
@ -1954,59 +1953,74 @@ namespace SRMultiplayer.Networking
{
if (player.IsLocal)
{
var euler = SRSingleton<SceneContext>.Instance.player.GetComponentInChildren<WeaponVacuum>().transform.eulerAngles;
euler.x = packet.WeaponY;
SRSingleton<SceneContext>.Instance.player.GetComponentInChildren<WeaponVacuum>().transform.eulerAngles = euler;
SRSingleton<SceneContext>.Instance.player.transform.position = packet.Position;
SRSingleton<SceneContext>.Instance.player.transform.eulerAngles = new Vector3(0, packet.Rotation, 0);
SRSingleton<SceneContext>.Instance.PlayerState.model.SetCurrRegionSet((RegionRegistry.RegionSetId)packet.RegionSet);
//only reload inventory if this is a load up packet and NOT a tp packet
if (!Globals.IsServer && packet.OnLoad)
if (packet.OnLoad)
{
try
var euler = SRSingleton<SceneContext>.Instance.player.GetComponentInChildren<WeaponVacuum>().transform.eulerAngles;
euler.x = packet.WeaponY;
SRSingleton<SceneContext>.Instance.player.GetComponentInChildren<WeaponVacuum>().transform.eulerAngles = euler;
SRSingleton<SceneContext>.Instance.player.transform.position = packet.Position;
SRSingleton<SceneContext>.Instance.player.transform.eulerAngles = new Vector3(0, packet.Rotation, 0);
SRSingleton<SceneContext>.Instance.PlayerState.model.SetCurrRegionSet((RegionRegistry.RegionSetId)packet.RegionSet);
//only reload inventory if this is a load up packet and NOT a tp packet
if (!Globals.IsServer)
{
using (FileStream file = new FileStream(Path.Combine(SRMP.ModDataPath, Globals.CurrentGameName + ".player"), FileMode.Open))
try
{
using (BinaryReader reader = new BinaryReader(file))
using (FileStream file = new FileStream(Path.Combine(SRMP.ModDataPath, Globals.CurrentGameName + ".player"), FileMode.Open))
{
Debug.Log($"Loading {Path.Combine(SRMP.ModDataPath, Globals.CurrentGameName + ".player")}");
var ammoCount = reader.ReadInt32();
for (int i = 0; i < ammoCount; i++)
using (BinaryReader reader = new BinaryReader(file))
{
var state = (PlayerState.AmmoMode)reader.ReadByte();
SRSingleton<SceneContext>.Instance.PlayerState.model.ammoDict[state].usableSlots = reader.ReadInt32();
var slotCount = reader.ReadInt32();
SRSingleton<SceneContext>.Instance.PlayerState.model.ammoDict[state].slots = new Ammo.Slot[slotCount];
for (int j = 0; j < slotCount; j++)
Debug.Log($"Loading {Path.Combine(SRMP.ModDataPath, Globals.CurrentGameName + ".player")}");
var ammoCount = reader.ReadInt32();
for (int i = 0; i < ammoCount; i++)
{
if (reader.ReadBoolean())
var state = (PlayerState.AmmoMode)reader.ReadByte();
SRSingleton<SceneContext>.Instance.PlayerState.model.ammoDict[state].usableSlots = reader.ReadInt32();
var slotCount = reader.ReadInt32();
SRSingleton<SceneContext>.Instance.PlayerState.model.ammoDict[state].slots = new Ammo.Slot[slotCount];
for (int j = 0; j < slotCount; j++)
{
SRSingleton<SceneContext>.Instance.PlayerState.model.ammoDict[state].slots[j] = new Ammo.Slot((Identifiable.Id)reader.ReadUInt16(), reader.ReadInt32());
if (reader.ReadBoolean())
{
SRSingleton<SceneContext>.Instance.PlayerState.model.ammoDict[state].slots[j].emotions = new SlimeEmotionData();
var emotionCount = reader.ReadInt32();
for (int k = 0; k < emotionCount; k++)
SRSingleton<SceneContext>.Instance.PlayerState.model.ammoDict[state].slots[j] = new Ammo.Slot((Identifiable.Id)reader.ReadUInt16(), reader.ReadInt32());
if (reader.ReadBoolean())
{
SRSingleton<SceneContext>.Instance.PlayerState.model.ammoDict[state].slots[j].emotions.Add((SlimeEmotions.Emotion)reader.ReadUInt16(), reader.ReadSingle());
SRSingleton<SceneContext>.Instance.PlayerState.model.ammoDict[state].slots[j].emotions = new SlimeEmotionData();
var emotionCount = reader.ReadInt32();
for (int k = 0; k < emotionCount; k++)
{
SRSingleton<SceneContext>.Instance.PlayerState.model.ammoDict[state].slots[j].emotions.Add((SlimeEmotions.Emotion)reader.ReadUInt16(), reader.ReadSingle());
}
}
}
}
else
{
SRSingleton<SceneContext>.Instance.PlayerState.model.ammoDict[state].slots[j] = null;
else
{
SRSingleton<SceneContext>.Instance.PlayerState.model.ammoDict[state].slots[j] = null;
}
}
}
}
}
}
catch (Exception ex)
{
Debug.Log($"No savefile for {Globals.CurrentGameName}: {ex.Message}");
}
}
catch (Exception ex)
{
Debug.Log($"No savefile for {Globals.CurrentGameName}: {ex.Message}");
}
}
else
{
SRMP.Log("Player is being teleported", "CLIENT");
SRSingleton<SceneContext>.Instance.player.transform.position = packet.Position;
SRSingleton<SceneContext>.Instance.player.transform.eulerAngles = new Vector3(0, packet.Rotation, 0);
SRSingleton<SceneContext>.Instance.PlayerState.model.SetCurrRegionSet((RegionRegistry.RegionSetId)packet.RegionSet);
SRSingleton<Overlay>.Instance.PlayTeleport();
}
}
else

View file

@ -335,7 +335,7 @@ namespace SRMultiplayer.Networking
}
}
packet.SendToAllExcept(player);
}
}
private static void OnExchangePrepareDaily(PacketExchangePrepareDaily packet, NetworkPlayer player)
{
@ -1650,27 +1650,42 @@ namespace SRMultiplayer.Networking
break;
case (byte)PacketPlayerAnimation.AnimationType.Layer:
player.ReadAnimatorLayer(packet.internalData);
break;
break;
case (byte)PacketPlayerAnimation.AnimationType.Parameters:
player.ReadParameters(packet.internalData);
break;
}
//make the incoming message an out going message
packet.SendToAllExcept(player, NetDeliveryMethod.Unreliable);
}
}
private static void OnPlayerPosition(PacketPlayerPosition packet, NetworkPlayer player)
private static void OnPlayerPosition(PacketPlayerPosition packet, NetworkPlayer netPlayer)
{
//get player id from packet in case of a teleport
NetworkPlayer player = Globals.Players.Values.FirstOrDefault(p => p.ID.Equals(packet.ID));
if (player.HasLoaded)
{
player.PositionRotationUpdate(packet.Position, packet.Rotation, false);
player.UpdateWeaponRotation(packet.WeaponY);
player.CurrentRegionSet = (RegionRegistry.RegionSetId)packet.RegionSet;
if (player.IsLocal) //if the server player is the one being moved, teleport them
{
SRSingleton<SceneContext>.Instance.player.transform.position = packet.Position;
SRSingleton<SceneContext>.Instance.player.transform.eulerAngles = new Vector3(0, packet.Rotation, 0);
SRSingleton<SceneContext>.Instance.PlayerState.model.SetCurrRegionSet((RegionRegistry.RegionSetId)packet.RegionSet);
packet.ID = player.ID;
packet.SendToAllExcept(player, NetDeliveryMethod.Unreliable);
SRSingleton<Overlay>.Instance.PlayTeleport();
}
else //else process player movement
{
player.PositionRotationUpdate(packet.Position, packet.Rotation, false);
player.UpdateWeaponRotation(packet.WeaponY);
player.CurrentRegionSet = (RegionRegistry.RegionSetId)packet.RegionSet;
packet.ID = player.ID;
packet.SendToAllExcept(netPlayer, NetDeliveryMethod.Unreliable);
}
}
}

View file

@ -1,12 +1,10 @@
using Lidgren.Network;
using SRMultiplayer.Packets;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using static SRMultiplayer.Packets.PacketPlayerAnimation;
namespace SRMultiplayer.Networking
{
@ -68,37 +66,36 @@ namespace SRMultiplayer.Networking
var packet = new PacketPlayerAnimation()
{
Type = (byte)PacketPlayerAnimation.AnimationType.Layer,
ID = Globals.LocalID,
internalData = new NetBuffer()
ID = Globals.LocalID
};
//add extra parameters
WriteAnimatorLayer(packet.internalData, stateHash, normalizedTime, i, layerWeight[i]);
WriteAnimatorLayer(packet, stateHash, normalizedTime, i, layerWeight[i]);
//send the changes
//packet.Send();
packet.Send();
}
CheckSpeed();
}
void WriteAnimatorLayer(NetBuffer writer, int stateHash, float normalizedTime, int layerNumber, float layerWeight)
void WriteAnimatorLayer(PacketPlayerAnimation writer, int stateHash, float normalizedTime, int layerNumber, float layerWeight)
{
writer.Write(stateHash);
writer.Write(normalizedTime);
writer.Write(layerNumber);
writer.Write(layerWeight);
writer.Add(stateHash);
writer.Add(normalizedTime);
writer.Add(layerNumber);
writer.Add(layerWeight);
WriteParameters(writer);
}
public void ReadAnimatorLayer(NetBuffer im)
public void ReadAnimatorLayer(Queue<animateData> im)
{
if (m_Animator == null) return;
int stateHash = im.ReadInt32();
float normalizedTime = im.ReadFloat();
int layerNumber = im.ReadInt32();
float layerWeight = im.ReadFloat();
int stateHash = im.Dequeue().iData.Value;
float normalizedTime = im.Dequeue().fData.Value;
int layerNumber = im.Dequeue().iData.Value;
float layerWeight = im.Dequeue().fData.Value;
if (stateHash != 0 && m_Animator.enabled)
{
@ -122,28 +119,27 @@ namespace SRMultiplayer.Networking
var packet = new PacketPlayerAnimation()
{
Type = (byte)PacketPlayerAnimation.AnimationType.Speed,
ID = Globals.LocalID,
internalData = new NetBuffer()
ID = Globals.LocalID
};
//add extra parameters
WriteAnimatorSpeed(packet.internalData, newSpeed);
WriteAnimatorSpeed(packet, newSpeed);
//send the speed change
//packet.Send();
packet.Send();
}
}
void WriteAnimatorSpeed(NetBuffer writer, float newSpeed)
void WriteAnimatorSpeed(PacketPlayerAnimation writer, float newSpeed)
{
writer.Write(newSpeed);
writer.Add(newSpeed);
}
public void ReadAnimatorSpeed(NetBuffer im)
public void ReadAnimatorSpeed(Queue<animateData> im)
{
if (m_Animator == null) return;
var newSpeed = im.ReadFloat();
var newSpeed = im.Dequeue().fData.Value;
// set m_Animator
m_Animator.speed = newSpeed;
m_AnimatorSpeed = newSpeed;
@ -203,14 +199,14 @@ namespace SRMultiplayer.Networking
var packet = new PacketPlayerAnimation()
{
Type = (byte)PacketPlayerAnimation.AnimationType.Parameters,
ID = Globals.LocalID,
internalData = new NetBuffer()
ID = Globals.LocalID
};
//add extra parameters
WriteParameters(packet.internalData);
//packet.Send();
if (WriteParameters(packet))
{
packet.Send();
}
}
}
@ -251,10 +247,10 @@ namespace SRMultiplayer.Networking
return dirtyBits;
}
bool WriteParameters(NetBuffer writer, bool forceAll = false)
bool WriteParameters(PacketPlayerAnimation writer, bool forceAll = false)
{
ulong dirtyBits = forceAll ? (~0ul) : NextDirtyBits();
writer.Write(dirtyBits);
writer.Add(dirtyBits);
for (int i = 0; i < parameters.Length; i++)
{
if ((dirtyBits & (1ul << i)) == 0)
@ -264,53 +260,55 @@ namespace SRMultiplayer.Networking
if (par.type == AnimatorControllerParameterType.Int)
{
int newIntValue = m_Animator.GetInteger(par.nameHash);
writer.Write(newIntValue);
writer.Add(newIntValue);
}
else if (par.type == AnimatorControllerParameterType.Float)
{
float newFloatValue = m_Animator.GetFloat(par.nameHash);
writer.Write(newFloatValue);
writer.Add(newFloatValue);
}
else if (par.type == AnimatorControllerParameterType.Bool)
{
bool newBoolValue = m_Animator.GetBool(par.nameHash);
writer.Write(newBoolValue);
writer.Add(newBoolValue);
}
}
return dirtyBits != 0;
}
public void ReadParameters(NetBuffer reader)
{
public void ReadParameters(Queue<animateData> im)
{ //make sure
if (m_Animator == null) return;
bool m_AnimatorEnabled = m_Animator.enabled;
// need to read values from NetworkReader even if m_Animator is disabled
ulong dirtyBits = reader.ReadUInt64();
// need to read values from NetworkReader even if m_Animator is disabled
ulong dirtyBits = im.Dequeue().uData.Value;
for (int i = 0; i < parameters.Length; i++)
{
if ((dirtyBits & (1ul << i)) == 0)
continue;
AnimatorControllerParameter par = parameters[i];
if (par.type == AnimatorControllerParameterType.Int)
{
int newIntValue = reader.ReadInt32();
int? newIntValue = im.Dequeue().iData;
if (m_AnimatorEnabled)
m_Animator.SetInteger(par.nameHash, newIntValue);
m_Animator.SetInteger(par.nameHash, newIntValue.Value);
}
else if (par.type == AnimatorControllerParameterType.Float)
{
float newFloatValue = reader.ReadSingle();
float? newFloatValue = im.Dequeue().fData;
if (m_AnimatorEnabled)
m_Animator.SetFloat(par.nameHash, newFloatValue);
m_Animator.SetFloat(par.nameHash, newFloatValue.Value);
}
else if (par.type == AnimatorControllerParameterType.Bool)
{
bool newBoolValue = reader.ReadBoolean();
bool? newBoolValue = im.Dequeue().bData;
if (m_AnimatorEnabled)
m_Animator.SetBool(par.nameHash, newBoolValue);
m_Animator.SetBool(par.nameHash, newBoolValue.Value);
}
}
}

View file

@ -1,9 +1,12 @@
using Lidgren.Network;
using MonomiPark.SlimeRancher.DataModel;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static SRMultiplayer.Packets.PacketAccessDoors;
namespace SRMultiplayer.Packets
{
@ -20,16 +23,111 @@ namespace SRMultiplayer.Packets
public byte ID;
public byte Type;
public NetBuffer internalData;
public struct animateData
{
public byte type
{
get
{
if (fData.HasValue) return 0;
if (bData.HasValue) return 1;
if (iData.HasValue) return 2;
if (uData.HasValue) return 3;
return 8;
}
}
public float? fData;
public bool? bData;
public int? iData;
public ulong? uData;
}
public Queue<animateData> internalData { get; set; } = new Queue<animateData>();
public void Add<T>(T obj)
{
switch (obj)
{
case float itm:
internalData.Enqueue(new animateData() { fData = itm });
break;
case bool itm:
internalData.Enqueue(new animateData() { bData = itm });
break;
case int itm:
internalData.Enqueue(new animateData() { iData = itm });
break;
case ulong itm:
internalData.Enqueue(new animateData() { uData = itm });
break;
}
}
/// <summary>
/// mark construction inheritance incase we need it
/// </summary>
public PacketPlayerAnimation():base() { }
public PacketPlayerAnimation() : base() { }
/// <summary>
/// mark construction inheritance so the deserialization automatically happens for is
/// since the base decalres this
/// </summary>
public PacketPlayerAnimation(NetIncomingMessage im):base(im) { }
public PacketPlayerAnimation(NetIncomingMessage im) : base(im) { }
public override void Serialize(NetOutgoingMessage om)
{
base.Serialize(om);
om.Write(internalData.Count);
foreach (var data in internalData)
{
om.Write(data.type);
switch (data.type)
{
case 0:
om.Write(data.fData.Value);
break;
case 1:
om.Write(data.bData.Value);
break;
case 2:
om.Write(data.iData.Value);
break;
case 3:
om.Write(data.uData.Value);
break;
}
}
}
public override void Deserialize(NetIncomingMessage im)
{
base.Deserialize(im);
internalData = new Queue<animateData>();
int Count = im.ReadInt32();
for (int i = 0; i < Count; i++)
{
var data = new animateData();
byte type = im.ReadByte();
switch (type)
{
case 0:
data.fData = im.ReadFloat();
break;
case 1:
data.bData = im.ReadBoolean();
break;
case 2:
data.iData = im.ReadInt32();
break;
case 3:
data.uData = im.ReadUInt64();
break;
}
internalData.Enqueue(data);
}
}
}
}

View file

@ -15,6 +15,7 @@ namespace SRMultiplayer.Packets
public float Rotation;
public float WeaponY;
public byte RegionSet;
public bool OnLoad = true;
public PacketPlayerPosition() { }
public PacketPlayerPosition(NetIncomingMessage im) { Deserialize(im); }