Unity Networking [UNET]: Syncronizing static scene objects - networking

Hello everyone!
I'm relatively new to Unity and currently working around new game project using UNET. I have stuck for a few days with this problem: how I can syncronize existing (not spawned) scene objects in Unity?
I have object named "background" - it's a sprite. When server loads map it changes background's transform scale. All I want to do is to sync it with newly connected clients.
Documentation here says that it should be done automaticlly if object has NetworkIndentity and NetworkTransform components. But it doesn't work for me!
https://docs.unity3d.com/Manual/UNetSceneObjects.html
Here is the simplified project:
http://prntscr.com/csxoqd
I have sprite with scale 40;40.
Then in OnServerStart I change it to 100;100 - on the host or server only it works great!
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
public class NewBehaviourScript : NetworkBehaviour
{
// Use this for initialization
public override void OnStartServer()
{
this.transform.localScale = new Vector3(100, 100, 1);
}
// Update is called once per frame
void Update () {
}
}
But on client side anything happens. I tried adding NetworkServer.SpawnObjects(); inside this method. Doesn't work.
Any suggestions?

I'm afraid transform.scale synchronization is still not supported by UNET. It wasn't 1 year ago and it still is now :(
But luckily, you can workaround this problem by using [SyncVar attribute].

Related

An object reference is required for the non-static field, method, or property 'MainPage.readOut'

I'm really having problems resolving this.
The 'HandleNewTag' method is in the Droid MainActivity class. It's a non static but complains about the 'MainPage.HandleNFC' method it's calling, so I changed that to static and it didn't error.
The 'MainPage.HandleNFC' method also calls a method which was non static. I changed it to a static void to stop the error. Then inside that method, where it sets some properties of a XAML control, it complains that the control is not static which I am unable to change.
I've searched high and low on the internet to resolve this and although I can find similar errors, none of them refer to a non static control issue.
MainActivity.cs
public void HandleNewTag(object sender, NfcFormsTag e)
{
//MainPage mp = new MainPage();
byte[] bytes = e.Id;
Console.WriteLine(BitConverter.ToString(bytes));
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes);
Console.WriteLine(BitConverter.ToString(bytes));
// Call method to send byte stream across machine boundaries.
// Receive byte stream from beyond machine boundaries.
Console.WriteLine(BitConverter.ToString(bytes));
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes);
Console.WriteLine(BitConverter.ToString(bytes));
int result = BitConverter.ToInt32(bytes, 0);
MainPage.HandleNFC(result.ToString());
}
MainPage.xaml
public static void HandleNFC(string convertedtag)
{
addToReadout(convertedtag);
}
public static void addToReadout(string text)
{
Label label1 = new Label { Text = "Successfully clocked out # " + text, TextColor = Color.Black };
StackLayout sl = new StackLayout();
readOut.Children.Add(label1);
readOut.BackgroundColor = Color.Black;
readOut.Children.Count();
}
Something is wrong here. Why would you be calling your Forms MainPage (living in PCL or Shared Project) from the Xamarin.Android MainActivity? The dependency flow there is backwards. I'm also assuming "MainPage.xaml" is "MainPage.xaml.cs" as you are showing C# code and not XAML.
Either way, it looks like you want to add tags to a control on your MainPage. The HandleNewTag event handler living in MainActivity.cs probably shouldn't work like this because your solution will get complicated when you have to think about the other platforms. Typically you want your calls to triage from your PCL down to the platform specific projects, like what Xamarin.Forms.DependencyService does (basic container/IoC patterns).
I understand that on Android the NFC capabilities would require the Application or Activity Context to perform actions and the NFC readings you receive are coming in through your MainActivity. One way to handle this would be the MessagingCenter built into Xamarin.Forms. It was designed just for this purpose because then you can also send messages through the MessagingCenter from your iOS or UWP projects and everything will work fine. You would have one MessagingCenter subscription that lives in your MainPage.xaml.cs, I typically will use the constructor for that stuff.
Another option would be to create an "AppViewModel" that lives at your top level of your application. I typically make this a static variable in my App class so I can reference it from anywhere by calling App.ViewModel.(whatever). Your challenge will be taking that data and updating your UI. I would do this by just binding controls directly to the sources in that static instance and creating a "Refresh" mechanism that utilizes OnPropertyChanged to update the bindings. This is of course a more complex solution and is really built/designed around what you are trying to do exactly.
I hope this helps!
Disclosure: I work for Xamarin/Microsoft

Switching scenes in Unity C# after a short delay without the use of update

Title is self explanatory. I'm trying to switch scenes after a short delay WITHOUT using the update() function. The trigger is a collision between two objects which I have working, I also understand how to switch scenes. It is the delay after the collision which I am struggling with.
I am very new to Unity, any help is greatly appreciated!
Unity supports using Coroutines, which will help with calling the LoadScene function after a delay.
An example of this is as follows:
void OnCollisionEnter()
{
StartCoroutine("LoadLevelWithDelay");
}
IEnumarator LoadLevelWithDelay()
{
yield return new WaitForSeconds(2.0f);
LoadScene(scene);
}
This code isn't fully working since it's just an example, but this is how you could do it. Just create a function of type IEnumerator that waits for however long you want before continuing, and load the scene when it continues.

Getting the right syntax for SignalR server to call client

I'm putting together a very basic sort of "hello world" app with SignalR, with the minor caveat that it's self-hosted, which introduces an additional wrinkle or two. Basically, I'm trying to figure out the right way to call methods on my client(s) from the server.
On my client, for instance, I've got a method that looks like this:
roomHub.onEcho = function (msg) {
console.log("onEcho called: " + msg);
};
And I can call it successfully from my server-side hub like so:
public class RoomHub : Hub
{
public void Echo(string echo)
{
Clients.onEcho(echo);
}
}
And it works, but of course, it calls all the clients, not just one. And in the various samples I've seen online (e.g., https://github.com/SignalR/SignalR/blob/master/samples/Microsoft.AspNet.SignalR.Hosting.AspNet.Samples/Hubs/Benchmark/HubBench.cs, I see all sorts of commands that make it look like I should be able to specify who gets called, e.g.:
public void Echo(string echo)
{
Clients.Caller.onEcho(echo);
Clients.Caller(Context.ConnectionId).onEcho(echo);
Clients.All.onEcho(echo);
}
But I can't get any of the above syntaxes to work. For Clients.All.onEcho() and Clients.Caller.onEcho(), absolutely nothing happens. For Clients.Caller(Context.ConnectionId).onEcho(), Firebug tells me that it's actually trying to call a Caller() method on my JavaScript roomHub instance, which of course isn't there.
Here's the weird bit, though. If I look at the Hub class, I can see why none of these work - because the Hub constructor overrides a bunch of the properties of its "Clients" object with NullClientProxies:
protected Hub()
{
Clients = new HubConnectionContext();
Clients.All = new NullClientProxy();
Clients.Others = new NullClientProxy();
Clients.Caller = new NullClientProxy();
}
But I'm kinda mystified as to why it does that - or why the samples seem to work anyway - or what the expected approach should be.
Any thoughts? What am I doing wrong here?
We've been updating docs recently so you've probably seen lots of inconsistent data around the place. The latest version of SignalR is 1.0 alpha2 ( http://weblogs.asp.net/davidfowler/archive/2012/11/11/microsoft-asp-net-signalr.aspx ). All of the documentation has been updated to show the new syntax so if you're using an older version, please upgrade. Check out the wiki for examples https://github.com/SignalR/SignalR/wiki/Hubs

QML and QtGStreamer within plugin

I'm trying to prepare QML plugin to play video on embedded device in a way that other developers can use it without much hassle. However the way it is currently proposed requires almost always writing some C++ wrapper around your QML application. I'm refering to this example:
http://gstreamer.freedesktop.org/data/doc/gstreamer/head/qt-gstreamer/html/examples_2qmlplayer_2main_8cpp-example.html
I would like to be able to have plugin and simply write:
import AwesomeVideoPlugin 1.0
Rect
{
AwesomeVideo
{
width: 320
height: 240
url: "./myvideo.avi"
// ... some minor stuff like mouse click handling, controls, etc.
}
}
Currently QtGStreamer requires to provide videoSurface property to VideoItem. The only way to do this is to create and set context for additional property in rootContext(). And to create GraphicsVideoSurface I need QGraphicsView (QDeclarativeView fills this role).
Is it possible to:
Get QDeclarativeView from within QDeclarativeItem (to which I have only access from QML plugin) in a way that it can be later used to feed GraphicsVideoSurface? My guess is no - however I've found path QFraphicsItem::scene() ==> QGraphScene ==> QGraphScene::views() ==> QList of QGraphicsView - it looks like VERY bad programming but maybe somebody got it to work (I'm getting segfault)
Is there other way to provide video sink for QtGStreamer from within QDeclarativeItem ?
Greetz
Yatsa
I had the same question, but haven't come up with an elegant solution.
However, one thought would be to make the videosurface available via an accessor function from a sub-classed QApplication object.
This would, of course, mean that your plug-in depends on the application subclass having a getVideoSurface method, but it does remove the ugliness from the QML code.
class MyApp : public QApplication
{
....
QGst::Ui::GraphicsVideoSurface *getVideoSurface() { return m_videosurface; }
}
...
int MyApp::init()
{
m_viewer = new QDeclarativeView();
m_viewer->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
m_videosurface = new QGst::Ui::GraphicsVideoSurface(m_viewer);
}
MyVideoPlugin::MyVideoPlugin(QDeclarativeItem *parent) : QDeclarativeItem(parent)
{
QGst::Ui::GraphicsVideoSurface *surface = ((MyApp*)qApp)->getVideoSurface();
}
...
Now the MyVideoPlugin element may be used without referencing an exported videosurface context item.

Finding Display of an RCP App

I'm writing a testing Framework which is starting a GUI Application. To be able to test this GUI in the case of an SWT application I need to know it's display. In general, this display is loaded by another classloader, therefore I'm using the method findDisplay(Thread t) of the swt Display class by reflection to accomplish this task. My code looks something like this:
Thread[] threads = new Thread[10];
Thread.enumerate(threads);
Object foundObject = null;
for (Thread t : Arrays.asList(threads)){
foundObject = null;
Class<?> clazz = t.getContextClassLoader().loadClass("org.eclipse.swt.widgets.Display");
final Method method = clazz.getMethod("findDisplay", Thread.class);
foundObject = method.invoke(null, new Object[] {t});
if (foundObject != null) {
System.out.println("yeah, found it!");
break;
}
}
In my opinion this should find every Object of type Display in the current thread group. However I don't get any for the texteditor RCP example although the GUI is starting up perfectly.
Any ideas what is going wrong or how I can debug this in a reasonable way?
I figured out what the main problem was: The ContextClassloader had nothing to do with the classloader who actually loaded the classes.
To resolve my problem I took care of having the classloader which loads the swt display class both in the hierarchy of the RCP program and the hierarchy of my framework. This was possible by using the java extension classloader. (I couldn't use the application classloader since my RCP application doesn't work with it as parent, I haven't figured out yet why) It was then just a matter of adding the swt.jar to the java.ext.dirs property.
If you are using Eclipse RCP then maybe you can use:
PlatformUI.getWorkbench().getDisplay()

Resources