How to build Unity WebGl via command line specifying Scene name? - unity3d

I've a WebGl Unity application with some scenes.
I need to do a build for each scene, suppose SceneA, SceneB, SceneC...
So, to do build I wrote:
"C:\Program Files\Unity\Editor\Unity.exe" -buildTarget WebGL ... SceneName ?
Questions are:
How to specify SceneName ?
And how to specify destination directory ?
Thanks

Are you asking how to specify which scenes are used when making a build through the command line? If so, here's how I would go about it.
For your first question,
How to specify SceneName ?
I am unaware if you can directly specify scene names in the command line, but you can run specific functions using the command line that can change which scenes are built for the project.
Here is a snippet you would need but can change for your use case
using UnityEditor;
class MyEditorScript
{
static void PerformBuild ()
{
string[] scenes = { "Assets/MyScene.unity" };
BuildPipeline.BuildPlayer(scenes, ...);
}
}
The above snippet is quite simple, you specify each scene directly then add it to your build settings. You can pass in parameters to get different results or make multiple functions, whichever is easiest for you. Here is how you would call this function in the command line
"C:\Program Files\Unity\Editor\Unity.exe" -batchmode -executeMethod MyEditorScript.PerformBuild
I use -batchmode here so if any prompts are brought up, Unity will silence them so the process can be much more automated.
As for your second question,
And how to specify destination directory ?
I am not sure if you want to tie the directory where you save and the scenes you build with, but it might make everything easier. There is a build setting called BuildPlayerOptions.locationPathName, which allows you to specify where the build is save
static void WebGLProductionBuild()
{
// Build the player.\
BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();
buildPlayerOptions.scenes = new[] { "Assets/Scene1.unity", "Assets/Scene2.unity" };
buildPlayerOptions.locationPathName = "yourLocationNameHere";
buildPlayerOptions.target = BuildTarget.WebGL;
buildPlayerOptions.options = BuildOptions.None; // set whatever you want here
BuildPipeline.BuildPlayer(buildPlayerOptions); // apply the setting changes
}
To call the above method is exactly the same except for the function call as the above line
"C:\Program Files\Unity\Editor\Unity.exe" -batchmode -executeMethod MyEditorScript.WebGLProductionBuild
I do not believe what you want to achieve can completely be done from command line, but this answer is pretty close. I am also not exactly sure if you wanted the scenes and the new path bundled together. If you are looking to build each individual scene and specify a new path, you can do so by making a new function with a switch statement or just make multiple functions to call.

Unity already provides answer to a similar question here.
You can create a method to make build validations, change settings and build different players. These methods have to be inside a script file located in an Editor folder, for example Assets/Editor/Builders/Builder.cs. The class also doesn’t need to extend any Unity class - the only requirement is that static functions are used.
using UnityEditor;
using System;
class Builder
{
static void Build ()
{
string[] arguments = Environment.GetCommandLineArgs();
// ... your code here, validations, flag changes, etc.
// foreach(string arg in arguments)
// Filter...
string sceneName = argument[1];
string destinationDirectoryPath = arguments[2];
// Build the player.\
BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();
buildPlayerOptions.scenes = new[] { sceneName };
buildPlayerOptions.locationPathName = destinationDirectoryPath;
//buildPlayerOptions.target = "Your Target";
BuildPipeline.BuildPlayer(buildPlayerOptions);
}
}
You can then call the builder function using these command:
/Path/To/Unity -batchmode -executeMethod Builder.Build SceneName
DestinationDirectoryPath

Related

The type or namespace name 'Forms' does not exist in the namespace 'System.Windows' FIX

Can someone please help me with this, am trying to use OpenFileDialog class from System.Windows.Forms to open a file dialog and read the selected file. Then, this error showed up. I've referenced it but still the same, below is the code.
`using UnityEngine
using UnityEngine.UI
using System.Windows.Forms;
public class OpenFileButtonScript : MonoBehaviour
{
public TextFieldScript textFieldScript;
public void OpenFile()
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*";
openFileDialog.FilterIndex = 1;
openFileDialog.Multiselect = false;
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
string filePath = openFileDialog.FileName;
string text = System.IO.File.ReadAllText(filePath);
textFieldScript.inputField.text = text;
}
}
}`
It may look like you have access to all of the native Window system libraries, but it just looks like it. In actuality, a lot of the time you're simply given stubs, or shims, that look like the full Window libraries, because there's a certain element that Unity wants to use from those namespaces. If you think about it, the code you present above, what do you think it should do on Android or Nintendo devices? The simple answer is, it simply won't work.
Generally in cases like this, you have to gain access to the native operating system, and perform those calls directly. For example, there is a file browser asset on the Asset Store, that does this for you. It's not free, because the process isn't trivial.
Depending on how much effort you want to put in, you CAN read files from the local file stores (to varying degrees based on platform). It's possible to read the list of files in a location, and use either uGUI or UIToolkit to create your own File Open Dialogue box. Again, this isn't a trivial task either. So you have to be sure that you'd want to go down that path.

Flutter write script for to write code in project

I have a file inside my Flutter-project. A simple .dart file which looks like this:
class EnLanguage implements BaseLanguage {
#override
Map<String, String> get language => {'test': 'test'};
}
Now my goal is that I write I script which I by executing goes through all my Project-files, searches for specific Strings ( the ones with a .tr ending) and adds it to the map in the class above (key and value are the same).
I couldn't find any way to achieve this. How does a simple script looks like that can write inside my project files? Im not asking for the whole logic, I just need a start. I couldn't find anything..
Have a look at the package dcli and specifically the pack command. It does a chunk of what you need.
Not quite certain what you mean by strings ending with a .tr.
But to process each script.
var project = DartProject.self.pathToPackage;
find('*.dart', workingDirectory: project)
.forEach((script) {
read(script). forEach((line) {
If (line. contains('.tr'))
{
Extract line...
Write to generated file..
}

Is it possible on monogame to load content files to the Content Manager at run time?

The reason I want to do this is that I'd like users to be able to create their own racetrack and save it as an image. Users would then be able to select their image and race on their track.
I'm thinking of using the following code to test if the file exists
using System.IO;
public static bool TrackExists(string fileName)
{
return File.Exists($#"Content\Tracks\{fileName}.xnb");
}
If it doesn't exist in the pipeline, I'd like it to be added and built so it can then be used in the project.
How should I go about doing this?
if (File.Exists(path))
{
tex.FromFile(_graphicsDevice, path);
_game.ChangeState(new RaceState(_game, _graphicsDevice, _content, tex));
}
If you need to load an image file as a Texture2D, you need to use the static method Texture2D.FromFile() as follows
myTex2D = Texture2D.FromFile(GraphicsDevice, "path/to/file");
As a rule of thumb, you cannot use the pipeline to load files dynamically. Nevertheless, it is not necessary that you have to use it. AFAIK the pipeline is the best and fastest way to load the static content of your game. There will be methods to import your custom files as content dynamically, so don't worry just because you're not using the pipeline. There are many types in Monogame (like Texture2D) that support dynamic loading from files.
EDIT:
Just to clarify, The method is a static member of Texture2D class, so you should be using it as follows:
if (File.Exists(path))
{
tex = Texture2D.FromFile(_graphicsDevice, path);
//...Rest of your code
}

Changing working directory in Scala [duplicate]

How can I change the current working directory from within a Java program? Everything I've been able to find about the issue claims that you simply can't do it, but I can't believe that that's really the case.
I have a piece of code that opens a file using a hard-coded relative file path from the directory it's normally started in, and I just want to be able to use that code from within a different Java program without having to start it from within a particular directory. It seems like you should just be able to call System.setProperty( "user.dir", "/path/to/dir" ), but as far as I can figure out, calling that line just silently fails and does nothing.
I would understand if Java didn't allow you to do this, if it weren't for the fact that it allows you to get the current working directory, and even allows you to open files using relative file paths....
There is no reliable way to do this in pure Java. Setting the user.dir property via System.setProperty() or java -Duser.dir=... does seem to affect subsequent creations of Files, but not e.g. FileOutputStreams.
The File(String parent, String child) constructor can help if you build up your directory path separately from your file path, allowing easier swapping.
An alternative is to set up a script to run Java from a different directory, or use JNI native code as suggested below.
The relevant OpenJDK bug was closed in 2008 as "will not fix".
If you run your legacy program with ProcessBuilder, you will be able to specify its working directory.
There is a way to do this using the system property "user.dir". The key part to understand is that getAbsoluteFile() must be called (as shown below) or else relative paths will be resolved against the default "user.dir" value.
import java.io.*;
public class FileUtils
{
public static boolean setCurrentDirectory(String directory_name)
{
boolean result = false; // Boolean indicating whether directory was set
File directory; // Desired current working directory
directory = new File(directory_name).getAbsoluteFile();
if (directory.exists() || directory.mkdirs())
{
result = (System.setProperty("user.dir", directory.getAbsolutePath()) != null);
}
return result;
}
public static PrintWriter openOutputFile(String file_name)
{
PrintWriter output = null; // File to open for writing
try
{
output = new PrintWriter(new File(file_name).getAbsoluteFile());
}
catch (Exception exception) {}
return output;
}
public static void main(String[] args) throws Exception
{
FileUtils.openOutputFile("DefaultDirectoryFile.txt");
FileUtils.setCurrentDirectory("NewCurrentDirectory");
FileUtils.openOutputFile("CurrentDirectoryFile.txt");
}
}
It is possible to change the PWD, using JNA/JNI to make calls to libc. The JRuby guys have a handy java library for making POSIX calls called jnr-posix. Here's the maven info
As mentioned you can't change the CWD of the JVM but if you were to launch another process using Runtime.exec() you can use the overloaded method that lets you specify the working directory. This is not really for running your Java program in another directory but for many cases when one needs to launch another program like a Perl script for example, you can specify the working directory of that script while leaving the working dir of the JVM unchanged.
See Runtime.exec javadocs
Specifically,
public Process exec(String[] cmdarray,String[] envp, File dir) throws IOException
where dir is the working directory to run the subprocess in
If I understand correctly, a Java program starts with a copy of the current environment variables. Any changes via System.setProperty(String, String) are modifying the copy, not the original environment variables. Not that this provides a thorough reason as to why Sun chose this behavior, but perhaps it sheds a little light...
The working directory is a operating system feature (set when the process starts).
Why don't you just pass your own System property (-Dsomeprop=/my/path) and use that in your code as the parent of your File:
File f = new File ( System.getProperty("someprop"), myFilename)
The smarter/easier thing to do here is to just change your code so that instead of opening the file assuming that it exists in the current working directory (I assume you are doing something like new File("blah.txt"), just build the path to the file yourself.
Let the user pass in the base directory, read it from a config file, fall back to user.dir if the other properties can't be found, etc. But it's a whole lot easier to improve the logic in your program than it is to change how environment variables work.
I have tried to invoke
String oldDir = System.setProperty("user.dir", currdir.getAbsolutePath());
It seems to work. But
File myFile = new File("localpath.ext");
InputStream openit = new FileInputStream(myFile);
throws a FileNotFoundException though
myFile.getAbsolutePath()
shows the correct path.
I have read this. I think the problem is:
Java knows the current directory with the new setting.
But the file handling is done by the operation system. It does not know the new set current directory, unfortunately.
The solution may be:
File myFile = new File(System.getPropety("user.dir"), "localpath.ext");
It creates a file Object as absolute one with the current directory which is known by the JVM. But that code should be existing in a used class, it needs changing of reused codes.
~~~~JcHartmut
You can use
new File("relative/path").getAbsoluteFile()
after
System.setProperty("user.dir", "/some/directory")
System.setProperty("user.dir", "C:/OtherProject");
File file = new File("data/data.csv").getAbsoluteFile();
System.out.println(file.getPath());
Will print
C:\OtherProject\data\data.csv
You can change the process's actual working directory using JNI or JNA.
With JNI, you can use native functions to set the directory. The POSIX method is chdir(). On Windows, you can use SetCurrentDirectory().
With JNA, you can wrap the native functions in Java binders.
For Windows:
private static interface MyKernel32 extends Library {
public MyKernel32 INSTANCE = (MyKernel32) Native.loadLibrary("Kernel32", MyKernel32.class);
/** BOOL SetCurrentDirectory( LPCTSTR lpPathName ); */
int SetCurrentDirectoryW(char[] pathName);
}
For POSIX systems:
private interface MyCLibrary extends Library {
MyCLibrary INSTANCE = (MyCLibrary) Native.loadLibrary("c", MyCLibrary.class);
/** int chdir(const char *path); */
int chdir( String path );
}
The other possible answer to this question may depend on the reason you are opening the file. Is this a property file or a file that has some configuration related to your application?
If this is the case you may consider trying to load the file through the classpath loader, this way you can load any file Java has access to.
If you run your commands in a shell you can write something like "java -cp" and add any directories you want separated by ":" if java doesnt find something in one directory it will go try and find them in the other directories, that is what I do.
Use FileSystemView
private FileSystemView fileSystemView;
fileSystemView = FileSystemView.getFileSystemView();
currentDirectory = new File(".");
//listing currentDirectory
File[] filesAndDirs = fileSystemView.getFiles(currentDirectory, false);
fileList = new ArrayList<File>();
dirList = new ArrayList<File>();
for (File file : filesAndDirs) {
if (file.isDirectory())
dirList.add(file);
else
fileList.add(file);
}
Collections.sort(dirList);
if (!fileSystemView.isFileSystemRoot(currentDirectory))
dirList.add(0, new File(".."));
Collections.sort(fileList);
//change
currentDirectory = fileSystemView.getParentDirectory(currentDirectory);

TeamCity could not build Unity3D project

I am trying to build a simple Unity3D project using TeamCity. The problem is that TeamCity cannot find the scene file and I am getting the following error message:
"C:\Program Files (x86)\Unity\Editor\Unity.exe" -batchMode -quit -nographics -projectPath C:\unityProject
[catting log file]
'' is an incorrect path for a scene file. BuildPlayer expects paths relative to the project folder.
'' is an incorrect path for a scene file. BuildPlayer expects paths relative to the project folder.
The image shows how I set up the build. When I run the build using command line on computer I have no problem to build the project, just using the TeamCity.
I was thinking if there is a way to add scene file in the editor. I don't want to use "method execution" and run BuildPipeline.BuildPlayer() method.
The error occurs, if within your build command scenes : String[] parameter there are empty strings ''.
If you put AutoBuilder Script (C#, JavaScript) into any Assets/Editor folder or subfolder within your project, you can easily call the build script appropriate for your Player OS from -executeMethod like this:
Unity -buildTarget android -executeMethod "AutoBuilder.PerformAndroidBuild"
AutoBuilder does the job to pass the selected scenes automatically like this:
/**
* Gets the paths of the activated scenes from the BuildSettings
* #return {String[]} BuiltinArray of Strings
*/
function GetScenePaths () {
var scenes = new Array();
for(var i : int = 0; i < EditorBuildSettings.scenes.Length; i += 1) {
/**
* Only add scene, if it is enabled in the build settings.
*/
if (EditorBuildSettings.scenes[i].enabled) {
scenes.Push(EditorBuildSettings.scenes[i].path);
}
}
/**
* Return a builtin array instead of a JavaScript Array
*/
var builtinArray : String[] = scenes.ToBuiltin(String) as String[];
return builtinArray;
}
You can find AutoBuilder in JavaScript here: https://github.com/geildanke/UNT.autobuilder (I rewrite the great work from the C# AutoBuilder.cs into JavaScript for the ones that prefer JavaScript)
There is an option to set an Execute Method on your image. Have you created a static build class that sets up the build pipeline?
For example (taken directly from docs):
// C# example
using UnityEditor;
class MyEditorScript
{
static void PerformBuild ()
{
string[] scenes = { "Assets/MyScene.unity" };
BuildPipeline.BuildPlayer(scenes, ...);
}
}