Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added logic to traverse the dimensions directory tree #251

Merged
merged 9 commits into from
Aug 16, 2023

Conversation

Podshot
Copy link
Member

@Podshot Podshot commented Jul 18, 2023

This code changes now traverses the dimensions directory tree and searches for the following directories to exist to determine if the parent directory is a dimension: data, entities, poi and region

Notes:

  • This logic can also be migrated to anvil_world/format.py here but I put it into the anvil_forge_world.py file for now since it's Forge specific. Feel free to let me know if you want me to migrate it

Resolves Amulet-Team/Amulet-Map-Editor#922

@Podshot Podshot self-assigned this Jul 18, 2023
@CLAassistant
Copy link

CLAassistant commented Jul 18, 2023

CLA assistant check
All committers have signed the CLA.

@@ -33,5 +39,15 @@ def game_version_string(self) -> str:
except Exception:
return f"Java Forge Unknown Version"

def _register_modded_dimensions(self):
for path, directories, files in os.walk(os.path.join(self.path, "dimensions")):
if set(("data", "entities", "poi", "region")).issubset(set(directories)):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplified to the following

if {"data", "entities", "poi", "region"}.issubset(directories):

@@ -33,5 +39,15 @@ def game_version_string(self) -> str:
except Exception:
return f"Java Forge Unknown Version"

def _register_modded_dimensions(self):
for path, directories, files in os.walk(os.path.join(self.path, "dimensions")):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

files isn't used so this can be an _

if set(("data", "entities", "poi", "region")).issubset(set(directories)):
dimension_path_split = path.split(os.sep)
dimensions_directory_index = dimension_path_split.index("dimensions")
dimension_name = f"{dimension_path_split[dimensions_directory_index + 1]}:{'/'.join(dimension_path_split[dimensions_directory_index + 2:])}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should probably add a check if we are at least two directories deep otherwise this will error

for path, directories, files in os.walk(os.path.join(self.path, "dimensions")):
if set(("data", "entities", "poi", "region")).issubset(set(directories)):
dimension_path_split = path.split(os.sep)
dimensions_directory_index = dimension_path_split.index("dimensions")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You compute the relpath further down. The indexes will be constant in that output.

@gentlegiantJGC
Copy link
Member

If only the region directory is required this can be compacted down to a glob.
I can make these changes if you are busy.

@gentlegiantJGC
Copy link
Member

I haven't tested this but this is how I would implement it

    def _register_modded_dimensions(self):
        for region_path in glob.glob(
            os.path.join(glob.escape(self.path), "dimensions", "*", "**", "region"), 
            recursive=True
        ):
            dim_path = os.path.dirname(region_path)
            if not {"data", "entities", "poi", "region"}.issubset(filter(os.path.isdir, os.listdir(dim_path))):
                continue
            rel_dim_path = os.path.relpath(dim_path, self.path)
            _, dimension, *base_name = rel_dim_path.split(os.sep)

            dimension_name = f"{dimension}:{'/'.join(base_name)}"
            self._register_dimension(
                os.path.dirname(rel_dim_path), dimension_name
            )

@Podshot
Copy link
Member Author

Podshot commented Jul 18, 2023

Yeah I can test that glob code and see if it needs any additional changes but from a quick look it looks like it will work. I'll amend this later tonight

…antJGC with tweaks for it to properly check if the required paths are directories
…the check in-case /region is a file and not a directory
for basename in os.listdir(dim_path)
if os.path.isdir(os.path.join(dim_path, basename))
)
if not {"region"}.issubset(child_dir_names):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you only check one directory it should be.
The os.path.dirname in the last line was also wrong.

    def _register_modded_dimensions(self):
        for region_path in glob.glob(
            os.path.join(glob.escape(self.path), "dimensions", "*", "**", "region"),
            recursive=True,
        ):
            if not os.path.isdir(region_path):
               continue
            dim_path = os.path.dirname(region_path)
            rel_dim_path = os.path.relpath(dim_path, self.path)
            _, namespace, *base_name = rel_dim_path.split(os.sep)

            dimension_name = f"{namespace}:{'/'.join(base_name)}"
            self._register_dimension(rel_dim_path, dimension_name)

Copy link
Member Author

@Podshot Podshot Jul 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add this in tomorrow when I get the chance! I wanted to keep the directory check in and decided to keep the set approach in-case other directories would need to be added in the future but I think this is good and we can just do that change if/when it would be needed

Podshot and others added 3 commits July 27, 2023 20:24
`"*", "*", "**"` is required to match at least two directories deep.
dirname should not be on the last line. dirname there would give a different directory.
@gentlegiantJGC
Copy link
Member

Delved into the code to work out why the tests were breaking.
This code shouldn't be in the constructor. There is a method to reload world data with the same instance and it should be in there.
I will make these changes.

Moved the modded dimension finding code into the vanilla class.
The tests were breaking because the code was implemented in the constructor.
This code should be in the level reloading method.
@gentlegiantJGC gentlegiantJGC merged commit dafef97 into main Aug 16, 2023
10 checks passed
@gentlegiantJGC gentlegiantJGC deleted the impl-more-modded-dimensions branch August 16, 2023 09:38
@Podshot
Copy link
Member Author

Podshot commented Aug 16, 2023

Delved into the code to work out why the tests were breaking.

This code shouldn't be in the constructor. There is a method to reload world data with the same instance and it should be in there.

I will make these changes.

Ah gotcha, is there a particular reason why the tests just started to fail? They were passing fine until the commit where we only check the region directory.

I also think the logic should still be contained in anvil_forge_world.py since it's not vanilla behavior for the world to have more (or more rather, a non-static/dynamic number of dimensions) other than the Nether and End

@gentlegiantJGC
Copy link
Member

Your code caused a modded dimension to get registered twice (once in your code and once in the vanilla code) which triggered another issue. I don't think I finished implementing the reloading code so there are a number of issues.

It shouldn't do any harm in the vanilla class and is less likely to get broken when I refactor those classes.

I want to refactor the level wrappers so that the constructors don't actually load the world. They just initialise some default values.
Classmethods will do the actual loading.
The reason is because the same class is used to load an existing level and to create a level.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Amulet CAN'T open some Modded Dimensions
3 participants