from github
This commit is contained in:
@@ -0,0 +1,238 @@
|
||||
using SimpleFileBrowser;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR.Interaction.Toolkit;
|
||||
|
||||
//this script implements save logic for a room on any client
|
||||
|
||||
public class RoomSaver : MonoBehaviour
|
||||
{
|
||||
|
||||
//culture info for float parsing
|
||||
private CultureInfo ci = CultureInfo.InvariantCulture;
|
||||
[SerializeField] private ObjectSync objSyn;
|
||||
[SerializeField] private OBJLoader objLoader;
|
||||
private GameObject spawnedObject;
|
||||
[SerializeField] private Material defaultMat;
|
||||
|
||||
private string osPath;
|
||||
|
||||
// a class that can store all object data in one place (keep in mind DIFFERENT TO OTHER OBJData structs in other structs !!!)
|
||||
public class OBJData
|
||||
{
|
||||
public string objectName;
|
||||
public List<Vector3> vertices;
|
||||
public List<int> triangles;
|
||||
public Vector3 position;
|
||||
public Quaternion rotation;
|
||||
public Vector3 scale;
|
||||
}
|
||||
|
||||
//if a clients requests to create a save file, the server will call this function on the client
|
||||
[ClientRpc]
|
||||
public void GetAllRoomDataClientRPC(ulong clientID, ObjectSync.OBJData[] objData)
|
||||
{
|
||||
//only the requesting client should save the file
|
||||
if (clientID != NetworkManager.Singleton.LocalClientId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//generate a random string for save (save file can be renamed by user in their system file explorer)
|
||||
string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
char[] stringChars = new char[8];
|
||||
System.Random random = new System.Random();
|
||||
|
||||
for (int i = 0; i < stringChars.Length; i++)
|
||||
{
|
||||
stringChars[i] = chars[random.Next(chars.Length)];
|
||||
}
|
||||
|
||||
//add the current date to the save file
|
||||
string curDate = new String(DateTime.Today.ToString("d"));
|
||||
string finalString = new String(stringChars) + "_" + curDate;
|
||||
|
||||
//check if the saves directory does already existist -not-> create it
|
||||
if (!Directory.Exists(osPath + "vrcsaves"))
|
||||
{
|
||||
Directory.CreateDirectory(osPath + "vrcsaves");
|
||||
}
|
||||
|
||||
//the final path to the saves destination (please keep os specific file paths in mind "c:" for windows "/ etc." for unix based systems)
|
||||
string filePath = osPath + "vrcsaves/" + finalString.Replace("/", "_") + ".vrc";
|
||||
|
||||
StreamWriter writer = new StreamWriter(filePath);
|
||||
|
||||
//enumerate all objects sent by the server and write into the savefile
|
||||
foreach (ObjectSync.OBJData o in objData)
|
||||
{
|
||||
writer.WriteLine("o");
|
||||
foreach (Vector3 v in o.vertices)
|
||||
{
|
||||
writer.WriteLine("v$" + v.x + "$" + v.y + "$" + v.z);
|
||||
}
|
||||
|
||||
foreach (int t in o.triangles)
|
||||
{
|
||||
writer.WriteLine("t$" + t);
|
||||
}
|
||||
|
||||
writer.WriteLine("p$" + o.positionVector.x + "$" + o.positionVector.y + "$" + o.positionVector.z);
|
||||
writer.WriteLine("r$" + o.rotation.x + "$" + o.rotation.y + "$" + o.rotation.z + "$" + o.rotation.w);
|
||||
writer.WriteLine("s$" + o.scale.x + "$" + o.scale.y + "$" + o.scale.z);
|
||||
}
|
||||
|
||||
//"save file changes"
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
//a client requesting to save will call this function with its id
|
||||
[ServerRpc]
|
||||
public void GetAllRoomDataServerRPC(ulong clientID)
|
||||
{
|
||||
GetAllRoomDataClientRPC(clientID, objSyn.objDataList.ToArray());
|
||||
}
|
||||
|
||||
//this function will be called from the menu bar if a player wants to save
|
||||
public void SaveScene()
|
||||
{
|
||||
//ask the server for the current data in the room
|
||||
GetAllRoomDataServerRPC(NetworkManager.Singleton.LocalClientId);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
//set default save paths on windows and linux
|
||||
if (Application.platform == RuntimePlatform.LinuxEditor || Application.platform == RuntimePlatform.LinuxServer || Application.platform == RuntimePlatform.LinuxPlayer)
|
||||
{
|
||||
osPath = "/home/" + Environment.UserName + "/";
|
||||
}
|
||||
else
|
||||
{
|
||||
osPath = "c:/";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
//try to get a filepath to load a a save file
|
||||
//if there is no save file a blank classroom will be created
|
||||
if (PlayerPrefs.GetString("path") != "")
|
||||
{
|
||||
string path = PlayerPrefs.GetString("path");
|
||||
ReadEvenMoreObjDataFromFile(path);
|
||||
PlayerPrefs.SetString("path", "");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Debug.Log("Fehler beim Lesen der Datei");
|
||||
}
|
||||
}
|
||||
|
||||
//This is a meme <-- XD
|
||||
//this function does read and load a save file
|
||||
private void ReadEvenMoreObjDataFromFile(string path)
|
||||
{
|
||||
List<OBJData> objDataList = new List<OBJData>();
|
||||
//read the file data and split each line
|
||||
string[] lines = FileBrowserHelpers.ReadTextFromFile(path).Split("\n");
|
||||
OBJData dataStruct = new OBJData();
|
||||
|
||||
|
||||
string curString;
|
||||
|
||||
foreach (string line in lines)
|
||||
{
|
||||
line.Trim();
|
||||
curString = line.Replace("$", " ");
|
||||
|
||||
//if there is a "o" the data block of a new object will begin
|
||||
if (curString.StartsWith("o"))
|
||||
{
|
||||
dataStruct = new OBJData();
|
||||
dataStruct.vertices = new List<Vector3>();
|
||||
dataStruct.triangles = new List<int>();
|
||||
objDataList.Add(dataStruct);
|
||||
}
|
||||
//if there is a "v" at the start of the line there is a vertex stored
|
||||
else if (curString.StartsWith("v"))
|
||||
{
|
||||
dataStruct.vertices.Add(ComeBackOfTheObjVector3StringToVector3(curString));
|
||||
}
|
||||
//if there is a "t" at the start of the line there is a triangle index stored
|
||||
else if (curString.StartsWith("t"))
|
||||
{
|
||||
int curInt = int.Parse(curString.Trim().Replace("t", ""));
|
||||
dataStruct.triangles.Add((curInt));
|
||||
}
|
||||
//if there is a "p" at the start of the line position of the gameobject is stored here
|
||||
else if (curString.StartsWith("p"))
|
||||
{
|
||||
dataStruct.position = ComeBackOfTheObjVector3StringToVector3(curString);
|
||||
}
|
||||
//if there is a "r" at the start of the line rotation of the gameobject is stored here
|
||||
else if (curString.StartsWith("r"))
|
||||
{
|
||||
dataStruct.rotation = ObjQuanternion(curString);
|
||||
}
|
||||
//if there is a "s" at the start of the line scale of the gameobject is stored here
|
||||
else if (curString.StartsWith("s"))
|
||||
{
|
||||
dataStruct.scale = ComeBackOfTheObjVector3StringToVector3(curString);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//create a mesh/gameobject of each loaded object data
|
||||
for (int i = 0; i < objDataList.Count; i++)
|
||||
{
|
||||
GameObject finishedObj = objLoader.CreateMesh(objLoader.buildObjData(objDataList[i].vertices.ToArray(), objDataList[i].triangles.ToArray()), objDataList[i].position);
|
||||
//apply rotation and scale to the gameobject
|
||||
finishedObj.transform.rotation = objDataList[i].rotation;
|
||||
finishedObj.transform.localScale = objDataList[i].scale;
|
||||
//create info to keep track of the object in servers object list etc.
|
||||
ObjectSync.OBJData objsyncData = new ObjectSync.OBJData();
|
||||
objsyncData.vertices = objDataList[i].vertices.ToArray();
|
||||
objsyncData.triangles = objDataList[i].triangles.ToArray();
|
||||
objsyncData.positionVector = objDataList[i].position;
|
||||
objsyncData.rotation = objDataList[i].rotation;
|
||||
Debug.Log(objDataList[i].scale);
|
||||
//add the object to the sync
|
||||
objsyncData.scale = objDataList[i].scale;
|
||||
objSyn.objDataList.Add(objsyncData);
|
||||
objSyn.spawnedObjects.Add(finishedObj);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//This is another meme
|
||||
//this function creates a vector3 object from a vector stored in vrc file
|
||||
private Vector3 ComeBackOfTheObjVector3StringToVector3(string vecString)
|
||||
{
|
||||
vecString = vecString.Replace(",", ".");
|
||||
string[] lnSplit = vecString.Trim().Split(" ");
|
||||
return new Vector3(float.Parse(lnSplit[1], NumberStyles.Float, ci),
|
||||
float.Parse(lnSplit[2], NumberStyles.Float, ci),
|
||||
float.Parse(lnSplit[3], NumberStyles.Float, ci));
|
||||
}
|
||||
|
||||
//this function creates a quaternion object from a quaternion stored in vrc file
|
||||
private Quaternion ObjQuanternion(string quanString)
|
||||
{
|
||||
quanString = quanString.Replace(",", ".");
|
||||
string[] lnSplit = quanString.Trim().Split(" ");
|
||||
return new Quaternion(float.Parse(lnSplit[1], NumberStyles.Float, ci),
|
||||
float.Parse(lnSplit[2], NumberStyles.Float, ci),
|
||||
float.Parse(lnSplit[3], NumberStyles.Float, ci),
|
||||
float.Parse(lnSplit[4], NumberStyles.Float, ci));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user