News:

Simutrans Wiki Manual
The official on-line manual for Simutrans. Read and contribute.

Object to mark the ground

Started by Yona-TYT, November 26, 2024, 04:47:35 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Yona-TYT


I have a big problem assigning tiles to a specific player, using the squirrel api.

Rectangles can be created using rules to limit with coordinates but in online games this is expensive and even more so if it is a relatively large map.

Therefore it occurs to me that a tile can be marked with an X object, such as a text label for example, then it would no longer be necessary to check lists of coordinates to know if the tile belongs to the player or not.

The problem is that text labels are expensive in monetary terms and I think they cannot be hidden.

Another option would be to use objects such as bridge pillars, but there is no tool to build them separately (they always go with the bridge).

The main characteristic of these two objects is that they do not interfere too much with the player's constructions, which makes them ideal for marking the ground, in the absence of some method that allows us to identify a tile with a player, or several players.

prissi

Rectangles are not so expensive and do not scaled with map size. They are searched with binary search, and the only "expensive" action is on creation of the rules as the whole set must be transferred each time. That could be optimised, but then a rule is about 16 byte+string length, so not really a big rule. While a list of 100 x 100 tiles is already 10000 bytes. You can transfer many rules for that.

Testing each tile before every move is something, which a) can change the game state and b) takes a lot of time, especially for area/dragging tools.

Please be a little more specific what you mean by expensive, and probably something can be done about it. It never came up so far, as there were never more than two rules for the test cases.

Yona-TYT

Quote from: prissi on November 26, 2024, 11:23:11 PMRectangles are not so expensive and do not scaled with map size. They are searched with binary search, and the only "expensive" action is on creation of the rules as the whole set must be transferred each time. That could be optimised, but then a rule is about 16 byte+string length, so not really a big rule. While a list of 100 x 100 tiles is already 10000 bytes. You can transfer many rules for that.


Yes, I realized that, rectangles are the most viable option.

Thanks for enlightening me further on this.

Yona-TYT

#3
I did some mini automated tests for the rules, because I noticed that the forbids were not being applied correctly.

I did two tests, one for the simutrans release and another for the last nights.

For r11400: test-tool_rect_old.zip
For last nights: test-tool_rect_new.zip

In r11400 fails because a rule is applied that prevents the "tool_remover" tool from being used, however command_x(tool_remover) is not respecting this rule.

In last nights fails because a command_x.build_way is not respecting  the forbid rule.


Yona-TYT

I suspect that the logic in the rules was already broken before r11434, for example:

"rules.forbid_way_tool_rect" always overrides the "is_work_allowed_here" function and does not allow it to run, and that seems correct to me.

But "rules.allow_way_tool_rect" is not preventing the "is_work_allowed_here" function, therefore the rule is not being enforced, this behavior is not correct IMHO.

prissi

I think I caught now all in r11443. That revision should also handle large rule sets for individual players with much better performance.

In your example, in line 119, you have to test for null.

The allowance of rules deletes the matching forbid rule, if there is one. You cannot forbid all and then allow a rect only. That is not how the system works. Maybe a better name would be "remove_forbid_rule"

Yona-TYT

#6
Quote from: prissi on November 30, 2024, 02:52:17 AMIn your example, in line 119, you have to test for null.
Certainly, but if we just use:

too_list <- [
                tool_build_way,
                tool_remover,
            ]

function forbid_tools_map()
{
    for(local j=0; j<too_list.len(); j++) {
        rules.forbid_way_tool_rect(player_all, too_list[j], wt_all, "", coord(0, 0), coord(map_siz.x, map_siz.y), "Action Not Allowed")       
    }
}
You'll see that "tool_remover" should be forbidden, and it is for players but not for the command.

So:
function test_way_road_build_forbid()
{
    forbid_tools_map()
    local pl = player_x(0)
    local road_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0]
    local default_cash = pl.get_current_cash()

    ASSERT_TRUE(road_desc != null)

    {
        ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 1, 0), coord3d(4, 3, 0), road_desc, true), "")
        local t = command_x(tool_remover)
        ASSERT_EQUAL(t.work(pl, coord3d(4, 1, 0), ""), "")

    }

}

"t.work(pl, coord3d(4, 1, 0), "")" should not remove the road, since the "function forbid_tools_map()" is being called before.

Edit.
I haven't reviewed the code, but I suspect that "command_x(tool_remover).work" works differently than "command_x.build_way" and is therefore not taking the rules into account.

Yona-TYT

#7
Quote from: prissi on November 30, 2024, 02:52:17 AMThe allowance of rules deletes the matching forbid rule, if there is one. You cannot forbid all and then allow a rect only. That is not how the system works. Maybe a better name would be "remove_forbid_rule"

The name is certainly confusing, I thought this was possible:

Captura de pantalla -2024-11-30 10-39-41.png



So, since "rules.allow" only overrides "rules.forbid", then that would explain why the "is_work_allowed_here" function is not affected by it.

So it occurs to me that in order to do what I explained in the diagram above, a new type of rule is needed to allow and that dominates over the "is_work_allowed_here" function, for example:
tool_list <- [
                tool_build_way,
                tool_remover,
            ]


function allow_tools()
{
    for(local j=0; j<tool_list.len(); j++) {
        rules.allow_way_tool_rect(player_all, tool_list[j], wt_all, "",coord(10, 10), coord(60, 60))       
    }
}

function start()
{
    allow_tools()
}

function is_work_allowed_here(pl, tool_id, name, pos, tool)
{
    return "Action Not Allowed"
}


So, "is_work_allowed_here" will take care of restricting tools in the red area, while tools used within the area "coord(10, 10) and coord(60, 60)" will be allowed since the rule will not allow "is_work_allowed_here" to be called.

Currently this is how it works with the forbid rules.
 

Quote from: prissi on November 30, 2024, 02:52:17 AMMaybe a better name would be "remove_forbid_rule"
I agree with changing the name of this function, and I don't think there will be any objections to it.  ;)

Yona-TYT

Quote from: Yona-TYT on November 30, 2024, 02:39:03 PMSo, "is_work_allowed_here" will take care of restricting tools in the red area, while tools used within the area "coord(10, 10) and coord(60, 60)" will be allowed since the rule will not allow "is_work_allowed_here" to be called.


I did a little experiment, and surprisingly it works as expected. ;D

0001-Experiment-with-an-allow-rule.patch

Yona-TYT

Quote from: Yona-TYT on December 01, 2024, 03:13:48 AMI did a little experiment, and surprisingly it works as expected. ;D
0001-Experiment-with-an-allow-rule.patch
Would you like to discuss this in a separate thread?.

prissi

There are forbid and forbid_rect rules. Any allow rule should be also part of the type.

That it worked was luck and depended on the search order. You need a proper tzpe of allow rules, which are searched first before forbid rules.

enum forbid_type {
  forbid_tool      = 1,
  allow_tooo_rect  = 2,
  forbid_tool_rect = 3
};

That implies that any allow rule cannot nested. If there is an allow routine, it will be always allowed, even is there is a forbid rule inside.

Yona-TYT

#11
Quote from: prissi on December 05, 2024, 01:41:44 PMThere are forbid and forbid_rect rules. Any allow rule should be also part of the type.

That it worked was luck and depended on the search order. You need a proper tzpe of allow rules, which are searched first before forbid rules.

enum forbid_type {
  forbid_tool      = 1,
  allow_tooo_rect  = 2,
  forbid_tool_rect = 3
};

That implies that any allow rule cannot nested. If there is an allow routine, it will be always allowed, even is there is a forbid rule inside.

Something like this you say?.

Edit.
As @prissi said before, I would also like to change "allow_way_tool_cube" and "allow_way_tool_rect" to something like:
clear_way_tool_cube
clear_way_tool_rect
Then the new rules for allowing would, in effect, be called:
allow_way_tool_cube
allow_way_tool_rect

prissi

That could be done both, indeed. Also with returning an error code whether a rule was deleted or created or clear failed.

Yona-TYT

I have renamed allow_way_tool_rect and allow_way_tool_cube , but I'm not sure if I should do the same with "allow_tool" and "allow_way_tool"

0001-Rename-allow-rulues-to-clear.patch

prissi

Your patch was incomplete. Anyway, please test r11447.

Yona-TYT

Quote from: prissi on December 07, 2024, 04:19:50 AMYour patch was incomplete. Anyway, please test r11447.
Very grateful to you. :D

Edit.
Due to the large number of changes that have been made, I am planning to help update the documentation soon.

Yona-TYT

I have problems with "rules.forbid_way_tool_rect", because it affects the menus, this should not happen since these rules apply only to a specific area.

I modified the test script above to automate the process:

test-tool_menu_all.zip

The operation is as follows:

First I apply the following rules, this hides all construction tools (with waytypes) except for "tool_build_way", so the first command can build a section of road.

function forbid_tools_way_all()
{
    local list =    [

                        tool_build_bridge,
                        tool_build_tunnel,
                        tool_build_roadsign,
                        tool_build_wayobj,
                        tool_remove_way,
                        tool_remove_wayobj,
                        tool_build_station,
                        tool_build_bridge,
                        tool_build_depot,
                        tool_build_transformer,

                ]
    foreach(tool in list) {
        rules.forbid_way_tool(player_all, tool, wt_all, "")
    }
}



Now the rules for a rectangle are applied, they only apply for: tool_build_way, tool_build_bridge and tool_build_tunnel, in an area of (0,0)x(5,5).

After applying the "rules.forbid_way_tool_rect", it should not be possible to use any tool other than "tool_build_way".

function forbid_tools_way_all_rect()
{
    local list =    [
                        tool_build_way,
                        tool_build_bridge,
                        tool_build_tunnel,


                ]
    local c = {a = coord(0,0), b = coord(5,5)}
    foreach(tool in list) {
        rules.forbid_way_tool_rect(player_all, tool, wt_all, "", c.a, c.b, "Action Not Allowed")
    }
}

prissi

I forgot to change the wt_all to ignore_wt(0) instead 255. Otherwise it would be never found. Also, the logic to test if doing the binary search of not was broken (for quite some time actually). So in r11459 your script runs through.

Yona-TYT

Quote from: prissi on December 11, 2024, 01:39:32 AMI forgot to change the wt_all to ignore_wt(0) instead 255. Otherwise it would be never found. Also, the logic to test if doing the binary search of not was broken (for quite some time actually). So in r11459 your script runs through.
I confirm that it is now working fine. 8)