The application I am developing is Unity client(s) driven by a backend “server” that just dumps commands to connected clients. I recently discovered to my dismay that when I publish my unity client my communication no longer works. On startup I ping the server for an xml config file that I use to populate the scene, set states, etc. I am away from office now so I haven’t played with it more, but does anyone know of a reason why my custom plugin client socket would work as I expect when testing within the unity editor or when running as a standalone, but not when published as a web player?
“Plugins - Pro only feature
Unity has extensive support for C, C++ or Objective-C based Plugins. Plugins will work in standalones only. They are disabled when building a Web Player for security reasons.”
I still dont see it anywhere but then again it is almost impossible to find anything you are looking for unless a kind community member has already stumbled on your problem and is willing to help.
A search of plugins in the scripting reference returns nothing, and the only mention in the user manual is here Unity - Manual: Plug-ins and your quote isn’t there either. A victim of Unity’s documentation once again, but this one really hurts and is going to give us one hell of a black eye.
Um, oops…apparently that bit I quoted isn’t in the usual documentation yet. So you’re right in this case, although 99% of time time I have no problems finding anything in the docs.
It IS written in C#, compiled as a dll, and loaded as a plugin and works like a peach in all but webplayer. We HAVE to run as a web player though, so if plugins aren’t an option in the web player we are dead in the water.
Again, thousands of dollars down the tube and several weeks development.
Very unprofessional and potentially costly legal liability issue with that omission in the documentation.
First off, a fully functional demo is available. If your project relies on a plugin, and can’t work without it, you had time to test with no cost – and I would guess you will get a lot farther coming up with a solution by working with the community rather than not so subtly threatening the developers. And I assume that is why you are here - to figure out how to get things working.
In any case, if it is written in C# why does it have to be treated as a plugin? I ask because if it is written in C# and is a .NET DLL, it really isn’t a plugin - a .NET DLL should work in the web player. When they said that plugins don’t work, they are talking about actual plugins.
We use a couple of C# assemblies in our project that work fine in the webplayer.
They need to be compatible with the version of Mono that Unity uses. If you rely on namespaces that are not available to Unity but do exist in Mono, you can copy them into the Assets/Plugins folder. I haven’t tested this myself, but another user did this with SQLLite if I remember correctly - try searching his posts.
EDIT: btw the Mono files used in Unity can be found in Unity/Contents/Frameworks/Mono.framework
I’m confused about what “is” and “isn’t” an actual plugin in Unity terms then, if any one can explain I would be very appreciative.
Our C# com layer is compiled as a DLL and has a C# script interface inside Unity that works flawlessly in all cases except when running Unity as a web player so I don’t see how this could be a namespace issue but I would love to be wrong about that.
Shaun can you give me an actual link to the mono files you referenced? Or is that location in the actual Unity installation tree?
Shaun is referencing the path in the Unity.app bundle.
Regarding Plugins:
So a plugin provides a simple C interface and uses a script that invokes the functions exposed by the plugin. Plugins don’t work with the web player.
But C# can also be compiled into .NET DLLs and included in your project and referenced just like any other script (ie. no DllImport function declaration).
If what you wrote was in C#, I don’t think you will actually need a plugin, and you will probably be able to deploy using the webplayer. Where are you putting the DLL in your project?
Anything thats compiled to native platform code is a plugin, like Objective-C and C++ DLLs or Bundles. Assemblies (also called DLLs), written in .Net are compiled to a common intermediary language.
These kinds of assemblies should just work when dropped into the Assets folder, providing you’re not trying to use functionality outside of what Mono provides, particularly the version of Mono included with Unity.
If your DLL is written in C# 3.0 then it’s probably unlikely to work.
But if it is an assembly (which it sounds like it is), but used C# not supported by the Mono included with Unity, how would it have worked for standalone and the editor?
I placed the c# plugin in the Assets\Plugins folder in my project.
@Shaun Ah, there may be some hope. My developer that wrote the C# dll did use the latest Mono available (for MAC, if that matters) so I guess that could be the issue, but why would it work on my dev box in all but web player when all I have on it is what comes natively with OSX install and whatever unity installs on the box?
So my dll shouldnt be in the plugins folder, just the root Assets folder?
I don’t have access to the code right now. At home on weekend, I will post my script interface first thing Monday morning.
We keep our .Net DLLs in the Assets/Plugins folder and everything works fine.
If we use classes other than what Unity provides natively, we just copy them out from the Mono.framework folder (e.g. System.Web.Services.dll).
I’m not sure how you’re accessing your assembly, but you should just put a using at the top of your script (i.e. Using MyNamespace;) and access the classes as normal.
The fact that you’re using the latest version of Mono might be a problem, you could try to retrofit to the version included with Unity. Not sure why it’s working in the standalone and not webplayer - your wrapper code will probably reveal the reason.
@ Shaun. My unity installation does not contain a Unity/Contents/Frameworks/Mono.framework directory. All I have is Unity\Documentation, Unity\StandardPackages, and Unity\Tutorials. I find no framework directory at all in my unity install.
My C# assembly calling script is as follows.
using System;
using System.Collections.Generic;
using UnityBackend;
using RCCLUnityBackend;
using UnityEngine;
/// <summary>
/// The RCCLUnityScript is responsible for working with the RCCLUnityBackend to control
/// the POIs/Ship as well as process commands and data from a multicast socket connection
/// to the RCCLUnityServer.
/// </summary>
public class RCCLUnityScript : MonoBehaviour
{
#region Members
/// <summary>
/// The interface to the RCCLUnityBackend.
/// </summary>
private RCCLBackend backend;
/// <summary>
/// The CallbackDelegate fired whenever an event occurs in the backend.
/// </summary>
private CallbackDelegate callback;
/// <summary>
/// The local path to the XML configuration file.
/// </summary>
private string xmlFilePath = "RCCL_Config.xml";
/// <summary>
/// The URL to download the XML configuration file from.
/// </summary>
private string xmlURL = "http://www.21csi.com/aedge-3d/videos/unity/RCCL_Config.xml";
// handle to our selectable object handler script
private SelectableObjectHandler selectableObjHandlerScript;
private CameraAnimator camAnimatorScript;
private float zoomStepSize = 1.0f;
#endregion Members
#region Required Script Methods
/// <summary>
/// Initializes the script
/// </summary>
void Start()
{
// create the CallbackDelegate
callback = eventFired;
// create the backend
backend = new RCCLBackend(callback, xmlFilePath);
// download the XML config file
backend.downloadXMLFile(xmlURL);
// read in the entities from the config file
backend.fillEntityCache();
// Get a handle to our selectable object manager
GameObject selectableObjectHandler = GameObject.Find("SelectableObjectManager");
selectableObjHandlerScript = selectableObjectHandler.GetComponent(typeof(SelectableObjectHandler)) as SelectableObjectHandler;
// Grab a handle to our Camera Animator
GameObject cameramanager = GameObject.Find("CameraManager");
camAnimatorScript = cameramanager.GetComponent(typeof(CameraAnimator)) as CameraAnimator;
// Get our POIs
foreach(POI poi in backend.EntityCache.POIs)
{
//print(poi.Name);
//print(poi.Location);
selectableObjHandlerScript.createSelectableObject(poi.Name, poi.Location.Latitude, poi.Location.Longitude, poi.Location.Height, SelectableObjectHandler.Type.Poi);
}
// Get our Ships
foreach(CruiseLiner cruiseliner in backend.EntityCache.CruiseLiners)
{
//print(cruiseliner.Name);
//print(cruiseliner.Location);
selectableObjHandlerScript.createSelectableObject(cruiseliner.Name, cruiseliner.Location.Latitude, cruiseliner.Location.Longitude, cruiseliner.Location.Height, SelectableObjectHandler.Type.Ship);
}
}
/// <summary>
/// Updates the script on each repaint.
/// </summary>
void Update()
{
// do nothing
}
#endregion Required Script Methods
#region Methods
/// <summary>
/// This method handles the events fired by the backend. It is the method
/// called by the CallbackDelegate
/// </summary>
/// <param name="type">
/// A <see cref="CallbackType"/>
/// </param>
private void eventFired(Enum val)//(CallbackType callType)
{
CallbackType callType = (CallbackType) val;
switch (callType)
{
case CallbackType.XMLFileReceived:
{
// refill the EntityCache
backend.fillEntityCache();
break;
}
case CallbackType.XMLFileUpdated:
{
// refill the EntityCache
backend.fillEntityCache();
break;
}
case CallbackType.CommandReceived:
{
// perform the last received command
performCommand(backend.LastCommandReceived);
break;
}
default: {
break;
}
}
}
/// <summary>
/// Performs a received command
/// </summary>
///
/// <param name="command">
/// The received command
/// </param>
private void performCommand(CommandType command) {
switch(command) {
case CommandType.PAN_UP: {
// pan the map up
break;
}
case CommandType.PAN_DOWN: {
// pan the map down
break;
}
case CommandType.PAN_LEFT: {
// pan the map left
break;
}
case CommandType.PAN_RIGHT: {
// pan the map right
break;
}
case CommandType.ZOOM_IN: {
// zoom the map in
camAnimatorScript.zoomInOut(-zoomStepSize);
camAnimatorScript.scaleChildren();
break;
}
case CommandType.ZOOM_OUT: {
// zoom the map out
camAnimatorScript.zoomInOut(zoomStepSize);
camAnimatorScript.scaleChildren();
break;
}
case CommandType.SELECT_NEXT_ENTITY: {
// switch to the next selectable object
selectableObjHandlerScript.changeObjectSelection(1);
break;
}
case CommandType.SELECT_PREVIOUS_ENTITY: {
// switch to the previous selectable object
selectableObjHandlerScript.changeObjectSelection(-1);
break;
}
case CommandType.REFOCUS_ENTITY: {
// return to the selected POI
break;
}
case CommandType.TOGGLE_RESOLUTION: {
// toggle between drawer and full-screen mode
break;
}
case CommandType.TOGGLE_MINIMIZED: {
// toggle between minimized states
break;
}
case CommandType.QUIT_PROGRAM: {
// close the program
break;
}
default: {
// do nothing since this was not a valid command
break;
}
}
}
#endregion Methods
}