Category Archives: Coder

[Homebrew] has anyone encountered the warning generated by brew doctor[ The operating system is MAC 10.7.3]

Warning Message:

brew doctor

Warning: /usr/local/include isn’t writable.

This can happen if you “sudo make install” software that isn’t managed

by Homebrew.

 

If a brew tries to write a header file to this directory, the install will

fail during the link step.

 

You should probably `chown` /usr/local/include

 

Warning: /usr/local/share isn’t writable.

This can happen if you “sudo make install” software that isn’t managed

by Homebrew.

 

If a brew tries to write a file to this directory, the install will

fail during the link step.

 

You should probably `chown` /usr/local/share

 

Warning: Some directories in /usr/local/share/locale aren’t writable.

This can happen if you “sudo make install” software that isn’t managed

by Homebrew. If a brew tries to add locale information to one of these

directories, then the install will fail during the link step.

You should probably `chown` them:

 

/usr/local/share/locale

/usr/local/share/locale/be

/usr/local/share/locale/be/LC_MESSAGES

/usr/local/share/locale/ca

/usr/local/share/locale/ca/LC_MESSAGES

/usr/local/share/locale/da

/usr/local/share/locale/da/LC_MESSAGES

/usr/local/share/locale/de

/usr/local/share/locale/de/LC_MESSAGES

/usr/local/share/locale/el

/usr/local/share/locale/el/LC_MESSAGES

/usr/local/share/locale/es

/usr/local/share/locale/es/LC_MESSAGES

/usr/local/share/locale/fi

/usr/local/share/locale/fi/LC_MESSAGES

/usr/local/share/locale/fr

/usr/local/share/locale/fr/LC_MESSAGES

/usr/local/share/locale/id

/usr/local/share/locale/id/LC_MESSAGES

/usr/local/share/locale/ja

/usr/local/share/locale/ja/LC_MESSAGES

/usr/local/share/locale/nl

/usr/local/share/locale/nl/LC_MESSAGES

/usr/local/share/locale/ru

/usr/local/share/locale/ru/LC_MESSAGES

/usr/local/share/locale/sr

/usr/local/share/locale/sr/LC_MESSAGES

/usr/local/share/locale/sv

/usr/local/share/locale/sv/LC_MESSAGES

/usr/local/share/locale/tr

/usr/local/share/locale/tr/LC_MESSAGES

/usr/local/share/locale/uk

/usr/local/share/locale/uk/LC_MESSAGES

/usr/local/share/locale/vi

/usr/local/share/locale/vi/LC_MESSAGES

/usr/local/share/locale/zh_CN

/usr/local/share/locale/zh_CN/LC_MESSAGES

/usr/local/share/locale/zh_TW

/usr/local/share/locale/zh_TW/LC_MESSAGES

 

Warning: Some directories in /usr/local/share/man aren’t writable.

This can happen if you “sudo make install” software that isn’t managed

by Homebrew. If a brew tries to add locale information to one of these

directories, then the install will fail during the link step.

You should probably `chown` them:

 

/usr/local/share/man

/usr/local/share/man/man1

/usr/local/share/man/man7

 

Warning: The /usr/local directory is not writable.

Even if this directory was writable when you installed Homebrew, other

software may change permissions on this directory. Some versions of the

“InstantOn” component of Airfoil are known to do this.

 

You should probably change the ownership and permissions of /usr/local

back to your user account.

 

Warning: Unbrewed dylibs were found in /usr/local/lib.

If you didn’t put them there on purpose they could cause problems when

building Homebrew formulae, and may need to be deleted.

 

Unexpected dylibs:

/usr/local/lib/libgcc_ext.10.4.dylib /usr/local/lib/libgcc_ext.10.5.dylib /usr/local/lib/libgcc_s.1.dylib /usr/local/lib/libgfortran.3.dylib /usr/local/lib/libgomp.1.dylib /usr/local/lib/libitm.1.dylib /usr/local/lib/libquadmath.0.dylib /usr/local/lib/libssp.0.dylib /usr/local/lib/libstdc++.6.dylib

 

Warning: Unbrewed .la files were found in /usr/local/lib.

If you didn’t put them there on purpose they could cause problems when

building Homebrew formulae, and may need to be deleted.

 

Unexpected .la files:

/usr/local/lib/libgfortran.la /usr/local/lib/libgmp.la /usr/local/lib/libgomp.la /usr/local/lib/libitm.la /usr/local/lib/libmpc.la /usr/local/lib/libmpfr.la /usr/local/lib/libquadmath.la /usr/local/lib/libssp.la /usr/local/lib/libssp_nonshared.la /usr/local/lib/libstdc++.la /usr/local/lib/libsupc++.la

 

Warning: Unbrewed static libraries were found in /usr/local/lib.

If you didn’t put them there on purpose they could cause problems when

building Homebrew formulae, and may need to be deleted.

 

Unexpected static libraries:

/usr/local/lib/libgfortran.a /usr/local/lib/libgmp.a /usr/local/lib/libgomp.a /usr/local/lib/libiberty.a /usr/local/lib/libitm.a /usr/local/lib/libmpc.a /usr/local/lib/libmpfr.a /usr/local/lib/libquadmath.a /usr/local/lib/libssp.a /usr/local/lib/libssp_nonshared.a /usr/local/lib/libstdc++.a /usr/local/lib/libsupc++.a

 

Warning: Your Xcode is configured with an invalid path.

You should change it to the correct path. Please note that there is no correct

path at this time if you have *only* installed the Command Line Tools for Xcode.

If your Xcode is pre-4.3 or you installed the whole of Xcode 4.3 then one of

these is (probably) what you want:

 

sudo xcode-select -switch /Developer

sudo xcode-select -switch /Applications/Xcode.app

 

sudo chown 501 /usr/local/include

sudo chown 501 /usr/local/share

sudo chown 501 /usr/local/share/man

sudo chown 501 /usr/local/share/man/man7

sudo chown 501 /usr/local/share/man/man1

cd /usr/local/share/local

sudo chown -R 501 *

sudo chown 501 /usr/local

 

cd /usr/local/lib

rm -rf *.dylib

rm -rf *.a

rm -rf *.la

 

xcode-select: Error: Path “/Developer” is not a directory.

sudo xcode-select -switch /Developer

sudo xcode-select -switch /Applications/Xcode.app

Processing. Don’t know if anything will go wrong yet. Ran brew doctor again and

It shows: Your system is raring to brew.

C++ 11: How to Avoid Deadlock in unique_Lock and lock_Guard

#include <iostream>
#include <fstream>
#include <thread>
#include <mutex>
#include <string>

using namespace std;

class LogFile {
public:
    LogFile() {
        f.open("log.txt");
    }

    ~LogFile() {
    }

    void shared_print(string msg, int id) {
        lock_guard<mutex> guard(mu);
        f<<msg<<id<<endl;
    }

    // Never return f to the outside world
    ofstream& getStream() { return f;}
    // Never pass f as an augument to user provided function
    void processf(void fun(ofstream&)) {
            fun(f);
    }

private:
    ofstream f;
    mutex mu;
};

void function_1(LogFile& log) {
    for(int i = 0; i >-100; i--) {
        log.shared_print("From t1: ",i);
    }
}

int main()
{
    LogFile log;
    thread t1(function_1,ref(log));

    for(int i= 0; i < 100; i++) {
        log.shared_print("From main: ",i);
    }

    t1.join();

    return 0;
}

When multiple locks need to be applied at the same time, the following two methods are used
lock(mtx1,mtx2)
lock_guard(mtx1,adopt_lock)
lock_guard(mtx2,adopt_lock)

unique_lock lock1(mtx1,defer_lock)
unique_lock lock2(mtx2,defer_lock)
lock(lock1,lock2)


unique_lock VS lock_guard
lock_guard doesn't allow manual unlock/lock less performance intensive
unique_lock is more flexible, allows manual unlock/lock multiple times, high performance consumption

void foo() {
    unique_lock<mutex> locker(mtx,defer_lock); defer_lock assumes no locking yet
    // do something not using mtx
    mtx.lock(); 
    // do something using mtx to protect
    mtx.unlock();
    // do something else
}

Lazy Initialization

#include <iostream>
#include <thread>
#include <mutex>
#include <fstream>
#include <string>

using namespace std;

class LogFile {
private:
    ofstream f;
    mutex _mu;
    mutex _mu_open;
public:
    void shared_print(string& msg, int id) {
        {
            unique_lock<mutex> open_lck(_mu_open);
            if(!f.is_open()) {
                f.open("log.txt");
            }
        }

        unique_lock<mutex> locker(_mu);

        // do other things

    }
};


class LazyInitializationLogFile {
private:
    ofstream f;
    mutex _mu;
    once_flag _flag;
public:
    void shared_print(string7 msg, int id) {
        call_once(_flag,[&](){f.open("log.txt");});

        unique_lock<mutex> locker(_mu);

        // do other things
    }
}

int main()
{
    return 0;
}

Completely Uninstall Node.js from Mac OS X

Installation: Nodejs V5.5.0

executable: sudo npm -v

Score:

Error: Cannot find module 'minimatch'
    at Function.Module._resolveFilename (module.js:339:15)
    at Function.Module._load (module.js:290:25)
    at Module.require (module.js:367:17)
    at require (internal/module.js:16:19)
    at Object.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/rimraf/node_modules/glob/glob.js:44:17)
    at Module._compile (module.js:413:34)
    at Object.Module._extensions..js (module.js:422:10)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Module.require (module.js:367:17)

Solution: Remove node and npm modules completely and reinstall them

Completely Uninstall Node.js from Mac OS X

The following is the best way to completely uninstall node + npm:

go to /usr/local/lib and delete any node and node_modules
go to /usr/local/include and delete any node and node_modules directory
if you installed with brew install node, then run brew uninstall node in your terminal

check your Home directory for any local or lib or include folders, and delete any node or node_modules from there
go to /usr/local/bin and delete any node executable
You may need to do the additional instructions as well:

sudo rm /usr/local/bin/npm
sudo rm /usr/local/share/man/man1/node.1
sudo rm /usr/local/lib/dtrace/node.d
sudo rm -rf ~/.npm
sudo rm -rf ~/.node-gyp
sudo rm /opt/local/bin/node
sudo rm /opt/local/include/node
sudo rm -rf /opt/local/lib/node_modules

 

How does MAC uninstall Jenkins

Yesterday, when I installed Jenkins, I found that my Mac had already installed Jenkins, and I forgot my password. So I searched a lot of technical blogs, but I spent several hours without finding them. Finally, I found them on foreign websites http://stackoverflow.com/questions/11608996/how-to-uninstall-jenkins
The first time I wrote a blog, it was wrong. I’m sorry

First, uninstall Jenkins, open your Mac terminal, enter the following command/or find your Jenkins file, double-click the folder to run install. Command

2. Delete some configurations that may be forgotten

sudo rm -rf /var/root/.jenkins ~/.jenkins

3. If the old Jenkins version cannot be found, use the following command

sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist
sudo rm /Library/LaunchDaemons/org.jenkins-ci.plist
sudo rm -rf /Applications/Jenkins "/Library/Application Support/Jenkins" /Library/Documentation/Jenkins

4. Delete all the contents of Jenkins folder

sudo rm -rf /<User you replace>/Shared/Jenkins

5. Delete user and group

sudo dscl . -delete /Users/jenkins
sudo dscl . -delete /Groups/jenkins

6. The following command is also uninstalled from the newer version of Jenkins in the script

sudo rm -f /etc/newsyslog.d/jenkins.conf
pkgutil --pkgs | grep 'org\.jenkins-ci\.' | xargs -n 1 sudo pkgutil --forget

Rigidbody.moveposition rigid body movement

using UnityEngine;

public class PlayerContrller1 : MonoBehaviour 
{
    private Transform mmTransform;
    private Rigidbody mmRigidbody;

    
    void Start ()
    {
        mmTransform=gameObject.GetComponent<Transform>();
        mmRigidbody=gameObject.GetComponent<Rigidbody>();
    }
    void Update ()
    {
        PlayerMove();
    }
    //Method

    private void PlayerMove()
    {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        Vector3 dir = new Vector3(h, 0, v);
        mmRigidbody.MovePosition(mmTransform.position + dir * 0.2f);
    }
}

Input input key settings.

Upper menu bar: edit=>Project settings=>input

Unity – JSON array deserialization

Editor’s note

When editors want to load unity

    private string getjson()
    {
        String result;

        Uri uri = new Uri(string.Format("http://localhost:8080/rest/scene"));

        HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;

        using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
        {
            StreamReader reader = new StreamReader(response.GetResponseStream());
            result = reader.ReadToEnd();
        }

        Debug.Log("[json]:" + result);

        return result;
    }

    private SceneEntity[] JsonToEntity(string json)
    {
        json = "{\"Items\":" + json + "}";
        Debug.Log("[json]:" + json);
		 
        SceneEntity[] scenes = JsonHelper.FromJson<SceneEntity>(json);

        foreach (SceneEntity entity in scenes)
        {
			Debug.Log("[scene][id]:" + entity.id + " [name]:" + entity.name);
        }

		Debug.Log ("[0][id]:" + scenes[0].id);
		Debug.Log ("[1][id]:" + scenes[1].id);

        return scenes;
    }

 

Log system reconstruction of unity3d

Editor’s note

Because the log system of unity3d needs to be rewritten, it is changed to the custom mode, and the content method of log4j is used

Log of unity3d

In general, write the log entry code in unity3d

Debug.Log("hello message");

In unityeditor and unityengine, besides message, stack information is also printed. The performance is low. According to an experienced person, printing a large number of logs on the client will seriously reduce the rendering performance

Debug principle of unity3d

Principle analysis

Check the implementation of debug. Log in rider, and we can see the following

public static void Log(object message)
{
    Debug.unityLogger.Log(LogType.Log, message);
}

We can understand that the essence is to call debug. Unitylogger

public static ILogger unityLogger
{
    get
    {
        return Debug.s_Logger;
    }
}

Unitylogger actually calls debug. S_ Logger, and S is defined below_ Implementation of logger

internal static ILogger s_Logger = (ILogger) new Logger((ILogHandler) new DebugLogHandler());

The essence of debugglohandler is to call static methods, which are called according to the implementation of various platforms of unityengine

using System;
using System.Runtime.CompilerServices;
using UnityEngine.Scripting;

namespace UnityEngine
{
  internal sealed class DebugLogHandler : ILogHandler
  {
    [ThreadAndSerializationSafe]
    [GeneratedByOldBindingsGenerator]
    [MethodImpl(MethodImplOptions.InternalCall)]
    internal static extern void Internal_Log(LogType level, string msg, [Writable] Object obj);

    [ThreadAndSerializationSafe]
    [GeneratedByOldBindingsGenerator]
    [MethodImpl(MethodImplOptions.InternalCall)]
    internal static extern void Internal_LogException(Exception exception, [Writable] Object obj);

    public void LogFormat(LogType logType, Object context, string format, params object[] args)
    {
      DebugLogHandler.Internal_Log(logType, string.Format(format, args), context);
    }

    public void LogException(Exception exception, Object context)
    {
      DebugLogHandler.Internal_LogException(exception, context);
    }
  }
}

There are only two ways to achieve it

internal static extern void Internal_Log(LogType level, string msg, [Writable] Object obj);
internal static extern void Internal_LogException(Exception exception, [Writable] Object obj);

Code testing

Debug.unityLogger.Log(LogType.Log,"hello message");

Unityeditor printing

hello message
UnityEngine.Logger:Log(LogType, Object)
InitController:Start() (at Assets/Scripts/Controller/InitController.cs:14)

Conclusion: the problem of reducing stack information printing cannot be solved

UnityEngine.Application

According to the logcallback document of unityengine. Application, we can understand the application. Logmessage received and application. Logmessage received threaded related to logcallback

public delegate void LogCallback(string condition, string stackTrace, LogType type);

Since logcallback uses the delegate delegate method, you need to specify the implementation method, which is officially recommended by unity as follows

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour {
    public string output = "";
    public string stack = "";
    void OnEnable() {
        Application.logMessageReceived += HandleLog;
    }
    void OnDisable() {
        Application.logMessageReceived -= HandleLog;
    }
    void HandleLog(string logString, string stackTrace, LogType type) {
        output = logString;
        stack = stackTrace;
    }
}

Principle analysis

Logmessage received only works on the main thread. That’s the main line of unity. And the document describes the implementation method is not thread safe. The implementation code of logmessage receivedthreaded must be thread safe and support access from outside the main thread

    public static event Application.LogCallback logMessageReceived
    {
      add
      {
        Application.s_LogCallbackHandler += value;
        Application.SetLogCallbackDefined(true);
      }
      remove
      {
        Application.s_LogCallbackHandler -= value;
      }
    }

    public static event Application.LogCallback logMessageReceivedThreaded
    {
      add
      {
        Application.s_LogCallbackHandlerThreaded += value;
        Application.SetLogCallbackDefined(true);
      }
      remove
      {
        Application.s_LogCallbackHandlerThreaded -= value;
      }
    }

According to CSharp’s annotation, calllogcallback is called by local code. In other words, the logcallbackhandler implementation of the main thread will be called first, and then the callbackhandlerthreaded implementation will be called regardless of whether the main thread is called or not

    [RequiredByNativeCode]
    private static void CallLogCallback(string logString, string stackTrace, LogType type, bool invokedOnMainThread)
    {
      if (invokedOnMainThread)
      {
        Application.LogCallback logCallbackHandler = Application.s_LogCallbackHandler;
        if (logCallbackHandler != null)
          logCallbackHandler(logString, stackTrace, type);
      }
      Application.LogCallback callbackHandlerThreaded = Application.s_LogCallbackHandlerThreaded;
      if (callbackHandlerThreaded == null)
        return;
      callbackHandlerThreaded(logString, stackTrace, type);
    }

SetLogCallbackDefined

    [GeneratedByOldBindingsGenerator]
    [MethodImpl(MethodImplOptions.InternalCall)]
    private static extern void SetLogCallbackDefined(bool defined);

Design of log system

Demand

It doesn’t affect unity

File output

Support unity debug

Support output log level

Log4Net

According to the previous Java way, log4j is easy to use. First, we decided to use it in the way of slf4j interface. Secondly, log4net is used to realize the requirements, as long as it does not affect the running of unity. The actual test did not affect the unity operation

Interface design

LoggerFactory

using log4net;

namespace Assets.Scripts.Utils.Log4Unity
{
    public class LoggerFactory
    {
        public static Log4Unity getLogger(string name)
        {
            return new Log4Unity(LogManager.GetLogger(name));
        }
    }
}

Log4unity: originally, I wanted to use logger directly, but it was occupied by unity

using System;
using System.IO;
using log4net;
using log4net.Config;
using UnityEngine;

namespace Assets.Scripts.Utils.Log4Unity
{
    public class Log4Unity
    {
        private ILog log;
        public Log4Unity(ILog log)
        {
            this.log = log;
        }

        public void debug(string message)
        {
            this.log.Debug(message);
            LogConfigurator.refresh();
        }

        public void info(string message)
        {
            this.log.Info(message);
            LogConfigurator.refresh();
        }

        public void warning(string message)
        {
            this.log.Warn(message);
            LogConfigurator.refresh();
        }

        public void error(string message)
        {
            Debug.LogError(message);
            if(!LogConfigurator.lazy_mode)
                this.log.Error(message);
            LogConfigurator.refresh();
        }

        public void exception(Exception exception)
        {
            Debug.LogException(exception);
            if(!LogConfigurator.lazy_mode)
                this.log.Warn(exception.ToString());
            LogConfigurator.refresh();
        }

        public void fatal(string message)
        {
            Debug.LogAssertion(message);
            if(!LogConfigurator.lazy_mode)
                this.log.Fatal(message);
            LogConfigurator.refresh();
        }
    }

    
}

Initialization of log4unity

Log4unity initialization, using unity’s monobehavior to complete, while printing some simple logs, check the log file location

using System.IO;
using log4net;
using log4net.Appender;
using log4net.Config;
using log4net.Core;
using UnityEngine;

namespace Assets.Scripts.Utils.Log4Unity
{
public class LogConfigurator : MonoBehaviour
    {
        private static readonly string config_path = "log4unity.properties";
        private static readonly ILog logger = LogManager.GetLogger("LogConfigurator");
        private static bool config_load = false;
        public static bool refresh_realtime = true;
        public static bool lazy_mode = true;

        private static FileInfo fileInfo = new FileInfo(config_path);
        
        private void Awake()
        {
            if (fileInfo.Exists)
            {
                XmlConfigurator.Configure(fileInfo);
                IAppender appender = LogManager.GetRepository().GetAppenders()[0];
                if (appender.Name.Equals("FileAppender"))
                {
                    FileAppender fileAppender = (FileAppender) appender;

                    Debug.Log("[logpath]:" + fileAppender.File);
                }
                
                
                config_load = true;
            }
            else
            {
                Debug.LogError("class Log4Unity method Awake configfile " + fileInfo.FullName + " is not existed.");
            }
        }

        private void OnEnable()
        {
            logger.Debug("method OnEnable");
            if(config_load == true)
            {
                Application.logMessageReceivedThreaded += ThreadLog;
            }
        }

        private void ThreadLog(string condition, string stackTrace, LogType type)
        {
            if (LogType.Warning.Equals(type))
            {
                logger.Warn(condition);
            }
            else if(LogType.Log.Equals(type))
            {
                logger.Info(condition);
            }
            
            // fixed:double print
            if(lazy_mode)
                if (LogType.Exception.Equals(type))
                {
                    logger.Warn(condition);
                }
                else if (LogType.Error.Equals(type))
                {
                    logger.Error(condition);
                }
                else if (LogType.Assert.Equals(type))
                {
                    logger.Fatal(condition);
                }

            refresh();
        }

        public static void refresh()
        {
            if(refresh_realtime)
                fileInfo.Refresh();
        }

        private void OnDisable()
        {
            logger.Debug("method OnDisable");
            if(config_load == true)
            {
                Application.logMessageReceivedThreaded -= ThreadLog;
            }
        }

        private void OnDestroy()
        {
            logger.Debug("method OnDestroy");
            fileInfo.Refresh();
        }
    }
}

log4unity.properties

<?xml version='1.0' encoding='UTF-8'?>
<log4net>
	<appender name="FileAppender" type="log4net.Appender.FileAppender">
		<file value="log4unity.log" />
		<appendToFile value="true" />
		<layout type="log4net.Layout.PatternLayout">
			<conversionPattern value="%date %-5level --- [%-5thread]  %-20logger : %message%newline" />
		</layout>
	</appender>
	
	<root>
        <level value="DEBUG" />
		<appender-ref ref="FileAppender" />
    </root>
</log4net>

log4net.dll

Note: unity has two runtimes dotnet2.0 and dotnet4.6 on windows, both of which need to load the correct DLL version. In addition, the behavior of unityeditor is different in the two dotnet versions. Pay attention to the output location of the log. There is no problem after build

How to use it

public class FpsCounter : MonoBehaviour
    {
        private static readonly Log4Unity logger = LoggerFactory.getLogger("FpsCounter");
        
        ....
        
        private void Start()
        {
            logger.info("method Start");
            ....
        }

make complaints about

There are a lot of holes recently. Fill this up first

Unity3d: How to Change Font

using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
using UnityEngine.UI;

public class ChangeFontEditor : EditorWindow {

	[MenuItem("Tools/Change Font")]
	static void CreateWindow()
	{
		GetWindow<ChangeFontEditor>("Change Font");
	}


	Font newFont;
	int tabIdx;
	string[] tabNames = new string[] { "Modify all UI prefabs", "Specify the objects to be modified"};
	string uiprefabsDir = "Assets/Resources/UI";
	GameObject targetPrefab;
    bool NormalFont;

	private void OnGUI()
	{
		EditorGUILayout.LabelField("The tool will replace the default Arial font with the specified new font");

		newFont = EditorGUILayout.ObjectField("new font", newFont, typeof(Font), false) as Font;

        //List<GameObject> targets = new List<GameObject>();
        GUILayout.Space(20);
        NormalFont = GUILayout.Toggle(NormalFont, "Bold font changed to normal");

        GUILayout.Space(20);
		tabIdx = GUILayout.Toolbar(tabIdx, tabNames);
		switch (tabIdx)
		{
			case 0:
				{
					uiprefabsDir = EditorGUILayout.TextField("UI prefabs Catalog", uiprefabsDir);
					if (GUILayout.Button("replace"))
					{
						if (newFont)
						{
							string[] guids = AssetDatabase.FindAssets("t:Prefab", new string[] { uiprefabsDir });
							foreach (string guid in guids)
							{
								string filepath = AssetDatabase.GUIDToAssetPath(guid);
								GameObject go = AssetDatabase.LoadAssetAtPath<GameObject>(filepath);
								DoChange(go);
							} 
						}
						else
						{
							Debug.LogError("Need to specify new font");
						}
					}
				}
				break;
			case 1:
				{
					targetPrefab = EditorGUILayout.ObjectField(targetPrefab, typeof(GameObject), true) as GameObject;
					if (GUILayout.Button("repolace"))
					{
						if (newFont && targetPrefab)
						{
							DoChange(targetPrefab);
						}
						else if (newFont == null)
						{
							Debug.LogError("Need to specify new font");
						}
						else if (targetPrefab == null)
						{
							Debug.LogError("Need to specify the object to be modified");
						}
					}
				}
				break;
		}
	}

	void DoChange(GameObject target)
	{
		Text[] texts = target.GetComponentsInChildren<Text>(true);
		bool changed = false;
		bool boldchanged = false;
        int cnt = 0;
        int boldCnt = 0;
        foreach (Text t in texts)
		{
			if (t.font && t.font.name == "Arial")
			{
				t.font = newFont;
				changed = true;
				cnt++;
			}
            if (NormalFont && t.fontStyle == FontStyle.Bold)//The current font Microsoft elegant black, does not contain bold, change to Normal , size +2
            {
                t.fontStyle = FontStyle.Normal;
                t.fontSize += 2;
                boldchanged = true;
                boldCnt++;
            }
        }

		if (changed)
		{
			EditorUtility.SetDirty(target);
			Debug.LogFormat("fontChanged - {0} - {1}", target.name, cnt);
		}
        if (boldchanged)
        {
            EditorUtility.SetDirty(target);
            Debug.LogFormat("boldChanged - {0} - {1}", target.name, boldCnt);
        }
    }
}

A brief summary of hash calculation in resource packaging of unity

1. Generally, when calculating resource hash, we need to consider: resource + resource meta, dependency + dependency meta

2. Generally, when computing resource hash, the calculation results need to be encrypted, which can be directly encrypted with MD5 of C #

Specific implementation, the code is as follows (learning to use, structure is not perfect):

 1 using System;
 2 using System.IO;
 3 using System.Collections.Generic;
 4 using UnityEditor;
 5 using UnityEngine;
 6 using System.Security.Cryptography;
 7 using System.Text;
 8 
 9 public class Test
10 {
11     [MenuItem("BuildTool/Lugs")]
12     static void LugsTest()
13     {
14         Debug.Log(ComputeAssetHash("Assets/UI/Prefab/ui_login/ui_login.prefab"));
15     }
16 
17     static string ComputeAssetHash(string assetPath)
18     {
19         if (!File.Exists(assetPath))
20             return null;
21 
22         List<byte> list = new List<byte>();
23 
24         //Read the resource and its meta file as an array of bytes
25 list.AddRange(GetAssetBytes(assetPath));
26 
27         // Read the resource's dependencies and its meta file as an array of bytes (dependencies are essentially paths to the resource as well)
28         string[] dependencies = AssetDatabase.GetDependencies(assetPath);
29         for (int i = 0, iMax = dependencies.Length; i < iMax; ++i)
30             list.AddRange(GetAssetBytes(dependencies[i]));
31 
32         //If the resource has other dependencies, the corresponding byte array should also be read into the list, and then the hash code should be calculated
33 
34         //return the resource hash
35         return ComputeHash(list.ToArray());
36     }
37 
38     static byte[] GetAssetBytes(string assetPath)
39     {
40         if (!File.Exists(assetPath))
41             return null;
42 
43         List<byte> list = new List<byte>();
44 
45         var assetBytes = File.ReadAllBytes(assetPath);
46         list.AddRange(assetBytes);
47 
48         string metaPath = assetPath + ".meta";
49         var metaBytes = File.ReadAllBytes(metaPath);
50         list.AddRange(metaBytes);
51 
52         return list.ToArray();
53     }
54 
55     static MD5 md5 = null;
56     static MD5 MD5
57     {
58         get
59         {
60             if (null == md5)
61                 md5 = MD5.Create();
62             return md5;
63         }
64     }
65 
66     static string ComputeHash(byte[] buffer)
67     {
68         if (null == buffer || buffer.Length < 1)
69             return "";
70 
71         byte[] hash = MD5.ComputeHash(buffer);
72         StringBuilder sb = new StringBuilder();
73 
74         foreach (var b in hash)
75             sb.Append(b.ToString("x2"));
76 
77         return sb.ToString();
78     }
79 
80    
81 }

The following results are:

Procedural Mesh Component in C++:Getting Started

I create a simple triangle using the UProceduralMeshComponent API, from there extending it should be easy. Once the class is compiled you can just drag it into your scene.

To use this component, include the paths in the build.cs file of your project:

MyProject.Build.cs:

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "ProceduralMeshComponent" });

and in your .uproject file (MyProject.uproject) in case you work on a project:

"AdditionalDependencies": [..., ..., "ProceduralMeshComponent"]

After 4.17, plugins can now depend on other plugins, so in case you are working on aplugininstead of a project, you will have to add this to your .uplugin file:

"Modules": [
      {
        ....
      }
    ],
    "Plugins": [                       // <--
      {                                // <--
        "Name": "ProceduralMeshComponent",    // <--
        "Enabled": true                // <--
      }                                // <--
    ]

To fix errors with Visual Studio IntelliSense you need to right-click MyProject.uproject and re-generate Visual Studio project files. In Visual Studio 2017, open “Solution Explorer” and open the “Game” folder, right-click on the first line, which should be the root of your solution, select: “Rescan Solution”.

I’ve created an Actor class.

Add the header to your MyActor.h file above the “MyActor.generated.h” include which has to be the last include.

#include "ProceduralMeshComponent.h"
#include "MyActor.generated.h"

In the header file, the following is added to support assigning a material.

private:
    UPROPERTY(VisibleAnywhere)
    UProceduralMeshComponent * mesh;

In my cpp file I have added the following to the constructor:

MyActor.cpp

// Creating a standard root object.
AMyActor::AMyActor()
{
    mesh = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("GeneratedMesh"));
    RootComponent = mesh;
        // New in UE 4.17, multi-threaded PhysX cooking.
        mesh->bUseAsyncCooking = true;
}


// This is called when actor is spawned (at runtime or when you drop it into the world in editor)
void AMyActor::PostActorCreated()
{
    Super::PostActorCreated();
    CreateTriangle();
}

// This is called when actor is already in level and map is opened
void AMyActor::PostLoad()
{
    Super::PostLoad();
    CreateTriangle();
}

void AMyActor::CreateTriangle()
{
    TArray<FVector> vertices;
    vertices.Add(FVector(0, 0, 0));
    vertices.Add(FVector(0, 100, 0));
    vertices.Add(FVector(0, 0, 100));

    TArray<int32> Triangles;
    Triangles.Add(0);
    Triangles.Add(1);
    Triangles.Add(2);

    TArray<FVector> normals;
    normals.Add(FVector(1, 0, 0));
    normals.Add(FVector(1, 0, 0));
    normals.Add(FVector(1, 0, 0));

    TArray<FVector2D> UV0;
    UV0.Add(FVector2D(0, 0));
    UV0.Add(FVector2D(10, 0));
    UV0.Add(FVector2D(0, 10));
    

    TArray<FProcMeshTangent> tangents;
    tangents.Add(FProcMeshTangent(0, 1, 0));
    tangents.Add(FProcMeshTangent(0, 1, 0));
    tangents.Add(FProcMeshTangent(0, 1, 0));

    TArray<FLinearColor> vertexColors;
    vertexColors.Add(FLinearColor(0.75, 0.75, 0.75, 1.0));
    vertexColors.Add(FLinearColor(0.75, 0.75, 0.75, 1.0));
    vertexColors.Add(FLinearColor(0.75, 0.75, 0.75, 1.0));

    mesh->CreateMeshSection_LinearColor(0, vertices, Triangles, normals, UV0, vertexColors, tangents, true);
        
        // Enable collision data
    mesh->ContainsPhysicsTriMeshData(true);
}

The documentation for CreateMeshSection and CreateMeshSection_LinearColor functions is this:

/**
    *    Create/replace a section for this procedural mesh component.
    *    @param    SectionIndex        Index of the section to create or replace.
    *    @param    Vertices            Vertex buffer of all vertex positions to use for this mesh section.
    *    @param    Triangles            Index buffer indicating which vertices make up each triangle. Length must be a multiple of 3.
    *    @param    Normals                Optional array of normal vectors for each vertex. If supplied, must be same length as Vertices array.
    *    @param    UV0                    Optional array of texture co-ordinates for each vertex. If supplied, must be same length as Vertices array.
    *    @param    VertexColors        Optional array of colors for each vertex. If supplied, must be same length as Vertices array.
    *    @param    Tangents            Optional array of tangent vector for each vertex. If supplied, must be same length as Vertices array.
    *    @param    bCreateCollision    Indicates whether collision should be created for this section. This adds significant cost.
    */

// '''Don't use this function'''. It is deprecated. Use LinearColor version.
void CreateMeshSection(int32 SectionIndex, const TArray<FVector>& Vertices, const TArray<int32>& Triangles, const TArray<FVector>& Normals, const TArray<FVector2D>& UV0, const TArray<FColor>& VertexColors, const TArray<FProcMeshTangent>& Tangents, bool bCreateCollision);

// In this one you can send FLinearColor instead of FColor for the Vertex Colors.
void CreateMeshSection_LinearColor(int32 SectionIndex, const TArray<FVector>& Vertices, const TArray<int32>& Triangles, const TArray<FVector>& Normals, const TArray<FVector2D>& UV0, const TArray<FLinearColor>& VertexColors, const TArray<FProcMeshTangent>& Tangents, bool bCreateCollision)

// Updates a section of this procedural mesh component. This is faster than CreateMeshSection, but does not let you change topology. Collision info is also updated.
void UpdateMeshSection_LinearColor(int32 SectionIndex, const TArray<FVector>& Vertices, const TArray<FVector>& Normals, const TArray<FVector2D>& UV0, const TArray<FLinearColor>& VertexColors, const TArray<FProcMeshTangent>& Tangents);

If you have a <YourGameName>GameModeBase.cpp, make sure to add a reference to the header of the class where you added the above code, that way you will see it in your Editor in “C++ Classes” Content Browser and will be able to drag it to your scene.