Jump to content

Recommended Posts

Posted (edited)
1 minute ago, verbrannt said:

It's already reverted.

 

Ah, ok :) How about boss_id - that shouldn't be global map ID or should it be?

Edited by eressea
Posted (edited)
11 minutes ago, eressea said:

 

Ah, ok :) How about boss_id - that shouldn't be global map ID or should it be?

Idk. I have only one occurrence of this variable in my ai.obj files, so can't tell.

 

Also I think boss_pch.txt should be renamed to gm_pch.txt. "Boss" prefix is misleading here.

Edited by verbrannt
Posted
5 hours ago, verbrannt said:

Idk. I have only one occurrence of this variable in my ai.obj files, so can't tell.

 

Something tells me it should be int - objectID/index of NPC who is boss for the group, but I'm really not sure about that

 

5 hours ago, verbrannt said:

Also I think boss_pch.txt should be renamed to gm_pch.txt. "Boss" prefix is misleading here.

 

+1 maybe globalmap_pch.txt... OR maybe parse all of them from manual_pch.txt - that would be the best way

Posted

Comments inside ai.obj like
 // -- test comment -- 

ect, causes the decompiler to throw errors like "Decompile default_npcPHP Fatal error:  Uncaught TypeError: Argument 1 passed to Parser::fixTypeCase() must be of the type string, null given, "

but if the comments are removed, it decompiles fine. If at all possible can support for these types of comments be added?, l2npc handles them fine

Posted

After adding C1 support, I've compared all ai.obj from original one, and after decompilation/compilation. There is bunch of classes (about 15 of them of 2200) with 2 significant differences.

 

Here is one example of 1 style of difference. Could you check, what's the problem here?

https://drive.google.com/open?id=1WZx4FGF_FrkAOkem3bC8Stdd3Y--ixUj

 

Most probably the same thing is in other chronicles, since looks like it's related with some nested if() conditions

Posted
7 minutes ago, MasterToma said:

After adding C1 support, I've compared all ai.obj from original one, and after decompilation/compilation. There is bunch of classes (about 15 of them of 2200) with 2 significant differences.

 

Here is one example of 1 style of difference. Could you check, what's the problem here?

https://drive.google.com/open?id=1WZx4FGF_FrkAOkem3bC8Stdd3Y--ixUj

 

Most probably the same thing is in other chronicles, since looks like it's related with some nested if() conditions

Looks like nothing serious, only one missing shift stack pointer command :D
I think is always at the end of the handlers?
Can you post second type of difference?

Posted (edited)
	push_reg_sp
	fetch_i

is missed in files from the link, which I posted. Also two jumps at the end

    jump L23975
    jump L23982
L23977
L23982
L23975
    shift_sp -1

 

I think, there is no "no op" operands, and those lines are simply missed from the decompiled/compiled code. Doesn't look good for me. Also, shift_sp -1 is called before exit_handler(). So, caller will receive not-shifted stack

 

I will post second difference, when find some smaller handler for it, right now there are about 30kb obj files

Edited by MasterToma
Posted
2 hours ago, MasterToma said:

	push_reg_sp
	fetch_i

is missed in files from the link, which I posted. Also two jumps at the end


    jump L23975
    jump L23982
L23977
L23982
L23975
    shift_sp -1

 

I think, there is no "no op" operands, and those lines are simply missed from the decompiled/compiled code. Doesn't look good for me. Also, shift_sp -1 is called before exit_handler(). So, caller will receive not-shifted stack

 

I will post second difference, when find some smaller handler for it, right now there are about 30kb obj files

 

I think last “if” in this class should be “select” with one case inside. Jumps looks like “break” inside that case.

I can’t test it today tho.

Posted
1 hour ago, jornik said:

@MasterToma can you please post whole hander code for the original and compiled ai.obj? Can you also share decompiled code?

Everything is inside archive under the link, which I posted. Here it is again: 

https://drive.google.com/file/d/1WZx4FGF_FrkAOkem3bC8Stdd3Y--ixUj/view

 

Decompiled code looks is

class guard_babenco : guard_fixed {
handler:
	EventHandler TALK_SELECTED(talker) {
		if (_from_choice == 0) {
			if (HaveMemo(talker, @path_to_elven_scout) == 1 && GetMemoState(talker, @path_to_elven_scout) == 1) {
				_choiceN = _choiceN + 1;
				_code = 0;
				AddChoice(0, "询问有关废墟的事");
			}

			if (_choiceN > 1) {
				ShowChoicePage(talker, 1);
				return;
			}
		}

		if (_from_choice || _choiceN == 1) {
			if (_code == 0) {
				if (_from_choice == 0 || HaveMemo(talker, @path_to_elven_scout) == 1 && GetMemoState(talker, @path_to_elven_scout) == 1) {
					ShowPage(talker, "guard_babenco_q0407_01.htm");
				}
			}

			return;
		}

		super;
	}
}

There is some mess with _from_choice. Tonight I will try to decompile it manually. 

 

Posted
1 hour ago, MasterToma said:

There is some mess with _from_choice. Tonight I will try to decompile it manually.

 

Replace

if (_code == 0) {
    if (_from_choice == 0 || HaveMemo(talker, @path_to_elven_scout) == 1 && GetMemoState(talker, @path_to_elven_scout) == 1) {
        ShowPage(talker, "guard_babenco_q0407_01.htm");
    }
}

with

select (_code) {
    case 0:
        if (_from_choice == 0 || HaveMemo(talker, @path_to_elven_scout) == 1 && GetMemoState(talker, @path_to_elven_scout) == 1) {
            ShowPage(talker, "guard_babenco_q0407_01.htm");
        }
        
        break;
}

& check compiled code

Posted

Ok, now it works. Another bug with operator precedence. For instance, look at blacksmith_duning (code is too large).

Here is how it should look like:

	fetch_i
	push_const 10
	mod
	mul
	greater_equal
			else if(reply == 6)
				{
					if (OwnItemCount(talker, @q_gold_wyvern) >= (4*(talker.param2 % 10)))
					{
						DeleteItem1(talker, @q_gold_wyvern, 4*(talker.param2 % 10));
						talker.param1 = talker.param1+((Rand(3)+1)*16);
					}
					else
						ShowPage(talker, "blacksmith_duning_q0336_10.htm");	
				}

Note about two points

1. (4*(talker.param2 % 10))

2. ((Rand(3)+1)*4)

 

Decompiler generates 

 

} else if (reply == 6) {
				if (OwnItemCount(talker, @q_gold_wyvern) >= 4 * talker.param2 % 10) {
					if (GetCurrentTick() - talker.quest_last_reward_time > 1) {
						DeleteItem1(talker, @q_gold_wyvern, 4 * talker.param2 % 10);
						talker.param1 = talker.param1 + (Rand(3) + 1) * 4;
						talker.param1 = talker.param1 + (Rand(3) + 1) * 16;
					}
				} else {
					ShowPage(talker, "blacksmith_duning_q0336_10.htm");
				}

1. 4 * talker.param2 % 10

2. (Rand(3) + 1) * 4

 

While point #2 in THIS case is not crucial (but in other cases it might be crucial), point #1 is for sure wrongly decompiled - extra () are missed and cause wrong calculation, which will be

 

	fetch_i
	mul
	push_const 10
	mod
	greater_equal

 

Posted

I've noticed the same with nested &&. Original pseudo-code

if (a && (c && d))

after decompilation will be 

if (a && c && d)

Which is OK. But some times not:

if (a && (c || d))

goes into

if (a && c || d)

 

Trying to find some nice example...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now



  • Posts

    • And Discord: https://discord.gg/3aYqWNqb
    • Ofc: https://discord.gg/3aYqWNqb
    • You can find some H5 skins shared in old L2 modding Discords, but most of the higher‑quality ones are either paid or come bundled with full client edits. I usually mix in commissioned work and whatever I can patch myself. On a side note, I fund a lot of these commissions by selling off game items through instant sell cs2 skins, which has been a quick way for me to get some cash for projects.
    • There is no need for gRPC in this case, even tho originally it was gRPC based but since we don't need it to be bi-directional, we switched to simple http requests for the web calls and SSEs for the data streamed from the server. There are distributed locks in place to precent race conditions between actions that can happen between multiple web instances and the server.   Local models can also be slow depending on the model, and most external models can actually be faster than local ones if you use Flash 2.5 or something along those lines. I am running on 512GB of Unified Memory on my Mac Studio M3 Ultra so the speed of the local model for a small model is pretty good but I tested it with Gemini too and it works equally as fast and in some cases faster. The way it works is that I'm using pgvector (one of the benefits of moving to Postgres) to search the data and see what the player can see etc and there is some batching of the next few actions for 2-4 seconds for the user until the next LLM request fires. The batching also includes branching on logic so if they for example fall under some HP they will move to kiting instead of attacking or maybe they heal etc.   Everything is authed and permission-based. The server and the backend of the frontend have secure communication between them, either with a symmetric key (not recommended for production) or a certificate (the recommended way), so there is no worry. It's all tied to the account's access level, etc., so nobody can make an action that they normally wouldn't be allowed to do. Even the MCP is token-based, and there are prompt injection protections in place. The MCP is audited, and every mutation needs confirmation. The admin area is only accessible to the admin account anyway so normal users can't access it.  
  • Topics

×
×
  • Create New...

Important Information

This community uses essential cookies to function properly. Non-essential cookies and third-party services are used only with your consent. Read our Privacy Policy and We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue..