From a8b6e6b15e7bdb3ae89dce79403ffe78d962c680 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Mon, 6 Oct 2025 17:41:18 -0600 Subject: [PATCH] Checkpoint initial implementation --- bin/activate.sh | 1 + bin/setup.sh | 5 + bin/test.sh | 2 + bin/watch_test.sh | 2 + requirements.txt | 8 + tungston/__init__.py | 0 tungston/core/__init__.py | 0 tungston/core/altitude.py | 74 +++++++ tungston/core/altitude_test.py | 18 ++ tungston/core/ecology/__init__.py | 0 tungston/core/ecology/biome.py | 70 +++++++ tungston/core/ecology/biome_test.py | 25 +++ tungston/core/ecology/biomecatalog.py | 25 +++ tungston/core/ecology/biomecatalog_test.py | 46 +++++ tungston/core/ecology/biomefilter.py | 57 ++++++ tungston/core/ecology/biomefilter_test.py | 61 ++++++ tungston/core/ecology/biometrait.py | 49 +++++ tungston/core/ecology/biometrait_test.py | 58 ++++++ tungston/core/ecology/flora.py | 28 +++ tungston/core/ecology/flora_test.py | 9 + tungston/core/ecology/geology.py | 19 ++ tungston/core/ecology/geology_test.py | 9 + tungston/core/ecology/heat.py | 33 ++++ tungston/core/ecology/heat_test.py | 13 ++ tungston/core/ecology/humidity.py | 26 +++ tungston/core/ecology/humidity_test.py | 9 + tungston/core/ecology/soil.py | 23 +++ tungston/core/ecology/soil_test.py | 9 + tungston/core/ecology/water.py | 21 ++ tungston/core/ecology/water_test.py | 9 + tungston/core/fauna/__init__.py | 0 tungston/core/fauna/active.py | 30 +++ tungston/core/fauna/active_test.py | 9 + tungston/core/fauna/group.py | 50 +++++ tungston/core/fauna/group_test.py | 17 ++ tungston/core/fauna/location.py | 27 +++ tungston/core/fauna/mob.py | 36 ++++ tungston/core/fauna/mob_test.py | 39 ++++ tungston/core/fauna/mobcatalog.py | 16 ++ tungston/core/fauna/mobplacement.py | 15 ++ tungston/core/fauna/mobplacement_test.py | 43 ++++ tungston/core/geology/__init__.py | 0 tungston/core/geology/bulk.py | 33 ++++ tungston/core/geology/bulk_test.py | 20 ++ tungston/core/geology/deposit/__init__.py | 22 +++ tungston/core/geology/deposit/metaldeposit.py | 43 ++++ .../core/geology/deposit/metaldeposit_test.py | 55 ++++++ tungston/core/geology/depositcatalog.py | 27 +++ tungston/core/geology/depositcatalog_test.py | 53 +++++ tungston/core/geology/inclusion.py | 24 +++ tungston/core/geology/inclusion_test.py | 24 +++ tungston/core/geology/mineral.py | 32 +++ tungston/core/geology/mineral_test.py | 28 +++ tungston/core/geology/mineralcatalog.py | 26 +++ tungston/core/geology/mineralcatalog_test.py | 34 ++++ tungston/core/geology/proportion.py | 34 ++++ tungston/core/geology/proportion_test.py | 12 ++ tungston/core/geology/replacement.py | 40 ++++ tungston/core/geology/replacement_test.py | 28 +++ tungston/core/habitat.py | 89 +++++++++ tungston/core/habitat_test.py | 45 +++++ tungston/core/placement.py | 26 +++ tungston/core/placement_test.py | 38 ++++ tungston/core/resourceid.py | 56 ++++++ tungston/core/resourceid_test.py | 16 ++ tungston/core/scarcity.py | 27 +++ tungston/core/scarcity_test.py | 9 + tungston/core/season.py | 44 +++++ tungston/core/season_test.py | 16 ++ tungston/core/world.py | 21 ++ tungston/core/world_test.py | 7 + tungston/generator/datapack/__init__.py | 14 ++ tungston/generator/datapack/blockstate.py | 18 ++ .../generator/datapack/blockstate_test.py | 20 ++ .../datapack/blockstateprovider/__init__.py | 7 + .../blockstateprovider/simplestateprovider.py | 18 ++ .../simplestateprovider_test.py | 28 +++ .../datapack/configuredfeature/__init__.py | 6 + .../datapack/configuredfeature/randompatch.py | 31 +++ .../configuredfeature/randompatch_test.py | 38 ++++ .../datapack/configuredfeature/simpleblock.py | 20 ++ .../configuredfeature/simpleblock_test.py | 38 ++++ tungston/generator/datapack/heightmaptype.py | 24 +++ .../generator/datapack/heightmaptype_test.py | 7 + tungston/generator/datapack/placedfeature.py | 6 + .../generator/datapack/placedfeature_test.py | 6 + .../generator/datapack/placement/__init__.py | 6 + .../generator/datapack/placement/biome.py | 13 ++ .../datapack/placement/biome_test.py | 18 ++ .../generator/datapack/placement/heightmap.py | 17 ++ .../datapack/placement/heightmap_test.py | 20 ++ .../generator/datapack/placement/insquare.py | 13 ++ .../datapack/placement/insquare_test.py | 18 ++ .../datapack/placement/rarityfilter.py | 17 ++ .../datapack/placement/rarityfilter_test.py | 19 ++ tungston/generator/markdown/__init__.py | 0 tungston/generator/markdown/mineralreport.py | 19 ++ .../generator/markdown/mineralreport_test.py | 55 ++++++ tungston/generator/markdown/report.py | 70 +++++++ tungston/generator/markdown/report_test.py | 31 +++ tungston/modpack/mysteriousisland/__init__.py | 0 .../modpack/mysteriousisland/biomecatalog.py | 165 ++++++++++++++++ .../mysteriousisland/depositcatalog.py | 28 +++ .../mysteriousisland/mineralcatalog.py | 109 +++++++++++ .../modpack/mysteriousisland/mobcatalog.py | 183 ++++++++++++++++++ tungston/modpack/mysteriousisland/world.py | 10 + 106 files changed, 3012 insertions(+) create mode 100755 bin/activate.sh create mode 100755 bin/setup.sh create mode 100755 bin/test.sh create mode 100755 bin/watch_test.sh create mode 100644 requirements.txt create mode 100644 tungston/__init__.py create mode 100644 tungston/core/__init__.py create mode 100644 tungston/core/altitude.py create mode 100644 tungston/core/altitude_test.py create mode 100644 tungston/core/ecology/__init__.py create mode 100644 tungston/core/ecology/biome.py create mode 100644 tungston/core/ecology/biome_test.py create mode 100644 tungston/core/ecology/biomecatalog.py create mode 100644 tungston/core/ecology/biomecatalog_test.py create mode 100644 tungston/core/ecology/biomefilter.py create mode 100644 tungston/core/ecology/biomefilter_test.py create mode 100644 tungston/core/ecology/biometrait.py create mode 100644 tungston/core/ecology/biometrait_test.py create mode 100644 tungston/core/ecology/flora.py create mode 100644 tungston/core/ecology/flora_test.py create mode 100644 tungston/core/ecology/geology.py create mode 100644 tungston/core/ecology/geology_test.py create mode 100644 tungston/core/ecology/heat.py create mode 100644 tungston/core/ecology/heat_test.py create mode 100644 tungston/core/ecology/humidity.py create mode 100644 tungston/core/ecology/humidity_test.py create mode 100644 tungston/core/ecology/soil.py create mode 100644 tungston/core/ecology/soil_test.py create mode 100644 tungston/core/ecology/water.py create mode 100644 tungston/core/ecology/water_test.py create mode 100644 tungston/core/fauna/__init__.py create mode 100644 tungston/core/fauna/active.py create mode 100644 tungston/core/fauna/active_test.py create mode 100644 tungston/core/fauna/group.py create mode 100644 tungston/core/fauna/group_test.py create mode 100644 tungston/core/fauna/location.py create mode 100644 tungston/core/fauna/mob.py create mode 100644 tungston/core/fauna/mob_test.py create mode 100644 tungston/core/fauna/mobcatalog.py create mode 100644 tungston/core/fauna/mobplacement.py create mode 100644 tungston/core/fauna/mobplacement_test.py create mode 100644 tungston/core/geology/__init__.py create mode 100644 tungston/core/geology/bulk.py create mode 100644 tungston/core/geology/bulk_test.py create mode 100644 tungston/core/geology/deposit/__init__.py create mode 100644 tungston/core/geology/deposit/metaldeposit.py create mode 100644 tungston/core/geology/deposit/metaldeposit_test.py create mode 100644 tungston/core/geology/depositcatalog.py create mode 100644 tungston/core/geology/depositcatalog_test.py create mode 100644 tungston/core/geology/inclusion.py create mode 100644 tungston/core/geology/inclusion_test.py create mode 100644 tungston/core/geology/mineral.py create mode 100644 tungston/core/geology/mineral_test.py create mode 100644 tungston/core/geology/mineralcatalog.py create mode 100644 tungston/core/geology/mineralcatalog_test.py create mode 100644 tungston/core/geology/proportion.py create mode 100644 tungston/core/geology/proportion_test.py create mode 100644 tungston/core/geology/replacement.py create mode 100644 tungston/core/geology/replacement_test.py create mode 100644 tungston/core/habitat.py create mode 100644 tungston/core/habitat_test.py create mode 100644 tungston/core/placement.py create mode 100644 tungston/core/placement_test.py create mode 100644 tungston/core/resourceid.py create mode 100644 tungston/core/resourceid_test.py create mode 100644 tungston/core/scarcity.py create mode 100644 tungston/core/scarcity_test.py create mode 100644 tungston/core/season.py create mode 100644 tungston/core/season_test.py create mode 100644 tungston/core/world.py create mode 100644 tungston/core/world_test.py create mode 100644 tungston/generator/datapack/__init__.py create mode 100644 tungston/generator/datapack/blockstate.py create mode 100644 tungston/generator/datapack/blockstate_test.py create mode 100644 tungston/generator/datapack/blockstateprovider/__init__.py create mode 100644 tungston/generator/datapack/blockstateprovider/simplestateprovider.py create mode 100644 tungston/generator/datapack/blockstateprovider/simplestateprovider_test.py create mode 100644 tungston/generator/datapack/configuredfeature/__init__.py create mode 100644 tungston/generator/datapack/configuredfeature/randompatch.py create mode 100644 tungston/generator/datapack/configuredfeature/randompatch_test.py create mode 100644 tungston/generator/datapack/configuredfeature/simpleblock.py create mode 100644 tungston/generator/datapack/configuredfeature/simpleblock_test.py create mode 100644 tungston/generator/datapack/heightmaptype.py create mode 100644 tungston/generator/datapack/heightmaptype_test.py create mode 100644 tungston/generator/datapack/placedfeature.py create mode 100644 tungston/generator/datapack/placedfeature_test.py create mode 100644 tungston/generator/datapack/placement/__init__.py create mode 100644 tungston/generator/datapack/placement/biome.py create mode 100644 tungston/generator/datapack/placement/biome_test.py create mode 100644 tungston/generator/datapack/placement/heightmap.py create mode 100644 tungston/generator/datapack/placement/heightmap_test.py create mode 100644 tungston/generator/datapack/placement/insquare.py create mode 100644 tungston/generator/datapack/placement/insquare_test.py create mode 100644 tungston/generator/datapack/placement/rarityfilter.py create mode 100644 tungston/generator/datapack/placement/rarityfilter_test.py create mode 100644 tungston/generator/markdown/__init__.py create mode 100644 tungston/generator/markdown/mineralreport.py create mode 100644 tungston/generator/markdown/mineralreport_test.py create mode 100644 tungston/generator/markdown/report.py create mode 100644 tungston/generator/markdown/report_test.py create mode 100644 tungston/modpack/mysteriousisland/__init__.py create mode 100644 tungston/modpack/mysteriousisland/biomecatalog.py create mode 100644 tungston/modpack/mysteriousisland/depositcatalog.py create mode 100644 tungston/modpack/mysteriousisland/mineralcatalog.py create mode 100644 tungston/modpack/mysteriousisland/mobcatalog.py create mode 100644 tungston/modpack/mysteriousisland/world.py diff --git a/bin/activate.sh b/bin/activate.sh new file mode 100755 index 0000000..8624131 --- /dev/null +++ b/bin/activate.sh @@ -0,0 +1 @@ +source .venv/bin/activate diff --git a/bin/setup.sh b/bin/setup.sh new file mode 100755 index 0000000..03ec6d9 --- /dev/null +++ b/bin/setup.sh @@ -0,0 +1,5 @@ +[[ -d .venv ]] && rm -rf .venv +python -m venv .venv +source .venv/bin/activate +pip install --upgrade pip +pip install -r requirements.txt diff --git a/bin/test.sh b/bin/test.sh new file mode 100755 index 0000000..6fd1cfa --- /dev/null +++ b/bin/test.sh @@ -0,0 +1,2 @@ +source bin/activate.sh +pytest tungston -vv $* diff --git a/bin/watch_test.sh b/bin/watch_test.sh new file mode 100755 index 0000000..2cb9d1c --- /dev/null +++ b/bin/watch_test.sh @@ -0,0 +1,2 @@ +source bin/activate.sh +watch -c "pytest -q --color=yes --tb=short tungston" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c97357c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,8 @@ +exceptiongroup==1.3.0 +iniconfig==2.1.0 +packaging==25.0 +pluggy==1.6.0 +Pygments==2.19.2 +pytest==8.4.2 +tomli==2.2.1 +typing_extensions==4.15.0 diff --git a/tungston/__init__.py b/tungston/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tungston/core/__init__.py b/tungston/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tungston/core/altitude.py b/tungston/core/altitude.py new file mode 100644 index 0000000..c40f67b --- /dev/null +++ b/tungston/core/altitude.py @@ -0,0 +1,74 @@ +# Class ############################################################################################ + +class Altitude: + """ + A range of world heights from a bottom to a top. + """ + + def __init__(self, name:str, bottom:int, top:int): + self.name = name + self.bottom = bottom + self.top = top + + def __eq__(self, other) -> bool: + if type(self) != type(other): return False + if self.bottom != other.bottom: return False + if self.top != other.top: return False + return True + + def __hash__(self) -> int: + return hash((self.bottom, self.top)) + + def __str__(self) -> str: + return self.name + + def __repr__(self) -> str: + return f"{self.name} <{self.bottom} to {self.top}>" + +# Constants ######################################################################################## + +# Aboveground +SKY = Altitude("sky", 284, 316) +SUMMIT = Altitude("summit", 252, 284) +PEAKS = Altitude("peaks", 222, 252) +CRAGS = Altitude("crags", 190, 222) +ALPINE = Altitude("alpine", 156, 190) +HILLS = Altitude("hills", 124, 156) +UPLANDS = Altitude("uplands", 92, 124) +LOWLANDS = Altitude("lowlands", 70, 92) +DUNES = Altitude("dunes", 62, 70) + +# Transition +EVAPORATES = Altitude("evaporates", 60, 64) +ANYWHERE = Altitude("anywhere", -64, 320) + +# Underground +SOIL = Altitude("soil", 48, 62) +SUBSTRATE = Altitude("substrate", 32, 48) +OVERBURDEN = Altitude("overburden", 0, 32) +CRUST = Altitude("crust", -32, 32) +MANTLE = Altitude("mantle", -54, -32) +PLUTONIC = Altitude("plutonic", -64, -54) + +# Underwater +SURFACE = Altitude("surface", 58, 62) +SHALLOWS = Altitude("shallows", 46, 58) +DEEPS = Altitude("deeps", 0, 46) +ABYSS = Altitude("abyss", -32, 0) + +# Groups +OVERGROUND = (DUNES, LOWLANDS, UPLANDS, HILLS, ALPINE, CRAGS, PEAKS, SUMMIT, SKY) +UNDERGROUND = (SOIL, SUBSTRATE, OVERBURDEN, CRUST, MANTLE, PLUTONIC) +UNDERWATER = (SURFACE, SHALLOWS, DEEPS, ABYSS) + +# Helper Functions ################################################################################# + +def span(*altitudes): + if not altitudes: return ANYWHERE + result = Altitude("", ANYWHERE.top, ANYWHERE.bottom) + + for altitude in altitudes: + result.bottom = min(result.bottom, altitude.bottom) + result.top = max(result.top, altitude.top) + + return result diff --git a/tungston/core/altitude_test.py b/tungston/core/altitude_test.py new file mode 100644 index 0000000..27edd03 --- /dev/null +++ b/tungston/core/altitude_test.py @@ -0,0 +1,18 @@ +from pytest import fixture + +import tungston.core.altitude as A + + +# Fixtures ######################################################################################### + +@fixture(name="merged") +def mergeRange(): + yield A.span(A.UPLANDS, A.LOWLANDS) + + +# Tests ############################################################################################ + +def test_span(merged): + assert merged.bottom == A.LOWLANDS.bottom + assert merged.top == A.UPLANDS.top + diff --git a/tungston/core/ecology/__init__.py b/tungston/core/ecology/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tungston/core/ecology/biome.py b/tungston/core/ecology/biome.py new file mode 100644 index 0000000..78d8dc1 --- /dev/null +++ b/tungston/core/ecology/biome.py @@ -0,0 +1,70 @@ +from tungston.core.ecology.biometrait import BiomeTrait +from tungston.core.ecology.flora import Flora +from tungston.core.ecology.geology import Geology +from tungston.core.ecology.heat import Heat +from tungston.core.ecology.humidity import Humidity +from tungston.core.ecology.soil import Soil +from tungston.core.ecology.water import Water + + +#################################################################################################### + +class Biome(object): + """ + A region of the world defined by a unique combination of geology, topography, and ecology. + """ + + def __init__( + self, + city:str, + gameId:str, + flora:Flora, + geology:Geology, + heat:Heat, + humidity:Humidity, + soil:Soil, + water:Water, + ): + self.city = city + self.gameId = gameId + + self.flora = flora + self.geology = geology + self.heat = heat + self.humidity = humidity + self.soil = soil + self.water = water + + def __eq__(self, other) -> bool: + if type(self) != type(other): return False + if self.biomeId != other.biomeId: return False + if self.city != other.city: return False + return True + + def __hash__(self) -> int: + return hash((self.biomeId, self.city)) + + def __str__(self) -> str: + return f"{self.city}<{self.gameId}>" + + def __repr__(self) -> str: + return "".join([str(p) for p in [ + str(self), "{", + repr(self.flora), ", ", + repr(self.geology), ", ", + repr(self.heat), ", ", + repr(self.humidity), ", ", + repr(self.soil), ", ", + repr(self.water), + "}" + ]]) + + def traits(self) -> set[BiomeTrait]: + return set([ + self.flora, + self.geology, + self.heat, + self.humidity, + self.soil, + self.water, + ]) diff --git a/tungston/core/ecology/biome_test.py b/tungston/core/ecology/biome_test.py new file mode 100644 index 0000000..ce6e6d5 --- /dev/null +++ b/tungston/core/ecology/biome_test.py @@ -0,0 +1,25 @@ +from pytest import fixture +from tungston.core.ecology.biome import Biome + +import tungston.core.ecology.flora as F +import tungston.core.ecology.geology as G +import tungston.core.ecology.heat as E +import tungston.core.ecology.humidity as U +import tungston.core.ecology.soil as S +import tungston.core.ecology.water as W + + +# Fixtures ######################################################################################### + +@fixture(name="desert") +def createDesert(): + return Biome( + "phoenix", "minecraft:desert", + F.BARREN, G.SEDIMENTARY, E.TROPICAL, U.DRY, S.SANDY, W.INLAND + ) + +# Tests ############################################################################################ + +def test_createBiome(desert): + assert desert.city == "phoenix" + assert desert.soil == S.SANDY diff --git a/tungston/core/ecology/biomecatalog.py b/tungston/core/ecology/biomecatalog.py new file mode 100644 index 0000000..1ad5c47 --- /dev/null +++ b/tungston/core/ecology/biomecatalog.py @@ -0,0 +1,25 @@ +from tungston.core.ecology.biome import Biome +from tungston.core.ecology.biomefilter import BiomeFilter + + +# Classes ########################################################################################## + +class BiomeCatalog: + """ + A comprehensive list of all available biomes in the modpack. + """ + + def __init__(self, biomes): + self.biomes = sorted(biomes, key=lambda b: b.city) + + def all(self) -> list[Biome]: + return list(self.biomes) + + def matching(self, biomeFilter:BiomeFilter) -> list[Biome]: + result = [] + + for biome in self.biomes: + if biomeFilter.accepts(biome): + result.append(biome) + + return result diff --git a/tungston/core/ecology/biomecatalog_test.py b/tungston/core/ecology/biomecatalog_test.py new file mode 100644 index 0000000..720ece0 --- /dev/null +++ b/tungston/core/ecology/biomecatalog_test.py @@ -0,0 +1,46 @@ +from tungston.core.ecology.biome import Biome +from tungston.core.ecology.biomecatalog import BiomeCatalog +from tungston.core.ecology.biomefilter import BiomeFilter +from pytest import fixture + +import tungston.core.ecology.flora as F +import tungston.core.ecology.geology as G +import tungston.core.ecology.heat as E +import tungston.core.ecology.humidity as U +import tungston.core.ecology.soil as S +import tungston.core.ecology.water as W + +# Fixtures ######################################################################################### + +@fixture(name="jungles") +def createJungleFilter(): + yield BiomeFilter([U.WET, E.TROPICAL, F.within(F.CANOPY, F.CLEARING)]) + +@fixture(name="catalog") +def createCatalog(): + yield BiomeCatalog([ + Biome("dallas", "minecraft:savanna", + F.FIELD, G.SEDIMENTARY, E.SUBTROPICAL, U.DRY, S.SANDY, W.INLAND + ), + Biome("kansascity", "minecraft:plains", + F.FIELD, G.SEDIMENTARY, E.TEMPERATE, U.DAMP, S.LOAMY, W.INLAND + ), + Biome("mobile", "minecraft:swamp", + F.CLEARING, G.SEDIMENTARY, E.TEMPERATE, U.WET, S.PEATY, W.SWAMP + ), + Biome("phoenix", "minecraft:desert", + F.BARREN, G.SEDIMENTARY, E.TROPICAL, U.DRY, S.SANDY, W.INLAND + ), + Biome("portland", "minecraft:forest", + F.FOREST, G.SEDIMENTARY, E.TEMPERATE, U.DAMP, S.LOAMY, W.INLAND + ), + Biome("singapore", "minecraft:jungle", + F.CANOPY, G.SEDIMENTARY, E.TROPICAL, U.WET, S.ACIDIC, W.INLAND + ), + ]) + + +# Tests ############################################################################################ + +def test_findJungles(catalog, jungles): + assert [b.city for b in catalog.matching(jungles)] == ["singapore"] diff --git a/tungston/core/ecology/biomefilter.py b/tungston/core/ecology/biomefilter.py new file mode 100644 index 0000000..a01e517 --- /dev/null +++ b/tungston/core/ecology/biomefilter.py @@ -0,0 +1,57 @@ +from tungston.core.ecology.biome import Biome +from tungston.core.ecology.biometrait import BiomeTrait + + +# Class ############################################################################################ + +class BiomeFilter: + """ + A description of which biomes may be considered for a given purpose. + + This class works by allowing *both* allowed and prohibited traits. + + The list of allowed traits may contain either individual trait objects, or a list of such + objects. When an individual trait is given, only biomes with that exact trait are permitted. + When a list of traits is given, biomes containing any of the listed traits are permitted. To + put it another way, each individual item in the required list is an "OR" filter, and the results + of the entire list are "AND"ed together. + + The list of prohibited traits only permits individual traits, but multiple traits of the same + sort may be given. + + The filter only accepts biomes which pass *both* lists. That is, it must possess *all* the + required traits while simultaneously not possessing *any* of the prohibited ones. + """ + + def __init__( + self, + required:list[BiomeTrait|list[BiomeTrait]]=None, + prohibited:list[BiomeTrait]=None, + ): + self.required = required or [] + self.prohibited = prohibited or [] + + def __repr__(self) -> str: + return f"BiomeFilter([{repr(self.required)}], [{repr(self.prohibited)}])" + + def accepts(self, biome: Biome) -> bool: + biomeTraits = biome.traits() + + for condition in self.required: + if isinstance(condition, BiomeTrait): + trait = condition + if trait not in biomeTraits: return False + else: + traitOptions = condition + foundMatch = False + for trait in traitOptions: + if trait in biomeTraits: + foundMatch = True + break + + if not foundMatch: return False + + for prohibitedTrait in self.prohibited: + if prohibitedTrait in biomeTraits: return False + + return True diff --git a/tungston/core/ecology/biomefilter_test.py b/tungston/core/ecology/biomefilter_test.py new file mode 100644 index 0000000..35c4a8b --- /dev/null +++ b/tungston/core/ecology/biomefilter_test.py @@ -0,0 +1,61 @@ +from tungston.core.ecology.biome import Biome +from tungston.core.ecology.biomefilter import BiomeFilter +from pytest import fixture + +import tungston.core.ecology.flora as F +import tungston.core.ecology.geology as G +import tungston.core.ecology.heat as E +import tungston.core.ecology.humidity as U +import tungston.core.ecology.soil as S +import tungston.core.ecology.water as W + + +# Fixtures ######################################################################################### + +@fixture(name="barren") +def createBarrenFilter(): + yield BiomeFilter([F.BARREN]) + +@fixture(name="barrenNotSandy") +def createBarrenNotSandFilter(): + yield BiomeFilter([F.BARREN], [S.SANDY]) + +@fixture(name="desert") +def createDesertBiome(): + yield Biome( + "phoenix", "minecraft:desert", + F.BARREN, G.SEDIMENTARY, E.TROPICAL, U.DRY, S.SANDY, W.INLAND + ) + +@fixture(name="fertile") +def createFertileFilter(): + yield BiomeFilter([(S.LOAMY, S.PEATY)]) + +@fixture(name="forest") +def createForestBiome(): + yield Biome( + "portland", "minecraft:forest", + F.FOREST, G.SEDIMENTARY, E.TEMPERATE, U.DAMP, S.LOAMY, W.INLAND + ) + +@fixture(name="notDry") +def createNotDryFilter(): + yield BiomeFilter([], [U.DRY]) + + +# Tests ############################################################################################ + +def test_prohibitsSingleTrait(notDry, desert, forest): + assert notDry.accepts(forest) + assert not notDry.accepts(desert) + +def test_requireSingleTrait(barren, desert, forest): + assert barren.accepts(desert) + assert not barren.accepts(forest) + +def test_requireOptions(fertile, desert, forest): + assert fertile.accepts(forest) + assert not fertile.accepts(desert) + +def test_vetoed(barrenNotSandy, desert): + assert not barrenNotSandy.accepts(desert) diff --git a/tungston/core/ecology/biometrait.py b/tungston/core/ecology/biometrait.py new file mode 100644 index 0000000..4a59992 --- /dev/null +++ b/tungston/core/ecology/biometrait.py @@ -0,0 +1,49 @@ +# Class ############################################################################################ + +class BiomeTrait: + """ + Any of the many characteristics which uniquely define a biome. + """ + + def __init__(self, name:str): + self.name = name + + def __eq__(self, other) -> bool: + if type(self).__name__ != type(other).__name__: return False + if self.name != other.name: return False + return True + + def __hash__(self) -> int: + return hash((type(self).__name__, self.name)) + + def __str__(self): + return self.name + + def __repr__(self) -> str: + return f"{type(self).__name__}<{self.name}>" + + +# Helper Functions ################################################################################# + +def within(allTraits:list[BiomeTrait], start:BiomeTrait, end:BiomeTrait) -> list[BiomeTrait]: + if not allTraits: return [] + start = start if start else allTraits[0] + end = end if end else allTraits[-1] + + minIndex = 0 + maxIndex = len(allTraits) - 1 + + for index, trait in enumerate(allTraits): + if trait == start: + minIndex = index + elif trait == end: + maxIndex = index + + if minIndex > maxIndex: + minIndex, maxIndex = maxIndex, minIndex + + result = [] + for index in range(minIndex, maxIndex+1): + result.append(allTraits[index]) + + return result diff --git a/tungston/core/ecology/biometrait_test.py b/tungston/core/ecology/biometrait_test.py new file mode 100644 index 0000000..2885f2f --- /dev/null +++ b/tungston/core/ecology/biometrait_test.py @@ -0,0 +1,58 @@ +from tungston.core.ecology.biometrait import BiomeTrait +from pytest import fixture + +import tungston.core.ecology.biometrait as biomeTrait + + +# Fixtures ######################################################################################### + +@fixture(name="blue") +def defineBlue(): + yield BiomeTrait("blue") + +@fixture(name="green") +def defineGreen(): + yield BiomeTrait("green") + +@fixture(name="yellow") +def defineYellow(): + yield BiomeTrait("yellow") + +@fixture(name="orange") +def defineOrange(): + yield BiomeTrait("orange") + +@fixture(name="red") +def defineRed(): + yield BiomeTrait("red") + +@fixture(name="traitMap") +def createTraitMap(green, blue): + yield { + green: "emerald", + blue: "sapphire" + } + +@fixture(name="traitList") +def createTraitList(green, blue, yellow, orange, red): + yield [blue, green, yellow, orange, red] + + +# Tests ############################################################################################ + +def test_eq(green, blue): + assert green == BiomeTrait("green") + assert green != blue + +def test_hash(green, blue, traitMap): + assert traitMap[green] == "emerald" + assert traitMap[blue] == "sapphire" + +def test_repr(green): + assert repr(green) == "BiomeTrait" + +def test_str(green): + assert str(green) == "green" + +def test_within(traitList, green, yellow, orange): + assert biomeTrait.within(traitList, green, orange) == [green, yellow, orange] diff --git a/tungston/core/ecology/flora.py b/tungston/core/ecology/flora.py new file mode 100644 index 0000000..83e0baa --- /dev/null +++ b/tungston/core/ecology/flora.py @@ -0,0 +1,28 @@ +from tungston.core.ecology.biometrait import BiomeTrait + +import tungston.core.ecology.biometrait as biomeTrait + + +# Class ############################################################################################ + +class Flora(BiomeTrait): + """ + Describes how densely the foiliage covers a biome. + """ + pass + + +# Constants ######################################################################################## + +CANOPY = Flora("canopy") +FOREST = Flora("forest") +CLEARING = Flora("clearing") +FIELD = Flora("field") +BARREN = Flora("barren") + +ALL = [CANOPY, FOREST, CLEARING, FIELD, BARREN] + +# Helpers ########################################################################################## + +def within(start:Flora, end:Flora) -> list[Flora]: + return biomeTrait.within(ALL, start, end) diff --git a/tungston/core/ecology/flora_test.py b/tungston/core/ecology/flora_test.py new file mode 100644 index 0000000..63b8fa3 --- /dev/null +++ b/tungston/core/ecology/flora_test.py @@ -0,0 +1,9 @@ +from pytest import fixture + +import tungston.core.ecology.flora as flora + + +# Tests ############################################################################################ + +def test_within(): + assert flora.within(flora.FOREST, flora.FIELD) == [flora.FOREST, flora.CLEARING, flora.FIELD] diff --git a/tungston/core/ecology/geology.py b/tungston/core/ecology/geology.py new file mode 100644 index 0000000..f3e8869 --- /dev/null +++ b/tungston/core/ecology/geology.py @@ -0,0 +1,19 @@ +from tungston.core.ecology.biometrait import BiomeTrait + + +# Class ############################################################################################ + +class Geology(BiomeTrait): + """ + The natural of the rock strata in a biome. + """ + pass + + +# Constants ######################################################################################## + +IGNEOUS = Geology("igneous") +METAMORPHIC = Geology("metamorphic") +SEDIMENTARY = Geology("sedimentary") + +ALL = [IGNEOUS, METAMORPHIC, SEDIMENTARY] diff --git a/tungston/core/ecology/geology_test.py b/tungston/core/ecology/geology_test.py new file mode 100644 index 0000000..454e0db --- /dev/null +++ b/tungston/core/ecology/geology_test.py @@ -0,0 +1,9 @@ +from pytest import fixture + +import tungston.core.ecology.geology as geology + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/tungston/core/ecology/heat.py b/tungston/core/ecology/heat.py new file mode 100644 index 0000000..e2ed46d --- /dev/null +++ b/tungston/core/ecology/heat.py @@ -0,0 +1,33 @@ +from tungston.core.ecology.biometrait import BiomeTrait + +import tungston.core.ecology.biometrait as biomeTrait + + +# Class ############################################################################################ + +class Heat(BiomeTrait): + """ + The general range of ambient temperatures in a biome (in °F). + """ + + def __init__(self, name, low:int, high:int): + super().__init__(name) + self.low = low + self.high = high + + +# Constants ######################################################################################## + +TROPICAL = Heat("tropical", 75, 88) +SUBTROPICAL = Heat("subtropical", 58, 82) +TEMPERATE = Heat("temperate", 36, 66) +BOREAL = Heat("boreal", 10, 54) +FROZEN = Heat("frozen", -20, 32) + +ALL = [TROPICAL, SUBTROPICAL, TEMPERATE, BOREAL, FROZEN] + + +# Helpers ########################################################################################## + +def within(start:Heat, end:Heat) -> list[Heat]: + return biomeTrait.within(ALL, start, end) diff --git a/tungston/core/ecology/heat_test.py b/tungston/core/ecology/heat_test.py new file mode 100644 index 0000000..22d7026 --- /dev/null +++ b/tungston/core/ecology/heat_test.py @@ -0,0 +1,13 @@ +from pytest import fixture + +import tungston.core.ecology.heat as heat + + +# Tests ############################################################################################ + +def test_within(): + assert ( + heat.within(heat.SUBTROPICAL, heat.BOREAL) + == + [heat.SUBTROPICAL, heat.TEMPERATE, heat.BOREAL] + ) diff --git a/tungston/core/ecology/humidity.py b/tungston/core/ecology/humidity.py new file mode 100644 index 0000000..3cd46c7 --- /dev/null +++ b/tungston/core/ecology/humidity.py @@ -0,0 +1,26 @@ +from tungston.core.ecology.biometrait import BiomeTrait + +import tungston.core.ecology.biometrait as biomeTrait + + +# Class ############################################################################################ + +class Humidity(BiomeTrait): + """ + The general level of humidity present in the air. + """ + pass + + +# Constants ######################################################################################## + +WET = Humidity("wet") +DAMP = Humidity("damp") +DRY = Humidity("dry") + +ALL = [WET, DAMP, DRY] + +# Helpers ########################################################################################## + +def within(start:Humidity, end:Humidity) -> list[Humidity]: + return biomeTrait.within(ALL, start, end) diff --git a/tungston/core/ecology/humidity_test.py b/tungston/core/ecology/humidity_test.py new file mode 100644 index 0000000..9d3999b --- /dev/null +++ b/tungston/core/ecology/humidity_test.py @@ -0,0 +1,9 @@ +from pytest import fixture + +import tungston.core.ecology.humidity as humidity + + +# Tests ############################################################################################ + +def test_within(): + assert humidity.within(humidity.DAMP, humidity.DRY) == [humidity.DAMP, humidity.DRY] diff --git a/tungston/core/ecology/soil.py b/tungston/core/ecology/soil.py new file mode 100644 index 0000000..e72d178 --- /dev/null +++ b/tungston/core/ecology/soil.py @@ -0,0 +1,23 @@ +from tungston.core.ecology.biometrait import BiomeTrait + + +# Class ############################################################################################ + +class Soil(BiomeTrait): + """ + The nature of the soil within a certain region. + """ + pass + + +# Constants ######################################################################################## + +ACIDIC = Soil("acidic") +CLAYEY = Soil("clayey") +FUNGAL = Soil("fungal") +LOAMY = Soil("loamy") +PEATY = Soil("peaty") +ROCKY = Soil("rocky") +SANDY = Soil("sandy") + +ALL = [ACIDIC, CLAYEY, FUNGAL, LOAMY, PEATY, ROCKY, SANDY] diff --git a/tungston/core/ecology/soil_test.py b/tungston/core/ecology/soil_test.py new file mode 100644 index 0000000..f11a625 --- /dev/null +++ b/tungston/core/ecology/soil_test.py @@ -0,0 +1,9 @@ +from pytest import fixture + +import tungston.core.ecology.soil as soil + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/tungston/core/ecology/water.py b/tungston/core/ecology/water.py new file mode 100644 index 0000000..a288715 --- /dev/null +++ b/tungston/core/ecology/water.py @@ -0,0 +1,21 @@ +from tungston.core.ecology.biometrait import BiomeTrait + + +# Class ############################################################################################ + +class Water(BiomeTrait): + """ + The kind of large body of water which dominates a biome. + """ + pass + + +# Constants ######################################################################################## + +RIVER = Water("river") +SWAMP = Water("swamp") +OCEAN = Water("ocean") +COAST = Water("coast") +INLAND = Water("inland") + +ALL = (RIVER, SWAMP, OCEAN, COAST, INLAND) diff --git a/tungston/core/ecology/water_test.py b/tungston/core/ecology/water_test.py new file mode 100644 index 0000000..b7d5c4f --- /dev/null +++ b/tungston/core/ecology/water_test.py @@ -0,0 +1,9 @@ +from pytest import fixture + +import tungston.core.ecology.water as water + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/tungston/core/fauna/__init__.py b/tungston/core/fauna/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tungston/core/fauna/active.py b/tungston/core/fauna/active.py new file mode 100644 index 0000000..610c258 --- /dev/null +++ b/tungston/core/fauna/active.py @@ -0,0 +1,30 @@ +# Class ############################################################################################ + +class Active: + """ + The time of day when a creature is normally most active. + """ + + def __init__(self, name: str, start:int, end:int): + self.name = name + self.start = start + self.end = end + + def __str__(self) -> str: + return self.name + + def __repr__(self) -> str: + return f"Active<{self.name}>{{start:{self.start}, end:{self.end}}}" + + +# Constants ######################################################################################## + +DAY = Active("day", 0, 12000) +NIGHT = Active("night", 13000, 23000) +SUNRISE = Active("sunrise", 23000, 24000) +SUNSET = Active("sunset", 12000, 13000) + +ANY = (SUNRISE, DAY, SUNSET, NIGHT) +DIURNAL = (DAY) +NOCTURNAL = (NIGHT) +CREPUSCULAR = (SUNRISE, SUNSET) diff --git a/tungston/core/fauna/active_test.py b/tungston/core/fauna/active_test.py new file mode 100644 index 0000000..4746b96 --- /dev/null +++ b/tungston/core/fauna/active_test.py @@ -0,0 +1,9 @@ +from pytest import fixture + +import tungston.core.fauna.active as active + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/tungston/core/fauna/group.py b/tungston/core/fauna/group.py new file mode 100644 index 0000000..24c4145 --- /dev/null +++ b/tungston/core/fauna/group.py @@ -0,0 +1,50 @@ +# Class ############################################################################################ + +class Group: + """ + How many individuals are commonly present when encountering a creature. + """ + + def __init__(self, name, smallest, largest): + self.name = name + self.smallest = smallest + self.largest = largest + + def __eq__(self, other) -> bool: + if type(other) != type(self): return False + if other.largest != self.largest: return False + if other.smallest != self.smallest: return False + return True + + def __hash__(self) -> int: + return hash((self.smallest, self.largest)) + + def __str__(self) -> str: + return self.name + + def __repr__(self) -> str: + return str(self) + f"<{self.smallest} to {self.largest}>" + + +# Constants ######################################################################################## + +SOLO = Group("solo", 1, 1) +PAIR = Group("pair", 2, 2) +FAMILY = Group("family", 2, 4) +TROUP = Group("troup", 3, 6) +HERD = Group("herd", 4, 8) + +ALL = [SOLO, PAIR, FAMILY, TROUP, HERD] + + +# Helper Functions ################################################################################# + +def merge(*groups): + if not groups: return SOLO + + result = Group(f"", HERD.largest, SOLO.smallest) + for group in groups: + result.smallest = min(result.smallest, group.smallest) + result.largest = max(result.largest, group.largest) + + return result diff --git a/tungston/core/fauna/group_test.py b/tungston/core/fauna/group_test.py new file mode 100644 index 0000000..4d7069b --- /dev/null +++ b/tungston/core/fauna/group_test.py @@ -0,0 +1,17 @@ +from pytest import fixture + +import tungston.core.fauna.group as group + + +# Fixtures ######################################################################################### + +@fixture(name="atomicFamily") +def createAtomicFamily(): + yield group.merge(group.PAIR, group.FAMILY) + + +# Tests ############################################################################################ + +def test_merge(atomicFamily): + assert atomicFamily.smallest == 2 + assert atomicFamily.largest == 4 diff --git a/tungston/core/fauna/location.py b/tungston/core/fauna/location.py new file mode 100644 index 0000000..f8f705b --- /dev/null +++ b/tungston/core/fauna/location.py @@ -0,0 +1,27 @@ +from tungston.core.ecology.biometrait import BiomeTrait + + +# Class ############################################################################################ + +class Location: + """ + Where a creature is most likely to be encountered. + """ + + def __init__(self, name): + self.name = name + + def __str__(self) -> str: + return self.name + + def __repr__(self) -> str: + return f"Location<{self.name}>" + + +# Constants ######################################################################################## + +OUTSIDE = Location("outside") +CAVE = Location("cave") +WATER = Location("water") + +ALL = [OUTSIDE, CAVE, WATER] diff --git a/tungston/core/fauna/mob.py b/tungston/core/fauna/mob.py new file mode 100644 index 0000000..6743cab --- /dev/null +++ b/tungston/core/fauna/mob.py @@ -0,0 +1,36 @@ +from tungston.core.fauna.active import Active + +import tungston.core.fauna.active as AC + + +# Class ############################################################################################ + +class Mob: + """ + A creature which may appear in the game world. + """ + + def __init__(self, name:str, gameId:str, active:tuple[Active]=AC.DIURNAL): + self.name = name + self.gameId = gameId + self.active = active + + if not self.active: + self.active = AC.DIURNAL + + if isinstance(self.active, Active): + self.active = (self.active,) + + def __eq__(self, other) -> bool: + if type(self) != type(other): return False + if self.gameId != other.gameId: return False + return True + + def __hash__(self) -> int: + return hash(self.gameId) + + def __str__(self) -> str: + return self.name + + def __repr__(self) -> str: + return f"{self.name}<{self.gameId}>{{active:{self.active}}}" diff --git a/tungston/core/fauna/mob_test.py b/tungston/core/fauna/mob_test.py new file mode 100644 index 0000000..3f1b1fc --- /dev/null +++ b/tungston/core/fauna/mob_test.py @@ -0,0 +1,39 @@ +from tungston.core.fauna.mob import Mob +from pytest import fixture + +import tungston.core.fauna.active as AC + + +# Fixtures ######################################################################################### + +@fixture(name="squid") +def createSquid(): + yield Mob("squid", "minecraft:squid", AC.ANY) + +@fixture(name="cow") +def createCow(): + yield Mob("cow", "minecraft:cow", AC.DIURNAL) + +@fixture(name="mobMap") +def createMobMap(cow, squid): + yield { + cow: "beef", + squid: "calamari" + } + + +# Tests ############################################################################################ + +def test_eq(squid): + assert squid == Mob("squid", "minecraft:squid") + assert squid != Mob("squid", "animalsplus:squid") + +def test_hash(cow, squid, mobMap): + assert mobMap[cow] == "beef" + assert mobMap[squid] == "calamari" + +def test_str(squid): + assert str(squid) == "squid" + +def test_repr(cow): + assert repr(cow) == "cow{active:(Active{start:0, end:12000},)}" diff --git a/tungston/core/fauna/mobcatalog.py b/tungston/core/fauna/mobcatalog.py new file mode 100644 index 0000000..232dd05 --- /dev/null +++ b/tungston/core/fauna/mobcatalog.py @@ -0,0 +1,16 @@ +from tungston.core.fauna.mob import Mob + + +# Class ############################################################################################ + +class MobCatalog: + + def __init__(self, mobs): + self.mobs = mobs + + def findByName(self, name): + for mob in self.mobs: + if mob.name == name: + return mob + + return None diff --git a/tungston/core/fauna/mobplacement.py b/tungston/core/fauna/mobplacement.py new file mode 100644 index 0000000..ef200e9 --- /dev/null +++ b/tungston/core/fauna/mobplacement.py @@ -0,0 +1,15 @@ +from tungston.core.habitat import Habitat +from tungston.core.fauna.mob import Mob +from tungston.core.placement import Placement + + +# Class ############################################################################################ + +class MobPlacement(Placement): + """ + A description of where a creature should appear in the world. + """ + + def __init__(self, mob:Mob, habitats:list[Habitat]=None): + super().__init__(habitats) + self.mob = mob diff --git a/tungston/core/fauna/mobplacement_test.py b/tungston/core/fauna/mobplacement_test.py new file mode 100644 index 0000000..1f6701f --- /dev/null +++ b/tungston/core/fauna/mobplacement_test.py @@ -0,0 +1,43 @@ +from pytest import fixture +from tungston.core.ecology.biomefilter import BiomeFilter +from tungston.core.fauna.mob import Mob +from tungston.core.fauna.mobplacement import MobPlacement +from tungston.core.habitat import Habitat + +import tungston.core.ecology.flora as F +import tungston.core.ecology.heat as E + + +# Fixtures ######################################################################################### + +@fixture(name="cow") +def createCow(): + yield Mob("cow", "minecraft:cow") + +@fixture(name="fields") +def createFieldsHabitat(): + yield Habitat(biomeFilter=BiomeFilter([F.FIELD, E.TEMPERATE])) + +@fixture(name="placement") +def createMobPlacement(cow, fields): + yield MobPlacement(cow, fields) + + +# Tests ############################################################################################ + +def test_cowsInFields(placement): + assert str(placement) == ( + "Placement{" + + "habitats: [" + + "Habitat{" + + "altitude: [anywhere <-64 to 320>], " + + "biomeFilter: BiomeFilter([[Flora, Heat]], [[]]), " + + "seasons: [Season, Season, Season, Season], " + + "group: solo<1 to 1>, " + + "location: Location, " + + "scarcity: Scarcity" + + "}" + + "]" + + "}" + ) + diff --git a/tungston/core/geology/__init__.py b/tungston/core/geology/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tungston/core/geology/bulk.py b/tungston/core/geology/bulk.py new file mode 100644 index 0000000..caf865e --- /dev/null +++ b/tungston/core/geology/bulk.py @@ -0,0 +1,33 @@ +import math + + +# Class ############################################################################################ + +class Bulk: + + def __init__(self, name:str, smallest:int, largest:int): + self.name = name + self.smallest = smallest + self.largest = largest + + def __str__(self) -> str: + return self.name + + def __repr__(self) -> str: + return f"Bulk<{self.name}>{{smallest: {self.smallest}, largest: {self.largest}}}" + + def scale(self, factor) -> "Bulk": + return Bulk( + self.name, + math.floor(self.smallest * factor), + math.floor(self.largest * factor) + ) + + +# Constants ######################################################################################## + +SMALL = Bulk("tiny", 250, 500) +MEDIUM = Bulk("small", 500, 1000) +LARGE = Bulk("small", 1000, 2000) + +ALL = [SMALL, MEDIUM, LARGE] diff --git a/tungston/core/geology/bulk_test.py b/tungston/core/geology/bulk_test.py new file mode 100644 index 0000000..c61dc30 --- /dev/null +++ b/tungston/core/geology/bulk_test.py @@ -0,0 +1,20 @@ +from pytest import fixture +from tungston.core.geology.bulk import Bulk + + +# Fixture ########################################################################################## + +@fixture(name="bulk") +def createBulk(): + return Bulk("chunk", 64, 128) + +@fixture(name="scaledBulk") +def scaleBulk(bulk): + yield bulk.scale(2.0) + + +# Fixture ########################################################################################## + +def test_repr(bulk, scaledBulk): + assert repr(bulk) == "Bulk{smallest: 64, largest: 128}" + assert repr(scaledBulk) == "Bulk{smallest: 128, largest: 256}" diff --git a/tungston/core/geology/deposit/__init__.py b/tungston/core/geology/deposit/__init__.py new file mode 100644 index 0000000..0492ab0 --- /dev/null +++ b/tungston/core/geology/deposit/__init__.py @@ -0,0 +1,22 @@ +from tungston.core.ecology.biomefilter import BiomeFilter +from tungston.core.geology.bulk import Bulk +from tungston.core.geology.mineral import Mineral +from tungston.core.scarcity import Scarcity + +import tungston.core.scarcity as scarcity + + +# Class ############################################################################################ + +class Deposit: + + def __init__( + self, + name:str, + scarcity:Scarcity=scarcity.SPARSE, + biomeFilter:BiomeFilter|None=None, + ): + self.name = name + self.biomeFilter = biomeFilter or BiomeFilter() + self.scarcity = scarcity + diff --git a/tungston/core/geology/deposit/metaldeposit.py b/tungston/core/geology/deposit/metaldeposit.py new file mode 100644 index 0000000..51335ab --- /dev/null +++ b/tungston/core/geology/deposit/metaldeposit.py @@ -0,0 +1,43 @@ +from tungston.core.ecology.biomefilter import BiomeFilter +from tungston.core.geology.bulk import Bulk +from tungston.core.geology.deposit import Deposit +from tungston.core.geology.inclusion import Inclusion +from tungston.core.geology.proportion import Proportion +from tungston.core.scarcity import Scarcity + +import tungston.core.geology.bulk as BU +import tungston.core.geology.proportion as PR +import tungston.core.scarcity as SC + + +# Class ############################################################################################ + +class MetalDeposit(Deposit): + + def __init__( + self, + name:str, + inclusions:tuple[Inclusion], + bulk:Bulk=BU.MEDIUM, + proportion:Proportion=PR.BODY, + biomeFilter:BiomeFilter=None, + scarcity:Scarcity=SC.SPARSE, + ): + super().__init__(name, scarcity, biomeFilter) + self.inclusions = inclusions + self.bulk = bulk + self.proportion = proportion + + def __str__(self) -> str: + return self.name + + def __repr__(self) -> str: + return "".join([str(p) for p in [ + "MetalDeposit<", self.name, ">{", + "scarcity: ", repr(self.scarcity), ", ", + "biomeFilter: ", self.biomeFilter, ", ", + "inclusions: [", ", ".join([repr(m) for m in self.inclusions]), "], ", + "bulk: ", repr(self.bulk), ", ", + "proportion: ", repr(self.proportion), + "}" + ]]) diff --git a/tungston/core/geology/deposit/metaldeposit_test.py b/tungston/core/geology/deposit/metaldeposit_test.py new file mode 100644 index 0000000..af39fd9 --- /dev/null +++ b/tungston/core/geology/deposit/metaldeposit_test.py @@ -0,0 +1,55 @@ +from pytest import fixture +from tungston.core.ecology.biomefilter import BiomeFilter +from tungston.core.geology.deposit.metaldeposit import MetalDeposit +from tungston.core.geology.inclusion import Inclusion +from tungston.core.geology.mineral import Mineral +from tungston.core.geology.replacement import Replacement + +import tungston.core.ecology.flora as FL +import tungston.core.geology.bulk as BU +import tungston.core.geology.proportion as PR +import tungston.core.scarcity as SC + + +# Fixtures ######################################################################################### + +@fixture(name="quartz") +def createQuartz(): + yield Mineral("quartz", [ + Replacement("#minecraft:stone_replaceables", "minecraft:quartz_ore"), + Replacement("#minecraft:deepslate_replaceables", "minecraft:deepslate_quartz_ore") + ]) + +@fixture(name="iron") +def createIron(): + yield Mineral("iron", [ + Replacement("#minecraft:stone_replaceables", "minecraft:iron_ore"), + Replacement("#minecraft:deepslate_replaceables", "minecraft:deepslate_iron_ore") + ]) + +@fixture(name="bifIron") +def createBifIron(iron, quartz): + yield MetalDeposit( + name = "bifiron", + biomeFilter = BiomeFilter([FL.FOREST]), + bulk = BU.LARGE, + inclusions = [Inclusion(iron, 60), Inclusion(quartz, 40)], + proportion = PR.LENS, + scarcity = SC.COMMON, + ) + +# Tests ############################################################################################ + +def test_repr(bifIron): + assert repr(bifIron) == ( + "MetalDeposit{" + + "scarcity: Scarcity, " + + "biomeFilter: BiomeFilter([[Flora]], [[]]), " + + "inclusions: [" + + "Inclusion{mineral: iron, weight: 60}, " + + "Inclusion{mineral: quartz, weight: 40}" + + "], " + + "bulk: Bulk{smallest: 1000, largest: 2000}, " + + "proportion: Proportion{ratio: 0.4}" + + "}" + ) diff --git a/tungston/core/geology/depositcatalog.py b/tungston/core/geology/depositcatalog.py new file mode 100644 index 0000000..b47c9d3 --- /dev/null +++ b/tungston/core/geology/depositcatalog.py @@ -0,0 +1,27 @@ +from tungston.core.geology.mineralcatalog import MineralCatalog +from tungston.core.geology.deposit import Deposit +from typing import Iterator + + +# Class ############################################################################################ + +class DepositCatalog: + + def __init__(self, deposits:None|tuple[Deposit]=None): + self._deposits = {} + + for deposit in (deposits or []): + self.add(deposit) + + def add(self, deposit:Deposit) -> "DepositCatalog": + if deposit.name in self._deposits: + raise Exception("Catalog already has an entry for {deposit.name}") + + self._deposits[deposit.name] = deposit + + def all(self) -> Iterator[Deposit]: + for deposit in self._deposits.values(): + yield deposit + + def get(self, name:str) -> Deposit|None: + return self._deposits.get(name, None) diff --git a/tungston/core/geology/depositcatalog_test.py b/tungston/core/geology/depositcatalog_test.py new file mode 100644 index 0000000..faa27a5 --- /dev/null +++ b/tungston/core/geology/depositcatalog_test.py @@ -0,0 +1,53 @@ +from pytest import fixture +from tungston.core.ecology.biomefilter import BiomeFilter +from tungston.core.geology.deposit import Deposit +from tungston.core.geology.deposit.metaldeposit import MetalDeposit +from tungston.core.geology.depositcatalog import DepositCatalog +from tungston.core.geology.inclusion import Inclusion +from tungston.core.geology.mineral import Mineral +from tungston.core.geology.replacement import Replacement + +import tungston.core.ecology.flora as FL +import tungston.core.geology.bulk as BU +import tungston.core.scarcity as SC + + +# Fixtures ######################################################################################### + +@fixture(name="quartz") +def createQuartz(): + yield Mineral("quartz", [ + Replacement("#minecraft:stone_replaceables", "minecraft:quartz_ore"), + Replacement("#minecraft:deepslate_replaceables", "minecraft:deepslate_quartz_ore") + ]) + +@fixture(name="iron") +def createIron(): + yield Mineral("iron", [ + Replacement("#minecraft:stone_replaceables", "minecraft:iron_ore"), + Replacement("#minecraft:deepslate_replaceables", "minecraft:deepslate_iron_ore") + ]) + +@fixture(name="bifiron") +def createBifIron(iron, quartz): + yield MetalDeposit( + name = "bif_iron", + scarcity = SC.COMMON, + biomeFilter = BiomeFilter([FL.FOREST]), + inclusions = [Inclusion(iron, 60), Inclusion(quartz, 40)], + bulk = BU.LARGE, + proportion = 0.5, + ) + +@fixture(name="catalog") +def createCatalog(bifiron): + yield DepositCatalog([bifiron]) + + +# Tests ############################################################################################ + +def test_all(catalog): + assert [m.name for m in catalog.all()] == ["bif_iron"] + +def test_get(catalog): + assert catalog.get("bif_iron").name == "bif_iron" diff --git a/tungston/core/geology/inclusion.py b/tungston/core/geology/inclusion.py new file mode 100644 index 0000000..8eb07a5 --- /dev/null +++ b/tungston/core/geology/inclusion.py @@ -0,0 +1,24 @@ +from tungston.core.geology.mineral import Mineral + + +# Class ############################################################################################ + +class Inclusion: + + def __init__(self, mineral:Mineral, weight:int=100): + self.mineral = mineral + self.weight = weight + + def __str__(self) -> str: + if self.weight == 100: + return self.mineral.name + + return f"{self.mineral.name} ({self.weight}%)" + + def __repr__(self) -> str: + return "".join([str(p) for p in [ + "Inclusion{", + "mineral: ", self.mineral.name, ", ", + "weight: ", self.weight, + "}" + ]]) diff --git a/tungston/core/geology/inclusion_test.py b/tungston/core/geology/inclusion_test.py new file mode 100644 index 0000000..ac0c59a --- /dev/null +++ b/tungston/core/geology/inclusion_test.py @@ -0,0 +1,24 @@ +from pytest import fixture +from tungston.core.geology.inclusion import Inclusion +from tungston.core.geology.mineral import Mineral +from tungston.core.geology.replacement import Replacement + + +# Fixtures #########################################################################################I + +@fixture(name="iron") +def createIron(): + yield Mineral("iron", [ + Replacement("#minecraft:stone_replaceables", "minecraft:iron_ore"), + Replacement("#minecraft:deepslate_replaceables", "minecraft:deepslate_iron_ore") + ]) + +@fixture(name="inclusion") +def createInclusion(iron): + yield Inclusion(iron, 75) + + +# Tests ############################################################################################I + +def test_repr(inclusion): + assert repr(inclusion) == "Inclusion{mineral: iron, weight: 75}" diff --git a/tungston/core/geology/mineral.py b/tungston/core/geology/mineral.py new file mode 100644 index 0000000..8fcc054 --- /dev/null +++ b/tungston/core/geology/mineral.py @@ -0,0 +1,32 @@ +from tungston.core.geology.replacement import Replacement +from tungston.core.resourceid import ResourceId + + +# Class ############################################################################################ + +class Mineral: + + def __init__(self, name:str, replacements:None|tuple[Replacement]=None): + self.name = name + self.replacements = replacements or [] + + def __str__(self) -> str: + return self.name + + def __repr__(self) -> str: + return "".join([str(p) for p in [ + f"Mineral<{self.name}>", "{", + "replacements: [", + ", ".join([str(r) for r in self.replacements]), + "]", + "}" + ]]) + + def addStoneReplacement(self, blockId:str) -> "Mineral": + blockId = ResourceId.canonical(blockId) + self.replacements.append(Replacement(STONE_REPLACEABLES, blockId)) + return self + + def addDeepslateReplacement(self, blockId:str) -> "Mineral": + blockId = ResourceId.canonical(blockId) + self.replacements.append(Replacement(DEEPSLATE_REPLACEABLES, blockId)) diff --git a/tungston/core/geology/mineral_test.py b/tungston/core/geology/mineral_test.py new file mode 100644 index 0000000..fe281ef --- /dev/null +++ b/tungston/core/geology/mineral_test.py @@ -0,0 +1,28 @@ +from tungston.core.geology.mineral import Mineral +from tungston.core.geology.replacement import Replacement +from pytest import fixture + +import tungston.core.geology.mineral as mineral + + +# Fixtures ######################################################################################### + +@fixture(name="iron") +def createIron(): + yield Mineral("iron", [ + Replacement.inStone("iron_ore"), + Replacement.inDeepslate("deepslate_iron_ore"), + ]) + + +# Tests ############################################################################################ + +def test_repr(iron): + assert repr(iron) == ( + "Mineral{" + + "replacements: [" + + "#minecraft:stone_ore_replaceables => minecraft:iron_ore, " + + "#minecraft:deepslate_ore_replaceables => minecraft:deepslate_iron_ore" + + "]" + + "}" + ) diff --git a/tungston/core/geology/mineralcatalog.py b/tungston/core/geology/mineralcatalog.py new file mode 100644 index 0000000..d5440b5 --- /dev/null +++ b/tungston/core/geology/mineralcatalog.py @@ -0,0 +1,26 @@ +from tungston.core.geology.mineral import Mineral +from typing import Iterator + + +# Class ############################################################################################ + +class MineralCatalog: + + def __init__(self, minerals:tuple[Mineral]=None): + self._minerals = {} + + for mineral in (minerals or []): + self.add(mineral) + + def add(self, mineral:Mineral) -> "MineralCatalog": + if mineral.name in self._minerals: + raise Exception(f"Catalog already contains an entry for {mineral.name}") + + self._minerals[mineral.name] = mineral + + def all(self) -> Iterator[Mineral]: + for mineral in self._minerals.values(): + yield mineral + + def get(self, name:str) -> Mineral|None: + return self._minerals.get(name, None) diff --git a/tungston/core/geology/mineralcatalog_test.py b/tungston/core/geology/mineralcatalog_test.py new file mode 100644 index 0000000..4eadafc --- /dev/null +++ b/tungston/core/geology/mineralcatalog_test.py @@ -0,0 +1,34 @@ +from tungston.core.geology.mineral import Mineral +from tungston.core.geology.mineralcatalog import MineralCatalog +from tungston.core.geology.replacement import Replacement +from pytest import fixture + + +# Fixtures ######################################################################################### + +@fixture(name="copper") +def createCopper(): + yield Mineral("copper", [ + Replacement("#minecraft:stone_replaceables", "minecraft:copper_ore"), + Replacement("#minecraft:deepslate_replaceables", "minecraft:deepslate_copper_ore") + ]) + +@fixture(name="iron") +def createIron(): + yield Mineral("iron", [ + Replacement("#minecraft:stone_replaceables", "minecraft:iron_ore"), + Replacement("#minecraft:deepslate_replaceables", "minecraft:deepslate_iron_ore") + ]) + +@fixture(name="catalog") +def createCatalog(copper, iron): + yield MineralCatalog([copper, iron]) + + +# Tests ############################################################################################ + +def test_all(catalog): + assert [m.name for m in catalog.all()] == ["copper", "iron"] + +def test_get(catalog): + assert catalog.get("iron").name == "iron" diff --git a/tungston/core/geology/proportion.py b/tungston/core/geology/proportion.py new file mode 100644 index 0000000..d40bd43 --- /dev/null +++ b/tungston/core/geology/proportion.py @@ -0,0 +1,34 @@ +# Class ############################################################################################ + +class Proportion: + + def __init__(self, name:str, ratio:float): + self.name = name + self.ratio = ratio + + def __eq__(self, other) -> bool: + if type(self) != type(other): return False + if self.name != other.name: return False + return True + + def __hash__(self) -> int: + return hash(self.name) + + def __str__(self) -> str: + return self.name + + def __repr__(self) -> str: + return f"Proportion<{self.name}>{{ratio: {self.ratio}}}" + + +# Constants ######################################################################################## + +BED = Proportion("bed", 0.1) # salt, nitrate, redbed, loam, bif iron, peat coal +LENS = Proportion("lens", 0.4) # bit.coal, aluminum, lapis, quartzite +LODE = Proportion("lode", 0.7) # au.quartz, mvt lead +BODY = Proportion("body", 1.0) # sed.iron +STOCK = Proportion("stock", 1.3) # tin +VENT = Proportion("vent", 1.6) # sulfur +PIPE = Proportion("pipe", 1.9) # por.copper + +ALL = [BED, LENS, LODE, BODY, STOCK, VENT, PIPE] diff --git a/tungston/core/geology/proportion_test.py b/tungston/core/geology/proportion_test.py new file mode 100644 index 0000000..ce8a8fc --- /dev/null +++ b/tungston/core/geology/proportion_test.py @@ -0,0 +1,12 @@ +from pytest import fixture + +import tungston.core.geology.proportion as proportion + + +# Tests ############################################################################################ + +def test_str(): + assert str(proportion.LENS) == "lens" + +def test_repr(): + assert repr(proportion.LENS) == "Proportion{ratio: 0.4}" diff --git a/tungston/core/geology/replacement.py b/tungston/core/geology/replacement.py new file mode 100644 index 0000000..604b4ce --- /dev/null +++ b/tungston/core/geology/replacement.py @@ -0,0 +1,40 @@ +from tungston.core.resourceid import ResourceId + + +# Constants ######################################################################################## + +STONE_REPLACEABLES = "#minecraft:stone_ore_replaceables" +DEEPSLATE_REPLACEABLES = "#minecraft:deepslate_ore_replaceables" + + +# Class ############################################################################################ + +class Replacement: + + @staticmethod + def inStone(target:str, weight:int=100): + return Replacement(STONE_REPLACEABLES, target, weight) + + @staticmethod + def inDeepslate(target:str, weight:int=100): + return Replacement(DEEPSLATE_REPLACEABLES, target, weight) + + def __init__(self, source:str, target:str, weight:int=100): + self.source = ResourceId.canonical(source) + self.target = ResourceId.canonical(target) + self.weight = weight + + def __str__(self) -> str: + if self.weight == 100: + return f"{self.source} => {self.target}" + + return f"{self.source} => {self.target} ({self.weight}%)" + + def __repr__(self) -> str: + return "".join([str(p) for p in [ + "Replacement{" + + "source: ", self.source, ", ", + "target: ", self.target, ", ", + "weight: ", self.weight, + "}" + ]]) diff --git a/tungston/core/geology/replacement_test.py b/tungston/core/geology/replacement_test.py new file mode 100644 index 0000000..844e374 --- /dev/null +++ b/tungston/core/geology/replacement_test.py @@ -0,0 +1,28 @@ +from pytest import fixture +from tungston.core.geology.replacement import Replacement + + +# Fixtures ######################################################################################### + +@fixture(name="replacement") +def createReplacement(): + yield Replacement("#minecraft:stone", "minecraft:iron_ore") + +@fixture(name="weightedReplacement") +def createWeightedReplacement(): + yield Replacement("#minecraft:dirt", "minecraft:gravel", 25) + + +# Tests ############################################################################################ + +def test_repr(replacement, weightedReplacement): + assert repr(replacement) == ( + "Replacement{source: #minecraft:stone, target: minecraft:iron_ore, weight: 100}" + ) + assert repr(weightedReplacement) == ( + "Replacement{source: #minecraft:dirt, target: minecraft:gravel, weight: 25}" + ) + +def test_str(replacement, weightedReplacement): + assert str(replacement) == "#minecraft:stone => minecraft:iron_ore" + assert str(weightedReplacement) == "#minecraft:dirt => minecraft:gravel (25%)" diff --git a/tungston/core/habitat.py b/tungston/core/habitat.py new file mode 100644 index 0000000..d2ec6ce --- /dev/null +++ b/tungston/core/habitat.py @@ -0,0 +1,89 @@ +from tungston.core.altitude import Altitude +from tungston.core.ecology.biomefilter import BiomeFilter +from tungston.core.fauna.group import Group +from tungston.core.fauna.location import Location +from tungston.core.scarcity import Scarcity +from tungston.core.season import Season + +import tungston.core.altitude as A +import tungston.core.fauna.group as G +import tungston.core.fauna.location as L +import tungston.core.scarcity as C +import tungston.core.season as E + + +# Class ############################################################################################ + +class Habitat: + """ + A description of where and when various features may be present. + """ + + def __init__( + self, + + altitudes:tuple[Altitude]|Altitude=[A.ANYWHERE], + biomeFilter:BiomeFilter=None, + seasons:tuple[Season]=E.ALL, + + group:Group=G.SOLO, + location:Location=L.OUTSIDE, + scarcity:Scarcity=C.SPARSE, + ): + self.altitudes = (altitudes,) if isinstance(altitudes, Altitude) else altitudes + self.biomeFilter = biomeFilter or BiomeFilter() + self.seasons = (seasons,) if isinstance(seasons, Season) else seasons + + self.group = group + self.location = location + self.scarcity = scarcity + + self._source = None + + def __str__(self) -> str: + return "".join(str(p) for p in [ + self.altitude, "|", + self.biomeFilter, "|", + self.seasons, "|", + self.group, "|", + self.location, "|", + self.scarcity + ]) + + def __repr__(self) -> str: + return "".join([str(p) for p in [ + "Habitat{", + "altitude: [", ", ".join([repr(a) for a in self.altitudes]), "], ", + "biomeFilter: ", repr(self.biomeFilter), ", ", + "seasons: [", ", ".join([repr(s) for s in self.seasons]), "], ", + "group: ", repr(self.group), ", ", + "location: ", repr(self.location), ", ", + "scarcity: ", repr(self.scarcity), + "}" + ]]) + + def derive(self, **kwargs): + kwargs = { + "altitudes": self.altitudes, + "biomeFilter": self.biomeFilter, + "seasons": self.seasons, + "group": self.group, + "location": self.location, + "scarcity": self.scarcity + } | kwargs + + result = Habitat(**kwargs) + result._source = self + + return result + + def collect(self) -> "tuple[Habitat]": + result = [] + + current = self + while current: + result.append(current) + current = current._source + + return tuple(reversed(result)) + diff --git a/tungston/core/habitat_test.py b/tungston/core/habitat_test.py new file mode 100644 index 0000000..287df29 --- /dev/null +++ b/tungston/core/habitat_test.py @@ -0,0 +1,45 @@ +from pytest import fixture +from tungston.core.ecology.biomefilter import BiomeFilter +from tungston.core.habitat import Habitat + +import tungston.core.ecology.flora as FL +import tungston.core.ecology.heat as HE +import tungston.core.season as SE +import tungston.core.scarcity as SC + + +# Fixtures ######################################################################################### + +@fixture(name="fields") +def createFieldsFilter(): + yield BiomeFilter([FL.FIELD, HE.TEMPERATE]) + +@fixture(name="derivedHabitats") +def createDerivedHabitat(fields): + yield ( + Habitat(biomeFilter=fields, seasons=SE.SUMMER, scarcity=SC.COMMON) + .derive(seasons=SE.AUTUMN, scarcity=SC.UNCOMMON) + .derive(seasons=SE.WINTER, scarcity=SC.ABSENT) + .collect() + ) + +@fixture(name="fields") +def createFieldsHabitat(fields): + yield Habitat(biomeFilter=fields) + +# Tests ############################################################################################ + +def test_derive(derivedHabitats): + assert [h.scarcity for h in derivedHabitats] == [SC.COMMON, SC.UNCOMMON, SC.ABSENT] + +def test_repr(fields): + assert repr(fields) == ( + "Habitat{" + + "altitude: [anywhere <-64 to 320>], " + + "biomeFilter: BiomeFilter([[Flora, Heat]], [[]]), " + + "seasons: [Season, Season, Season, Season], " + + "group: solo<1 to 1>, " + + "location: Location, " + + "scarcity: Scarcity" + + "}" + ) diff --git a/tungston/core/placement.py b/tungston/core/placement.py new file mode 100644 index 0000000..8cd9890 --- /dev/null +++ b/tungston/core/placement.py @@ -0,0 +1,26 @@ +from tungston.core.habitat import Habitat + + +# Class ############################################################################################ + +class Placement: + """ + Abstract base class for placing something into its various habitats. + """ + + def __init__(self, habitats:tuple[Habitat]=None): + self.habitats = habitats + + if not self.habitats: + self.habitats = () + + if isinstance(self.habitats, Habitat): + self.habitats = self.habitats.collect() + + + def __repr__(self) -> str: + return ( + "Placement{" + + f"habitats: [{', '.join([repr(h) for h in self.habitats])}]" + + "}" + ) diff --git a/tungston/core/placement_test.py b/tungston/core/placement_test.py new file mode 100644 index 0000000..73774c1 --- /dev/null +++ b/tungston/core/placement_test.py @@ -0,0 +1,38 @@ +from pytest import fixture +from tungston.core.ecology.biomefilter import BiomeFilter +from tungston.core.habitat import Habitat +from tungston.core.placement import Placement + +import tungston.core.ecology.flora as F +import tungston.core.ecology.heat as E + + +# Fixtures ######################################################################################### + +@fixture(name="fields") +def createFieldsHabitat(): + yield Habitat(biomeFilter=BiomeFilter([F.FIELD, E.TEMPERATE])) + +@fixture(name="placement") +def createPlacement(fields): + yield Placement([fields]) + + +# Tests ############################################################################################ + +def test_repr(placement): + assert repr(placement) == ( + "Placement{" + + "habitats: [" + + "Habitat{" + + "altitude: [anywhere <-64 to 320>], " + + "biomeFilter: BiomeFilter([[Flora, Heat]], [[]]), " + + "seasons: [Season, Season, Season, Season], " + + "group: solo<1 to 1>, " + + "location: Location, " + + "scarcity: Scarcity" + + "}" + + "]" + + "}" + ) + diff --git a/tungston/core/resourceid.py b/tungston/core/resourceid.py new file mode 100644 index 0000000..7872e65 --- /dev/null +++ b/tungston/core/resourceid.py @@ -0,0 +1,56 @@ +from collections.abc import Callable + + +# Class ############################################################################################ + +class ResourceId: + + @staticmethod + def alterName(text:str, doTransform:Callable[[str],str]) -> str: + resourceId = ResourceId.parse(text) + resourceId.name = doTransform(resourceId.name) + return str(resourceId) + + @staticmethod + def canonical(text:str): + return str(ResourceId.parse(text)) + + @staticmethod + def parse(text:str): + isTag = False + if text.startswith("#"): + isTag = True + text = text[1:] + + index = text.find(":") + if index > 0: + mod = text[0:index] + name = text[index+1:] + elif index == 0: + mod = "minecraft" + name = text[1:] + else: + mod = "minecraft" + name = text + + return ResourceId(isTag, mod, name) + + def __init__(self, isTag:bool, mod:str, name:str): + self.isTag = isTag + self.mod = mod + self.name = name + + def __str__(self) -> str: + if not self.isTag: + return f"{self.mod}:{self.name}" + + return f"#{self.mod}:{self.name}" + + def __repr__(self) -> str: + return "".join([str(p) for p in [ + "ResourceId{", + "isTag: ", ("True" if self.isTag else "False"), ", ", + "mod: ", self.mod, ", ", + "name: ", self.name, + "}" + ]]) diff --git a/tungston/core/resourceid_test.py b/tungston/core/resourceid_test.py new file mode 100644 index 0000000..20cc7a3 --- /dev/null +++ b/tungston/core/resourceid_test.py @@ -0,0 +1,16 @@ +from tungston.core.resourceid import ResourceId + + +# Tests ############################################################################################ + +def test_singlePart(): + assert str(ResourceId.parse("alpha")) == "minecraft:alpha" + +def test_leadingSeparator(): + assert str(ResourceId.parse(":bravo")) == "minecraft:bravo" + +def test_fullResource(): + assert str(ResourceId.parse("charlie:delta")) == "charlie:delta" + +def test_fullTag(): + assert str(ResourceId.parse("#charlie:delta")) == "#charlie:delta" diff --git a/tungston/core/scarcity.py b/tungston/core/scarcity.py new file mode 100644 index 0000000..7088d66 --- /dev/null +++ b/tungston/core/scarcity.py @@ -0,0 +1,27 @@ +# Class ############################################################################################ + +class Scarcity: + """ + How frequently something appears within a given region. + """ + + def __init__(self, name): + self.name = name + + def __str__(self) -> str: + return self.name + + def __repr__(self) -> str: + return f"Scarcity<{self.name}>" + +# Constants ######################################################################################## + +ABSENT = Scarcity("absent") +RARE = Scarcity("rare") +UNUSUAL = Scarcity("unusual") +SPARSE = Scarcity("sparse") +UNCOMMON = Scarcity("uncommon") +COMMON = Scarcity("common") +CARPET = Scarcity("carpet") + +ALL = [ABSENT, RARE, UNUSUAL, SPARSE, UNCOMMON, COMMON, CARPET] diff --git a/tungston/core/scarcity_test.py b/tungston/core/scarcity_test.py new file mode 100644 index 0000000..89926d5 --- /dev/null +++ b/tungston/core/scarcity_test.py @@ -0,0 +1,9 @@ +from tungston.core.scarcity import Scarcity +from pytest import fixture + + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/tungston/core/season.py b/tungston/core/season.py new file mode 100644 index 0000000..95d80c4 --- /dev/null +++ b/tungston/core/season.py @@ -0,0 +1,44 @@ +# Class ############################################################################################ + +class Season: + """ + A time of year demonstrating different climate and activity among flora and fauna. + """ + + def __init__(self, name): + self.name = name + + def __str__(self) -> str: + return self.name + + def __repr__(self) -> str: + return f"Season<{self.name}>" + + +# Constants ######################################################################################## + +SPRING = Season("spring") +SUMMER = Season("summer") +AUTUMN = Season("autumn") +WINTER = Season("winter") + +ALL = [SPRING, SUMMER, AUTUMN, WINTER] + +WET = [WINTER, SPRING] +DRY = [SUMMER, AUTUMN] + +HOT = [SUMMER] +COOL = [SPRING, AUTUMN] +COLD = [WINTER] + + +# Constants ######################################################################################## + +def excluding(target:Season) -> list[Season]: + result = [] + + for season in ALL: + if season == target: continue + result.append(season) + + return result diff --git a/tungston/core/season_test.py b/tungston/core/season_test.py new file mode 100644 index 0000000..c3e4199 --- /dev/null +++ b/tungston/core/season_test.py @@ -0,0 +1,16 @@ +from pytest import fixture + +import tungston.core.season as season + + +# Fixtures ######################################################################################### + +@fixture(name="notSummer") +def createNotSummerList(): + yield season.excluding(season.SUMMER) + + +# Tests ############################################################################################ + +def test_excluding(notSummer): + assert ", ".join([str(s) for s in notSummer]) == "spring, autumn, winter" diff --git a/tungston/core/world.py b/tungston/core/world.py new file mode 100644 index 0000000..b1fc9cb --- /dev/null +++ b/tungston/core/world.py @@ -0,0 +1,21 @@ +from tungston.core.ecology.biomecatalog import BiomeCatalog +from tungston.core.fauna.mobcatalog import MobCatalog +from tungston.core.geology.mineralcatalog import MineralCatalog +from tungston.core.geology.depositcatalog import DepositCatalog + + +# Class ############################################################################################ + +class World: + + def __init__( + self, + biomes:BiomeCatalog, + deposits:DepositCatalog, + minerals:MineralCatalog, + mobs:MobCatalog + ): + self.biomes = biomes + self.deposits = deposits + self.minerals = minerals + self.mobs = mobs diff --git a/tungston/core/world_test.py b/tungston/core/world_test.py new file mode 100644 index 0000000..ddb0b63 --- /dev/null +++ b/tungston/core/world_test.py @@ -0,0 +1,7 @@ +from tungston.core.world import World + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/tungston/generator/datapack/__init__.py b/tungston/generator/datapack/__init__.py new file mode 100644 index 0000000..442773f --- /dev/null +++ b/tungston/generator/datapack/__init__.py @@ -0,0 +1,14 @@ +import os + + +# Class ############################################################################################ + +class Datapack: + + def __init__(self, path:str): + self.path = path + + @property + def name(self) -> str: + return os.path.basename(self.path) + diff --git a/tungston/generator/datapack/blockstate.py b/tungston/generator/datapack/blockstate.py new file mode 100644 index 0000000..bbbdb44 --- /dev/null +++ b/tungston/generator/datapack/blockstate.py @@ -0,0 +1,18 @@ +from typing import Any + + +# Class ############################################################################################ + +class BlockState: + + def __init__(self, blockId:str, properties:dict[str,str]=None): + self.blockId = blockId + self.properties = properties + + def asData(self) -> dict[str,Any]: + result = { "Name": self.blockId } + + if self.properties: + result["Properties"] = self.properties + + return result diff --git a/tungston/generator/datapack/blockstate_test.py b/tungston/generator/datapack/blockstate_test.py new file mode 100644 index 0000000..a5790bf --- /dev/null +++ b/tungston/generator/datapack/blockstate_test.py @@ -0,0 +1,20 @@ +from pytest import fixture +from tungston.generator.datapack.blockstate import BlockState + + +# Fixtures ######################################################################################### + +@fixture(name="state") +def createBlockState(): + yield BlockState("minecraft:button", {"waterlogged": "true"}) + + +# Tests ############################################################################################ + +def test_asData(state): + assert state.asData() == { + "Name": "minecraft:button", + "Properties": { + "waterlogged": "true" + } + } diff --git a/tungston/generator/datapack/blockstateprovider/__init__.py b/tungston/generator/datapack/blockstateprovider/__init__.py new file mode 100644 index 0000000..97ec61a --- /dev/null +++ b/tungston/generator/datapack/blockstateprovider/__init__.py @@ -0,0 +1,7 @@ +# Class ############################################################################################ + +class BlockStateProvider: + + def __init__(self, gameId:str): + self.gameId = gameId + diff --git a/tungston/generator/datapack/blockstateprovider/simplestateprovider.py b/tungston/generator/datapack/blockstateprovider/simplestateprovider.py new file mode 100644 index 0000000..6403472 --- /dev/null +++ b/tungston/generator/datapack/blockstateprovider/simplestateprovider.py @@ -0,0 +1,18 @@ +from tungston.generator.datapack.blockstate import BlockState +from tungston.generator.datapack.blockstateprovider import BlockStateProvider +from typing import Any + + +# Class ############################################################################################ + +class SimpleStateProvider(BlockStateProvider): + + def __init__(self, state:BlockState): + super().__init__("minecraft:simple_state_provider") + self.state = state + + def asData(self) -> dict[str, Any]: + return { + "type": self.gameId, + "state": self.state.asData(), + } diff --git a/tungston/generator/datapack/blockstateprovider/simplestateprovider_test.py b/tungston/generator/datapack/blockstateprovider/simplestateprovider_test.py new file mode 100644 index 0000000..86de4e7 --- /dev/null +++ b/tungston/generator/datapack/blockstateprovider/simplestateprovider_test.py @@ -0,0 +1,28 @@ +from tungston.generator.datapack.blockstate import BlockState +from tungston.generator.datapack.blockstateprovider.simplestateprovider import SimpleStateProvider +from pytest import fixture + + +# Fixtures ######################################################################################### + +@fixture(name="state") +def createBlockState(): + yield BlockState("minecraft:button", {"waterlogged": "true"}) + +@fixture(name="provider") +def createProvider(state): + return SimpleStateProvider(state) + + +# Tests ############################################################################################ + +def test_asData(provider): + assert provider.asData() == { + "type": "minecraft:simple_state_provider", + "state": { + "Name": "minecraft:button", + "Properties": { + "waterlogged": "true" + } + } + } diff --git a/tungston/generator/datapack/configuredfeature/__init__.py b/tungston/generator/datapack/configuredfeature/__init__.py new file mode 100644 index 0000000..1e6dc79 --- /dev/null +++ b/tungston/generator/datapack/configuredfeature/__init__.py @@ -0,0 +1,6 @@ +# Class ############################################################################################ + +class ConfiguredFeature: + + def __init__(self, gameId:str): + self.gameId = gameId diff --git a/tungston/generator/datapack/configuredfeature/randompatch.py b/tungston/generator/datapack/configuredfeature/randompatch.py new file mode 100644 index 0000000..8d5ad04 --- /dev/null +++ b/tungston/generator/datapack/configuredfeature/randompatch.py @@ -0,0 +1,31 @@ +from tungston.generator.datapack.configuredfeature.configuredfeature import ConfiguredFeature +from typing import Any + + +# Class ############################################################################################ + +class RandomPatch(ConfiguredFeature): + + def __init__( + self, + gameId:str, + feature:"PlacedFeature", + tries:int=128, + xzSpread:int=7, + ySpread:int=3, + ): + super().__init__("minecraft:random_patch") + + self.feature = feature + self.tries = tries + self.xzSpread = xzSpread + self.ySpread = ySpread + + def asData(self) -> dict[str,Any]: + return { + "type": self.type, + "feature": self.feature.gameId, + "tries": self.tries, + "xz_spread": self.xySpread, + "y_spread": self.ySpread + } diff --git a/tungston/generator/datapack/configuredfeature/randompatch_test.py b/tungston/generator/datapack/configuredfeature/randompatch_test.py new file mode 100644 index 0000000..27e1aaf --- /dev/null +++ b/tungston/generator/datapack/configuredfeature/randompatch_test.py @@ -0,0 +1,38 @@ +from pytest import fixture +from tungston.generator.datapack.blockstate import BlockState +from tungston.generator.datapack.blockstateprovider.simplestateprovider import SimpleStateProvider +from tungston.generator.datapack.configuredfeature.simpleblock import SimpleBlock + + +# Fixtures ######################################################################################### + +@fixture(name="state") +def createBlockState(): + yield BlockState("minecraft:button", {"waterlogged": "true"}) + +@fixture(name="provider") +def createProvider(state): + return SimpleStateProvider(state) + +@fixture(name="feature") +def createSimpleBlockFeature(provider): + return SimpleBlock(provider) + + +# Tests ############################################################################################ + +def test_asData(feature): + assert feature.asData() == { + "type": "minecraft:simple_block", + "config": { + "to_place": { + "type": "minecraft:simple_state_provider", + "state": { + "Name": "minecraft:button", + "Properties": { + "waterlogged": "true" + } + } + } + } + } diff --git a/tungston/generator/datapack/configuredfeature/simpleblock.py b/tungston/generator/datapack/configuredfeature/simpleblock.py new file mode 100644 index 0000000..a7d5879 --- /dev/null +++ b/tungston/generator/datapack/configuredfeature/simpleblock.py @@ -0,0 +1,20 @@ +from tungston.generator.datapack.blockstateprovider import BlockStateProvider +from tungston.generator.datapack.configuredfeature import ConfiguredFeature +from typing import Any + + +# Class ############################################################################################ + +class SimpleBlock(ConfiguredFeature): + + def __init__(self, toPlace:BlockStateProvider): + super().__init__("minecraft:simple_block") + self.toPlace = toPlace + + def asData(self) -> dict[str, Any]: + return { + "type": self.gameId, + "config": { + "to_place": self.toPlace.asData() + } + } diff --git a/tungston/generator/datapack/configuredfeature/simpleblock_test.py b/tungston/generator/datapack/configuredfeature/simpleblock_test.py new file mode 100644 index 0000000..27e1aaf --- /dev/null +++ b/tungston/generator/datapack/configuredfeature/simpleblock_test.py @@ -0,0 +1,38 @@ +from pytest import fixture +from tungston.generator.datapack.blockstate import BlockState +from tungston.generator.datapack.blockstateprovider.simplestateprovider import SimpleStateProvider +from tungston.generator.datapack.configuredfeature.simpleblock import SimpleBlock + + +# Fixtures ######################################################################################### + +@fixture(name="state") +def createBlockState(): + yield BlockState("minecraft:button", {"waterlogged": "true"}) + +@fixture(name="provider") +def createProvider(state): + return SimpleStateProvider(state) + +@fixture(name="feature") +def createSimpleBlockFeature(provider): + return SimpleBlock(provider) + + +# Tests ############################################################################################ + +def test_asData(feature): + assert feature.asData() == { + "type": "minecraft:simple_block", + "config": { + "to_place": { + "type": "minecraft:simple_state_provider", + "state": { + "Name": "minecraft:button", + "Properties": { + "waterlogged": "true" + } + } + } + } + } diff --git a/tungston/generator/datapack/heightmaptype.py b/tungston/generator/datapack/heightmaptype.py new file mode 100644 index 0000000..8738b85 --- /dev/null +++ b/tungston/generator/datapack/heightmaptype.py @@ -0,0 +1,24 @@ +# Class ############################################################################################ + +class HeightMapType: + """ + A cached record of the top block at all points in the world. + + see: https://minecraft.wiki/w/Heightmap + """ + + def __init__(self, gameId:str): + self.gameId = gameId + + def asData(self) -> str: + return self.gameId + + +# Constants ######################################################################################## + +MOTION_BLOCKING = HeightMapType("MOTION_BLOCKING") +MOTION_BLOCKING_NO_LEAVES = HeightMapType("MOTION_BLOCKING_NO_LEAVES") +OCEAN_FLOOR = HeightMapType("OCEAN_FLOOR") +OCEAN_FLOOR_WG = HeightMapType("OCEAN_FLOOR_WG") +WORLD_SURFACE = HeightMapType("WORLD_SURFACE") +WORLD_SURFACE_WG = HeightMapType("WORLD_SURFACE_WG") diff --git a/tungston/generator/datapack/heightmaptype_test.py b/tungston/generator/datapack/heightmaptype_test.py new file mode 100644 index 0000000..0328339 --- /dev/null +++ b/tungston/generator/datapack/heightmaptype_test.py @@ -0,0 +1,7 @@ +from tungston.generator.datapack.heightmaptype import HeightMapType + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/tungston/generator/datapack/placedfeature.py b/tungston/generator/datapack/placedfeature.py new file mode 100644 index 0000000..ca8ef54 --- /dev/null +++ b/tungston/generator/datapack/placedfeature.py @@ -0,0 +1,6 @@ +# Class ############################################################################################ + +class PlacedFeature: + + def __init__(self, gameId:str): + self.gameId = gameId diff --git a/tungston/generator/datapack/placedfeature_test.py b/tungston/generator/datapack/placedfeature_test.py new file mode 100644 index 0000000..27bf6fa --- /dev/null +++ b/tungston/generator/datapack/placedfeature_test.py @@ -0,0 +1,6 @@ +from tungston.generator.datapack.placedfeature import PlacedFeature + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/tungston/generator/datapack/placement/__init__.py b/tungston/generator/datapack/placement/__init__.py new file mode 100644 index 0000000..58d433f --- /dev/null +++ b/tungston/generator/datapack/placement/__init__.py @@ -0,0 +1,6 @@ +# Class ############################################################################################ + +class Placement: + + def __init__(self, gameId:str): + self.gameId = gameId diff --git a/tungston/generator/datapack/placement/biome.py b/tungston/generator/datapack/placement/biome.py new file mode 100644 index 0000000..c9a4f01 --- /dev/null +++ b/tungston/generator/datapack/placement/biome.py @@ -0,0 +1,13 @@ +from tungston.generator.datapack.placement import Placement +from typing import Any + +# Class ############################################################################################ + +class Biome(Placement): + + def __init__(self): + super().__init__("minecraft:biome") + + def asData(self) -> dict[str,Any]: + return { "type": self.gameId } + diff --git a/tungston/generator/datapack/placement/biome_test.py b/tungston/generator/datapack/placement/biome_test.py new file mode 100644 index 0000000..f479a2a --- /dev/null +++ b/tungston/generator/datapack/placement/biome_test.py @@ -0,0 +1,18 @@ +from pytest import fixture +from tungston.generator.datapack.placement.biome import Biome + + +# Fixtures ######################################################################################### + +@fixture(name="placement") +def createPlacement(): + yield Biome() + + +# Tests ############################################################################################ + +def test_asData(placement): + assert placement.asData() == { + "type": "minecraft:biome", + } + diff --git a/tungston/generator/datapack/placement/heightmap.py b/tungston/generator/datapack/placement/heightmap.py new file mode 100644 index 0000000..51b00a3 --- /dev/null +++ b/tungston/generator/datapack/placement/heightmap.py @@ -0,0 +1,17 @@ +from tungston.generator.datapack.placement import Placement +from tungston.generator.datapack.heightmaptype import HeightMapType +from typing import Any + +# Class ############################################################################################ + +class HeightMap(Placement): + + def __init__(self, heightMap:HeightMapType): + super().__init__("minecraft:heightmap") + self.heightMap = heightMap + + def asData(self) -> dict[str,Any]: + return { + "type": self.gameId, + "heightmap": self.heightMap.asData() + } diff --git a/tungston/generator/datapack/placement/heightmap_test.py b/tungston/generator/datapack/placement/heightmap_test.py new file mode 100644 index 0000000..aaa9e46 --- /dev/null +++ b/tungston/generator/datapack/placement/heightmap_test.py @@ -0,0 +1,20 @@ +from pytest import fixture +from tungston.generator.datapack.placement.heightmap import HeightMap +from tungston.generator.datapack.heightmaptype import WORLD_SURFACE + + +# Fixtures ######################################################################################### + +@fixture(name="placement") +def createPlacement(): + yield HeightMap(WORLD_SURFACE) + + +# Tests ############################################################################################ + +def test_asData(placement): + assert placement.asData() == { + "type": "minecraft:heightmap", + "heightmap": "WORLD_SURFACE" + } + diff --git a/tungston/generator/datapack/placement/insquare.py b/tungston/generator/datapack/placement/insquare.py new file mode 100644 index 0000000..8e88b76 --- /dev/null +++ b/tungston/generator/datapack/placement/insquare.py @@ -0,0 +1,13 @@ +from tungston.generator.datapack.placement import Placement +from typing import Any + +# Class ############################################################################################ + +class InSquare(Placement): + + def __init__(self): + super().__init__("minecraft:in_square") + + def asData(self) -> dict[str,Any]: + return { "type": self.gameId } + diff --git a/tungston/generator/datapack/placement/insquare_test.py b/tungston/generator/datapack/placement/insquare_test.py new file mode 100644 index 0000000..f8ea5cc --- /dev/null +++ b/tungston/generator/datapack/placement/insquare_test.py @@ -0,0 +1,18 @@ +from pytest import fixture +from tungston.generator.datapack.placement.insquare import InSquare + + +# Fixtures ######################################################################################### + +@fixture(name="placement") +def createPlacement(): + yield InSquare() + + +# Tests ############################################################################################ + +def test_asData(placement): + assert placement.asData() == { + "type": "minecraft:in_square", + } + diff --git a/tungston/generator/datapack/placement/rarityfilter.py b/tungston/generator/datapack/placement/rarityfilter.py new file mode 100644 index 0000000..fc07430 --- /dev/null +++ b/tungston/generator/datapack/placement/rarityfilter.py @@ -0,0 +1,17 @@ +from tungston.generator.datapack.placement import Placement +from typing import Any + +# Class ############################################################################################ + +class RarityFilter(Placement): + + def __init__(self, chance:int): + super().__init__("minecraft:rarity_filter") + self.chance = chance + + def asData(self) -> dict[str,Any]: + return { + "type": self.gameId, + "chance": self.chance + } + diff --git a/tungston/generator/datapack/placement/rarityfilter_test.py b/tungston/generator/datapack/placement/rarityfilter_test.py new file mode 100644 index 0000000..64e2c95 --- /dev/null +++ b/tungston/generator/datapack/placement/rarityfilter_test.py @@ -0,0 +1,19 @@ +from pytest import fixture +from tungston.generator.datapack.placement.rarityfilter import RarityFilter + + +# Fixtures ######################################################################################### + +@fixture(name="placement") +def createPlacement(): + yield RarityFilter(4) + + +# Tests ############################################################################################ + +def test_asData(placement): + assert placement.asData() == { + "type": "minecraft:rarity_filter", + "chance": 4 + } + diff --git a/tungston/generator/markdown/__init__.py b/tungston/generator/markdown/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tungston/generator/markdown/mineralreport.py b/tungston/generator/markdown/mineralreport.py new file mode 100644 index 0000000..fa70c0f --- /dev/null +++ b/tungston/generator/markdown/mineralreport.py @@ -0,0 +1,19 @@ +from tungston.core.world import World +from tungston.generator.markdown.report import Report + + +# Class ############################################################################################ + +class MineralReport(Report): + + def build(self): + for mineral in self.world.minerals.all(): + self.line(f"# Mineral: {mineral.name}") + self.line() + + self.indent() + for replacement in mineral.replacements: + self.line(str(replacement)) + self.outdent() + + self.line() diff --git a/tungston/generator/markdown/mineralreport_test.py b/tungston/generator/markdown/mineralreport_test.py new file mode 100644 index 0000000..c63bfa6 --- /dev/null +++ b/tungston/generator/markdown/mineralreport_test.py @@ -0,0 +1,55 @@ +from pytest import fixture +from tungston.core.geology.mineral import Mineral +from tungston.core.geology.mineralcatalog import MineralCatalog +from tungston.core.geology.replacement import Replacement +from tungston.core.world import World +from tungston.generator.markdown.mineralreport import MineralReport + +import textwrap + + +# Fixtures ######################################################################################### + +@fixture(name="copper") +def createCopper(): + yield Mineral("copper", [ + Replacement("#minecraft:stone_replaceables", "minecraft:copper_ore"), + Replacement("#minecraft:deepslate_replaceables", "minecraft:deepslate_copper_ore") + ]) + +@fixture(name="iron") +def createIron(): + yield Mineral("iron", [ + Replacement("#minecraft:stone_replaceables", "minecraft:iron_ore"), + Replacement("#minecraft:deepslate_replaceables", "minecraft:deepslate_iron_ore") + ]) + +@fixture(name="minerals") +def createMineralCatalog(copper, iron): + yield MineralCatalog([copper, iron]) + +@fixture(name="world") +def createWorld(minerals): + yield World(None, None, minerals, None) + +@fixture(name="report") +def createReport(world): + report = MineralReport(world) + report.build() + yield report + + +# Tests ############################################################################################ + +def test_report(report): + assert str(report) == textwrap.dedent(""" + # Mineral: copper + + #minecraft:stone_replaceables => minecraft:copper_ore + #minecraft:deepslate_replaceables => minecraft:deepslate_copper_ore + + # Mineral: iron + + #minecraft:stone_replaceables => minecraft:iron_ore + #minecraft:deepslate_replaceables => minecraft:deepslate_iron_ore + """).strip() diff --git a/tungston/generator/markdown/report.py b/tungston/generator/markdown/report.py new file mode 100644 index 0000000..e934830 --- /dev/null +++ b/tungston/generator/markdown/report.py @@ -0,0 +1,70 @@ +from collections.abc import Iterator +from tungston.core.world import World + + +# Constants ######################################################################################## + +INDENT = " " + +# Class ############################################################################################ + +class Report: + + def __init__(self, world:World): + self.world = world + self.reset() + + def __str__(self) -> str: + return "\n".join(self._lines).strip() + + def __repr__(self) -> str: + return ( + "Report{" + + f"lines: {len(self._lines)} lines, " + + f"lineBuffer: {len(self._lineBuffer)} chunks, " + + f"indent: {self._indent}" + + "}" + ) + + def build(self): + raise NotImplementedError() + + def reset(self) -> "Report": + self._lineBuffer = [] + self._lines = [] + self._indent = 0 + return self + + def asLines(self) -> Iterator[str]: + for line in self._lines: + yield line + + # Helper Methods ########################################################### + + def indent(self) -> "Report": + self._indent += 1 + self._lineBuffer.insert(0, INDENT) + return self + + def line(self, text:str="") -> "Report": + self.text(text) + + self._lines.append("".join(self._lineBuffer)) + self._lineBuffer = [] + while len(self._lineBuffer) < self._indent: + self._lineBuffer.append(INDENT) + + return self + + def outdent(self) -> "Report": + self._indent = max(0, self._indent - 1) + + if self._lineBuffer: + if self._lineBuffer[0] == INDENT: + self._lineBuffer.pop() + + return self + + def text(self, text:str) -> "Report": + self._lineBuffer.append(str(text)) + return self diff --git a/tungston/generator/markdown/report_test.py b/tungston/generator/markdown/report_test.py new file mode 100644 index 0000000..0f88af2 --- /dev/null +++ b/tungston/generator/markdown/report_test.py @@ -0,0 +1,31 @@ +from pytest import fixture +from tungston.generator.markdown.report import Report + + +# Fixtures ######################################################################################### + +@fixture(name="emptyReport") +def createEmptyReport(): + return Report() + +@fixture(name="report") +def createReport(): + return ( + Report(None) + .text("alpha") + .line("bravo") + .indent() + .line("charlie") + .indent() + .line("delta") + .outdent() + .line("echo") + ) + +# Tests ############################################################################################ + +def test_repr(report): + assert repr(report) == "Report{lines: 4 lines, lineBuffer: 1 chunks, indent: 1}" + +def test_str(report): + assert str(report) == "alphabravo\n charlie\n delta\n echo" diff --git a/tungston/modpack/mysteriousisland/__init__.py b/tungston/modpack/mysteriousisland/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tungston/modpack/mysteriousisland/biomecatalog.py b/tungston/modpack/mysteriousisland/biomecatalog.py new file mode 100644 index 0000000..bf04c00 --- /dev/null +++ b/tungston/modpack/mysteriousisland/biomecatalog.py @@ -0,0 +1,165 @@ +from tungston.core.ecology.biome import Biome +from tungston.core.ecology.biomecatalog import BiomeCatalog +from tungston.core.ecology.biomefilter import BiomeFilter + +import tungston.core.ecology.flora as F +import tungston.core.ecology.geology as G +import tungston.core.ecology.heat as E +import tungston.core.ecology.humidity as U +import tungston.core.ecology.soil as S +import tungston.core.ecology.water as W + +# Constants ######################################################################################## + +CATALOG = BiomeCatalog([ + Biome("aberdeen", "minecraft:windswept_gravelly_hills", + F.BARREN, G.METAMORPHIC, E.BOREAL, U.DAMP, S.ROCKY, W.INLAND + ), + Biome("archangel", "minecraft:frozen_ocean", + F.BARREN, G.SEDIMENTARY, E.FROZEN, U.WET, S.SANDY, W.OCEAN + ), + Biome("aspen", "minecraft:frozen_peaks", + F.BARREN, G.IGNEOUS, E.FROZEN, U.WET, S.ROCKY, W.INLAND + ), + Biome("bombay", "minecraft:lukewarm_ocean", + F.BARREN, G.SEDIMENTARY, E.SUBTROPICAL, U.WET, S.SANDY, W.OCEAN + ), + Biome("boston", "minecraft:cold_ocean", + F.BARREN, G.SEDIMENTARY, E.BOREAL, U.WET, S.CLAYEY, W.OCEAN + ), + Biome("bryce", "minecraft:eroded_badlands", + F.BARREN, G.SEDIMENTARY, E.SUBTROPICAL, U.DRY, S.CLAYEY, W.INLAND + ), + Biome("calcutta", "minecraft:mangrove_swamp", + F.FOREST, G.SEDIMENTARY, E.SUBTROPICAL, U.WET, S.CLAYEY, W.INLAND + ), + Biome("cornwall", "minecraft:windswept_hills", + F.BARREN, G.METAMORPHIC, E.BOREAL, U.DAMP, S.ROCKY, W.INLAND + ), + Biome("dallas", "minecraft:savanna", + F.FIELD, G.SEDIMENTARY, E.SUBTROPICAL, U.DRY, S.SANDY, W.INLAND + ), + Biome("duluth", "minecraft:frozen_river", + F.BARREN, G.SEDIMENTARY, E.FROZEN, U.WET, S.SANDY, W.RIVER + ), + Biome("durango", "minecraft:savanna_plateau", + F.FIELD, G.IGNEOUS, E.SUBTROPICAL, U.DRY, S.SANDY, W.INLAND + ), + Biome("freiburg", "minecraft:dark_forest", + F.CANOPY, G.SEDIMENTARY, E.TEMPERATE, U.WET, S.CLAYEY, W.INLAND + ), + Biome("glasgow", "minecraft:windswept_forest", + F.CLEARING, G.METAMORPHIC, E.BOREAL, U.DAMP, S.ACIDIC, W.INLAND + ), + Biome("haarlem", "minecraft:flower_forest", + F.CLEARING, G.SEDIMENTARY, E.TEMPERATE, U.DAMP, S.LOAMY, W.INLAND + ), + Biome("halifax", "minecraft:deep_cold_ocean", + F.BARREN, G.SEDIMENTARY, E.BOREAL, U.WET, S.SANDY, W.OCEAN + ), + Biome("hammerfest", "minecraft:ice_spikes", + F.BARREN, G.METAMORPHIC, E.FROZEN, U.WET, S.ROCKY, W.INLAND + ), + Biome("havana", "minecraft:deep_lukewarm_ocean", + F.BARREN, G.SEDIMENTARY, E.SUBTROPICAL, U.WET, S.SANDY, W.OCEAN + ), + Biome("hilo", "minecraft:mushroom_fields", + F.CLEARING, G.IGNEOUS, E.SUBTROPICAL, U.WET, S.FUNGAL, W.INLAND + ), + Biome("honolulu", "minecraft:deep_ocean", + F.BARREN, G.SEDIMENTARY, E.TEMPERATE, U.WET, S.SANDY, W.OCEAN + ), + Biome("innnesbruk", "minecraft:meadow", + F.FIELD, G.SEDIMENTARY, E.BOREAL, U.DAMP, S.PEATY, W.INLAND + ), + Biome("irkutsk", "minecraft:taiga", + F.FOREST, G.METAMORPHIC, E.BOREAL, U.DAMP, S.ACIDIC, W.INLAND + ), + Biome("jackson", "minecraft:jagged_peaks", + F.BARREN, G.METAMORPHIC, E.BOREAL, U.DRY, S.ROCKY, W.INLAND + ), + Biome("juneau", "minecraft:old_growth_spruce_taiga", + F.FOREST, G.METAMORPHIC, E.BOREAL, U.DAMP, S.PEATY, W.INLAND + ), + Biome("kansascity", "minecraft:plains", + F.FIELD, G.SEDIMENTARY, E.TEMPERATE, U.DAMP, S.LOAMY, W.INLAND + ), + Biome("kola", "minecraft:snowy_taiga", + F.BARREN, G.METAMORPHIC, E.FROZEN, U.DAMP, S.ACIDIC, W.INLAND + ), + Biome("kyoto", "minecraft:cherry_grove", + F.CLEARING, G.SEDIMENTARY, E.TEMPERATE, U.DAMP, S.ROCKY, W.INLAND + ), + Biome("madras", "minecraft:sparse_jungle", + F.CLEARING, G.SEDIMENTARY, E.TROPICAL, U.WET, S.ACIDIC, W.INLAND + ), + Biome("memphis", "minecraft:river", + F.CLEARING, G.SEDIMENTARY, E.TEMPERATE, U.WET, S.SANDY, W.RIVER + ), + Biome("minsk", "minecraft:old_growth_birch_forest", + F.FOREST, G.SEDIMENTARY, E.TEMPERATE, U.DAMP, S.ACIDIC, W.INLAND + ), + Biome("moab", "minecraft:windswept_savanna", + F.FIELD, G.IGNEOUS, E.SUBTROPICAL, U.DRY, S.ROCKY, W.INLAND + ), + Biome("mobile", "minecraft:swamp", + F.CLEARING, G.SEDIMENTARY, E.TEMPERATE, U.WET, S.PEATY, W.SWAMP + ), + Biome("moscow", "minecraft:snowy_plains", + F.FIELD, G.SEDIMENTARY, E.FROZEN, U.DAMP, S.LOAMY, W.INLAND + ), + Biome("nassau", "minecraft:warm_ocean", + F.BARREN, G.SEDIMENTARY, E.TROPICAL, U.WET, S.SANDY, W.COAST + ), + Biome("nice", "minecraft:beach", + F.BARREN, G.SEDIMENTARY, E.SUBTROPICAL, U.DAMP, S.SANDY, W.COAST + ), + Biome("nuuk", "minecraft:beach", + F.BARREN, G.SEDIMENTARY, E.FROZEN, U.DAMP, S.SANDY, W.COAST + ), + Biome("perm", "minecraft:old_growth_pine_taiga", + F.FOREST, G.METAMORPHIC, E.BOREAL, U.DAMP, S.ACIDIC, W.INLAND + ), + Biome("phoenix", "minecraft:desert", + F.BARREN, G.SEDIMENTARY, E.TROPICAL, U.DRY, S.SANDY, W.INLAND + ), + Biome("plymouth", "minecraft:stony_shore", + F.BARREN, G.METAMORPHIC, E.TEMPERATE, U.DAMP, S.ROCKY, W.COAST + ), + Biome("portland", "minecraft:forest", + F.FOREST, G.SEDIMENTARY, E.TEMPERATE, U.DAMP, S.LOAMY, W.INLAND + ), + Biome("quito", "minecraft:stony_peaks", + F.BARREN, G.IGNEOUS, E.BOREAL, U.DRY, S.ROCKY, W.INLAND + ), + Biome("rangoon", "minecraft:bamboo_jungle", + F.BARREN, G.SEDIMENTARY, E.SUBTROPICAL, U.DRY, S.LOAMY, W.INLAND + ), + Biome("sanfrancisco", "minecraft:ocean", + F.BARREN, G.SEDIMENTARY, E.TEMPERATE, U.WET, S.SANDY, W.OCEAN + ), + Biome("santafe", "minecraft:wooded_badlands", + F.CLEARING, G.SEDIMENTARY, E.SUBTROPICAL, U.DRY, S.CLAYEY, W.INLAND + ), + Biome("singapore", "minecraft:jungle", + F.CANOPY, G.SEDIMENTARY, E.TROPICAL, U.WET, S.ACIDIC, W.INLAND + ), + Biome("tombstone", "minecraft:badlands", + F.BARREN, G.SEDIMENTARY, E.SUBTROPICAL, U.DRY, S.CLAYEY, W.INLAND + ), + Biome("topeka", "minecraft:sunflower_plains", + F.FIELD, G.SEDIMENTARY, E.TEMPERATE, U.DAMP, S.LOAMY, W.INLAND + ), + Biome("tromso", "minecraft:deep_frozen_ocean", + F.BARREN, G.SEDIMENTARY, E.FROZEN, U.WET, S.SANDY, W.OCEAN + ), + Biome("umea", "minecraft:grove", + F.CLEARING, G.METAMORPHIC, E.FROZEN, U.DAMP, S.ACIDIC, W.INLAND + ), + Biome("warsaw", "minecraft:birch_forest", + F.FOREST, G.SEDIMENTARY, E.TEMPERATE, U.DAMP, S.ACIDIC, W.INLAND + ), + Biome("zurich", "minecraft:snowy_slopes", + F.BARREN, G.METAMORPHIC, E.FROZEN, U.DAMP, S.ROCKY, W.INLAND + ), +]) diff --git a/tungston/modpack/mysteriousisland/depositcatalog.py b/tungston/modpack/mysteriousisland/depositcatalog.py new file mode 100644 index 0000000..73ae0c0 --- /dev/null +++ b/tungston/modpack/mysteriousisland/depositcatalog.py @@ -0,0 +1,28 @@ +from tungston.core.ecology.biomefilter import BiomeFilter as BF +from tungston.core.geology.depositcatalog import DepositCatalog +from tungston.core.geology.deposit.inclusion import Inclusion as I +from tungston.core.geology.deposit.metaldeposit import MetalDeposit +from tungston.modpack.mysteriousisland.mineralcatalog import CATALOG as M + +import tungston.core.altitude as AL +import tungston.core.ecology.flora as FL +import tungston.core.ecology.geology as GE +import tungston.core.ecology.heat as HE +import tungston.core.ecology.humidity as HU +import tungston.core.ecology.soil as SO +import tungston.core.ecology.water as WA +import tungston.core.geology.bulk as BU +import tungston.core.scarcity as SC + +# Catalog ########################################################################################## + +CATALOG = C = DepositCatalog(minerals) + +C.add(MetalDeposit( + name = "bif_iron", + biomeFilter = BF([GE.METAMORPHIC, (HE.BOREAL, HE.FROZEN), HU.DAMP]), + scarcity = SC.COMMON, + minerals = [I(M.get("iron"), 50), I(M.get("quartz"), 45), I(M.get("uranium"), 5)], + bulk = BU.LARGE, + proportion = 0.2, +)) diff --git a/tungston/modpack/mysteriousisland/mineralcatalog.py b/tungston/modpack/mysteriousisland/mineralcatalog.py new file mode 100644 index 0000000..b303f80 --- /dev/null +++ b/tungston/modpack/mysteriousisland/mineralcatalog.py @@ -0,0 +1,109 @@ +from tungston.core.geology.mineral import Mineral +from tungston.core.geology.mineralcatalog import MineralCatalog +from tungston.core.geology.replacement import Replacement + + +# Constants ######################################################################################## + +IE = "immersiveengineering" +OQ = "overworldquartzore" +RC = "railcraft" + + +# Helpers ########################################################################################## + +def makeMineral(name:str, blockId:str, deepslateBlockId:None|str=None) -> Mineral: + deepslateBlockId = deepslateBlockId if deepslateBlockId else blockId + + return Mineral(name, [ + R.inStone(blockId), + R.inDeepslate(blockId) + ]) + +def makeOreMineral(name:str) -> Mineral: + return Mineral(name, [ + R.inStone(f"{name}_ore"), + R.inDeepslate(f"deepslate_{name}_ore") + ]) + +def makeImmersiveEngineeringOreMineral(name:str) -> Mineral: + return Mineral(name, [ + R.inStone(f"{IE}:ore_{name}"), + R.inDeepslate("{IE}:deepslate_ore_{name}") + ]), + +def makeRailcraftOreMineral(name:str) -> Mineral: + return Mineral(name, [ + R.inStone(f"{RC}:{name}_ore"), + R.inDeepslate("{RC}:deepslate_{name}_ore") + ]), + + +# Catalog ########################################################################################## + +CATALOG = C = MineralCatalog() + +# Basic Ores +C.add(makeOreMineral("coal")) +C.add(makeOreMineral("copper")) +C.add(makeOreMineral("diamond")) +C.add(makeOreMineral("emerald")) +C.add(makeOreMineral("gold")) +C.add(makeOreMineral("iron")) +C.add(makeOreMineral("lapis")) +C.add(makeOreMineral("redstone")) + +# Crystals +C.add(makeMineral("amethyst", "amethyst_block")) +C.add(makeMineral("glowstone", "glowstone")) +C.add(makeMineral("quartz", f"{OQ}:quartz_ore") f"{OQ}:deepslate_quartz_ore") +C.add(makeMineral("salt", "butcher:saltblock")) + +# Earth, gravel, etc. +C.add(makeMineral("clay", "clay")) +C.add(makeMineral("coarsedirt", "coarse_dirt")) +C.add(makeMineral("dirt", "dirt")) +C.add(makeMineral("gravel", "gravel")) +C.add(makeMineral("loam", "farmersdelight:rich_soil")) +C.add(makeMineral("packedice", "packed_ice")) +C.add(makeMineral("peat", "kubejs:peat_block")) +C.add(makeMineral("redsand", "redsand")) +C.add(makeMineral("sand", "sand")) +C.add(makeMineral("soulsand", "soulsand")) + +# Stone +C.add(makeMineral("andesite", "andesite")) +C.add(makeMineral("arkrose", "red_sandstone")) +C.add(makeMineral("basalt", "basalt")) +C.add(makeMineral("breccia", "cobblestone")) +C.add(makeMineral("chalk", "calcite")) +C.add(makeMineral("diorite", "diorite")) +C.add(makeMineral("dolostone", "end_stone")) +C.add(makeMineral("gneiss", "deepslate")) +C.add(makeMineral("granite", "granite")) +C.add(makeMineral("greywacke", "stone")) +C.add(makeMineral("komatite", "blackstone")) +C.add(makeMineral("limestone", "dripstone_block")) +C.add(makeMineral("magma", "magma_block")) +C.add(makeMineral("marble", f"{RC}:quarried_stone")) +C.add(makeMineral("netherite", "ancient_debris")) +C.add(makeMineral("obsidian", "obsidian")) +C.add(makeMineral("pumice", "netherrack")) +C.add(makeMineral("sandstone", "sandstone")) +C.add(makeMineral("tuff", "tuff")) + +# Immersive Engineering Ores +C.add(makeImmersiveEngineeringOreMineral("aluminum")) +C.add(makeImmersiveEngineeringOreMineral("lead")) +C.add(makeImmersiveEngineeringOreMineral("nickel")) +C.add(makeImmersiveEngineeringOreMineral("silver")) +C.add(makeImmersiveEngineeringOreMineral("uranium")) + +# Railcraft Ores +C.add(Mineral("saltpeter", [ + Replacement("sand", f"{RC}:saltpeter_ore"), + Replacement("sandstone", f"{RC}:saltpeter_ore"), +])) +C.add(makeRailcraftOreMineral("sulfur")) +C.add(makeRailcraftOreMineral("tin")) +C.add(makeRailcraftOreMineral("zinc")) diff --git a/tungston/modpack/mysteriousisland/mobcatalog.py b/tungston/modpack/mysteriousisland/mobcatalog.py new file mode 100644 index 0000000..1368d31 --- /dev/null +++ b/tungston/modpack/mysteriousisland/mobcatalog.py @@ -0,0 +1,183 @@ +from tungston.core.ecology.biomefilter import BiomeFilter as BF +from tungston.core.fauna.mob import Mob +from tungston.core.fauna.mobplacement import MobPlacement +from tungston.core.fauna.mobcatalog import MobCatalog + +import tungston.core.active as AC +import tungston.core.altitude as AL +import tungston.core.ecology.flora as FL +import tungston.core.ecology.geology as GE +import tungston.core.ecology.heat as HE +import tungston.core.ecology.humidity as HU +import tungston.core.ecology.soil as SO +import tungston.core.ecology.water as WA +import tungston.core.fauna.group as GR +import tungston.core.fauna.location as LO +import tungston.core.scarcity as SC +import tungston.core.season as SE + + +# Constants ######################################################################################## + +CATALOG = MobCatalog([ + MobPlacement(Mob("armadillo", "minecraft:armadillo", AC.NOCTURNAL), + Habitat( + altitude = AL.LOWLANDS, + biomeFilter = BF([HE.SUBTROPICAL, HU.DRY]), + seasons = SE.SUMMER, + group = GR.merge(GR.SOLO, GR.PAIR), + scarcity = SC.COMMON + ).derive( + altitude = AL.UPLANDS, scarcity = SC.SPARSE, + ).derive( + altitude = AL.LOWLANDS, SE.excluding(SE.SUMMER), scarcity = SC.UNCOMMON, + ).derive( + altitude = AL.UPLANDS, scarcity = SC.UNUSUAL, + ) + ), + MobPlacement(Mob("black_bear", "bearminimum:black_bear"), + Habitat( + altitudes = AL.span(AL.LOWLANDS, AL.ALPINE), + biomeFilter = BF([HE.TEMPERATE, FL.FOREST]), + seasons = SE.AUTUMN, + group = GR.merge(GR.SOLO, GR.FAMILY), + scarcity = SC.UNCOMMON, + ).derive( + seasons = [SE.SPRING, SE.SUMMER], scarcity = SC.SPARSE + ).derive( + seasons = SE.WINTER, scarcity = SC.UNUSUAL + ).derive( + biomeFilter = BF([HE.BOREAL, (HE.CANOPY, HE.FOREST)]), + seasons = SE.AUTUMN, + scarcity = SC.SPARSE + ).derive( + seasons = [SE.SPRING, SE.SUMMER], scarcity = SC.UNUSUAL + ).derive( + seasons = SE.WINTER, scarcity = SC.RARE + ) + ), + MobPlacement(Mob("blaze", "minecraft:blaze"), + Habitat( + altitudes = AL.PLUTONIC, + location = LO.CAVE, + group = GR.SOLO, + scarcity = SC.UNCOMMON + ) + ), + MobPlacement(Mob("bogged", "minecraft:bogged")), + MobPlacement(Mob("brown_bear", "bearminimum:brown_bear") + Habitat( + altitudes = AL.span(AL.LOWLANDS, AL.ALPINE), + biomeFilter = BF([HE.BOREAL, (FL.CANOPY, FL.FOREST)]), + seasons = SE.AUTUMN, + group = GR.SOLO, + scarcity = SC.SPARSE + ).derive( + seasons = [SE.SPRING, SE.SUMMER], scarcity = SC.UNUSUAL + ).derive( + seasons = SE.WINTER, scarcity = SC.RARE + ) + ), + MobPlacement(Mob("bulwark", "immersiveengineering:bulwark")), + MobPlacement(Mob("camel", "minecraft:camel", AC.CREPUSCULAR), + Habitat( + altitudes = AL.span(AL.DUNES, AL.LOWLANDS), + biomeFilter = BF([HE.TROPICAL, HU.DRY, FL.BARREN, SO.SANDY]), + seasons = SE.WET, + group = GR.FAMILY, + scarcity = SC.UNUSUAL, + ).derive( + seasons = SE.DRY, scarcity = SC.RARE + ) + ), + MobPlacement(Mob("cat", "minecraft:cat")), + MobPlacement(Mob("cave_spider", "minecraft:cave_spider"), + Habitat( + altitudes = AL.SPAN(AL.OVERBURDEN, AL.HILLS), + location = LO.CAVE, + group = GR.SOLO, + scarcity = SC.UNCOMMON + ) + ), + MobPlacement(Mob("chameleon", "cold_sweat:chameleon"), + Habitat( + altitudes = AL.span(AL.DUNES, AL.UPLANDS), + biomeFilters = BF([HE.TROPICAL, HU.WET, [FL.CANOPY, FL.FOREST]]), + seasons = SE.WET, + groups = GR.merge(GR.SOLO, GR.FAMILY), + scarcity = SC.COMMON, + ).derive( + seasons = SE.DRY, scarcity = SC.UNCOMMON, + ).derive( + biomeFilters = BF([HE.TROPICAL, HU.WET, FL.CLEARING]), + seasons = SE.WET, + scarcity = SC.UNCOMMON + ).derive( + seasons = SE.DRY, scarcity = SC.SPARSE, + ) + ), + MobPlacement(Mob("chicken", "minecraft:chicken") + Habitat( + altitudes = AL.span(AL.LOWLANDS, AL.UPLANDS), + biomeFilters = BF([HE.TROPICAL, HU.WET, FL.within(FL.CANOPY, FL.CLEARING)]), + seasons = SE.SUMMER, + groups = GR.TROUP, + scarcity.COMMON, + ).derive( + seasons = SE.excluding(SE.SUMMER), scarcity = SC.UNCOMMON + ) + ), + MobPlacement(Mob("cod", "minecraft:cod")), + MobPlacement(Mob("commando", "immersiveengineering:commando")), + MobPlacement(Mob("cow", "minecraft:cow")), + MobPlacement(Mob("crab", "crabbersdelight:crab")), + MobPlacement(Mob("creeper", "minecraft:creeper")), + MobPlacement(Mob("dolphin", "minecraft:dolphin")), + MobPlacement(Mob("donkey", "minecraft:donkey")), + MobPlacement(Mob("drowned", "minecraft:drowned")), + MobPlacement(Mob("enderman", "minecraft:enderman")), + MobPlacement(Mob("evoker", "minecraft:evoker")), + MobPlacement(Mob("fox", "minecraft:fox")), + MobPlacement(Mob("frog", "minecraft:frog")), + MobPlacement(Mob("fusilier", "immersiveengineering:fusilier")), + MobPlacement(Mob("glow_squid", "minecraft:glow_squid")), + MobPlacement(Mob("goat", "minecraft:goat")), + MobPlacement(Mob("hoglin", "minecraft:hoglin")), + MobPlacement(Mob("horse", "minecraft:horse")), + MobPlacement(Mob("husk", "minecraft:husk")), + MobPlacement(Mob("llama", "minecraft:llama")), + MobPlacement(Mob("magma_cube", "minecraft:magma_cube")), + MobPlacement(Mob("mooshroom", "minecraft:mooshroom")), + MobPlacement(Mob("mule", "minecraft:mule")), + MobPlacement(Mob("ocelot", "minecraft:ocelot")), + MobPlacement(Mob("panda", "minecraft:panda")), + MobPlacement(Mob("parrot", "minecraft:parrot")), + MobPlacement(Mob("pig", "minecraft:pig")), + MobPlacement(Mob("pillager", "minecraft:pillager")), + MobPlacement(Mob("polar_bear", "minecraft:polar_bear")), + MobPlacement(Mob("pufferfish", "minecraft:pufferfish")), + MobPlacement(Mob("rabbit", "minecraft:rabbit")), + MobPlacement(Mob("raccoon", "animalplus:raccoon")), + MobPlacement(Mob("ravager", "minecraft:ravager")), + MobPlacement(Mob("red_panda", "animalplus:red_panda")), + MobPlacement(Mob("salmon", "minecraft:salmon")), + MobPlacement(Mob("sheep", "minecraft:sheep")), + MobPlacement(Mob("skeleton", "minecraft:skeleton")), + MobPlacement(Mob("slime", "minecraft:slime")), + MobPlacement(Mob("spider", "minecraft:spider")), + MobPlacement(Mob("squid", "minecraft:squid")), + MobPlacement(Mob("tropical_fish", "minecraft:tropical_fish")), + MobPlacement(Mob("turtle", "minecraft:turtle")), + MobPlacement(Mob("vex", "minecraft:vex")), + MobPlacement(Mob("villager", "minecraft:villager")), + MobPlacement(Mob("vindicator", "minecraft:vindicator")), + MobPlacement(Mob("wandering_trader", "minecraft:wandering_trader")), + MobPlacement(Mob("warden", "minecraft:warden")), + MobPlacement(Mob("witch", "minecraft:witch")), + MobPlacement(Mob("wither_skeleton", "minecraft:wither_skeleton")), + MobPlacement(Mob("wither", "minecraft:wither")), + MobPlacement(Mob("wolf", "minecraft:wolf")), + MobPlacement(Mob("zoglin", "minecraft:zoglin")), + MobPlacement(Mob("zombie_villager", "minecraft:zombie_villager")), + MobPlacement(Mob("zombie", "minecraft:zombie")), +]) diff --git a/tungston/modpack/mysteriousisland/world.py b/tungston/modpack/mysteriousisland/world.py new file mode 100644 index 0000000..eacad72 --- /dev/null +++ b/tungston/modpack/mysteriousisland/world.py @@ -0,0 +1,10 @@ +from tungston.core.world import World +from tungston.modpacks.mysteriousisland.biomecatalog import CATALOG as biomeCatalog +from tungston.modpacks.mysteriousisland.depositcatalog import CATALOG as depositCatalog +from tungston.modpacks.mysteriousisland.mineralcatalog import CATALOG as mineralCatalog +from tungston.modpacks.mysteriousisland.mobcatalog import CATALOG as mobCatalog + + +# Constants ######################################################################################## + +WORLD = World(biomeCatalog, depositCatalog, mineralCatalog, mobCatalog)