Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - ArenMook

Pages: 1 2 [3] 4 5 ... 1447
31
NGUI 3 Support / Re: Fuzzy edge after update to Unity 2017
« on: November 23, 2017, 01:25:00 AM »
Since the culprit for the change is upgrading Unity from 5 to 2017, and you're creating your atlas at run-time, I can only suggest you check the texture's format and filter settings. My guess is that iOS either defaults to some texture format that has compression artifacts, or your quality settings for mobiles force compression.

32
This is intentional, default behaviour. Your text input gets handled by the device's keyboard. NGUI has no access to it, or its caret position. All it has access to is the final text.

33
NGUI 3 Support / Re: Setting up Healthbars
« on: November 23, 2017, 01:19:36 AM »
This is an old post. What's your question exactly?

34
Dev Blog / Nov 11, 2017 -- How to edit UnityEngine.dll
« on: November 11, 2017, 09:41:34 AM »
I'm currently working on performance optimizations for Project 5: Sightseer, and a part of that involved editing the UnityEngine.dll to fix a nasty bug Unity introduced back in ~2014 that they seem to refuse to fix. That bug, is an absurd amount of GC allocations coming from the AttributeHelperEngine.

The bug in question is glaringly obvious to anyone even with a little proficiency in C#, and stems from the lack of caching of expensive GetAttributes calls: https://github.com/MattRix/UnityDecompiled/blob/master/UnityEngine/UnityEngine/AttributeHelperEngine.cs

Amusingly, the bug has been reported to Unity years ago, alongside the code required to fix it (https://fogbugz.unity3d.com/default.asp?746364_pjnmdhk7c9imgdsk)... and yet -- Unity refused to do anything about it, claiming that a future redesign of the system will fix it. Well, guys -- fast forward to several years later -- the bug is still there, all the way in Unity 2017.2, and no actions have been taken to address it.

Here's the thing about closing bugs that are affecting people today hoping for a future redesign to fix it later -- until this "later" comes, the problem will still keep affecting all 4.5 million Unity developers, and it can be (and usually is) years before gets resolved! And if someone submits a bug report with actual code on how to fix it -- why not fix it? Boggles my mind...

Anyway -- this post isn't meant to be a rant about Unity's choices -- I'll do that in another one. Instead, let me explain how you -- the developer -- can fix this problem yourself, to an extent. Fortunately, this particular problem comes from the side of Unity that lives in the UnityEngine.dll file, and C# files are quite easy to modify. The first thing we need to do is make a new C# project in Visual Studio.

I was editing Unity 5.6.4f1 -- so I made the application target .NET Framework 3.5. "The Output type" needs to be a Class Library -- as we need to create a DLL with the edited functions first.

Compile this code into a DLL:
  1. using System;
  2.  
  3. namespace UnityEngine
  4. {
  5.         internal class AttributeHelperEngine
  6.         {
  7.                 private static Type GetParentTypeDisallowingMultipleInclusion (Type type)
  8.                 {
  9.                         return null;
  10.                 }
  11.  
  12.                 private static Type[] GetRequiredComponents (Type klass)
  13.                 {
  14.                         return null;
  15.                 }
  16.         }
  17. }
This simple DLL will not be referencing any Unity classes, so there is no need to reference the UnityEngine.dll. Compile the DLL (I targeted Release) and move it into the solution folder, or somewhere you can find it. I called mine FixUnityEngine.dll. If you choose to fix it by adding caching instead, like in the bug report's suggested fix code, you will need to reference the UnityEngine.dll. Personally, I saw no adverse effects of simply returning 'null' in Sightseer. Worked just fine.

The next step is to create a program that will replace the code in one DLL (UnityEngine.dll) with code from another (FixUnityEngine.dll). Since I no longer needed the code above, I simply commented it out, choosing to reuse the project instead of making a new one -- but if you plan on editing your replacement code you may want to create a separate VS solution.

The API that lets us devs replace C# code is part of Mono.Cecil, but interestingly enough it's actually a part of the Visual Studio installation, at least in the current version (2017). Here's all the code needed to edit the DLL:
  1. using System;
  2. using Mono.Cecil;
  3.  
  4. public class Application
  5. {
  6.         static MethodDefinition Extract (AssemblyDefinition asm, string type, string func)
  7.         {
  8.                 var mod = asm.MainModule;
  9.                 if (mod == null) return null;
  10.  
  11.                 var existingType = mod.GetType(type);
  12.                 if (existingType == null) return null;
  13.  
  14.                 var methods = existingType.Methods;
  15.  
  16.                 foreach (var method in methods)
  17.                 {
  18.                         if (method.Name == func)
  19.                         {
  20.                                 return method;
  21.                         }
  22.                 }
  23.                 return null;
  24.         }
  25.  
  26.         static bool Replace (AssemblyDefinition original, AssemblyDefinition replacement, string type, string func)
  27.         {
  28.                 var method0 = Extract(original, type, func);
  29.                 var method1 = Extract(replacement, type, func);
  30.  
  31.                 if (method0 != null && method1 != null)
  32.                 {
  33.                         method0.Body = method1.Body;
  34.                         Console.WriteLine("Replaced " + type + "." + func);
  35.                         return true;
  36.                 }
  37.  
  38.                 Console.WriteLine("Unable to replace " + type + "." + func);
  39.                 return false;
  40.         }
  41.  
  42.         static int Main (string[] args)
  43.         {
  44.                 var dll0 = "C:/Projects/FixUnityEngine/UnityEngine.dll";
  45.                 var dll1 = "C:/Projects/FixUnityEngine/FixUnityEngine.dll";
  46.  
  47.                 var asm0 = AssemblyDefinition.ReadAssembly(dll0);
  48.                 var asm1 = AssemblyDefinition.ReadAssembly(dll1);
  49.  
  50.                 Replace(asm0, asm1, "UnityEngine.AttributeHelperEngine", "GetParentTypeDisallowingMultipleInclusion");
  51.                 Replace(asm0, asm1, "UnityEngine.AttributeHelperEngine", "GetRequiredComponents");
  52.  
  53.                 asm0.Write("C:/Projects/FixUnityEngine/UnityEngine_edited.dll");
  54.  
  55.                 Console.ReadKey();
  56.                 return 0;
  57.         }
  58. }
You may notice that I'm referencing a local copy of UnityEngine.dll -- I chose to copy it to the project's folder, but you can reference it all the way in Program Files if you like. Its default location is "C:\Program Files\Unity\Editor\Data\Managed\UnityEngine.dll".

So what does the code do? It simply reads the two DLLs and replaces the body of one function with another! In the replacement DLL I kept the same namespace, class name and function names for consistency (but as far as I can tell this isn't actually necessary). In my case though, since I did, the code to perform the replacement ended up being shorter.

Once you compile and run the program, it will spit out an edited version of the DLL (UnityEngine_edited.dll). Simply close all instances of Unity and replace C:\Program Files\Unity\Editor\Data\Managed\UnityEngine.dll with this version. That's it.

Want to test the result? Here's a test program for you:
  1. using UnityEngine;
  2.  
  3. public class Test : MonoBehaviour
  4. {
  5.     private void Update ()
  6.     {
  7.         var go = gameObject;
  8.         if (Input.GetKeyDown(KeyCode.Alpha1))
  9.         {
  10.             for (int i = 0; i < 1000; ++i)
  11.             {
  12.                 var t2 = go.AddComponent<Test2>();
  13.                 Destroy(t2);
  14.             }
  15.         }
  16.     }
  17. }
  1. using UnityEngine;
  2.  
  3. public class Test2 : MonoBehaviour {}
  4.  
The actual GC amounts and timings will vary greatly with project complexity (the more C# scripts you have, the slower the whole process becomes thanks to Unity), but this is what I was seeing before the edit and after:



There's nothing I can do about Unity calling this useless functions, and indeed in my project Unity doing so wastes 0.16 ms per call to AddComponent... but at least the 325 MB of memory allocation is gone. Yay for small victories.

35
When I said PM, I meant that -- private message. Posting NGUI's code in entirety in public is a violation of copyright, and is mentioned in a pinned post: http://www.tasharen.com/forum/index.php?topic=8314.0

36
Is your game's time paused when you do this? IIRC colliders don't actually update until FixedUpdate() has a chance to run, and it doesn't run if the time is paused.

Other than that, it's quite possible that Unity broke something. They do that from time to time...

37
NGUI 3 Support / Re: UIWrapContent ItemHeight (itemSize)
« on: November 09, 2017, 08:06:41 PM »
Place all your items underneath your "Label Item" object underneath a UIGrid. Put a UITable on the root object containing your Label Item objects. UIWrapContent is not going to help you here.

Panel ScrollView
- UITable
-- Label Item
--- UIGrid, TweenScale
---- Item1
---- Item2
---- Item3
-- Label Item
--- UIGrid, TweenScale
---- Item1
---- Item2
---- Item3

TweenScale should animate the transform's Y scale to shrink the object. Just check the Quest Log example for how it's used.

38
TNet 3 Support / Re: Objects Instantiate with No Owner
« on: November 09, 2017, 08:03:08 PM »
Because Awake() is the wrong place to interact with other components. Awake() is basically the constructor -- it runs as soon as the component gets added. Channel ID is not yet set at this point. You had to wait for it to be set.

39
TNet 3 Support / Re: Modifying GameServer for an authoritative server
« on: November 07, 2017, 05:24:32 PM »
The "it's possible and easy but shouldn't be done" response is because I always advise keeping as much work on the client side as possible. By default, TNet's server is basically there to echo packets, forwarding them to their correct destination in the correct order, and remembering states of everything important. It's like a post office forwarding mail. You can certainly modify the TNet.GameServer class to add your own custom logic for custom packets defined in the TNPacket.cs file, but I generally question the need for it.

40
TNet 3 Support / Re: TNet 3 and Unity 2017
« on: November 07, 2017, 05:03:47 PM »
If you run into any issues, just let me know.

41
TNet 3 Support / Re: Objects Instantiate with No Owner
« on: November 07, 2017, 02:29:48 AM »
Where is SpawnPlayer called from? Wherever it is, it must be done after joining your "channelID" channel.

42
TNet 3 Support / Re: Objects Instantiate with No Owner
« on: November 06, 2017, 08:02:08 AM »
I never use IDs. Really no reason to. :P

And what cmifwdll said: RCCs must be on a MonoBehaviour, not a random class. Even receiver class doesn't have anything to do with this.

43
TNet 3 Support / Re: Discord Chat
« on: November 06, 2017, 07:52:09 AM »
There is a Tasharen discord chat: https://discord.gg/tasharen

I use it for game dev feedback mainly, but you're welcome to ping me with TNet questions too.

44
TNet 3 Support / Re: data that all players can access?
« on: November 06, 2017, 07:50:48 AM »
Current version of TNet I'm using for Sightseer explicitly disallows multiple players from using the same save file to avoid this kind of confusion.

SetServerData can be used by admins for important stuff that players should not be able to change - configuration, message of the day, etc.
SetChannelData in a common channel (such as the global chat channel) can be used for player-settable configuration.

Keep in mind that all players have access to all other players' data, as long as they are in the same channel -- so SetPlayerData will work too.

45
TNet 3 Support / Re: MathD does not exist
« on: November 06, 2017, 07:47:52 AM »
My bad, it's a file from Sightseer. Basically a copy of Mathf, but with double precision.

You can resolve it by replacing MathD with adding a Clamp function:
  1.                 static public double Angle (Vector3D from, Vector3D to)
  2.                 {
  3.                         return Math.Acos(Clamp(Dot(from.normalized, to.normalized), -1d, 1d)) * 57.29578d;
  4.                 }
  5.  
  6.                 static double Clamp (double value, double min, double max)
  7.                 {
  8.                         if (value < min) value = min;
  9.                         else if (value > max) value = max;
  10.                         return value;
  11.                 }
The other MathD usage can be replaced with Math.

Pages: 1 2 [3] 4 5 ... 1447