Giter Club home page Giter Club logo

devblog's People

Watchers

 avatar  avatar

devblog's Issues

2019/10

  • Transferred to a blockchain app department.
  • Learning some Solidity, practiced contract deployment/managment.
  • Wrote a JS tool to interact with Geth.
  • Learning some technical knowledge about ETH . (EC, VRS, ChainID, Transaction Procedure...)

~Late October

  • Have no backend experience.
  • Assigned to remake a mathematic server for product A.
  • Using dotnet core.
  • Fighting with performance issue and bad designs from my inexperience.

Unscaled Time script which respect Unity Editor Pausing

Why

When working on some Time-Freezing gameplay, I found that Unity does not provide any Time member for "actual time length in play mode".
All the provided Time members basically based on previous frame and don't care about Play Mode Pause State, which is a pain in the neck when you want to test your Time code in Play Mode.

Thingy: A Component Based Data Framework

Goal

To create a high performance, easy to extend/manage, component oriented data entity framework.

Possible Usage

  • A item crafting engine with extreme possibility.
  • A dynamic magic spell composition system. (Still a crafting engine)
  • A solid foundation for a superior Item system.
  • Dynamic body structure for multiple race system

A + B = C

The formula above are describing that:

A thing that can be referred as C is a combined result of A (referred) and B (referred) putting together.

Based on this concept, we can consider A/B as Filter, which is to classify a thing. While C is a template, which is a predefined thing with certain modules built in.

Everything is a composition

The core concept of Thingy is Something is something because it can be.

Let's say here we got a thing with these modules:

  • Object
    • Material:
      • 0.8kg Wood
      • 3.3kg Alloy
        • 3.2kg Iron
        • 0.1kg Misc
      • 0.6kg Misc
    • Dimension: 1.2m x 0.2m * 0.1m
  • Craft
    • Crafted by: Someone
    • Crafted since: 1977/12/12
    • Quality: Excellent
  • Tool
    • Usage: Hand-held
    • Purpose: Cutting/Puncturing
  • Sharpness
    • Rating: 8
  • Condition
    • Ageing: 42
    • Maintenance: 100

What could it be? I'd say it's a good old iron sword.

How could it be made? Let's make up a simple and minecraft-ish one:

Wood Stick + Iron = Iron Sword

So what is Wood Stick? If we want it to be simple, this is how you do in traditional crafting mechanic:

  • ID == "Wood Stick"

So only stuff that is labeled "Wood Stick" can fit the first slot... which is a common approach, boring and inflexible.

If we review the formula Wood Stick + Iron = Iron Sword, we could notice that, it's actually Sword Handle + Body Material = Sword. That's where we can utilize the design of Thingy, Imagine a "Sword Handle" Filter:

  • ANY, AND // AND type filter means all the sub filter has to be matched
    • Dimension
      • L > 0.2m // It has to be long enough
    • Appearance
      • Straight // It's a handle, it has to be straight
    • Condition
      • Wetness < 5 // Wet and rotten wood is not going to be a good handle

Using the filter, a lot of thing would be valid for the first input slot of this Sword recipe, even if you put in a torch, it's possible the torch body could be a valid sword handle.

Vue Cli Notes

  • Have a vue.config.js in your project folder
  • Specify device local ip on serve command to open to local test
  • Use 1 way message flow
    • Parent -> Child: Prop
    • Child -> Parent: Emitting Events

C# For loop Performance Note

  • for loops on List are a bit more than 2 times cheaper than foreach loops on List.
  • Looping on array is around 2 times cheaper than looping on List.
  • As a consequence, looping on array using for is 5 times cheaper than looping on List using foreach (which I believe, is what we all do).

Portal

Randomness in Unity ECS IJobChunk

Randomness in Unity ECS IJobChunk

Posted on HackMD

This article assumes you know Unity ECS.

Before ECS, most of our code runs within MonoBehaviour which is restricted to be on MainThread, so whenever we need Randomness, we generated the RNG with a seed and keep getting random values from it.

The only thing we care back then is assuring the random seed is different from time to time we use the RNG, we usaully use time for this purpose.

As you may know, with IJobChunk, Unity ECS perform your Execute() on all chunks of one same archetype to achieve high performance.

To schdule a IJobChunk, you ususally make a IJobChunk struct then call Scheduel()/ScheduleParallel(), this means you are passing a set of parameters into all job execution.

The Unity.Mathematics API comes with a Random struct which just like most Random API, needs a seed to initialize. If you wants random number per Job, you'd need a way to guarantee every job execution use different seed.

Include one Random struct into the IJobChunk then is definitely a no-no. For example you have 2 chunks of same archetype, that 2 IJobChunk execution will get identical values from the Random.

What about instead of a made Random struct, we include a seed into the IJobChunk? Unfortunately this is essentially same as including a Random which is a wrapper of a seed value.

So eventually, we need a value vary from execution to execution, to guarantee different RNG between jobs of same batch.

ThreadIndex

We are scheduling jobs to multiple threads, if there's something is guaranteed to be different between all parallel running jobs, it'd be the thread index.

Unity provides us a way to inject the thread index value into a int field: Unity.Collections.LowLevel.Unsafe.NativeSetThreadIndexAttribute

It's quite easy and handy, you simply tag a int field in your IJobChunk struct, then the value will be automatically injected at runtime.

[BurstCompile]
    struct RandomJob : IJobChunk
    {
        [Unity.Collections.LowLevel.Unsafe.NativeSetThreadIndex]
        public int threadIndex;
        public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
        {
            var random = new Random((uint) threadIndex);
            
        }
    }

Now, the question is: Does this guarantee randomness?

No.

Limited randomness

ThreadIndex is limited by the host machines CPU specs, this method provide you a limited randomness that guaranteed to work perfectly until, the total chunks begin executed exceeds your threads number.

In that case, more then one execution shares same thread index value, because a thread may continue working on another job scheduled of this IJobChunk type after it has finished one, which will results in identical random output sequence.

We need to introduce more factors for more possibilities.

Momentary randomness

If you take a look on Execute() signature, you'd notice there's chunkIndex and firstEntitiyIndex, which are basically the serial number of the chunk being operated on.

If we integrate these value into the Random seed, we can make seed duplication only happens when the job worker thread works on one same chunk twice.

[BurstCompile]
    struct RandomJob : IJobChunk
    {
        [Unity.Collections.LowLevel.Unsafe.NativeSetThreadIndex]
        public int threadIndex;
        public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
        {
            var random = new Random((uint) ((threadIndex + 1) * (chunkIndex + 1)));
            
        }
    }

That is basically impossible... for 1 Schedule().

It's already good enough for some, but as long as you keep scheduling the job, previous used seed will keep being generated again and again.

Almost full randomness

Take a look back on top of this article, you remember what did we use as RNG seed? Time.

We've already guaranteed that no jobs in one Schedule() will share RNG, let's just integrate a value vary from time to time.

We don't have to use the old UnityEngine.Time API, in SystemBase there's a inherited property Time, which contains a ElapsedTime value, storing the total cumulative elapsed time in seconds.

We pass this value into our jobs... Now we have full randomness.

[BurstCompile]
    struct RandomJob : IJobChunk
    {
        [Unity.Collections.LowLevel.Unsafe.NativeSetThreadIndex]
        public int threadIndex;
        public int randomSeed;
        public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
        {
            var random = new Random(((uint) ((threadIndex + 1) * (chunkIndex + 1) * randomSeed) *& uint.MaxValue));
            
        }
    }
    
    protected override void OnUpdate()
    {
        var job = new RandomJob()
        {
            randomSeed = (int) (Time.Elapsed*100+1),
        };

        Dependency = job.ScheduleParallel(m_Group, Dependency);
    }

Full randomness

At this stage, since the start of your game/system, you job can always get random value, but you get same RNG everytime you restart your game.

That means we have to introduce one more factor that makes everytime you start your game, the RNG seed would be different.

It's quite simple, just use time of day.

    double baseTime = System.DateTime.Now.TimeOfDay.TotalSeconds;
    protected override void OnUpdate()
    {
        var job = new RandomJob()
        {
            randomSeed = (int) (float) (baseTime + Time.ElapsedTime*100),
        };

        Dependency = job.ScheduleParallel(m_Group, Dependency);
    }

2019/08~09

  • Started my career at Wanin.
  • Learning Typescript, utilizing my limited JS knowledge.
  • Ported my StatePatternCSharp to Typescript, ported a old slot game with it.
  • Analyzed and modifed the main game framework to allow passing parameters to sub games.
  • Built some trivial dev tools for my team: Simple code generation, Unity animation file resolver for Laya.
  • Kinda fall in love with JS with npm.

Math

費馬小定律 (Fermat's Little Theorem)

如果 p 是質數,無論任何自然數 n,img一定能被 p 整除
img (n的p次方與n同餘模p)

又因 img,當 n 本身不是 p 的倍數,也就是說,n 無法被 p 整除,那 麼 img 應該能夠被 p 整除
img

A與B沒有1以外的公因數,則A與B為互質數 (Coprime)

歐拉 (Euler's totient function)

  • φ(m):與 m 互為質數,且小於 m 的自然數 n 的個數
  • 當 m 為質數時
    • φ(m) = m - 1
  • 當 m, q 為不同質數時
    • φ(m×q)=(m - 1)×(q - 1)

歐拉定理在 m 是質數的情況下,就會成為費馬小定理

歐拉:當 m, n 互質 => img
當 m 是質數的情況,因為 φ(m) = m - 1,將 m 代入img
img

DOTween Note

Tweens in Sequences are orderded by time

A sequence is a tween. Tween is based on time.
When you do:

s.Append(...);
s.AppendCallback(...);
s.Append(...);
s.AppendCallback(...);
s.AppendCallback(...);

All the appended items are added to the same time pos, and, at least in DOTween, these items could be executed in no particular order, which may not be desired behaviour.

To properly order the sequence, add interval inbetween items:

s.Append(...);
s.AddInterval(0.001f);
s.AppendCallback(...);
s.AddInterval(0.001f);
s.Append(...);
s.AddInterval(0.001f);
s.AppendCallback(...);
s.AddInterval(0.001f);
s.AppendCallback(...);

2019/12

  • Back to being fully committed to build product A server system.
  • The coworker encountered some technical obstacle during building the user router prototype.
  • Helped with some, decided to build my own project to see where are the problems.
  • Made my router server.
  • Made my test client and fake game server.
  • Amazed by Go.
  • Encountered TCP performance issue, messed with it, then solved it with byte[] buffer stuff learnt last month. Again, nothing fancy, pertty useful. (TCP is for server system communication)
  • The user router decodes client request from JSON to object, and encode it back to JSON then send the message to server. It also decodes server response from JSON to objects, then encode it to JSON then send it to client.
  • So every request basically means 2 encode + 2 decode, with just official package and no optimization, the user router can handle 161K message/s.
  • My supervisor ask me to try the performance of CSV .
  • Same procedure (2 encode + 2 decode), the userrouter can achieve 360K message/s using CSV, even if tested with 1K per request which contains 20 delimiters, it could run at 230K/s.
  • We ditched JSON from all the servers, turned to CSV.
  • Had a chance learning some knowledge about credentials, openssl, TLS, https/wss since product A use WSS.
  • Tried to use the byte stream protocol TCP communication using because Go allows direct interaction with underlying TCP connection in WS connection.
  • Figured out that in dotnet this is not possible (Unity client). It seems all available WS implementation only do WS message.
  • So the router-client communication is message-based now, should hurt performance, not benchmarked.
  • Adding features... Polishing...
  • Assigned a bonus task to add threading to the app of product A, moving cpu intensive works out of render thread.

putty and pscp

Had a chance to try putty because we are going to deploy the math server on Linux.

  • Built it
  • Found how to transfer a lot of file with pscp
  • Figured how to set permission of the executable
  • Ran it, worked smoothly

DOD

Principles

  • Data is not the Problem Domain
    • Data means almost nothing.
    • Meaning is applied to Data
    • EX:
      • 4 means... 4?
      • But 4cm means a length, 4kb means a size.

2019/11

  • Keep working on the math server, build, test, undo, build, test, undo.
  • Encountered TCP performance issue.
  • Tried several API (TCPClient, Socket, SocketAsyncEventArgs...)
  • Nothing works, my server couldn't achieve the performance as java TCP demo wrote by my superior.
  • My superior suggest me take a look at his demo.
  • It turns out that the key is reduce r/w operation on the socket using a byte array. Nothing fancy, pretty useful.

~ Late November

  • For some external reason, assigned to help testing/debugging the blockchain app.
  • No really busy at these days.
  • Assigned to assist a coworker to investigate and prepare for building a new user router server for product A.
  • Decided to try Go for the user router.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.