Sunday, September 17, 2023

How Network Interface Metric Mess With Genshin Login System

TL;DR: If your Genshin Impact, for some reason, unable to save your login session across shutdowns or reboots, check the Interface Metric numbers across shutdowns/reboots in your network settings and make sure it stays same.

Remember when I have issues with Genshin Impact logging me out on system reboot or shutdown 2 years ago? Well now it happends again in the laptop I bought a year ago. This time however, I decided to diagnose it further.

Ok first of all, it's important to know what's changed before the issue occur. Since I know that it doesn't happen last week, it must be some sort of driver updates. From my previous experience, it has to do with network drivers. This means I can narrow it down to network driver updates. I remember Windows Update asked me to restart to install Wi-Fi driver. Gottem, it must be bad Wi-Fi drivers. Uninstalled it, restarted it, and now the game loads fine.

Network driver messing itself and watch me suffer as Genshin doesn't remember me again.
... except the next day, it doesn't. Could it be some nondeterminism with network order going on? Ok so I tried an experiment. Restarted the system, game loads fine. Okay good. Shutdown the laptop then start it again. Now the game doesn't remember me. Ok then shutdown again, nope. Restarted it, works. Shutdown it again bypassing "Fast Startup" (Protip: Press Shift while pressing "Shutdown), works. Shutdown with fast startup? nope.

From that experiment I can conclude that:

  1. Fresh start (from reboot or full shutdown) will make the game think I'm on current device, logging me in.
  2. Starting up from fast startup will make the game thinkthe network adapter has changed, logged me out.

Then, what else can we use to find out the exact issue? In Windows 11, there's "Hardware and connection properties". It lists all adapters excluding WSL/Hyper-V adapter but including Wi-Fi Direct adapters. Re-doing the experiment while watching this gives me some insights:

  1. On fresh start, the Ethernet is listed on topmost.
  2. On starting from fast startup, the Ethernet is listed on the bottom, not bottommost.

Well, okay that probably explains why. Genshin Impact "calculates" the key to load the session key based on the network order. So the next question is, how to change the order?

Googling "windows change network order" mentions changing "Interface Metric". There are 2 ways, with Powershell and with GUI. The powershell command is "Get-NetIPInterface", when run, shows as follows.

https://cdn.discordapp.com/attachments/922182394323292173/1152589110029070426/gambar.png
Top is the problematic output. Bottom is the correct output that Genshin recognize for my laptop.

Redoing the experiment again reveals that the "Ethernet" "InterfaceMetric" is set to 5 on fresh start (which it remembers my login). However on fast startup, it sets to 75. Just to confirm, it was set to 75. Entering the game, the game doesn't remember me. Ok set the "InterfaceMetric" of "Ethernet" IPv4 and IPv6 to 5 (see link above on how-to), and viola the game remembers me back.

This finally solves the mystery that I also had 2 years ago. It should be same issue where "InterfaceMetric" went non-deterministic across reboots/shutdowns. I was about to schedule my whole day to perform clean installation of the laptop but the mystery is solved once for all

Me looking her the first time be like: "Yup. I'm going to marry this girl!"
... until it logs me out again.



Thursday, January 19, 2023

Can I have 10ms Latency in Genshin Impact in Indonesia?

On the other day, my friend wonder if there will be an Indonesia ISP which allows him to play Genshin Impact with 10ms ping.

Well, sorry to disappoint, but that's impossible. No, it's not because our technology is advanced enough (actually it is), but it's not possible because there's hard limit related to the laws of physics: speed of light.

Why? First let's do some background. Genshin Impact is a single-player-oriented online game (weirdly). Since it's online, it has various servers which are Europe, America, Asia, Taiwan, and China (only for people who live in China). Focus on the Asia, the server is hosted in Tokyo, Japan. My friend and I live in Indonesia.

Now the reason why it's impossible because the distance between Indonesia and Japan is 4821.39 km (Wolfram says it's 4912 km, see below). The speed of light constant is 299792458 m/s. Doing the calculation tells me the minimum attainable latency by that distance is ~16.38ms. That means I need around 1 game frame at 60Hz monitor with VSync (or 1 game frame in Genshin Impact) to travel from Indonesia to Japan. Multiply it by 2 for the round-trip latency gives you ~32.76ms. By that alone, it's been concluded that getting 10ms ping is not possible. 

"But data transfer instantly"
No it's not. It still obey the laws of physics. That means in best case, your data transfer speed is limited by speed of light. Well, the best case. In fact, light travels slower in fiber optics, around 2/3 of it. Taking that into account, the minimum attainable latency is ~49.15ms. This can be worsen furthermore by additional latency introduced by your WiFi and/or router and the ISP on both ends. That means, 49.15ms is the data transfer speeds only, ignoring the router and ISP latency.

"Alright then, but I want exactly 10ms latency. I don't want to live in Japan though. Where should I live?"
For this, I assume the overhead latency of your router and ISP is ignored (a.k.a exactly 0ms). For 10ms round-trip latency, you need to live at 1998 km away from Tokyo, Japan. The closest would be South Korea, then Shanghai, China (but in this case you better go with their China client with China servers for minimum latency), then area around Sakhalin Oblast in Russia. If you want to take your router and ISP latency into account then you may want to live in Yuzhno-Sakhalinsk in Russia or South Korea. It's as closest to Japan without having to live in Japan.

Note that if you have copper wire running from Russia to Japan instead of fiber optic, it may be faster, but electromagnetic interference will assure ...

... you're gonna have a bad time

Also on cohost: https://cohost.org/AuahDark/post/866048-can-i-have-10ms-late

Sunday, November 20, 2022

Slashes in Lua "require" function: Use periods/dots!

This is somewhat a kind of misunderstood but I hope this blog post will resolve this once for all. I often saw people using Lua require like this

local gamera = require("libs/gamera")
local nvec = require("libs/nvec")
-- Rest of the code

At first glance, there's nothing wrong right? No. Using slashes in require works because it's an accident, but no this is not a happy accident. What you should do is:

local gamera = require("libs.gamera")
local nvec = require("libs.nvec")
-- Rest of the code

So, why the dots there? Because require is not expecting path, it's expecting module name. To explain why, first let's take a tour to Programming in Lua Section 8.1, with important text marked as bold.

The path used by require is a little different from typical paths. Most programs use paths as a list of directories wherein to search for a given file. However, ANSI C (the abstract platform where Lua runs) does not have the concept of directories. Therefore, the path used by require is a list of patterns, each of them specifying an alternative way to transform a virtual file name (the argument to require) into a real file name.

So, it's clear that require does not expect a path to filename, but it expects module name (or virtual file name; we'll use module name from now on). To understand how Lua transform the module name to actual path that Lua will try to load, it's important to know about package.loaders.

package.loaders is an array of function which tries to load a module based on module name passed by require. The Lua 5.1 manual has more information about this, but I'll try to explain it as simple as possible. In Lua 5.1 (and LuaJIT), there are 4 loaders in this entry but I'll only explain the first 3, tried in this order:

  1. Checks for existing module loader in package.preload table with the module name (passed from require) as the table key, such that when called, it loads the module. If it's non-nil, then the value is returned.
  2. Replace all dots in module name to OS-specific directory separator (we'll call this file path). Then for each semicolon-separated path specified in package.path, substitute question mark with the file path then try to open that as Lua file. If it's loaded successfully then the function chunk is returned.
  3. For this, it needs 2 components: file path and entry point. Replace all dots in module name to OS-specific directory separator to get file path, and replace all dots in module name to underscore with luaopen_ prepended to get entry point. Then for each semicolon-separated path specified in package.cpath (note the "c" in cpath), it tries to load said file as shared library (or DLL in Windows), then returns Lua C function with specified entry point inside the shared library.
  4. It's all-in-one loader, doesn't matter in our case. 

If you're still confused, this pseudo-Python code will help you know how it works.

import os

package.preload = dict()
package.path = "?.lua;path/to/?.lua"
package.cpath = "?.dll;?.so;path/to/?.dll;path/to/?.so"

def loader_1(modname):
	module = pacakge.preload.get(modname)
	if module is not None:
		return module
	return f"no field package.preload['{module}']"

def loader_2(modname):
	file_path = modname.replace(".", os.sep)
	tested = []
	for path in package.path.split(";"):
		file_name = path.replace("?", file_path)
		chunk = load_lua_file(file_name)
		if chunk is not None:
			return chunk
		tested.append(f"no file '{file_name}'")
	return "\n".join(tested)

def loader_3(modname):
	file_path = modname.replace(".", os.sep)
	entry_point = "luaopen_" + modname.replace(".", "_")
	tested = []
	for path in package.cpath.split(";"):
		file_name = path.replace("?", file_path)
		module = open_shared_library(file_name) # dlopen or LoadLibraryA
		if module:
			symbol = get_symbol(module, entry_point) # dlsym or GetProcAddress
			if symbol is not None:
				return make_symbol_callable(symbol)
		close_shared_library(module) # dlclose or FreeLibrary
		tested.append(f"no file '{file_name}'")
	return "\n".join(tested)

If that's clear enough, then stop reading and start fixing your require by replacing slashes with dots!

Saturday, October 8, 2022

The Case of Rare Laptop SKU: Lenovo Ideapad Gaming 3 15ACH6

 I bought a gaming laptop a month ago (as of writing this blog post). The laptop name is in the title, with these key-selling specs:

  • AMD Ryzen 5 5600H
  • RTX 3060 Laptop (90W)
  • 16GB of DDR-3200 RAM at dual-channel, upgradeable
  • 1920x1080 165Hz display, 100% sRGB
  • 512GB NVMe SSD (which I later upgraded with additional 512GB)

Honestly getting RTX 3060 laptop for cheap (I really mean "cheap", my touchscreen laptop is more expensive) is a blessing. The cooling are also good and I never able to reach 80 degrees Celsius when I use it for gaming (70 is the highest). Now there's just a slight issue: This is a rare SKU.

Why? There are no reviews of this laptop with this GPU. If you look at internet, all reviews of this laptop is the ones with RTX 3050 or 3050 Ti. None of them with 3060. This means there's no way for me to have expectation on the performance and there's no way for me to evaluate the pros and the cons of this variant. I'm on my own.

Lenovo published Product Specifications Reference for this laptop but even some of the information there does not reflect 100% the ones I have. Some of those are:

  • The sheet wrote one of the SSD slots runs at PCIe 3.0x2, but on my unit it runs on 3.0x4 on both slots, checked with Crystal Disk Info.
  • The sheet wrote one of the SSD needs 2242 form-factor (this one is running at 3.0x4), but this is not the case for my unit. They both accepts 2280 form-factor. I mistakenly bought 2242 SSD without knowing because I assume their PSR are correct.

Fortunately I'm relieved to find out that there are many advantages of getting this variant. For example, the RTX 3050 with maximum TGP still beaten by RTX 3060 with lowest TGP and the fact that 3060 Laptop it's almost on-par with the desktop variant (3050, 3070, and 3080 has significant difference). Furthermore the higher VRAM (6GB instead of 3050 4GB) means I can barely run Stable Diffusion locally

1girl long_hair blue_aqua_hair purple_eyes red_glasses blunt_bangs straight_hair black_blazer red_ribbon black_skirt school_girl cat_ears

... to generate waifus.

Tuesday, August 3, 2021

Repeating Sakura Cleansing Ritual

Spoiler alert: If you haven't unlocked the Sakura Cleansing Ritual world quest or Inazuma, don't read this blog post!

This is supposed to be a simple blog post related to Genshin Impact. I have pending blog post which I'm too lazy to write, but I plan an educating blog post using Genshin Impact and programming in the future.

I think most people will say this is one of the best, and saddest world quest. Some people (including me) however used the Kazari's mask so if you want to see her memories in-game then it's gone forever.

... not quite. Turns out you can repeat some of the sakura cleansing ritual. That means, if you do the correct sequence, the enemies and the dialog will show as if you're still doing the world quest. However, you can only repeat this once per day (not sure if relogin allows you to repeat this?). You can repeat this sakura cleansing in these locations:

  • Mt. Yougou (Abandoned shrine)
  • Chinju Forest (The ones where you need to find Tanukis)
  • Kamisato Estate (With the electro radiation)

That means you can't repeat ones in:

  • Konda Village. Nothing happends when you do the correct sequence.
  • Araumi. Even if you managed to use Memento Lens to reveal the other parts and do the correct sequence, nothing happends.

So if you miss her and you already used the mask, then performing some part of the ritual may make you feel better. The other memories I have on her is


 ... a screenshot