Merge pull request #3 from Twirlbug/main

Version 1510
This commit is contained in:
Saty 2023-07-07 16:30:27 +02:00 committed by GitHub
commit 7327368999
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 5501 additions and 661 deletions

1
.gitignore vendored
View file

@ -329,3 +329,4 @@ ASALocalRun/
# MFractors (Xamarin productivity tool) working folder
.mfractor/
/SRMP/_info.txt

Binary file not shown.

BIN
Libs/Newtonsoft.Json.dll Normal file

Binary file not shown.

BIN
Libs/SRML.Editor.dll Normal file

Binary file not shown.

BIN
Libs/SRML.dll Normal file

Binary file not shown.

3810
Libs/SRML.xml Normal file

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -1,21 +1,42 @@
# srmp-public
This is the code for the Slime Rancher MultiPlayer Mod (SRMP) by SatyPardus.
It's bad. It's really really bad.
The user manual which includes information about compatability information, download and installation instructions and standard troubleshooting can be found [here](/manual.md).
There is so much to clean up in this project, I would not even know where to begin.
Kinda the reason why it's already uploaded. No idea where and how to clean it up.
But this is the source code of my Slime Rancher Multiplayer mod.
It went through many iterations and each new one had stuff copy pasted.
## Bug Status
Note: Bug list compiled from last known bug list of version 1488
It's a mess within a mess.
Oh god, forgive me.
FIXED:
- Multiplayer window doesn't show up on resolutions < 1920x1080
- Exchange sometimes skips rewards if multiple players put items in at the same time
- Exchange chest disappears without rewards
-
IN PROGRESS: N/A
---------------------------------------------------------------------------------
Known Bugs:
- Plort collectors don't work properly sometimes (Playing effect but not pulling anything)
- Nutcracker doesn't spit out right amount, or spits out "babies"
- Slimes sometimes appear "angry" for other players
- Game stutters when placing/removing gadgets
- First time using the mod can apparently break a lot of things (falling through world, slimes not eating) - Restarting the game fixes it
- DLCs don't seem to be loaded correctly when leaving and joining
- DLC are not initialized on game start, making the "You need following DLCs:" message pop up (Can be fixed by loading the "Manage DLCs" menu and trying again)
- Gordos don't drop things sometimes
- Slimes sometimes dont produce plorts
- Drones get stuck in place sometimes
- Chat sometimes empty for remote players
- Upgrades sometimes does not get applied to All players
But for real. Have fun digging through my unoptimized and undocumented code.
I never thought I actually gonna release this, yet here we are.
Would have dressed differently if I would have known.
Don't judge me tho. It still .... "works".
Just not as good as it could!
## Current Status
[@Twirlbug](https://github.com/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:
- Networking
- Packets
- Patches

View file

@ -1,32 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.1267
# Visual Studio Version 17
VisualStudioVersion = 17.6.33815.320
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SRMP", "SRMP\SRMP.csproj", "{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{623884D3-E475-43F6-A6DF-64B8860E3EDD}"
ProjectSection(SolutionItems) = preProject
SRMP\_info.txt = SRMP\_info.txt
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
SRML|Any CPU = SRML|Any CPU
SRML NoVer|Any CPU = SRML NoVer|Any CPU
Standalone|Any CPU = Standalone|Any CPU
SRML|Any CPU = SRML|Any CPU
Standalone NoVer|Any CPU = Standalone NoVer|Any CPU
Standalone|Any CPU = Standalone|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}.Release|Any CPU.Build.0 = Release|Any CPU
{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}.SRML|Any CPU.ActiveCfg = SRML|Any CPU
{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}.SRML|Any CPU.Build.0 = SRML|Any CPU
{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}.SRML NoVer|Any CPU.ActiveCfg = SRML NoVer|Any CPU
{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}.SRML NoVer|Any CPU.Build.0 = SRML NoVer|Any CPU
{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}.Standalone|Any CPU.ActiveCfg = Standalone|Any CPU
{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}.Standalone|Any CPU.Build.0 = Standalone|Any CPU
{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}.SRML|Any CPU.ActiveCfg = SRML|Any CPU
{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}.SRML|Any CPU.Build.0 = SRML|Any CPU
{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}.Standalone NoVer|Any CPU.ActiveCfg = Standalone NoVer|Any CPU
{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}.Standalone NoVer|Any CPU.Build.0 = Standalone NoVer|Any CPU
{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}.Standalone|Any CPU.ActiveCfg = Standalone|Any CPU
{E1BF7CDA-F2AE-4042-A992-DCBF62E79238}.Standalone|Any CPU.Build.0 = Standalone|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -0,0 +1,27 @@
The following console Commands work in the pop up console
cheat money [amount]
Add or Remove the given amount from the curret money score
cheat keys [amount]
Add or Remove the given amount of keys from the current amount
cheat allgadgets
Unlocks all of the gagets in the game
cheat spawn [id] ([amount])
spawns given item for the given ammount
tp [(optional)TargetPlayer] [DestinationPlayer]
Teleports the player in spot 1 to player/destination entered
if spot 1 is empty the palayer that entered in the command in infered as the target
listplayers
Prints the list of current players to the console
sleep [Hours]
Sleep command followed by the time in in game hours to "sleep"". Fast forwards the game the alotted hours.
console [enable/disable] [logtype]
Sets whether a specific log type should be displaying in the console.
All type default to enabled.
Log Types: Error, Assert, Warning, Log, Exception

View file

@ -1,4 +1,5 @@
using System;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -9,7 +10,46 @@ namespace SRMultiplayer
{
public string inputString = "";
public event Action<string> OnInputText;
/// <summary>
/// Handle updates the console
/// This is to catch key presses and process them
/// </summary>
public void Update()
{
if (Console.KeyAvailable)
{
ConsoleKeyInfo consoleKeyInfo = Console.ReadKey();
switch (consoleKeyInfo.Key)
{
case ConsoleKey.Enter: this.OnEnter(); break;
case ConsoleKey.Backspace: this.OnBackspace(); break;
case ConsoleKey.Escape: this.OnEscape(); break;
case ConsoleKey.UpArrow: this.GetCommand(1); break;
case ConsoleKey.DownArrow: this.GetCommand(-1); break;
default:
//check if pressed key is a character
bool flag = consoleKeyInfo.KeyChar > '\0';
if (flag)
{
//if so at it tothe input line
this.inputString += consoleKeyInfo.KeyChar.ToString();
this.RedrawInputLine();
}
break;
}
}
}
#region Console Processors
/// <summary>
/// Clears out the current console line
/// </summary>
public void ClearLine()
{
Console.CursorLeft = 0;
@ -17,7 +57,9 @@ namespace SRMultiplayer
Console.CursorTop--;
Console.CursorLeft = 0;
}
/// <summary>
/// Used to redraw the input line incase we had to hold for console write lines
/// </summary>
public void RedrawInputLine()
{
bool flag = Console.CursorLeft > 0;
@ -29,7 +71,12 @@ namespace SRMultiplayer
Console.Write("> ");
Console.Write(this.inputString);
}
#endregion region
#region Key Press Events
/// <summary>
/// Process Backspace pressed
/// </summary>
internal void OnBackspace()
{
bool flag = this.inputString.Length <= 0;
@ -39,7 +86,9 @@ namespace SRMultiplayer
this.RedrawInputLine();
}
}
/// <summary>
/// Process Escape pressed
/// </summary>
internal void OnEscape()
{
this.ClearLine();
@ -47,6 +96,9 @@ namespace SRMultiplayer
this.RedrawInputLine();
}
/// <summary>
/// Process Enter pressed
/// </summary>
internal void OnEnter()
{
this.ClearLine();
@ -57,47 +109,56 @@ namespace SRMultiplayer
bool flag = this.OnInputText != null;
if (flag)
{
//on text inputed reset the search loc and cycle the search tree
searchLoc = -1; //searchLoc set to -1 to always go to place 0 on first arrow
AddToCommandTree(obj);
this.OnInputText(obj);
}
}
public void Update()
#endregion
#region Command History Retrieval
List<string> cmdTree = new List<string>();
int maxCommands = 10;
/// <summary>
/// Manages the Command tree for the up and down arrows
/// </summary>
/// <param name="cmdText"></param>
internal void AddToCommandTree(string cmdText)
{
bool flag = !Console.KeyAvailable;
if (!flag)
cmdTree.Insert(0, cmdText);
//if tree gets larger than 10 remove the 11th item
if (cmdTree.Count > maxCommands) { cmdTree.RemoveAt(10); };
}
//handle internal cycling of last 10 commands
int searchLoc = -1;
/// <summary>
/// Gets the command at the designaed slot from the current possition
/// </summary>
/// <param name="diff">Possition from the current Command </param>
internal void GetCommand(int diff)
{
if (cmdTree.Count > 0)
{
ConsoleKeyInfo consoleKeyInfo = Console.ReadKey();
bool flag2 = consoleKeyInfo.Key == ConsoleKey.Enter;
if (flag2)
{
this.OnEnter();
}
else
{
bool flag3 = consoleKeyInfo.Key == ConsoleKey.Backspace;
if (flag3)
{
this.OnBackspace();
}
else
{
bool flag4 = consoleKeyInfo.Key == ConsoleKey.Escape;
if (flag4)
{
this.OnEscape();
}
else
{
bool flag5 = consoleKeyInfo.KeyChar > '\0';
if (flag5)
{
this.inputString += consoleKeyInfo.KeyChar.ToString();
this.RedrawInputLine();
}
}
}
}
searchLoc = searchLoc + diff;
//prevent below 0 or over max position
if (searchLoc > (cmdTree.Count - 1)) searchLoc = (cmdTree.Count - 1);
if (searchLoc < 0) searchLoc = 0;
//if a new location is found enter the search text in the input and redraw it.
this.inputString = cmdTree[searchLoc];
this.RedrawInputLine();
}
else
{
Console.WriteLine("cmdTree is empty");
}
}
#endregion
}
}
}

View file

@ -14,7 +14,9 @@ namespace SRMultiplayer
private TextWriter oldOutput;
private const int STD_OUTPUT_HANDLE = -11;
/// <summary>
/// Create the console window
/// </summary>
public void Initialize()
{
bool flag = !ConsoleWindow.AttachConsole(uint.MaxValue);

482
SRMP/Console/SRMPConsole.cs Normal file
View file

@ -0,0 +1,482 @@
using JetBrains.Annotations;
using MonomiPark.SlimeRancher.Regions;
using SRMultiplayer.Networking;
using SRMultiplayer.Packets;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using UnityEngine;
namespace SRMultiplayer
{
enum LogItems
{
CLIENT,
SERVER,
PLAYERAMMO,
EXCHANGE
}
public class SRMPConsole : MonoBehaviour
{
ConsoleWindow console = new ConsoleWindow();
ConsoleInput input = new ConsoleInput();
//
// Create console window, register callbacks
//
void Awake()
{
DontDestroyOnLoad(gameObject);
console.Initialize();
console.SetTitle("Slime Rancher");
input.OnInputText += OnInputText;
Application.logMessageReceived += Application_logMessageReceived;
SRMP.Log("Console Started");
}
//used to prevent duplicate messages displaying and list what number duplicate it is
string LastMessage = "";
int duplicateCount = 0;
//types of console types that can be enabled/disabled
//server automatically starts with all active
List<LogType> blockMessages = new List<LogType>(); //keeps a list of message types that have been disabled
List<LogItems> blockLogs = new List<LogItems>(); //keeps a list of log message types that have been disabled
bool DisplayTrace = false;
private void Application_logMessageReceived(string condition, string stackTrace, LogType type)
{
// We're half way through typing something, so clear this line ..
if (Console.CursorLeft != 0)
input.ClearLine();
//construct message
string message = condition;
if (!string.IsNullOrEmpty(stackTrace) && DisplayTrace)
{
//add stack strace if included
message += Environment.NewLine + stackTrace;
}
if (message == LastMessage)
{
//do not process duplicate marks if the last item was not written
if (duplicateCount > 0) duplicateCount++;
}
else
{
//add write line for duplicate notices if necessary
if (duplicateCount > 0)
{
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine("Output Duplicated: " + duplicateCount);
}
//format color for message
if (type == LogType.Warning)
Console.ForegroundColor = ConsoleColor.Yellow;
else if (type == LogType.Error)
Console.ForegroundColor = ConsoleColor.Red;
else
Console.ForegroundColor = ConsoleColor.White;
// mark new message
LastMessage = message;
bool displayLog = true;
//if log type is blocked turn off display
if (blockMessages.Contains(type)) displayLog = false;
//check data for specific inner types
string data = condition;
//remove the srmp tag and the time to check inner tags
if (type == LogType.Log && data.StartsWith("[SRMP]"))
{
data = data.Substring(17);
//if is still able to display make sure the log message blocker isnt blocking it
if (displayLog)
{
//try to pase the log message
if (Enum.TryParse(data.Split("]"[0])[0].Substring(1), true, out LogItems logMessage))
{
if (blockLogs.Contains(logMessage)) displayLog = false;
}
}
}
//always allow console reply to display
if (data.StartsWith("[Console]")) displayLog = true;
//only write the message type if its not blocked
if (displayLog)
{
//write the new line if not blocked
duplicateCount = 0;
Console.WriteLine(message);
}
else
{
//for testing log disabled display
//Console.ForegroundColor = ConsoleColor.Magenta;
Console.WriteLine(type.ToString() + " Dismissed");
//mark dupilcate count to -1
//prevent duplicate count for supressed messages from displaying
duplicateCount = -1;
}
}
// If we were typing something re-add it.
input.RedrawInputLine();
}
//create a log call that marks all console sent replys
void ConsoleLog(string message)
{
SRMP.Log(message, "Console");
}
//
// Text has been entered into the console
// Run it as a console command
//
void OnInputText(string obj)
{
var args = obj.Split(' ');
var cmd = args.FirstOrDefault();
args = args.Skip(1).ToArray();
switch (cmd.ToLower())
{
case "cheat":
{
if (args.Length > 0)
{
if (args[0].Equals("money"))
{
if (args.Length != 2 || !int.TryParse(args[1], out int money))
{
ConsoleLog("Usage: cheat money <amount>");
}
else
{
if (money > 0)
SRSingleton<SceneContext>.Instance.PlayerState.AddCurrency(money);
else
SRSingleton<SceneContext>.Instance.PlayerState.SpendCurrency(money);
}
}
else if (args[0].Equals("enable"))
{
//TestUI.Instance.cheat = !TestUI.Instance.cheat;
}
else if (args[0].Equals("keys"))
{
if (args.Length != 2 || !int.TryParse(args[1], out int value))
{
ConsoleLog("Usage: cheat keys <amount>");
}
else
{
SRSingleton<SceneContext>.Instance.PlayerState.model.keys = value;
}
}
else if (args[0].Equals("allgadgets"))
{
foreach (var data in (Gadget.Id[])Enum.GetValues(typeof(Gadget.Id)))
{
SRSingleton<SceneContext>.Instance.GadgetDirector.model.gadgets[data] = int.MaxValue;
}
foreach (var data in Identifiable.CRAFT_CLASS.Union(Identifiable.PLORT_CLASS))
{
SRSingleton<SceneContext>.Instance.GadgetDirector.model.craftMatCounts[data] = int.MaxValue;
}
}
else if (args[0].Equals("spawn"))
{
if (args.Length == 2)
{
if (Enum.TryParse<Identifiable.Id>(args[1].ToUpper(), out Identifiable.Id id))
{
GameObject prefab = SRSingleton<GameContext>.Instance.LookupDirector.GetPrefab(id);
if (prefab != null)
{
SRBehaviour.InstantiateActor(prefab, SRSingleton<SceneContext>.Instance.GameModel.player.currRegionSetId, SRSingleton<SceneContext>.Instance.GameModel.player.GetPos() + new Vector3(0, 4, 0), Quaternion.identity, false);
}
else
{
ConsoleLog(id + " can not be spawned");
}
}
else
{
var data = Enum.GetNames(typeof(Identifiable.Id)).Where(n => n.ToLower().Contains(args[1].ToLower()));
SRMP.Log(args[1] + " not found. " + (data.Count() > 0 ? " Did you mean one of these?" : ""));
foreach (var name in data)
{
ConsoleLog(name);
}
}
}
else if (args.Length == 3 && int.TryParse(args[2], out int amount))
{
if (Enum.TryParse<Identifiable.Id>(args[1].ToUpper(), out Identifiable.Id id))
{
GameObject prefab = SRSingleton<GameContext>.Instance.LookupDirector.GetPrefab(id);
if (prefab != null)
{
for (int i = 0; i < amount; i++)
{
SRBehaviour.InstantiateActor(prefab, SRSingleton<SceneContext>.Instance.GameModel.player.currRegionSetId, SRSingleton<SceneContext>.Instance.GameModel.player.GetPos() + new Vector3(0, 4, 0), Quaternion.identity, false);
}
}
else
{
SRMP.Log(id + " can not be spawned");
}
}
else
{
var data = Enum.GetNames(typeof(Identifiable.Id)).Where(n => n.ToLower().Contains(args[1].ToLower()));
ConsoleLog(args[1] + " not found. " + (data.Count() > 0 ? " Did you mean one of these?" : ""));
foreach (var name in data)
{
ConsoleLog(name);
}
}
}
else
{
ConsoleLog("Usage: cheat spawn <id> (<amount>)");
}
}
}
else
{
ConsoleLog("Available sub commands:");
ConsoleLog("cheat money <amount>");
ConsoleLog("cheat keys <amount>");
ConsoleLog("cheat spawn <id> (<amount>)");
ConsoleLog("cheat allgadgets");
}
}
break;
case "tp":
{
if (args.Length < 1 || args.Length > 2)
{
ConsoleLog("Usage: tp <(optional)target:username> <destination>");
return;
}
//mark target and destination seperately
string target = args.Length == 2 ? args[0] : "";
string destination = args.Length == 2 ? args[1] : args[0];
//mark target transform location
PacketPlayerPosition packet = null;
string destSummary = "";
//first check distination
switch (destination.ToLower())
{
case "home":
var home = SRSingleton<SceneContext>.Instance.GetWakeUpDestination();
packet = new PacketPlayerPosition()
{
Position = home.transform.position,
Rotation = home.transform.eulerAngles.y,
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));
if (play == null)
{
ConsoleLog("Destination not found");
return;
}
packet = new PacketPlayerPosition()
{
Position = play.transform.position,
Rotation = play.transform.eulerAngles.y,
RegionSet = (byte)play.CurrentRegionSet
};
destSummary = play.Username;
break;
}
if (packet != null)
{
//set as not load destination
packet.OnLoad = false;
NetworkPlayer targetPlayer = null;
if (target.Length > 0)
{
targetPlayer = Globals.Players.Values.FirstOrDefault(p => p.Username.Equals(target, StringComparison.CurrentCultureIgnoreCase));
}
else
{
targetPlayer = Globals.LocalPlayer;
}
//check if target is local user
if (targetPlayer == null)
{
ConsoleLog("Target Player not found");
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;
}
else
{
//if we have have made it here the tp in question is for the instances player
//so move that player
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();
}
}
else
{
ConsoleLog("Destination not found");
}
}
break;
case "listplayers":
{
ConsoleLog("Players:");
foreach (var player in Globals.Players.Values)
{
SRMP.Log(player.Username);
}
}
break;
case "sleep":
{
if (args.Length == 1)
{
SRSingleton<SceneContext>.Instance.TimeDirector.FastForwardTo(SRSingleton<SceneContext>.Instance.TimeDirector.HoursFromNow(float.Parse(args[0])));
ConsoleLog("Sleeoing for " + args[0] + " hours");
}
else
{
ConsoleLog("Usage: sleep <hours>");
}
}
break;
case "console": //add toggle option for turning on and off logging types
if (args.Length > 1 && (args[0] == "enable" || args[0] == "disable"))
{
bool enable = args[0] == "enable";
//double check type
if (Enum.TryParse(args[1], true, out LogType logType)) //check for main log type
{
if (enable)
{
if (!blockMessages.Contains(logType)) blockMessages.Remove(logType);
ConsoleLog(logType.ToString() + " Messages Enabled");
}
else
{
if (blockMessages.Contains(logType)) blockMessages.Add(logType);
ConsoleLog("[Console] " + logType.ToString() + " Messages Disabled");
}
}
else if (Enum.TryParse(args[1], true, out LogItems logMessage)) //check for log message item types
{
if (enable)
{
if (!blockLogs.Contains(logMessage)) blockLogs.Remove(logMessage);
ConsoleLog(logMessage.ToString() + " Log Messages Enabled");
}
else
{
if (blockLogs.Contains(logMessage)) blockLogs.Add(logMessage);
ConsoleLog(logMessage.ToString() + " Log Messages Disabled");
}
}
else if (args[1].Equals("stacktrace", StringComparison.InvariantCultureIgnoreCase) || args[1].Equals("stack_trace", StringComparison.InvariantCultureIgnoreCase))
{
if (enable)
{
DisplayTrace = true;
ConsoleLog("Stack Trace Information Enabled");
}
else
{
DisplayTrace = false;
ConsoleLog("Stack Trace Information Disabled");
}
}
else
{
ConsoleLog("Invalid Feed back Type");
ConsoleLog("Valid Types: ");
ConsoleLog(string.Join(", ", Enum.GetValues(typeof(LogType))));
ConsoleLog(string.Join(", ", Enum.GetValues(typeof(LogItems))));
}
}
else
{
ConsoleLog("Usage: console <enable/disable> <feedbackType>");
}
break;
}
}
//
// Update the input every frame
// This gets new key input and calls the OnInputText callback
//
void Update()
{
input.Update();
}
//
// It's important to call console.ShutDown in OnDestroy
// because compiling will error out in the editor if you don't
// because we redirected output. This sets it back to normal.
//
void OnDestroy()
{
console.Shutdown();
}
}
}

View file

@ -13,7 +13,11 @@ public class ChatUI : SRSingleton<ChatUI>
private float fadeTime;
private List<ChatMessage> messages = new List<ChatMessage>();
private Vector2 chatScroll;
int maxWidth = 290;
/// <summary>
/// create a chat message to be displayed
/// </summary>
public class ChatMessage
{
public string Text;
@ -27,52 +31,68 @@ public class ChatUI : SRSingleton<ChatUI>
Time = DateTime.Now;
}
}
/// <summary>
/// On chat ui update triggered, handle it
/// </summary>
private void Update()
{
//only display chat if in multiplayer mode
if (!Globals.IsMultiplayer)
{
openChat = false;
message = "";
return;
}
//if enter is pressed start chat typing mode
if (Input.GetKeyUp(KeyCode.Return))
{
StartCoroutine(FocusChat());
}
}
/// <summary>
/// Crreate the Chat gui
/// </summary>
private void OnGUI()
{
//only mess with the gui in multiplayer mode
if (!Globals.IsMultiplayer) return;
if (openChat)
{
GUILayout.BeginArea(new Rect(20, Screen.height / 2, 500, 300), GUI.skin.box);
//draw chat area
GUILayout.BeginArea(new Rect(20, Screen.height / 2, maxWidth + 10, 300), GUI.skin.box);
chatScroll = GUILayout.BeginScrollView(chatScroll);
var skin = GUI.skin.box;
skin.wordWrap = true;
skin.alignment = TextAnchor.MiddleLeft;
//add each mesage into the chat box scroller
foreach (var msg in messages)
{
GUILayout.Label(wrapString(msg.Text, 490), skin, GUILayout.MaxWidth(490));
GUILayout.Label(wrapString(msg.Text, maxWidth), skin, GUILayout.MaxWidth(maxWidth));
}
GUILayout.EndScrollView();
//add display for text input area
GUI.SetNextControlName("ChatInput");
message = GUILayout.TextField(message);
GUILayout.EndArea();
//focus the input
GUI.FocusControl("ChatInput");
//watch for changes to the text input
Event e = Event.current;
if (e.rawType == EventType.KeyUp && e.keyCode == KeyCode.Return)
{
//on send close chat
openChat = !openChat;
if (!string.IsNullOrWhiteSpace(message))
{
//if server send message to all plauers
if (Globals.IsServer)
{
//if server send it to the server
AddChatMessage(Globals.Username + ": " + message);
new PacketPlayerChat()
{
@ -81,6 +101,7 @@ public class ChatUI : SRSingleton<ChatUI>
}
else
{
//if player send it to the server
new PacketPlayerChat()
{
message = message
@ -90,13 +111,16 @@ public class ChatUI : SRSingleton<ChatUI>
}
}
}
else
else //if chat isnt open yet
{
GUILayout.BeginArea(new Rect(20, Screen.height / 2, 500, 300));
//draw chat area
GUILayout.BeginArea(new Rect(20, Screen.height / 2, maxWidth+ 10, 300));
chatScroll = GUILayout.BeginScrollView(chatScroll);
var skin = GUI.skin.box;
skin.wordWrap = true;
skin.alignment = TextAnchor.MiddleLeft;
//add each mesage into the chat box scroller
foreach (var msg in messages)
{
if (msg.FadeTime > 0f)
@ -105,26 +129,34 @@ public class ChatUI : SRSingleton<ChatUI>
var c = GUI.color;
c.a = (msg.FadeTime / 5f);
GUI.color = c;
GUILayout.Label(wrapString(msg.Text, 490), skin, GUILayout.MaxWidth(490));
GUILayout.Label(wrapString(msg.Text, maxWidth), skin, GUILayout.MaxWidth(maxWidth));
}
}
GUILayout.EndScrollView();
GUILayout.EndArea();
}
}
/// <summary>
/// Add a chat message to be displayed
/// </summary>
/// <param name="message">Message to display</param>
public void AddChatMessage(string message)
{
fadeTime = 10f;
messages.Add(new ChatMessage(message));
chatScroll = new Vector2(0, 100000);
}
/// <summary>
/// Trigger a full clear of the chat
/// </summary>
public void Clear()
{
messages.Clear();
}
/// <summary>
/// Trigger focus on the chat box for when the uer hits enter
/// </summary>
private IEnumerator FocusChat()
{
yield return new WaitForEndOfFrame();
@ -133,6 +165,12 @@ public class ChatUI : SRSingleton<ChatUI>
GUI.FocusControl("ChatInput");
}
/// <summary>
/// Create the wrapped string to display in the chat box
/// </summary>
/// <param name="msg">Message to display</param>
/// <param name="width">Width of the chat box</param>
/// <returns></returns>
string wrapString(string msg, int width)
{
string[] words = msg.Split(" "[0]);

View file

@ -8,18 +8,38 @@ using SRMultiplayer.Networking;
public class MultiplayerUI : SRSingleton<MultiplayerUI>
{
private Rect windowRect = new Rect(Screen.width - 300, 20, 300, 500);
private Rect windowRect = new Rect(Screen.width - 300 - 20, 20, 300, 500);
private Vector2 playersScroll = Vector2.zero;
private string ipaddress = "localhost";
private string port = "16500";
private string servercode = "";
private bool menuOpen;
//use internal name with getter and setter to allow the menu panel to remember the users last choice
private int _menuOpen;
private int menuOpen //menu open hold the current menu state (0 colapsed, 1 minimized, 2 open)
{
get
{
return _menuOpen;
}
set
{
_menuOpen = value;
//save users setting
PlayerPrefs.SetInt("SRMP_Menu", menuOpen);
}
}
private string username;
private float lastCodeUse;
private ConnectError error;
private ConnectHelp help;
private string errorMessage;
public enum ConnectError
{
None,
@ -36,65 +56,228 @@ public class MultiplayerUI : SRSingleton<MultiplayerUI>
Hosting,
}
/// <summary>
/// Creation of gui with side panel is last display state
/// </summary>
public override void Awake()
{
base.Awake();
//set default ui location width adapting numbers for smaller resolutions
float width = 300;
if (Screen.width / 4 < width) width = Screen.width / 4;
windowRect = new Rect(Screen.width - width - 20, 20, width, 500);
Globals.Username = PlayerPrefs.GetString("SRMP_Username", "");
ipaddress = PlayerPrefs.GetString("SRMP_IP", "localhost");
port = PlayerPrefs.GetString("SRMP_Port", "16500");
menuOpen = true;
menuOpen = PlayerPrefs.GetInt("SRMP_Menu", 2); ; //start panel open by default
username = Globals.Username;
}
/// <summary>
/// Update of panel display
/// </summary>
private void Update()
{
if(lastCodeUse > 0f)
if (lastCodeUse > 0f)
{
var prevTime = lastCodeUse;
lastCodeUse -= Time.deltaTime;
if(prevTime > 0f && lastCodeUse <= 0f)
if (prevTime > 0f && lastCodeUse <= 0f)
{
error = ConnectError.ServerCodeTimeout;
}
}
if(Input.GetKeyDown(KeyCode.F4))
//this sets presskey senarios
if (Input.GetKeyDown(KeyCode.F4))
{
menuOpen = !menuOpen;
//use the f4 key to swap between collapsed and minimized
menuOpen = menuOpen == 2 ? 0 : 2;
}
if (Input.GetKeyDown(KeyCode.F3))
{
//use the f3 key to set minimized or maximized
menuOpen = menuOpen < 2 ? 2 : 1;
}
}
/// <summary>
/// Handle draw event of the gui
/// </summary>
private void OnGUI()
{
if (!menuOpen || (!Levels.isMainMenu() && !Globals.IsMultiplayer && Globals.PauseState != PauseState.Pause)) return;
//verify on a window that the menu can be drawn on
if ((!Levels.isMainMenu() && !Globals.IsMultiplayer && Globals.PauseState != PauseState.Pause)) return;
if (Globals.IsMultiplayer && Globals.PauseState != PauseState.Pause) return;
//if yes draw the window for the given state
if (SceneManager.GetActiveScene().buildIndex >= 2)
{
windowRect = GUI.Window(1, windowRect, MultiplayerWindow, "SRMP v" + Globals.Version);
//check to make sure the panel is taking less than 25% of the screen if possible
float width = 300;
if(Screen.width/ 4 < width) width = Screen.width/4;
windowRect.width = width;
//check to see if the windows needs to move due to it being off the screen from size change
//also prevent the user from dragging it off the screen
if (windowRect.x + 20 + windowRect.width > Screen.width) windowRect.x = Screen.width - windowRect.width - 20;
if (windowRect.y + 20 + windowRect.height > Screen.height) windowRect.y = (Screen.height - windowRect.height - 20) >= 20 ? (Screen.height - windowRect.height - 20) : 20;
if (windowRect.x < 20) windowRect.x = 20;
if (windowRect.y < 20) windowRect.y = 20;
//drawn in the window
switch (menuOpen)
{
case 0: //collapsed
windowRect.height = 50;
windowRect = GUILayout.Window(1, windowRect, ClosedWindow, "SRMP v" + Globals.Version);
break;
case 1: //minimized
windowRect.height = 100;
windowRect = GUILayout.Window(1, windowRect, MiniWindow, "SRMP v" + Globals.Version);
break;
case 2: //open
windowRect.height = 500;
windowRect = GUILayout.Window(1, windowRect, MultiplayerWindow, "SRMP v" + Globals.Version);
break;
}
}
}
/// <summary>
/// display for the function keyps section of the gui
/// </summary>
private void FunctionKeys()
{
if (menuOpen != 0)
{
GUILayout.Label("Press Button or Key To Change Style");
}
GUILayout.BeginHorizontal();
if (GUILayout.Button(menuOpen == 1 ? "F3 - Full" : "F3 - Mini"))
{
menuOpen = menuOpen == 1 ? 2 : 1;
}
GUILayout.FlexibleSpace();
if (GUILayout.Button(menuOpen == 0 ? "F4 - Full" : "F4 - Colapsed"))
{
menuOpen = menuOpen == 0 ? 2 : 0;
}
GUILayout.EndHorizontal();
}
/// <summary>
/// Sets the window display for collapsed
/// Only activated if the id is the id for the window
/// </summary>
private void ClosedWindow(int id)
{
if (id != 1) return;
//display f3 and f4 commands
FunctionKeys();
GUI.DragWindow(new Rect(0, 0, 10000, 10000));
}
/// <summary>
/// Sets the window display for summary mode
/// Only activated if the id is the id for the window
/// </summary>
private void MiniWindow(int id)
{
if (id != 1) return;
//display f3 and f4 commands
FunctionKeys();
//show username and current connection status
GUIStyle standard = new GUIStyle(GUI.skin.label);
GUIStyle red = new GUIStyle(GUI.skin.label);
red.normal.textColor = Color.red;
if (string.IsNullOrWhiteSpace(Globals.Username))
{
GUILayout.Label("Username: Not Set", red);
}
else
{
GUILayout.Label("Username: " + Globals.Username);
if (Globals.IsServer)
{
GUILayout.Label("Status: Host");
}
else if (Globals.IsClient)
{
GUIStyle green = new GUIStyle(GUI.skin.label);
green.normal.textColor = Color.green;
GUILayout.Label("Status: Client", green);
}
else
{
bool canHost = true;
//check if user can host the session
if (!int.TryParse(port, out int numport) || numport < 1000 || numport > 65000)
{
canHost = false;
}
GUILayout.BeginHorizontal();
GUILayout.Label("Status: Disconnected", red);
GUILayout.FlexibleSpace();
if (canHost)
{
//only show host if not main menu
if (!Levels.isMainMenu())
{
if (GUILayout.Button("Host"))
{
NetworkServer.Instance.StartServer(numport);
SaveSettings();
}
}
}
GUILayout.EndHorizontal();
if (!canHost)
{
GUILayout.Label("Invalid Port Settings", red);
}
}
}
GUI.DragWindow(new Rect(0, 0, 10000, 10000));
}
/// <summary>
/// Sets the window display for full display mode
/// Only activated if the id is the id for the window
/// </summary>
private void MultiplayerWindow(int id)
{
if (id != 1) return;
GUILayout.Label("You can close this menu with F4");
GUILayout.Space(20);
//display f3 and f4 commands
FunctionKeys();
if(string.IsNullOrWhiteSpace(Globals.Username))
//now display standard
if (string.IsNullOrWhiteSpace(Globals.Username))
{
UsernameGUI();
}
else
{
if(Globals.IsServer)
if (Globals.IsServer)
{
ServerGUI();
}
else if(Globals.IsClient)
else if (Globals.IsClient)
{
ClientGUI();
}
@ -104,13 +287,13 @@ public class MultiplayerUI : SRSingleton<MultiplayerUI>
{
ErrorGUI();
}
else if(help != ConnectHelp.None)
else if (help != ConnectHelp.None)
{
HelpGUI();
}
else
{
if(lastCodeUse > 0f)
if (lastCodeUse > 0f)
{
GUILayout.Label("Trying to connect with server code...");
}
@ -129,6 +312,9 @@ public class MultiplayerUI : SRSingleton<MultiplayerUI>
GUI.DragWindow(new Rect(0, 0, 10000, 10000));
}
/// <summary>
/// Display the active server info part of the gui
/// </summary>
private void ServerGUI()
{
GUILayout.Label("You are the server");
@ -143,7 +329,7 @@ public class MultiplayerUI : SRSingleton<MultiplayerUI>
GUILayout.BeginHorizontal();
GUILayout.Label(player.Username);
if(GUILayout.Button("Kick"))
if (GUILayout.Button("Kick"))
{
player.Connection.Disconnect("kicked");
}
@ -151,7 +337,9 @@ public class MultiplayerUI : SRSingleton<MultiplayerUI>
}
GUILayout.EndScrollView();
}
/// <summary>
/// Display the client info part of the gui
/// </summary>
private void ClientGUI()
{
GUILayout.Label("You are a client");
@ -169,7 +357,11 @@ public class MultiplayerUI : SRSingleton<MultiplayerUI>
}
GUILayout.EndScrollView();
}
/// <summary>
/// Display the connection information of the gui
/// this section includes user information,
/// how to and other imbedded sections for handling display
/// </summary>
private void ConnectGUI()
{
GUILayout.Label("Username: " + Globals.Username);
@ -179,7 +371,7 @@ public class MultiplayerUI : SRSingleton<MultiplayerUI>
return;
}
GUILayout.Space(20);
if(GUILayout.Button("How do I host a game?"))
if (GUILayout.Button("How do I host a game?"))
{
help = ConnectHelp.Hosting;
}
@ -250,6 +442,9 @@ public class MultiplayerUI : SRSingleton<MultiplayerUI>
}
}
/// <summary>
/// Display the hosting info part of the gui
/// </summary>
private void HostGUI()
{
GUILayout.Label("Username: " + Globals.Username);
@ -277,10 +472,12 @@ public class MultiplayerUI : SRSingleton<MultiplayerUI>
}
}
}
/// <summary>
/// Display the Help info part of the gui with instructions for hosting
/// </summary>
private void HelpGUI()
{
switch(help)
switch (help)
{
case ConnectHelp.ServerCode:
{
@ -301,10 +498,12 @@ public class MultiplayerUI : SRSingleton<MultiplayerUI>
break;
}
}
/// <summary>
/// Display the Error summaries in the gui
/// </summary>
private void ErrorGUI()
{
switch(error)
switch (error)
{
case ConnectError.InvalidServerCode:
{
@ -354,7 +553,9 @@ public class MultiplayerUI : SRSingleton<MultiplayerUI>
break;
}
}
/// <summary>
/// Display the Current user information
/// </summary>
private void UsernameGUI()
{
GUILayout.BeginHorizontal();
@ -376,14 +577,18 @@ public class MultiplayerUI : SRSingleton<MultiplayerUI>
}
}
}
/// <summary>
/// Saves the gui settings for the user
/// </summary>
private void SaveSettings()
{
PlayerPrefs.SetString("SRMP_Username", Globals.Username);
PlayerPrefs.SetString("SRMP_IP", ipaddress);
PlayerPrefs.GetString("SRMP_Port", port);
}
/// <summary>
/// Handles connection resonces display when connection is lost from the server
/// </summary>
public void ConnectResponse(ConnectError connectError, string message = "")
{
lastCodeUse = 0f;

View file

@ -8,6 +8,24 @@
//using UnityEngine;
//using UnityEngine.SceneManagement;
/*
* TestUi is a version of the multiplayer ui that adds the following information
* Added
Chat
Cheats
* More stats
Quick silver race is active
client status
server status
server code
send and recieve sizes
packet sizes
*/
//namespace SRMultiplayer
//{
// class TestUI : SRSingleton<TestUI>
@ -130,11 +148,11 @@
// {
// SRSingleton<SceneContext>.Instance.PlayerState.AddCurrency(1000000);
// }
// if(GUILayout.Button("Remove all actors"))
// if (GUILayout.Button("Remove all actors"))
// {
// foreach(var actor in SRSingleton<SceneContext>.Instance.GameModel.AllActors().Values.ToList())
// foreach (var actor in SRSingleton<SceneContext>.Instance.GameModel.AllActors().Values.ToList())
// {
// if(actor != null && actor.transform != null && actor.transform.gameObject.activeInHierarchy && !Identifiable.SCENE_OBJECTS.Contains(actor.ident))
// if (actor != null && actor.transform != null && actor.transform.gameObject.activeInHierarchy && !Identifiable.SCENE_OBJECTS.Contains(actor.ident))
// {
// Destroyer.DestroyActor(actor.transform.gameObject, "Get.Removed");
// }
@ -265,10 +283,10 @@
// {
// try
// {
// if (GUILayout.Button("Clear " + ident.ToString()))
// {
// if (GUILayout.Button("Clear " + ident.ToString()))
// {
// SRSingleton<SceneContext>.Instance.ExchangeDirector.ClearOffer(ident);
// }
// }
// }
// catch { }
// }
@ -535,10 +553,10 @@
// if (Globals.IsMultiplayer)
// {
// QuicksilverEnergyGenerator generator = null;
// foreach(var region in Globals.LocalPlayer.Regions)
// foreach (var region in Globals.LocalPlayer.Regions)
// {
// generator = region.GetComponent<QuicksilverEnergyGenerator>();
// if(generator != null)
// if (generator != null)
// {
// break;
// }
@ -546,13 +564,13 @@
// GUILayout.Label("Is In Race: " + (generator != null ? generator.id : "None"));
// GUILayout.Label($"Client Status: {NetworkClient.Instance.Status}");
// GUILayout.Label($"Server Status: {NetworkServer.Instance.Status}");
// if(!string.IsNullOrWhiteSpace(Globals.ServerCode))
// if (!string.IsNullOrWhiteSpace(Globals.ServerCode))
// {
// GUILayout.Label($"Server Code: {Globals.ServerCode}");
// }
// //GUILayout.Label("Received Messages: " + SRSingleton<NetworkClient>.Instance.Statistics.ReceivedMessages);
// //GUILayout.Label("Send Messages: " + SRSingleton<NetworkClient>.Instance.Statistics.SentMessages);
// GUILayout.Label("Received Messages: " + SRSingleton<NetworkClient>.Instance.Statistics.ReceivedMessages);
// GUILayout.Label("Send Messages: " + SRSingleton<NetworkClient>.Instance.Statistics.SentMessages);
// if (NetworkServer.Instance != null && NetworkServer.Instance.Status == NetworkServer.ServerStatus.Running)
// {
@ -567,7 +585,7 @@
// //GUILayout.Space(20);
// //GUILayout.Label("Chat");
// chatScroll = GUILayout.BeginScrollView(chatScroll, GUI.skin.box);
// foreach(var sizes in Globals.PacketSize.OrderByDescending(c => c.Value))
// foreach (var sizes in Globals.PacketSize.OrderByDescending(c => c.Value))
// {
// GUILayout.Label(sizes.Key + ": " + Utils.GetHumanReadableFileSize(sizes.Value));
// }

View file

@ -11,12 +11,12 @@ namespace SRMultiplayer
{
public static class Globals
{
//setup global objects for refrence usage
public static int Version;
public static UserData UserData;
public static GameObject BeatrixModel;
public static RuntimeAnimatorController BeatrixController;
public static GameObject IngameMultiplayerMenuPrefab;
public static GameObject MainMultiplayerMenuPrefab;
public static Dictionary<byte, NetworkPlayer> Players = new Dictionary<byte, NetworkPlayer>();
public static string Username;
public static string ServerCode;
@ -53,6 +53,10 @@ namespace SRMultiplayer
public static List<string> LemonTrees = new List<string>();
public static Dictionary<PacketType, long> PacketSize = new Dictionary<PacketType, long>();
/// <summary>
/// get list of current installed mods
/// Excluding supporting files
/// </summary>
public static List<string> Mods
{
get

View file

@ -14,6 +14,10 @@ using UnityEngine;
namespace SRMultiplayer
{
/// <summary>
/// Handles mod being loaded from SRML
/// Takes the place of the Main Standalone file, but caters to the SRML
/// </summary>
public class MainSRML : ModEntryPoint
{
private static GameObject m_GameObject;
@ -35,10 +39,12 @@ namespace SRMultiplayer
SRMP.Log("Loading SRMP SRML Version");
//create the mod directory in the install folder if needed
if (!Directory.Exists(SRMP.ModDataPath))
{
Directory.CreateDirectory(SRMP.ModDataPath);
}
//create the user data file if not created yet
if (!File.Exists(Path.Combine(SRMP.ModDataPath, "userdata.json")))
{
Globals.UserData = new UserData()
@ -50,7 +56,7 @@ namespace SRMultiplayer
File.WriteAllText(Path.Combine(SRMP.ModDataPath, "userdata.json"), JsonConvert.SerializeObject(Globals.UserData));
SRMP.Log("Created userdata with UUID " + Globals.UserData.UUID);
}
else
else //if alreayd created load in the data
{
Globals.UserData = JsonConvert.DeserializeObject<UserData>(File.ReadAllText(Path.Combine(SRMP.ModDataPath, "userdata.json")));
if(Globals.UserData.IgnoredMods == null)
@ -60,6 +66,7 @@ namespace SRMultiplayer
SRMP.Log("Loaded userdata with UUID " + Globals.UserData.UUID);
}
//create the mods main game objects and start connecting everything
string[] args = System.Environment.GetCommandLineArgs();
m_GameObject = new GameObject("SRMP");
@ -71,12 +78,16 @@ namespace SRMultiplayer
m_GameObject.AddComponent<ChatUI>();
m_GameObject.AddComponent<SRMPConsole>();
//mark all mod objects and do not destroy
GameObject.DontDestroyOnLoad(m_GameObject);
//get current mod version
Globals.Version = Assembly.GetExecutingAssembly().GetName().Version.Revision;
//mark the mod as a background task
Application.runInBackground = true;
//initialize connect to the harmony patcher
HarmonyPatcher.GetInstance().PatchAll(Assembly.GetExecutingAssembly());
}

View file

@ -8,7 +8,9 @@ using UnityCoreMod;
using UnityEngine;
namespace SRMultiplayer
{
{ // <summary>
/// Handles mod being loaded from directly without the mod loader
/// </summary>
public class MainSaty : IUnityMod
{
private static GameObject m_GameObject;
@ -19,10 +21,12 @@ namespace SRMultiplayer
SRMP.Log("Loading SRMP Standalone Version");
//create the mod directory in the install folder if needed
if (!Directory.Exists(SRMP.ModDataPath))
{
Directory.CreateDirectory(SRMP.ModDataPath);
}
//create the user data file if not created yet
if (!File.Exists(Path.Combine(SRMP.ModDataPath, "userdata.json")))
{
Globals.UserData = new UserData()
@ -34,8 +38,9 @@ namespace SRMultiplayer
File.WriteAllText(Path.Combine(SRMP.ModDataPath, "userdata.json"), JsonConvert.SerializeObject(Globals.UserData));
SRMP.Log("Created userdata with UUID " + Globals.UserData.UUID);
}
else
else //if alreayd created load in the data
{
Globals.UserData = JsonConvert.DeserializeObject<UserData>(File.ReadAllText(Path.Combine(SRMP.ModDataPath, "userdata.json")));
if(Globals.UserData.IgnoredMods == null)
{
@ -44,6 +49,7 @@ namespace SRMultiplayer
SRMP.Log("Loaded userdata with UUID " + Globals.UserData.UUID);
}
//create the mods main game objects and start connecting everything
string[] args = System.Environment.GetCommandLineArgs();
m_GameObject = new GameObject("SRMP");
@ -55,13 +61,17 @@ namespace SRMultiplayer
m_GameObject.AddComponent<ChatUI>();
m_GameObject.AddComponent<SRMPConsole>();
//mark all mod objects and do not destroy
GameObject.DontDestroyOnLoad(m_GameObject);
//get current mod version
Globals.Version = Assembly.GetExecutingAssembly().GetName().Version.Revision;
//initialize harmony and init the patches
var harmony = new Harmony("saty.mod.srmp");
harmony.PatchAll(Assembly.GetExecutingAssembly());
//mark the mod as a background task
Application.runInBackground = true;
}

View file

@ -1,16 +1,12 @@
using Assets.Script.Util.Extensions;
using DG.Tweening;
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
@ -24,22 +20,24 @@ namespace SRMultiplayer.Networking
Globals.PacketSize[type] += im.LengthBytes;
switch (type)
{
//Player amimations
case PacketType.PlayerAnimation: OnPlayerAnimation(new PacketPlayerAnimation(im)); break;
//Players
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.PlayerAnimationLayer: OnPlayerAnimationLayer(im); break;
case PacketType.PlayerAnimationParameters: OnPlayerAnimationParameters(im); break;
case PacketType.PlayerAnimationSpeed: OnPlayerAnimationSpeed(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;
case PacketType.PlayerUpgrade: OnPlayerUpgrade(new PacketPlayerUpgrade(im)); break;
case PacketType.PlayerUpgradeUnlock: OnPlayerUpgradeUnlock(new PacketPlayerUpgradeUnlock(im)); break;
case PacketType.PlayerChat: OnPlayerChat(new PacketPlayerChat(im)); break;
// Region
case PacketType.RegionOwner: OnRegionOwner(new PacketRegionOwner(im)); break;
//Actors
case PacketType.Actors: OnActors(new PacketActors(im)); break;
case PacketType.ActorSpawn: OnActorSpawn(new PacketActorSpawn(im)); break;
@ -153,7 +151,7 @@ namespace SRMultiplayer.Networking
case PacketType.RaceTime: OnRaceTime(new PacketRaceTime(im)); break;
case PacketType.RaceTrigger: OnRaceTrigger(new PacketRaceTrigger(im)); break;
default:
SRMP.Log($"Got unhandled packet: {type}");
SRMP.Log($"Got unhandled packet: {type} " + Enum.GetName(typeof(PacketType), type));
break;
}
}
@ -274,7 +272,7 @@ namespace SRMultiplayer.Networking
private static void OnFireColumnActivate(PacketFireColumnActivate packet)
{
if(Globals.FireColumns.TryGetValue(packet.ID, out NetworkFireColumn netColumn))
if (Globals.FireColumns.TryGetValue(packet.ID, out NetworkFireColumn netColumn))
{
netColumn.Column.ActivateFire();
}
@ -321,9 +319,9 @@ namespace SRMultiplayer.Networking
private static void OnOasis(PacketOasis packet)
{
foreach(var oasisData in packet.Oasis)
foreach (var oasisData in packet.Oasis)
{
if(SRSingleton<SceneContext>.Instance.GameModel.AllOases().TryGetValue(oasisData.ID, out OasisModel model))
if (SRSingleton<SceneContext>.Instance.GameModel.AllOases().TryGetValue(oasisData.ID, out OasisModel model))
{
model.isLive = oasisData.Model.isLive;
@ -337,30 +335,51 @@ namespace SRMultiplayer.Networking
#region Exchanges
private static void OnExchangeTryAccept(PacketExchangeTryAccept packet)
{
//get the exchange type
var type = (ExchangeDirector.OfferType)packet.Type;
//check if current scene (view) contains the item in question
if (SRSingleton<SceneContext>.Instance.ExchangeDirector.worldModel.currOffers.ContainsKey(type))
{
//handle the scene changes for the given offer
var offer = SRSingleton<SceneContext>.Instance.ExchangeDirector.worldModel.currOffers[type];
//cycle through requested items
foreach (ExchangeDirector.RequestedItemEntry requestedItemEntry in offer.requests)
{
//check if the item can be accespted
//is on the board and not already completed
if (requestedItemEntry.id == (Identifiable.Id)packet.ID && !requestedItemEntry.IsComplete())
{
//mark submit to log
SRMP.Log($"Exchange TryAccept for {(Identifiable.Id)packet.ID} ({(ExchangeDirector.OfferType)packet.Type}", "SERVER");
//mark progress
requestedItemEntry.progress++;
//if the given item completes the necesary quantity
if (offer.IsComplete())
{
foreach(var rewarder in Resources.FindObjectsOfTypeAll<RancherProgressAwarder>())
foreach (var rewarder in Resources.FindObjectsOfTypeAll<RancherProgressAwarder>())
{
rewarder.AwardIfType(type);
}
SRSingleton<SceneContext>.Instance.ExchangeDirector.ClearOffer(type);
//trigger fireworks
//get ExchangeEjector
foreach (var eject in Resources.FindObjectsOfTypeAll<ExchangeEjector>())
{
//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);
}
//trigger offer status changed
SRSingleton<SceneContext>.Instance.ExchangeDirector.OfferDidChange();
}
}
}
}
private static void OnExchangePrepareDaily(PacketExchangePrepareDaily packet)
{
SRSingleton<SceneContext>.Instance.ExchangeDirector.worldModel.pendingOfferRancherIds = packet.pendingOfferRancherIds;
@ -414,7 +433,7 @@ namespace SRMultiplayer.Networking
private static void OnTreasurePods(PacketTreasurePods packet)
{
foreach(var pod in packet.TreasurePods)
foreach (var pod in packet.TreasurePods)
{
if (SRSingleton<SceneContext>.Instance.GameModel.AllPods().TryGetValue(pod.ID, out TreasurePodModel model))
{
@ -446,7 +465,7 @@ namespace SRMultiplayer.Networking
if (model.HasAttached())
{
var netDrone = model.attached.transform.GetComponentInChildren<NetworkDrone>(true);
if(netDrone != null)
if (netDrone != null)
{
netDrone.PositionRotationUpdate(packet.Position, packet.Rotation, false);
}
@ -675,7 +694,7 @@ namespace SRMultiplayer.Networking
extractor.nextProduceTime = packet.nextProduceTime;
extractor.queuedToProduce = packet.queuedToProduce;
if(extractor.cyclesRemaining <= 0)
if (extractor.cyclesRemaining <= 0)
{
var extractorScript = extractor.transform.GetComponent<Extractor>();
if (extractorScript != null && extractorScript.gameObject.activeInHierarchy)
@ -770,7 +789,7 @@ namespace SRMultiplayer.Networking
private static void OnGadgets(PacketGadgets packet)
{
List<int> regions = new List<int>();
foreach(var gadgetData in packet.Gadgets)
foreach (var gadgetData in packet.Gadgets)
{
if (SRSingleton<SceneContext>.Instance.GameModel.AllGadgetSites().TryGetValue(gadgetData.ID, out GadgetSiteModel model))
{
@ -823,7 +842,7 @@ namespace SRMultiplayer.Networking
}
}
foreach(var region in regions)
foreach (var region in regions)
{
if (Globals.Regions.TryGetValue(region, out NetworkRegion netRegion))
{
@ -881,7 +900,7 @@ namespace SRMultiplayer.Networking
private static void OnPuzzleSlots(PacketPuzzleSlots packet)
{
foreach(var puzzleSlotData in packet.PuzzleSlots)
foreach (var puzzleSlotData in packet.PuzzleSlots)
{
if (SRSingleton<SceneContext>.Instance.GameModel.AllSlots().TryGetValue(puzzleSlotData.ID, out PuzzleSlotModel model))
{
@ -919,7 +938,7 @@ namespace SRMultiplayer.Networking
private static void OnGordos(PacketGordos packet)
{
foreach(var gordoData in packet.Gordos)
foreach (var gordoData in packet.Gordos)
{
if (SRSingleton<SceneContext>.Instance.GameModel.AllGordos().TryGetValue(gordoData.ID, out GordoModel model))
{
@ -959,7 +978,7 @@ namespace SRMultiplayer.Networking
private static void OnAccessDoors(PacketAccessDoors packet)
{
foreach(var doorData in packet.Doors)
foreach (var doorData in packet.Doors)
{
if (SRSingleton<SceneContext>.Instance.GameModel.AllDoors().TryGetValue(doorData.ID, out AccessDoorModel model))
{
@ -1216,7 +1235,7 @@ namespace SRMultiplayer.Networking
}
var phaseSiteDirector = GameObject.FindObjectOfType<PhaseSiteDirector>();
if(phaseSiteDirector != null)
if (phaseSiteDirector != null)
{
phaseSiteDirector.ResetAllSites();
foreach (PhaseSite phaseSite in new List<PhaseSite>(phaseSiteDirector.availablePhaseSites))
@ -1295,7 +1314,7 @@ namespace SRMultiplayer.Networking
private static void OnLandPlotSiloAmmoAdd(PacketLandPlotSiloAmmoAdd packet)
{
if(NetworkAmmo.All.TryGetValue(packet.ID, out NetworkAmmo ammo))
if (NetworkAmmo.All.TryGetValue(packet.ID, out NetworkAmmo ammo))
{
ammo.MaybeAddToSpecificSlot((Identifiable.Id)packet.Ident, null, packet.Slot, packet.Count, packet.Overflow);
SRMP.Log($"NetworkAmmo add slot {packet.Slot} (Type: {(Identifiable.Id)packet.Ident} - Count: {packet.Count}) for {packet.ID}", "CLIENT");
@ -1488,7 +1507,7 @@ namespace SRMultiplayer.Networking
private static void OnLandPlots(PacketLandplots packet)
{
foreach(var plotData in packet.LandPlots)
foreach (var plotData in packet.LandPlots)
{
if (SRSingleton<SceneContext>.Instance.GameModel.AllLandPlots().TryGetValue(plotData.ID, out LandPlotModel model))
{
@ -1538,7 +1557,7 @@ namespace SRMultiplayer.Networking
{
var type = (PacketActorFX.FXType)packet.Type;
var slimeEat = netActor.GetComponentInChildren<SlimeEat>();
if(slimeEat != null)
if (slimeEat != null)
{
if (type == PacketActorFX.FXType.SlimeEatFavoriteFX)
{
@ -1748,7 +1767,7 @@ namespace SRMultiplayer.Networking
private static void OnActors(PacketActors packet)
{
foreach(var actorData in packet.Actors)
foreach (var actorData in packet.Actors)
{
if (!Globals.Actors.ContainsKey(actorData.ID))
{
@ -1809,7 +1828,7 @@ namespace SRMultiplayer.Networking
Globals.Actors.Add(netActor.ID, netActor);
}
catch(Exception ex)
catch (Exception ex)
{
SRMP.Log($"Could not create actor {actorData.ID}: {ex}");
}
@ -1906,30 +1925,23 @@ namespace SRMultiplayer.Networking
}
}
private static void OnPlayerAnimationSpeed(NetIncomingMessage im)
private static void OnPlayerAnimation(PacketPlayerAnimation packet)
{
byte id = im.ReadByte();
if (Globals.Players.TryGetValue(id, out NetworkPlayer player) && player.HasLoaded)
{
player.ReadAnimatorSpeed(im);
}
}
//handle character animation triggers
PacketPlayerAnimation.AnimationType type = (PacketPlayerAnimation.AnimationType)packet.Type;
private static void OnPlayerAnimationParameters(NetIncomingMessage im)
{
byte id = im.ReadByte();
if (Globals.Players.TryGetValue(id, out NetworkPlayer player) && player.HasLoaded)
{
player.ReadParameters(im);
}
}
private static void OnPlayerAnimationLayer(NetIncomingMessage im)
{
byte id = im.ReadByte();
if (Globals.Players.TryGetValue(id, out NetworkPlayer player) && player.HasLoaded)
if (Globals.Players.TryGetValue(packet.ID, out NetworkPlayer player) && player.HasLoaded)
{
player.ReadAnimatorLayer(im);
if(type == PacketPlayerAnimation.AnimationType.Speed)
player.ReadAnimatorSpeed(packet.internalData);
else if (type == PacketPlayerAnimation.AnimationType.Parameters)
{
player.ReadParameters(packet.internalData);
}
else
player.ReadAnimatorLayer(packet.internalData);
}
}
@ -1941,57 +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);
if (!Globals.IsServer)
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

@ -2,6 +2,7 @@
using Lidgren.Network;
using MonomiPark.SlimeRancher.DataModel;
using MonomiPark.SlimeRancher.Regions;
using Newtonsoft.Json.Linq;
using SRMultiplayer.Packets;
using System;
using System.Collections.Generic;
@ -19,14 +20,13 @@ namespace SRMultiplayer.Networking
if (!Globals.PacketSize.ContainsKey(type))
Globals.PacketSize.Add(type, 0);
Globals.PacketSize[type] += im.LengthBytes;
switch(type)
switch (type)
{
//Player animation
case PacketType.PlayerAnimation: OnPlayerAnimation(new PacketPlayerAnimation(im), player); break;
//Player
case PacketType.PlayerLoaded: OnPlayerLoaded(new PacketPlayerLoaded(im), player); break;
case PacketType.PlayerPosition: OnPlayerPosition(new PacketPlayerPosition(im), player); break;
case PacketType.PlayerAnimationLayer: OnPlayerAnimationLayer(im, player); break;
case PacketType.PlayerAnimationParameters: OnPlayerAnimationParameters(im, player); break;
case PacketType.PlayerAnimationSpeed: OnPlayerAnimationSpeed(im, player); break;
case PacketType.PlayerCurrency: OnPlayerCurrency(new PacketPlayerCurrency(im), player); break;
case PacketType.PlayerCurrencyDisplay: OnPlayerCurrencyDisplay(new PacketPlayerCurrencyDisplay(im), player); break;
case PacketType.PlayerUpgrade: OnPlayerUpgrade(new PacketPlayerUpgrade(im), player); break;
@ -132,7 +132,7 @@ namespace SRMultiplayer.Networking
case PacketType.RaceTime: OnRaceTime(new PacketRaceTime(im), player); break;
case PacketType.RaceTrigger: OnRaceTrigger(new PacketRaceTrigger(im), player); break;
default:
SRMP.Log($"Got unhandled packet from {player}: {type}");
SRMP.Log($"Got unhandled packet from {player}: {type}" + Enum.GetName(typeof(PacketType), type));
break;
}
}
@ -140,7 +140,7 @@ namespace SRMultiplayer.Networking
#region Race
private static void OnRaceTrigger(PacketRaceTrigger packet, NetworkPlayer player)
{
if(Globals.RaceTriggers.TryGetValue(packet.ID, out NetworkRaceTrigger trigger))
if (Globals.RaceTriggers.TryGetValue(packet.ID, out NetworkRaceTrigger trigger))
{
trigger.Activate();
}
@ -172,7 +172,7 @@ namespace SRMultiplayer.Networking
var generator = QuicksilverEnergyGenerator.allGenerators.FirstOrDefault(g => g.id == packet.ID);
if (generator)
{
if(Globals.LocalPlayer.CurrentGenerator.id == generator.id)
if (Globals.LocalPlayer.CurrentGenerator.id == generator.id)
{
generator.Activate();
}
@ -242,9 +242,9 @@ namespace SRMultiplayer.Networking
oasis.SetLive(!model.gameObj.activeInHierarchy);
var oasisTriggers = GameObject.FindObjectsOfType<OasisWaterTrigger>();
foreach(var trigger in oasisTriggers)
foreach (var trigger in oasisTriggers)
{
if(trigger.oasisToScale == oasis && !trigger.hasAlreadyActivated)
if (trigger.oasisToScale == oasis && !trigger.hasAlreadyActivated)
{
if (trigger.scaleCue != null)
{
@ -312,13 +312,23 @@ namespace SRMultiplayer.Networking
{
SRMP.Log($"Exchange TryAccept for {(Identifiable.Id)packet.ID} ({(ExchangeDirector.OfferType)packet.Type}", "SERVER");
requestedItemEntry.progress++;
if(offer.IsComplete())
if (offer.IsComplete())
{
foreach (var rewarder in Resources.FindObjectsOfTypeAll<RancherProgressAwarder>())
{
rewarder.AwardIfType(type);
}
SRSingleton<SceneContext>.Instance.ExchangeDirector.ClearOffer(type);
//trigger fireworks
//get ExchangeEjector
foreach (var eject in Resources.FindObjectsOfTypeAll<ExchangeEjector>())
{
//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);
}
SRSingleton<SceneContext>.Instance.ExchangeDirector.OfferDidChange();
}
@ -482,7 +492,7 @@ namespace SRMultiplayer.Networking
{
if (SRSingleton<SceneContext>.Instance.GameModel.AllGadgetSites().TryGetValue(packet.ID, out GadgetSiteModel model))
{
if(model.HasAttached())
if (model.HasAttached())
{
model.attached.transform.GetComponent<DroneGadget>().drone.ammo.MaybeAddToSpecificSlot((Identifiable.Id)packet.Ident, null, 0, 1);
}
@ -497,7 +507,7 @@ namespace SRMultiplayer.Networking
if (Globals.GadgetSites.TryGetValue(packet.ID, out NetworkGadgetSite netSite))
{
var echoNet = netSite.Site.GetComponentInChildren<EchoNet>(true);
if(echoNet != null)
if (echoNet != null)
{
echoNet.ResetSpawnTime(echoNet.model);
}
@ -510,7 +520,7 @@ namespace SRMultiplayer.Networking
if (Globals.GadgetSites.TryGetValue(packet.ID, out NetworkGadgetSite netSite))
{
var snare = netSite.Site.GetComponentInChildren<GordoSnare>(true);
if(snare != null)
if (snare != null)
{
if (!snare.IsBaited() || snare.HasSnaredGordo())
{
@ -579,7 +589,7 @@ namespace SRMultiplayer.Networking
{
Globals.GadgetSites.TryGetValue(packet.ID, out NetworkGadgetSite netSite);
bool didUnproxy = false;
if(netSite != null)
if (netSite != null)
{
if (!netSite.Region.Region.root.activeSelf)
{
@ -622,7 +632,7 @@ namespace SRMultiplayer.Networking
foreach (var data in packet.Amounts)
{
SRSingleton<SceneContext>.Instance.GameModel.GetGadgetsModel().craftMatCounts[(Identifiable.Id)data.Key] -= data.Value;
if(SRSingleton<SceneContext>.Instance.GameModel.GetGadgetsModel().craftMatCounts[(Identifiable.Id)data.Key] < 0)
if (SRSingleton<SceneContext>.Instance.GameModel.GetGadgetsModel().craftMatCounts[(Identifiable.Id)data.Key] < 0)
{
SRSingleton<SceneContext>.Instance.GameModel.GetGadgetsModel().craftMatCounts[(Identifiable.Id)data.Key] = 0;
}
@ -720,7 +730,7 @@ namespace SRMultiplayer.Networking
if (attachFashions != null)
{
var component = SRSingleton<GameContext>.Instance.LookupDirector.GetPrefab((Identifiable.Id)packet.Fashion)?.GetComponent<Fashion>();
if(component != null)
if (component != null)
{
attachFashions.Attach(component, !attachFashions.gameObject.activeInHierarchy);
}
@ -821,17 +831,17 @@ namespace SRMultiplayer.Networking
private static void OnWorldDecorizer(PacketWorldDecorizer packet, NetworkPlayer player)
{
foreach(var c in packet.Contents)
foreach (var c in packet.Contents)
{
for(int i = 0; i < c.Value; i++)
for (int i = 0; i < c.Value; i++)
{
SRSingleton<SceneContext>.Instance.GameModel.decorizer.contents.Increment(c.Key);
}
}
foreach(var setting in packet.Settings)
foreach (var setting in packet.Settings)
{
var storage = SRSingleton<SceneContext>.Instance.GameModel.decorizer.participants.FirstOrDefault(c => ((DecorizerStorage)c).id == setting.Key);
if(storage != null)
if (storage != null)
{
((DecorizerStorage)storage).selected = (Identifiable.Id)setting.Value;
}
@ -952,7 +962,7 @@ namespace SRMultiplayer.Networking
if (SRSingleton<SceneContext>.Instance.GameModel.AllLandPlots().TryGetValue(packet.ID, out LandPlotModel model))
{
var incinerate = model.gameObj.GetComponentInChildren<Incinerate>();
if(incinerate != null)
if (incinerate != null)
{
SRBehaviour.SpawnAndPlayFX(incinerate.ExplosionFX, packet.Position, packet.Rotation);
if (packet.Small)
@ -976,7 +986,7 @@ namespace SRMultiplayer.Networking
private static void OnGlobalFX(PacketGlobalFX packet, NetworkPlayer player)
{
if(Globals.FXPrefabs.TryGetValue(packet.Name, out GameObject prefabFX))
if (Globals.FXPrefabs.TryGetValue(packet.Name, out GameObject prefabFX))
{
SRBehaviour.SpawnAndPlayFX(prefabFX, packet.Position, Quaternion.identity);
}
@ -1080,7 +1090,7 @@ namespace SRMultiplayer.Networking
if (SRSingleton<SceneContext>.Instance.GameModel.AllLandPlots().TryGetValue(packet.ID, out LandPlotModel model))
{
var collector = model.gameObj.GetComponentInChildren<PlortCollector>();
if(collector != null)
if (collector != null)
{
collector.StartCollection();
}
@ -1268,14 +1278,14 @@ namespace SRMultiplayer.Networking
private static void OnRegionOwner(PacketRegionOwner packet, NetworkPlayer player)
{
if(Globals.Regions.TryGetValue(packet.ID, out NetworkRegion netRegion))
if (Globals.Regions.TryGetValue(packet.ID, out NetworkRegion netRegion))
{
if(packet.Owner == 0 && netRegion.Owner == player.ID)
if (packet.Owner == 0 && netRegion.Owner == player.ID)
{
netRegion.SetOwnership(0);
packet.SendToAll();
}
else if(packet.Owner != 0 && netRegion.Owner == 0)
else if (packet.Owner != 0 && netRegion.Owner == 0)
{
netRegion.SetOwnership(packet.Owner);
packet.SendToAll();
@ -1338,7 +1348,7 @@ namespace SRMultiplayer.Networking
var slimeFeral = netActor.GetComponentInChildren<SlimeFeral>(true);
if (slimeFeral != null)
{
if(packet.Feral)
if (packet.Feral)
{
slimeFeral.MakeFeral();
}
@ -1384,7 +1394,7 @@ namespace SRMultiplayer.Networking
if (Globals.Actors.TryGetValue(packet.ID, out NetworkActor netActor))
{
var cycle = netActor.GetComponentInChildren<ResourceCycle>(true);
if(cycle != null)
if (cycle != null)
{
var state = (ResourceCycle.State)packet.State;
//SRMP.Log($"Resource state for {netActor.name} ({netActor.ID}): {state}", "SERVER");
@ -1401,7 +1411,7 @@ namespace SRMultiplayer.Networking
}
TweenUtil.ScaleTo(cycle.gameObject, cycle.defaultScale, 4f, Ease.InOutQuad);
}
else if(state == ResourceCycle.State.EDIBLE)
else if (state == ResourceCycle.State.EDIBLE)
{
cycle.MakeEdible();
cycle.additionalRipenessDelegate = null;
@ -1427,7 +1437,7 @@ namespace SRMultiplayer.Networking
cycle.vacuumable.Pending = false;
}
}
else if(state == ResourceCycle.State.ROTTEN)
else if (state == ResourceCycle.State.ROTTEN)
{
cycle.Rot();
cycle.SetRotten(!cycle.gameObject.activeInHierarchy);
@ -1525,7 +1535,7 @@ namespace SRMultiplayer.Networking
netActor.KnownPlayers.AddRange(Globals.Players.Values.Where(p => p.HasLoaded));
var resourceCycle = actorObj.GetComponentInChildren<ResourceCycle>(true);
if(resourceCycle != null)
if (resourceCycle != null)
{
resourceCycle.SetInitState(ResourceCycle.State.UNRIPE, double.MaxValue);
}
@ -1574,7 +1584,7 @@ namespace SRMultiplayer.Networking
private static void OnPlayerCurrencyDisplay(PacketPlayerCurrencyDisplay packet, NetworkPlayer player)
{
SRSingleton<SceneContext>.Instance.PlayerState.SetCurrencyDisplay(packet.IsNull ? null : new int?(packet.Currency));
if(packet.IsNull)
if (packet.IsNull)
{
SRSingleton<PopupElementsUI>.Instance.CreateCoinsPopup(packet.Currency, PlayerState.CoinsType.DRONE);
}
@ -1629,58 +1639,56 @@ namespace SRMultiplayer.Networking
packet.SendToAllExcept(player);
}
private static void OnPlayerAnimationSpeed(NetIncomingMessage im, NetworkPlayer player)
private static void OnPlayerAnimation(PacketPlayerAnimation packet, NetworkPlayer player)
{
if (player.HasLoaded)
{
byte id = im.ReadByte();
player.ReadAnimatorSpeed(im);
switch (packet.Type)
{
case (byte)PacketPlayerAnimation.AnimationType.Speed:
player.ReadAnimatorSpeed(packet.internalData);
break;
case (byte)PacketPlayerAnimation.AnimationType.Layer:
player.ReadAnimatorLayer(packet.internalData);
break;
case (byte)PacketPlayerAnimation.AnimationType.Parameters:
player.ReadParameters(packet.internalData);
break;
}
NetOutgoingMessage om = NetworkServer.Instance.CreateMessage();
om.Write(im);
NetworkServer.Instance.SendToAll(om, player);
}
}
private static void OnPlayerAnimationParameters(NetIncomingMessage im, NetworkPlayer player)
{
if (player.HasLoaded)
{
byte id = im.ReadByte();
player.ReadParameters(im);
NetOutgoingMessage om = NetworkServer.Instance.CreateMessage();
om.Write(im);
NetworkServer.Instance.SendToAll(om, player);
}
}
private static void OnPlayerAnimationLayer(NetIncomingMessage im, NetworkPlayer player)
{
if(player.HasLoaded)
{
byte id = im.ReadByte();
player.ReadAnimatorLayer(im);
NetOutgoingMessage om = NetworkServer.Instance.CreateMessage();
om.Write(im);
NetworkServer.Instance.SendToAll(om, player);
}
}
private static void OnPlayerPosition(PacketPlayerPosition packet, NetworkPlayer player)
{
if (player.HasLoaded)
{
player.PositionRotationUpdate(packet.Position, packet.Rotation, false);
player.UpdateWeaponRotation(packet.WeaponY);
player.CurrentRegionSet = (RegionRegistry.RegionSetId)packet.RegionSet;
packet.ID = player.ID;
//make the incoming message an out going message
packet.SendToAllExcept(player, NetDeliveryMethod.Unreliable);
}
}
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)
{
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);
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);
}
}
}
private static void OnPlayerLoaded(PacketPlayerLoaded packet, NetworkPlayer player)
{
new PacketWorldData()
@ -1707,7 +1715,7 @@ namespace SRMultiplayer.Networking
Contents = SRSingleton<SceneContext>.Instance.GameModel.decorizer.contents.ToDictionary(c => c.Key, v => v.Value),
Settings = SRSingleton<SceneContext>.Instance.GameModel.decorizer.settings.ToDictionary(s => s.Key, v => (ushort)v.Value.selected)
}.Send(player, NetDeliveryMethod.ReliableOrdered);
new PacketLandplots()
{
LandPlots = Globals.LandPlots.Values.Where(l => l.Plot.model != null).Select(l => new PacketLandplots.LandPlotData() { ID = l.Location.id, Model = l.Plot.model }).ToList()

View file

@ -340,6 +340,7 @@ namespace SRMultiplayer.Networking
{
Globals.HandlePacket = true;
PacketType type = (PacketType)im.ReadUInt16();
var player = Globals.Players.Values.FirstOrDefault(p => p.Connection != null && p.Connection.RemoteUniqueIdentifier == im.SenderConnection.RemoteUniqueIdentifier);
if (player != null)
{

View file

@ -1,8 +1,10 @@
using MonomiPark.SlimeRancher.Regions;
using DG.Tweening;
using MonomiPark.SlimeRancher.Regions;
using SRMultiplayer.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
@ -52,7 +54,7 @@ namespace SRMultiplayer.Networking
private void OnEnable()
{
if(Owner == 0)
if (Owner == 0)
{
TakeOwnership();
}
@ -68,7 +70,7 @@ namespace SRMultiplayer.Networking
private void Update()
{
if(IsLocal)
if (IsLocal)
{
m_MovementUpdateTimer -= Time.deltaTime;
if (m_MovementUpdateTimer <= 0)
@ -92,7 +94,7 @@ namespace SRMultiplayer.Networking
}.Send(Lidgren.Network.NetDeliveryMethod.Unreliable);
}
if(SlimeEat != null &&
if (SlimeEat != null &&
(!Utils.CloseEnoughForMe(SlimeEat.emotions.GetCurr(SlimeEmotions.Emotion.AGITATION), m_PreviousEmotions[SlimeEmotions.Emotion.AGITATION], 0.1f) ||
!Utils.CloseEnoughForMe(SlimeEat.emotions.GetCurr(SlimeEmotions.Emotion.FEAR), m_PreviousEmotions[SlimeEmotions.Emotion.FEAR], 0.1f) ||
!Utils.CloseEnoughForMe(SlimeEat.emotions.GetCurr(SlimeEmotions.Emotion.HUNGER), m_PreviousEmotions[SlimeEmotions.Emotion.HUNGER], 0.1f)))
@ -113,7 +115,7 @@ namespace SRMultiplayer.Networking
}
else
{
if(m_Rigidbody != null)
if (m_Rigidbody != null)
{
m_Rigidbody.velocity = Vector3.zero;
}
@ -227,7 +229,7 @@ namespace SRMultiplayer.Networking
}
}
var destroyOnTouching = GetComponentInChildren<DestroyOnTouching>();
if(destroyOnTouching != null)
if (destroyOnTouching != null)
{
if (destroyOnTouching.destroyFX != null)
{
@ -237,6 +239,7 @@ namespace SRMultiplayer.Networking
var exchangeBreakOnImpact = GetComponentInChildren<ExchangeBreakOnImpact>();
if (exchangeBreakOnImpact != null)
{
SRMP.Log("Exchange Box Broke!", "ACTOR");
SRBehaviour.SpawnAndPlayFX(exchangeBreakOnImpact.breakFX, exchangeBreakOnImpact.gameObject.transform.position, exchangeBreakOnImpact.gameObject.transform.rotation);
}
var breakOnImpact = GetComponentInChildren<BreakOnImpactBase>();
@ -245,7 +248,7 @@ namespace SRMultiplayer.Networking
SRBehaviour.SpawnAndPlayFX(breakOnImpact.breakFX, breakOnImpact.gameObject.transform.position, breakOnImpact.gameObject.transform.rotation);
}
var quicksilver = GetComponentInChildren<QuicksilverPlortCollector>();
if(quicksilver != null)
if (quicksilver != null)
{
if (quicksilver.destroyFX != null)
{

View file

@ -10,7 +10,7 @@ namespace SRMultiplayer.Networking
{
public class NetworkGordo : MonoBehaviour
{
public string ID { get { return Gordo.id == null ? Gordo.GetComponentInParent<GadgetSite>(true).id : Gordo.id; } }
public string ID { get { return Gordo.id == null ? Gordo.GetComponentInParent<GadgetSite>(true).id : Gordo.id; } }
public GordoEat Gordo;
public NetworkRegion Region;
@ -33,36 +33,51 @@ namespace SRMultiplayer.Networking
public void Burst()
{
//if object is in active mark the reach target
if (gameObject.activeInHierarchy)
{
StartCoroutine(ReachedTarget());
}
else
{
//if not just dismiss the gordo completely
Gordo.gameObject.SetActive(false);
Gordo.SetEatenCount(-1);
}
}
//process the gordo burst reaction
private IEnumerator ReachedTarget()
{
//start the burst and begin sounds and animations
Gordo.WillStartBurst();
Gordo.GetComponent<GordoFaceAnimator>().SetTrigger("Strain");
SECTR_AudioSystem.Play(Gordo.strainCue, Gordo.transform.position, false);
//wait for amination/sounds to finish
yield return new WaitForSeconds(2f);
SECTR_AudioSystem.Play(Gordo.burstCue, Gordo.transform.position, false);
//if the gordo has a destroy effect process it
if (Gordo.destroyFX != null)
{
//play the spawn behavior for destroy events for the gordo that is bursting
GameObject gameObject = SRBehaviour.SpawnAndPlayFX(Gordo.destroyFX, Gordo.transform.position + Vector3.up * 2f, Gordo.transform.rotation);
//get the gordo slime type
Identifiable component = Gordo.gameObject.GetComponent<Identifiable>();
//get the color of the current gordo
Color[] colors = SlimeUtil.GetColors(Gordo.gameObject, (component != null) ? component.id : Identifiable.Id.NONE, true);
//get the slime children spawned by the gordo
RecolorSlimeMaterial[] componentsInChildren = gameObject.GetComponentsInChildren<RecolorSlimeMaterial>();
for (int i = 0; i < componentsInChildren.Length; i++)
{
//foreach slime in the count spawned by the gordo, set their coloring
componentsInChildren[i].SetColors(colors[0], colors[1], colors[2]);
}
}
//trigger the burst completed event
Gordo.DidCompleteBurst();
//despawn the bursted gordo from game
Gordo.gameObject.SetActive(false);
Gordo.SetEatenCount(-1);
yield break;

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
{
@ -62,33 +60,42 @@ namespace SRMultiplayer.Networking
continue;
}
NetOutgoingMessage writer = CreateMessage();
writer.Write((ushort)PacketType.PlayerAnimationLayer);
writer.Write(Globals.LocalID);
WriteAnimatorLayer(writer, stateHash, normalizedTime, i, layerWeight[i]);
Send(writer);
//NetOutgoingMessage writer = CreateMessage();
//add the object to the writer but dont send it yet
var packet = new PacketPlayerAnimation()
{
Type = (byte)PacketPlayerAnimation.AnimationType.Layer,
ID = Globals.LocalID
};
//add extra parameters
WriteAnimatorLayer(packet, stateHash, normalizedTime, i, layerWeight[i]);
//send the changes
packet.Send();
}
CheckSpeed();
}
void WriteAnimatorLayer(NetOutgoingMessage 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(NetIncomingMessage 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)
{
@ -106,24 +113,33 @@ namespace SRMultiplayer.Networking
if (Mathf.Abs(previousSpeed - newSpeed) > 0.001f)
{
previousSpeed = newSpeed;
NetOutgoingMessage writer = CreateMessage();
writer.Write((ushort)PacketType.PlayerAnimationSpeed);
writer.Write(Globals.LocalID);
WriteAnimatorSpeed(writer, newSpeed);
Send(writer);
//NetOutgoingMessage writer = CreateMessage();
//add the object to the writer but dont send it yet
var packet = new PacketPlayerAnimation()
{
Type = (byte)PacketPlayerAnimation.AnimationType.Speed,
ID = Globals.LocalID
};
//add extra parameters
WriteAnimatorSpeed(packet, newSpeed);
//send the speed change
packet.Send();
}
}
void WriteAnimatorSpeed(NetOutgoingMessage writer, float newSpeed)
void WriteAnimatorSpeed(PacketPlayerAnimation writer, float newSpeed)
{
writer.Write(newSpeed);
writer.Add(newSpeed);
}
public void ReadAnimatorSpeed(NetIncomingMessage 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;
@ -179,12 +195,17 @@ namespace SRMultiplayer.Networking
{
nextSendTime = now + syncInterval;
NetOutgoingMessage writer = CreateMessage();
writer.Write((ushort)PacketType.PlayerAnimationParameters);
writer.Write(Globals.LocalID);
if (WriteParameters(writer))
//add the object to the writer but dont send it yet
var packet = new PacketPlayerAnimation()
{
Send(writer);
Type = (byte)PacketPlayerAnimation.AnimationType.Parameters,
ID = Globals.LocalID
};
//add extra parameters
if (WriteParameters(packet))
{
packet.Send();
}
}
}
@ -226,10 +247,10 @@ namespace SRMultiplayer.Networking
return dirtyBits;
}
bool WriteParameters(NetOutgoingMessage 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)
@ -239,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(NetIncomingMessage 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

@ -150,6 +150,11 @@ namespace SRMultiplayer.Networking
}
}
public float GetWeaponLocation()
{
return m_ActualWeaponY;
}
private void OnAnimatorIK()
{
if(m_Animator != null && m_LeftHandTarget != null)

View file

@ -0,0 +1,133 @@
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
{
[Packet(PacketType.PlayerAnimation)]
public class PacketPlayerAnimation : Packet
{
public enum AnimationType : int
{
Layer,
Speed,
Parameters
}
public byte ID;
public byte Type;
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() { }
/// <summary>
/// mark construction inheritance so the deserialization automatically happens for is
/// since the base decalres this
/// </summary>
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); }

View file

@ -1,4 +1,5 @@
using Lidgren.Network;
using SRMultiplayer.Networking;
using System;
using System.Collections.Generic;
using System.Linq;
@ -9,7 +10,15 @@ namespace SRMultiplayer.Packets
public interface IPacket
{
PacketType GetPacketType();
/// <summary>
/// Searilizes the given packet item
/// </summary>
/// <param name="om">Outgoing Message that the packet should be added to</param>
void Serialize(NetOutgoingMessage om);
void Deserialize(NetIncomingMessage im);
/// <summary>
/// Deserializes the given packet item
/// </summary>
/// <param name="om">Incoming Message that the packet should be deserialized from</param>
void Deserialize(NetIncomingMessage im);
}
}

View file

@ -9,16 +9,42 @@ namespace SRMultiplayer.Packets
{
public abstract class Packet : IPacket
{
/// <summary>
/// Parameterless constructor to be used through inheritance
/// </summary>
public Packet() { }
/// <summary>
/// Incoming message based construtor that deserielizes the item for the message
/// </summary>
public Packet(NetIncomingMessage im) { Deserialize(im); }
/// <summary>
/// Searilizes the given packet item
/// </summary>
/// <param name="om">Outgoing Message that the packet should be added to</param>
public virtual void Serialize(NetOutgoingMessage om)
{
om.Write((ushort)GetPacketType());
//writes the object type using the gettype name
//this allows the object to assume its object packet type
//om.Write(this.GetType().AssemblyQualifiedName);
//
om.WriteAllFields(this, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
}
/// <summary>
/// Deserializes the given packet item
/// </summary>
/// <param name="om">Incoming Message that the packet should be deserialized from</param>
public virtual void Deserialize(NetIncomingMessage im)
{
im.ReadAllFields(this, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
}
public virtual void Serialize(NetOutgoingMessage om)
{
om.Write((ushort)GetPacketType());
om.WriteAllFields(this, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
}
public PacketType GetPacketType()
{

View file

@ -7,9 +7,7 @@
PlayerLeft,
PlayerPosition,
PlayerLoaded,
PlayerAnimationLayer,
PlayerAnimationSpeed,
PlayerAnimationParameters,
PlayerAnimation,
PlayerFX,
PlayAudio,
ActorSpawn,
@ -97,6 +95,7 @@
ExchangeTryAccept,
ExchangeClear,
ExchangeOffers,
ExchangeBreak,
GordoEat,
Oasis,
OasisLive,

View file

@ -1,9 +1,13 @@
using HarmonyLib;
using MonomiPark.SlimeRancher.Regions;
using SRMultiplayer.Networking;
using SRMultiplayer.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text;
using UnityEngine;
namespace SRMultiplayer.Patches
{
@ -11,11 +15,19 @@ namespace SRMultiplayer.Patches
[HarmonyPatch("BreakOpen")]
class ExchangeBreakOnImpact_BreakOpen
{
static bool Prefix(ExchangeBreakOnImpact __instance)
{
if (!Globals.IsMultiplayer) return true;
//if multiplayer, only the server can trigger the impact
if (!Globals.IsMultiplayer) return true;
var entity = __instance.GetComponent<NetworkActor>();
SRMP.Log("Exchange Box Break: " + (entity != null && entity.IsLocal), "EXCHANGE");
//if the box exists and the entity is local process the break
return (entity != null && entity.IsLocal);
}
}

View file

@ -22,7 +22,18 @@ namespace SRMultiplayer.Patches
{
if (Globals.Actors.ContainsKey(netActor.ID))
{
//check if this is an exchange box
var exchangeBreakOnImpact = netActor.GetComponentInChildren<ExchangeBreakOnImpact>();
if (exchangeBreakOnImpact != null)
{
//exchange box was found processing it with the ondestroy command instead of just removing it!
//netActor.OnDestroyEffect();
//Destroyer.DestroyActor(netActor.gameObject, "NetworkHandlerServer.OnActorDestroy");
}
//make sure the actor still gets cleaned up
Globals.Actors.Remove(netActor.ID);
new PacketActorDestroy()
{
ID = netActor.ID

View file

@ -17,7 +17,9 @@ namespace SRMultiplayer.Patches
{
if (!Globals.IsMultiplayer) return;
//only handle the client if the client is the one disconnecting
NetworkClient.Instance.Disconnect();
//if server ahndle the shutdown
NetworkServer.Instance.Disconnect();
}
}

View file

@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SRMultiplayer
{
public enum PauseState
{
Pause,
Playing
}
}

View file

@ -15,7 +15,7 @@ using System.Resources;
[assembly: AssemblyCulture("")]
// Version informationr(
[assembly: AssemblyVersion("0.0.0.1488")]
[assembly: AssemblyFileVersion("0.0.0.1488")]
[assembly: AssemblyVersion("0.0.0.1510")]
[assembly: AssemblyFileVersion("0.0.0.1510")]
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]

View file

@ -20,26 +20,41 @@ namespace SRMultiplayer
private float m_LastTimeSync;
/// <summary>
/// Acts as the initializer for the Mod
/// </summary>
public override void Awake()
{
base.Awake();
//attach scene manager to trigger event when in a menu or loading up a game
SceneManager.activeSceneChanged += SceneManager_activeSceneChanged;
//attach log messager to log all game errors and exceptions into the SRMP Logs
Application.logMessageReceived += Application_logMessageReceived;
//load up mod specific resources
var myLoadedAssetBundle = AssetBundle.LoadFromMemory(Utils.ExtractResource("SRMultiplayer.srmultiplayer.dat"));
if (myLoadedAssetBundle == null)
{
SRMP.Log("Failed to load AssetBundle!");
return;
}
//load up the Player moment animator for the Beatrix model
Globals.BeatrixController = myLoadedAssetBundle.LoadAsset<RuntimeAnimatorController>("Controller");
Globals.IngameMultiplayerMenuPrefab = myLoadedAssetBundle.LoadAsset<GameObject>("IngameMultiplayerMenu");
Globals.MainMultiplayerMenuPrefab = myLoadedAssetBundle.LoadAsset<GameObject>("MainMultiplayerMenu");
}
//unused prefab menus, these menus functions are handled in the floating gui
//Globals.IngameMultiplayerMenuPrefab = myLoadedAssetBundle.LoadAsset<GameObject>("IngameMultiplayerMenu");
//Globals.MainMultiplayerMenuPrefab = myLoadedAssetBundle.LoadAsset<GameObject>("MainMultiplayerMenu");
}
/// <summary>
/// Subscriber to the Applicaiton log and process it on to the Mods console
/// </summary>
/// <param name="condition">Log condition</param>
/// <param name="stackTrace">Stack trace of log strigger (if applicable)</param>
/// <param name="type">Log Type</param>
private void Application_logMessageReceived(string condition, string stackTrace, LogType type)
{
//if Error or Exception hand the error of to the Mods log/console to display
if(type == LogType.Error || type == LogType.Exception)
{
SRMP.Log(condition);
@ -54,6 +69,10 @@ namespace SRMultiplayer
//menuObj.AddComponent<NetworkClientUI>();
}
/// <summary>
/// After triggering base destroy
/// trigger disconnect and shut down the server
/// </summary>
public override void OnDestroy()
{
base.OnDestroy();
@ -62,18 +81,25 @@ namespace SRMultiplayer
NetworkServer.Instance.Disconnect();
}
/// <summary>
/// On Game quit trigger disconnect and shut down the server
/// </summary>
private void OnApplicationQuit()
{
NetworkClient.Instance.Disconnect();
NetworkServer.Instance.Disconnect();
}
/// <summary>
/// On Update triggered sync up game time
/// </summary>
private void Update()
{
if(Globals.GameLoaded)
{
if(Globals.IsServer)
{
//every 30 seconds send a time updater out to all clients
if(Time.time - m_LastTimeSync > 30)
{
m_LastTimeSync = Time.time;
@ -98,17 +124,28 @@ namespace SRMultiplayer
}
}
/// <summary>
/// Handle scene changed events triggered by the game
/// </summary>
/// <param name="from">Scene previously</param>
/// <param name="to">New Scene</param>
private void SceneManager_activeSceneChanged(Scene from, Scene to)
{
//trigger handlers for returning or going to the main menu
if (to.buildIndex == 2) OnMainMenuLoaded();
if (to.buildIndex == 3) OnGameLoaded();
//trigger handlers for loading the game
else if (to.buildIndex == 3) OnGameLoaded();
}
/// <summary>
/// Handle user changing to the main menu, whether it is start up or from saving/ being kicked out of the game
/// </summary>
private void OnMainMenuLoaded()
{
//var menuObj = Instantiate(Globals.MainMultiplayerMenuPrefab, null, false);
//menuObj.AddComponent<NetworkClientUI>();
//innitialize all necessary global variables
Globals.LocalID = 0;
Globals.DisableAchievements = false;
Globals.GameLoaded = false;
@ -135,6 +172,8 @@ namespace SRMultiplayer
Globals.Nutcrackers.Clear();
Globals.RaceTriggers.Clear();
NetworkAmmo.All.Clear();
//clean up any lingering players in the global list
foreach (var player in Globals.Players.Values.ToList())
{
if(player != null && player.gameObject != null)
@ -144,9 +183,14 @@ namespace SRMultiplayer
}
Globals.Players.Clear();
//reset the chat
ChatUI.Instance.Clear();
}
/// <summary>
/// Handle the user loading into the multiplayer game
/// </summary>
private void OnGameLoaded()
{
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
@ -365,6 +409,12 @@ namespace SRMultiplayer
private static FileStream m_LogFileStream;
private static StreamWriter m_LogWriter;
/// <summary>
/// Custom message logging of a given message
/// </summary>
/// <param name="msg">Main message to be logged</param>
/// <param name="prefix">Prefix to be displayed before the message. Prefix will be after time marker and before the message
/// It will also be incapsulated in []</param>
public static void Log(string msg, string prefix = null)
{
if(m_LogFileStream == null)

View file

@ -9,14 +9,14 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SRMultiplayer</RootNamespace>
<AssemblyName>SRMP</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<DebugType>portable</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\Builds\SRMP\</OutputPath>
<DefineConstants>__CONSTRAINED__;Standalone</DefineConstants>
@ -74,24 +74,25 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="0Harmony">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\0Harmony.dll</HintPath>
<HintPath>.\0Harmony.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Assembly-CSharp_publicized">
<HintPath>..\Libs\Assembly-CSharp_publicized.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="DOTween">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\DOTween.dll</HintPath>
<HintPath>.\DOTween.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="InControl">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\InControl.dll</HintPath>
<HintPath>.\InControl.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="SRML, Version=0.1.8.2, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libs\SRML.dll</HintPath>
<HintPath>..\Libs\Newtonsoft.Json.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@ -103,54 +104,73 @@
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="Unity.TextMeshPro">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\Unity.TextMeshPro.dll</HintPath>
<HintPath>.\Unity.TextMeshPro.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityCoreMod, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\UnityCoreMod.dll</HintPath>
<HintPath>.\UnityCoreMod.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\UnityEngine.dll</HintPath>
<HintPath>.\UnityEngine.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.AnimationModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
<HintPath>.\UnityEngine.AnimationModule.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.AssetBundleModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\UnityEngine.AssetBundleModule.dll</HintPath>
<HintPath>.\UnityEngine.AssetBundleModule.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
<HintPath>.\UnityEngine.CoreModule.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.IMGUIModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath>
<HintPath>.\UnityEngine.IMGUIModule.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.InputLegacyModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
<HintPath>.\UnityEngine.InputLegacyModule.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.InputModule">
<HintPath>.\UnityEngine.InputModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.JSONSerializeModule">
<HintPath>.\UnityEngine.JSONSerializeModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.PhysicsModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
<HintPath>.\UnityEngine.PhysicsModule.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.TextCoreModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\UnityEngine.TextCoreModule.dll</HintPath>
<HintPath>.\UnityEngine.TextCoreModule.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.TextRenderingModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
<HintPath>.\UnityEngine.TextRenderingModule.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.UI">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\UnityEngine.UI.dll</HintPath>
<HintPath>.\UnityEngine.UI.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.UIModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Slime Rancher\SlimeRancher_Data\Managed\UnityEngine.UIModule.dll</HintPath>
<HintPath>.\UnityEngine.UIModule.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ChatUI.cs" />
<Compile Include="Compression.cs" />
<Compile Include="Console\ConsoleInput.cs" />
<Compile Include="Console\ConsoleWindow.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="Custom UI\ChatUI.cs" />
<Compile Include="Custom UI\MultiplayerUI.cs" />
<Compile Include="Custom UI\TestUI.cs" />
<Compile Include="Globals.cs" />
<Compile Include="Lidgren.Network\Encryption\NetAESEncryption.cs" />
<Compile Include="Lidgren.Network\Encryption\NetBlockEncryptionBase.cs" />
@ -228,11 +248,13 @@
<Compile Include="Lidgren.Network\Platform\PlatformWinRT.cs" />
<Compile Include="MainSRML.cs" />
<Compile Include="MainStandalone.cs" />
<Compile Include="MultiplayerUI.cs" />
<Compile Include="Networking\Communication\NetworkClient.cs" />
<Compile Include="Networking\Communication\NetworkHandlerClient.cs" />
<Compile Include="Networking\Communication\NetworkHandlerServer.cs" />
<Compile Include="Networking\Communication\NetworkServer.cs" />
<Compile Include="Networking\NetworkAccessDoor.cs" />
<Compile Include="Networking\NetworkActor.cs" />
<Compile Include="Networking\NetworkAmmo.cs" />
<Compile Include="Networking\NetworkClient.cs" />
<Compile Include="Networking\NetworkClientUI.cs" />
<Compile Include="Networking\NetworkDirectedActorSpawner.cs" />
<Compile Include="Networking\NetworkDrone.cs" />
@ -241,8 +263,6 @@
<Compile Include="Networking\NetworkFireColumn.cs" />
<Compile Include="Networking\NetworkGadgetSite.cs" />
<Compile Include="Networking\NetworkGordo.cs" />
<Compile Include="Networking\NetworkHandlerClient.cs" />
<Compile Include="Networking\NetworkHandlerServer.cs" />
<Compile Include="Networking\NetworkHostUI.cs" />
<Compile Include="Networking\NetworkKookadobaPatchNode.cs" />
<Compile Include="Networking\NetworkLandplot.cs" />
@ -256,11 +276,11 @@
<Compile Include="Networking\NetworkPuzzleSlot.cs" />
<Compile Include="Networking\NetworkRaceTrigger.cs" />
<Compile Include="Networking\NetworkRegion.cs" />
<Compile Include="Networking\NetworkServer.cs" />
<Compile Include="Networking\NetworkSpawnResource.cs" />
<Compile Include="Networking\NetworkTreasurePod.cs" />
<Compile Include="Networking\NetworkWorldStateMasterSwitch.cs" />
<Compile Include="Packets\AccessDoors\PacketAccessDoors.cs" />
<Compile Include="Packets\Actors\PacketPlayerAnimation.cs" />
<Compile Include="Packets\Exchanges\PacketExchangeClear.cs" />
<Compile Include="Packets\Exchanges\PacketExchangeOffer.cs" />
<Compile Include="Packets\Exchanges\PacketExchangeOffers.cs" />
@ -462,19 +482,20 @@
<Compile Include="Patches\Patch_WeaponVacuum.cs" />
<Compile Include="Patches\Patch_WorldStateMasterSwitch.cs" />
<Compile Include="Patches\Patch_ZoneDirector.cs" />
<Compile Include="PauseState.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AssemblyInfo.tt</DependentUpon>
</Compile>
<Compile Include="SRMP.cs" />
<Compile Include="SRMPConsole.cs" />
<Compile Include="TestUI.cs" />
<Compile Include="UserData.cs" />
<Compile Include="Utils.cs" />
<Compile Include="Console\SRMPConsole.cs" />
<Compile Include="Utils\Compression.cs" />
<Compile Include="Utils\Extensions.cs" />
<Compile Include="Utils\Objects.cs" />
<Compile Include="Utils\Utils.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="Console\Console Commands.txt" />
<Content Include="modinfo.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>modinfo.json</LastGenOutput>
@ -487,6 +508,11 @@
<ItemGroup>
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'SRML|AnyCPU' ">
<Reference Include="SRML">
<HintPath>..\Libs\SRML.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="modinfo.json">
<AutoGen>True</AutoGen>

View file

@ -1,238 +0,0 @@
using MonomiPark.SlimeRancher.Regions;
using SRMultiplayer.Networking;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
namespace SRMultiplayer
{
public class SRMPConsole : MonoBehaviour
{
ConsoleWindow console = new ConsoleWindow();
ConsoleInput input = new ConsoleInput();
//
// Create console window, register callbacks
//
void Awake()
{
DontDestroyOnLoad(gameObject);
console.Initialize();
console.SetTitle("Slime Rancher");
input.OnInputText += OnInputText;
Application.logMessageReceived += Application_logMessageReceived;
SRMP.Log("Console Started");
}
private void Application_logMessageReceived(string condition, string stackTrace, LogType type)
{
if (type == LogType.Warning)
Console.ForegroundColor = ConsoleColor.Yellow;
else if (type == LogType.Error)
Console.ForegroundColor = ConsoleColor.Red;
else
Console.ForegroundColor = ConsoleColor.White;
// We're half way through typing something, so clear this line ..
if (Console.CursorLeft != 0)
input.ClearLine();
Console.WriteLine(condition);
if (!string.IsNullOrEmpty(stackTrace))
Console.WriteLine(stackTrace);
// If we were typing something re-add it.
input.RedrawInputLine();
}
//
// Text has been entered into the console
// Run it as a console command
//
void OnInputText(string obj)
{
var args = obj.Split(' ');
var cmd = args.FirstOrDefault();
args = args.Skip(1).ToArray();
switch (cmd.ToLower())
{
case "cheat":
{
if (args.Length > 0)
{
if (args[0].Equals("money"))
{
if (args.Length != 2 || !int.TryParse(args[1], out int money))
{
SRMP.Log("Usage: cheat money <amount>");
}
else
{
if(money > 0)
SRSingleton<SceneContext>.Instance.PlayerState.AddCurrency(money);
else
SRSingleton<SceneContext>.Instance.PlayerState.SpendCurrency(money);
}
}
else if(args[0].Equals("enable"))
{
//TestUI.Instance.cheat = !TestUI.Instance.cheat;
}
else if (args[0].Equals("keys"))
{
if (args.Length != 2 || !int.TryParse(args[1], out int value))
{
SRMP.Log("Usage: cheat keys <amount>");
}
else
{
SRSingleton<SceneContext>.Instance.PlayerState.model.keys = value;
}
}
else if (args[0].Equals("allgadgets"))
{
foreach (var data in (Gadget.Id[])Enum.GetValues(typeof(Gadget.Id)))
{
SRSingleton<SceneContext>.Instance.GadgetDirector.model.gadgets[data] = int.MaxValue;
}
foreach (var data in Identifiable.CRAFT_CLASS.Union(Identifiable.PLORT_CLASS))
{
SRSingleton<SceneContext>.Instance.GadgetDirector.model.craftMatCounts[data] = int.MaxValue;
}
}
else if (args[0].Equals("spawn"))
{
if (args.Length == 2)
{
if (Enum.TryParse<Identifiable.Id>(args[1].ToUpper(), out Identifiable.Id id))
{
GameObject prefab = SRSingleton<GameContext>.Instance.LookupDirector.GetPrefab(id);
if (prefab != null)
{
SRBehaviour.InstantiateActor(prefab, SRSingleton<SceneContext>.Instance.GameModel.player.currRegionSetId, SRSingleton<SceneContext>.Instance.GameModel.player.GetPos() + new Vector3(0, 4, 0), Quaternion.identity, false);
}
else
{
SRMP.Log(id + " can not be spawned");
}
}
else
{
var data = Enum.GetNames(typeof(Identifiable.Id)).Where(n => n.ToLower().Contains(args[1].ToLower()));
SRMP.Log(args[1] + " not found. " + (data.Count() > 0 ? " Did you mean one of these?" : ""));
foreach (var name in data)
{
SRMP.Log(name);
}
}
}
else if (args.Length == 3 && int.TryParse(args[2], out int amount))
{
if (Enum.TryParse<Identifiable.Id>(args[1].ToUpper(), out Identifiable.Id id))
{
GameObject prefab = SRSingleton<GameContext>.Instance.LookupDirector.GetPrefab(id);
if (prefab != null)
{
for (int i = 0; i < amount; i++)
{
SRBehaviour.InstantiateActor(prefab, SRSingleton<SceneContext>.Instance.GameModel.player.currRegionSetId, SRSingleton<SceneContext>.Instance.GameModel.player.GetPos() + new Vector3(0, 4, 0), Quaternion.identity, false);
}
}
else
{
SRMP.Log(id + " can not be spawned");
}
}
else
{
var data = Enum.GetNames(typeof(Identifiable.Id)).Where(n => n.ToLower().Contains(args[1].ToLower()));
SRMP.Log(args[1] + " not found. " + (data.Count() > 0 ? " Did you mean one of these?" : ""));
foreach (var name in data)
{
SRMP.Log(name);
}
}
}
else
{
SRMP.Log("Usage: cheat spawn <id> (<amount>)");
}
}
}
else
{
SRMP.Log("Available sub commands:");
SRMP.Log("cheat money <amount>");
SRMP.Log("cheat keys <amount>");
SRMP.Log("cheat spawn <id> (<amount>)");
SRMP.Log("cheat allgadgets");
}
}
break;
case "tp":
{
if (args.Length == 1)
{
var player = Globals.Players.Values.FirstOrDefault(p => p.Username.Equals(args[0], StringComparison.CurrentCultureIgnoreCase));
if (player != null)
{
SRSingleton<SceneContext>.Instance.player.transform.position = player.transform.position;
}
else
{
SRMP.Log("Player not found");
}
}
else
{
SRMP.Log("Usage: tp <username>");
}
}
break;
case "listplayers":
{
SRMP.Log("Players:");
foreach (var player in Globals.Players.Values)
{
SRMP.Log(player.Username);
}
}
break;
case "sleep":
{
if (args.Length == 1)
{
SRSingleton<SceneContext>.Instance.TimeDirector.FastForwardTo(SRSingleton<SceneContext>.Instance.TimeDirector.HoursFromNow(float.Parse(args[0])));
}
}
break;
}
}
//
// Update the input every frame
// This gets new key input and calls the OnInputText callback
//
void Update()
{
input.Update();
}
//
// It's important to call console.ShutDown in OnDestroy
// because compiling will error out in the editor if you don't
// because we redirected output. This sets it back to normal.
//
void OnDestroy()
{
console.Shutdown();
}
}
}

View file

@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SRMultiplayer
{
[Serializable]
public struct UserData
{
public Guid UUID;
public bool CheckDLC;
public List<string> IgnoredMods;
}
}

View file

@ -10,6 +10,10 @@ using UnityEngine;
namespace SRMultiplayer
{
/// <summary>
/// Extends multiple objects to add extras functionality
///
/// </summary>
public static class Extensions
{
public static void Rebuild(this RefineryUI ui)
@ -40,6 +44,7 @@ namespace SRMultiplayer
}
}
#region Ammo Slot Extensions
public static void WriteAmmoSlot(this NetOutgoingMessage om, Ammo.Slot slot)
{
om.Write(slot != null);
@ -78,7 +83,9 @@ namespace SRMultiplayer
}
return null;
}
#endregion
#region Packet Handling Extensions
public static void Send(this Packet packet, NetDeliveryMethod method = NetDeliveryMethod.ReliableOrdered, int sequence = 0)
{
if(!Globals.IsClient)
@ -160,6 +167,10 @@ namespace SRMultiplayer
NetworkServer.Instance.SendTo(packet, cons, method, sequence);
}
#endregion
#region Component Handling Extensions
public static T CopyComponent<T>(this T original, GameObject destination) where T : Component
{
System.Type type = original.GetType();
@ -245,5 +256,6 @@ namespace SRMultiplayer
}
return null;
}
#endregion
}
}

29
SRMP/Utils/Objects.cs Normal file
View file

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SRMultiplayer
{
/// <summary>
/// Used marking the game time movement status
/// </summary>
public enum PauseState
{
Pause,
Playing
}
/// <summary>
/// Handles basic user data to be used for connection communication
/// Uesr ID, mod count and dlc checkers
/// </summary>
[Serializable]
public struct UserData
{
public Guid UUID;
public bool CheckDLC;
public List<string> IgnoredMods;
}
}

View file

@ -11,6 +11,11 @@ namespace SRMultiplayer
{
public static class Utils
{
/// <summary>
/// Loads up any resources embedded in the mod
/// </summary>
/// <param name="filename">Name of resource</param>
/// <returns>Contents of resource</returns>
public static byte[] ExtractResource(String filename)
{
System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly();
@ -22,7 +27,9 @@ namespace SRMultiplayer
return ba;
}
}
/// <summary>
/// Sets what layer the given item is at
/// </summary>
public static void SetLayer(GameObject obj, int layer)
{
obj.layer = layer;
@ -31,18 +38,27 @@ namespace SRMultiplayer
SetLayer(child.gameObject, layer);
}
}
/// <summary>
/// Check to see if the provided values are close enough to be the same
/// </summary>
public static bool CloseEnoughForMe(double value1, double value2, double acceptableDifference)
{
return Math.Abs(value1 - value2) <= acceptableDifference;
}
/// <summary>
/// Check to see if the provided values are close enough to be the same
/// </summary>
public static bool CloseEnoughForMe(float value1, float value2, float acceptableDifference)
{
return Mathf.Abs(value1 - value2) <= acceptableDifference;
}
private static System.Random m_Random = new System.Random();
/// <summary>
/// Gets a new random actor id for netowork actors
/// </summary>
/// <returns>Random integer between in Min and int max that is not in the current sessions of NetworkActors</returns>
public static int GetRandomActorID()
{
int id = m_Random.Next(int.MinValue, int.MaxValue);
@ -55,6 +71,11 @@ namespace SRMultiplayer
static readonly string[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
const long byteConversion = 1000;
/// <summary>
/// Takes a count of bytes and turns it into a human readable version
/// </summary>
/// <param name="value">Count of Bytes as a long</param>
/// <returns>String statement of the bytes </returns>
public static string GetHumanReadableFileSize(long value)
{

View file

@ -1,11 +1,9 @@

{
"id": "srmp",
"name": "Slime Rancher Multiplayer",
"version": "0.0.1488",
"version": "0.0.1510",
"author": "SatyPardus",
"dependencies": [
]
}
}