Compare commits

..

9 Commits

Author SHA1 Message Date
APEX FIGHT
08db445a53 TODO 2025-01-02 16:23:23 -05:00
APEX FIGHT
39a9200d4a CSNC implementation on NODEjs 2025-01-02 16:23:18 -05:00
APEX FIGHT
f7926482d3 Unity Instructions 2025-01-02 16:23:05 -05:00
APEX FIGHT
351348a9d2 TODO 2025-01-02 16:22:46 -05:00
APEX FIGHT
9389114175 syncdata script 2025-01-02 16:22:35 -05:00
APEX FIGHT
2b2de1b52b GameObject registry script 2025-01-02 16:22:22 -05:00
APEX FIGHT
ed2e2c63ef CSNC prefab 2025-01-02 16:22:08 -05:00
APEX FIGHT
988f39144d CSNC script 2025-01-02 16:21:58 -05:00
APEX FIGHT
ec734b6f1e client sync behavior script 2025-01-02 16:21:47 -05:00
18 changed files with 393 additions and 0 deletions

0
Client/Godot/empty Normal file
View File

99
Client/Unity/CSNC.cs Normal file
View File

@ -0,0 +1,99 @@
using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class CSNC : MonoBehaviour
{
public string ip;
private class EZtransform //ez consistent serialization of transforms
{
public List<float> position;
public List<float> rotation;
public EZtransform(Transform transform)
{
position = new List<float>(3);
rotation = new List<float>(4);
position.Add(transform.position.x);
position.Add(transform.position.y);
position.Add(transform.position.z);
rotation.Add(transform.rotation.x);
rotation.Add(transform.rotation.y);
rotation.Add(transform.rotation.z);
rotation.Add(transform.rotation.w);
}
}
private class CSNCObject
{
public string type;
public EZtransform transform;
public CSNCObject(string type, Transform trans)
{
this.type = type;
this.transform = new EZtransform(trans);
}
public CSNCObject(string type, EZtransform trans)
{
this.type = type;
this.transform = trans;
}
}
private class SendData
{
public string uuid;
public List<CSNCObject> gameObjects;
public SendData(List<CSNCObject> gameobjects)
{
uuid = GameObjectRegistry.instance.uuid;
gameObjects = gameobjects;
}
}
void Start()
{
ip = CHANGEME; //CHANGE THIS VALUE to the ip address
}
void FixedUpdate()
{
IEnumerator req = request();
StartCoroutine(req);
}
IEnumerator request()
{
//Debug.Log(GameObjectRegistry.instance.registeredObjects);
List<CSNCObject> gameObjects = new List<CSNCObject>();
foreach (SyncData obj in GameObjectRegistry.instance.registeredObjects)
{
gameObjects.Add(new CSNCObject(obj.type, obj.transform));
}
SendData sendData = new SendData(gameObjects);
//Debug.Log(JsonConvert.SerializeObject(sendData));
using (UnityWebRequest req = UnityWebRequest.Post(ip, JsonConvert.SerializeObject(sendData), "application/json"))
{
req.SetRequestHeader("request-type", "csnc");
yield return req.SendWebRequest();
if (req.result != UnityWebRequest.Result.Success)
{
Debug.LogError(req.error);
}
else
{
Debug.Log(req.downloadHandler.text);
}
}
}
}

11
Client/Unity/CSNC.cs.meta Normal file
View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6772f36d5b93fd5498e8f3f1d8155ff2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

59
Client/Unity/CSNC.prefab Normal file
View File

@ -0,0 +1,59 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &9009233966360587498
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7121321073155658785}
- component: {fileID: 7629741995735410931}
- component: {fileID: 5596437124550187285}
m_Layer: 0
m_Name: CSNC
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &7121321073155658785
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9009233966360587498}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &7629741995735410931
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9009233966360587498}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1c20e30fdef1b0841aa0fdb48748a6a6, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &5596437124550187285
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9009233966360587498}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 6772f36d5b93fd5498e8f3f1d8155ff2, type: 3}
m_Name:
m_EditorClassIdentifier:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: bd3a56f07635e3c46b71afc5c7cf0e2f
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,15 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ClientSyncBehavior : MonoBehaviour
{
public string id; //the id of the gameobject (as of gameobjectregistry) to synchronize across clients
void Start()
{
GameObjectRegistry.instance.registeredObjects.Add(new SyncData(transform, id));
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3d577c3c9b709324fbfb594192714936
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,34 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameObjectRegistry : MonoBehaviour
{
public static GameObjectRegistry instance; //instance of gameobject registry in scene
public string uuid; //unique identifier for this client
public List<GameObject> gameObjects; //list to make it easy to register new gameobjects
public List<string> ids;
public Dictionary<string, GameObject> registry = new Dictionary<string, GameObject>(); //registry of game objects that can be synced (needs to be identical on both clients
public List<SyncData> registeredObjects = new List<SyncData>(); //game objcets that are currently being synced
void Start()
{
GameObjectRegistry.instance = this;
uuid = System.Guid.NewGuid().ToString(); //create a uuid for this player
initializeRegistry();
}
void initializeRegistry()
{
int i = 0;
foreach (string id in ids)
{
registry.Add(id, gameObjects[i]);
i++;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1c20e30fdef1b0841aa0fdb48748a6a6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: -20
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

37
Client/Unity/README.md Normal file
View File

@ -0,0 +1,37 @@
# Unity Setup
First, set the ip of the csnc compatible server.
![image](./InstructionalImages/ipchange.png)
Then schedule the GameObjectRegistry script to be\
(Go To: Edit / Project Settings / Script Execution Order)
![image](./InstructionalImages/scheduling.png)
then add the CSNC prefab to your scene
from here you can add references to the models that you want to synchronize across projects as per the image
(these are references to models that will be shown on the client, but controlled by another players client)
![image](./InstructionalImages/ineditor.png)
take note that the objects are children of the CSNC prefab and they are not enabled
in addition to this, the objects under CSNC have NO behaviour scripts attached to them, this is important because it may cause desynchronization if you dont know what you're doing
## Client Controlled GameObjects
Now that you have set up CSNC you can start adding client controlled GameObjects
it is quite trivial to add new Client Synchronized GameObjects, simply attach the "Client Sync Behavior" component to the gameobject you want to sync
![image](./InstructionalImages/clientobjectsetup.png)
As you can see, the client sync behavior is attached to the gameobject and given the id "razorblade" \
(remember what you entered earlier from when we set up the game object registry)
### Congratulations!!
And thats it!! once you have set this up the two gameobjects will be synchronized across clients (assuming you have set up the server - side)

14
Client/Unity/SyncData.cs Normal file
View File

@ -0,0 +1,14 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SyncData //structure for gameobjects and data sent over to the server
{
public SyncData(Transform pos, string type)
{
this.transform = pos;
this.type = type;
}
public Transform transform;
public string type; //key in registry data that defines which gameobject to instantiate with transform: position
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dbe7422037114f74c80f641e2b629993
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

0
Server/Go/empty Normal file
View File

84
Server/Node/CSNC.js Normal file
View File

@ -0,0 +1,84 @@
var gameObjectStore = {}; //object which stores CSNCgameobjects for each client
//below is an example of the structure of gameobjectstore
/**
* {
* "2c0a48e9-40c6-4139-9697-992397773b12": [
* {
"type": "razorblade",
"transform": {
"position": [
0.0,
0.53,
0.0
],
"rotation": [
0.0,
0.0,
0.0,
1.0
]
}
},
{
"type": "boomerang",
"transform": {
"position": [
0.0,
0.0,
0.0
],
"rotation": [
-0.7071068,
0.0,
0.0,
0.7071067
]
}
}
* ]
* }
*
*
*/
/**
* @param {http.ServerResponse<http.IncomingMessage>} res
* @param {string} req
*/
//reads data from client
async function handleResponse(res, req) {
try {
var request = JSON.parse(req);
let gameObjects = request.gameObjects;
gameObjectStore[request.uuid] = gameObjects; //store gameobjects to send to other players
res.writeHead(200);
res.write(JSON.stringify(responseObjectHelper(request.uuid)));
res.end();
} catch (err) {
console.log("Invalid Request");
console.log(err);
res.end();
}
}
//preps and returns data to send back to client
function responseObjectHelper(uuid) {
var responseObject = {
gameObjects: []
};
for (let key in gameObjectStore) {
if (key == uuid) continue; //dont send back players own data
responseObject.gameObjects = responseObject.gameObjects.concat(gameObjectStore[key]);
}
return responseObject;
}
exports.handleResponse = handleResponse;