From 46371371521b6b3d7d396d2cb24a8bac78e9b1cf Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Mon, 6 Oct 2025 20:57:46 -0600 Subject: [PATCH] Set up ability to run commands from the terminal --- bin/run.sh | 1 + requirements.txt | 3 + tungston/core/ecology/biome.py | 4 +- tungston/core/ecology/biometrait.py | 2 +- tungston/core/ecology/biometrait_test.py | 2 +- tungston/generator/markdown/biomereport.py | 22 +++++++ .../generator/markdown/biomereport_test.py | 61 +++++++++++++++++++ tungston/generator/markdown/mineralreport.py | 5 +- .../generator/markdown/mineralreport_test.py | 8 +-- tungston/generator/markdown/report.py | 5 +- tungston/generator/markdown/report_test.py | 8 +-- tungston/generator/markdown/reportwriter.py | 24 ++++++++ tungston/interface/runner.py | 28 +++++++++ tungston/interface/runner_test.py | 7 +++ .../mysteriousisland/depositcatalog.py | 10 +-- .../mysteriousisland/mineralcatalog.py | 22 +++---- .../modpack/mysteriousisland/mobcatalog.py | 33 +++++----- tungston/modpack/mysteriousisland/runner.py | 35 +++++++++++ 18 files changed, 231 insertions(+), 49 deletions(-) create mode 100755 bin/run.sh create mode 100644 tungston/generator/markdown/biomereport.py create mode 100644 tungston/generator/markdown/biomereport_test.py create mode 100644 tungston/generator/markdown/reportwriter.py create mode 100644 tungston/interface/runner.py create mode 100644 tungston/interface/runner_test.py create mode 100644 tungston/modpack/mysteriousisland/runner.py diff --git a/bin/run.sh b/bin/run.sh new file mode 100755 index 0000000..cb1ffc5 --- /dev/null +++ b/bin/run.sh @@ -0,0 +1 @@ +python -m tungston.modpack.mysteriousisland.runner $* diff --git a/requirements.txt b/requirements.txt index c97357c..5a0b69d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,11 @@ exceptiongroup==1.3.0 iniconfig==2.1.0 +jedi==0.19.2 packaging==25.0 +parso==0.8.4 pluggy==1.6.0 Pygments==2.19.2 pytest==8.4.2 +toml==0.10.2 tomli==2.2.1 typing_extensions==4.15.0 diff --git a/tungston/core/ecology/biome.py b/tungston/core/ecology/biome.py index 78d8dc1..7c842b9 100644 --- a/tungston/core/ecology/biome.py +++ b/tungston/core/ecology/biome.py @@ -59,8 +59,8 @@ class Biome(object): "}" ]]) - def traits(self) -> set[BiomeTrait]: - return set([ + def traits(self) -> list[BiomeTrait]: + return list([ self.flora, self.geology, self.heat, diff --git a/tungston/core/ecology/biometrait.py b/tungston/core/ecology/biometrait.py index 4a59992..98e8170 100644 --- a/tungston/core/ecology/biometrait.py +++ b/tungston/core/ecology/biometrait.py @@ -17,7 +17,7 @@ class BiomeTrait: return hash((type(self).__name__, self.name)) def __str__(self): - return self.name + return f"{type(self).__name__}: {self.name}" def __repr__(self) -> str: return f"{type(self).__name__}<{self.name}>" diff --git a/tungston/core/ecology/biometrait_test.py b/tungston/core/ecology/biometrait_test.py index 2885f2f..e2d6f90 100644 --- a/tungston/core/ecology/biometrait_test.py +++ b/tungston/core/ecology/biometrait_test.py @@ -52,7 +52,7 @@ def test_repr(green): assert repr(green) == "BiomeTrait" def test_str(green): - assert str(green) == "green" + assert str(green) == "BiomeTrait: green" def test_within(traitList, green, yellow, orange): assert biomeTrait.within(traitList, green, orange) == [green, yellow, orange] diff --git a/tungston/generator/markdown/biomereport.py b/tungston/generator/markdown/biomereport.py new file mode 100644 index 0000000..fbe7492 --- /dev/null +++ b/tungston/generator/markdown/biomereport.py @@ -0,0 +1,22 @@ +from tungston.core.world import World +from tungston.generator.markdown.report import Report + + +# Class ############################################################################################ + +class BiomeReport(Report): + + def __init__(self, world:World): + super().__init__("biomes.md", world) + + def build(self): + for biome in self.world.biomes.all(): + self.line(f"# Biome: {biome.city} <{biome.gameId}>") + self.line() + + self.indent() + for trait in biome.traits(): + self.text("* ").line(trait) + self.outdent() + + self.line() diff --git a/tungston/generator/markdown/biomereport_test.py b/tungston/generator/markdown/biomereport_test.py new file mode 100644 index 0000000..629e655 --- /dev/null +++ b/tungston/generator/markdown/biomereport_test.py @@ -0,0 +1,61 @@ +from pytest import fixture +from tungston.core.ecology.biome import Biome +from tungston.core.ecology.biomecatalog import BiomeCatalog +from tungston.core.world import World +from tungston.generator.markdown.biomereport import BiomeReport + +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 + +import textwrap + + +# Fixtures ######################################################################################### + +@fixture(name="biomes") +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 + ), + ]) + +@fixture(name="world") +def createWorld(biomes): + yield World(biomes, None, None, None) + +@fixture(name="report") +def createReport(world): + report = BiomeReport(world) + report.build() + yield report + +# Tests ############################################################################################ + +def test_report(report): + assert str(report) == textwrap.dedent(""" + # Biome: dallas + + * Flora: field + * Geology: sedimentary + * Heat: subtropical + * Humidity: dry + * Soil: sandy + * Water: inland + + # Biome: kansascity + + * Flora: field + * Geology: sedimentary + * Heat: temperate + * Humidity: damp + * Soil: loamy + * Water: inland + """).strip() diff --git a/tungston/generator/markdown/mineralreport.py b/tungston/generator/markdown/mineralreport.py index fa70c0f..7c119a6 100644 --- a/tungston/generator/markdown/mineralreport.py +++ b/tungston/generator/markdown/mineralreport.py @@ -6,6 +6,9 @@ from tungston.generator.markdown.report import Report class MineralReport(Report): + def __init__(self, world:World): + super().__init__("minerals.md", world) + def build(self): for mineral in self.world.minerals.all(): self.line(f"# Mineral: {mineral.name}") @@ -13,7 +16,7 @@ class MineralReport(Report): self.indent() for replacement in mineral.replacements: - self.line(str(replacement)) + self.text("* ").line(str(replacement)) self.outdent() self.line() diff --git a/tungston/generator/markdown/mineralreport_test.py b/tungston/generator/markdown/mineralreport_test.py index c63bfa6..f3431f2 100644 --- a/tungston/generator/markdown/mineralreport_test.py +++ b/tungston/generator/markdown/mineralreport_test.py @@ -45,11 +45,11 @@ def test_report(report): assert str(report) == textwrap.dedent(""" # Mineral: copper - #minecraft:stone_replaceables => minecraft:copper_ore - #minecraft:deepslate_replaceables => minecraft:deepslate_copper_ore + * #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 + * #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 index e934830..87d1add 100644 --- a/tungston/generator/markdown/report.py +++ b/tungston/generator/markdown/report.py @@ -4,13 +4,14 @@ from tungston.core.world import World # Constants ######################################################################################## -INDENT = " " +INDENT = " " # Class ############################################################################################ class Report: - def __init__(self, world:World): + def __init__(self, name:str, world:World): + self.name = name self.world = world self.reset() diff --git a/tungston/generator/markdown/report_test.py b/tungston/generator/markdown/report_test.py index 0f88af2..e66c133 100644 --- a/tungston/generator/markdown/report_test.py +++ b/tungston/generator/markdown/report_test.py @@ -4,14 +4,10 @@ from tungston.generator.markdown.report import Report # Fixtures ######################################################################################### -@fixture(name="emptyReport") -def createEmptyReport(): - return Report() - @fixture(name="report") def createReport(): return ( - Report(None) + Report("test", None) .text("alpha") .line("bravo") .indent() @@ -28,4 +24,4 @@ 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" + assert str(report) == "alphabravo\n charlie\n delta\n echo" diff --git a/tungston/generator/markdown/reportwriter.py b/tungston/generator/markdown/reportwriter.py new file mode 100644 index 0000000..b7a9120 --- /dev/null +++ b/tungston/generator/markdown/reportwriter.py @@ -0,0 +1,24 @@ +from tungston.generator.markdown.report import Report + +import shutil +import os + +# Class ############################################################################################ + +class ReportWriter: + + def __init__(self, reports:list[Report]): + self._reports = reports + + def write(self, reportDirPath:str): + if os.path.exists(reportDirPath): + shutil.rmtree(reportDirPath) + + os.makedirs(reportDirPath, exist_ok=True) + + for report in self._reports: + report.build() + + path = os.path.join(reportDirPath, report.name) + with open(path, "w") as file: + file.write(str(report)) diff --git a/tungston/interface/runner.py b/tungston/interface/runner.py new file mode 100644 index 0000000..a4c6f3a --- /dev/null +++ b/tungston/interface/runner.py @@ -0,0 +1,28 @@ +from tungston.core.world import World + +import inspect +import sys + + +# Class ############################################################################################ + +class Runner: + + def __init__(self, world:World): + self.world = world + + def abort(self, message:str, status:int=-1): + print(message) + sys.exit(status) + + def run(self, argv:list[str]): + if len(sys.argv) < 2: + abort("Please provide a command name") + + commandName = "_command_" + argv[1] + for name, doCommand in inspect.getmembers(self): + if name == commandName: + doCommand(*argv[2:]) + sys.exit(0) + + abort("No command named: " + argv[1]) diff --git a/tungston/interface/runner_test.py b/tungston/interface/runner_test.py new file mode 100644 index 0000000..d7bdb8a --- /dev/null +++ b/tungston/interface/runner_test.py @@ -0,0 +1,7 @@ +from tungston.interface.runner import Runner + +# Tests ############################################################################################ + +def test_syntax(): + pass + diff --git a/tungston/modpack/mysteriousisland/depositcatalog.py b/tungston/modpack/mysteriousisland/depositcatalog.py index 73ae0c0..c05931a 100644 --- a/tungston/modpack/mysteriousisland/depositcatalog.py +++ b/tungston/modpack/mysteriousisland/depositcatalog.py @@ -1,7 +1,7 @@ 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.core.geology.depositcatalog import DepositCatalog +from tungston.core.geology.inclusion import Inclusion as I from tungston.modpack.mysteriousisland.mineralcatalog import CATALOG as M import tungston.core.altitude as AL @@ -16,13 +16,13 @@ import tungston.core.scarcity as SC # Catalog ########################################################################################## -CATALOG = C = DepositCatalog(minerals) +CATALOG = C = DepositCatalog() 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)], + biomeFilter = BF([GE.METAMORPHIC, (HE.BOREAL, HE.FROZEN), HU.DAMP]), + inclusions = [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 index b303f80..7019286 100644 --- a/tungston/modpack/mysteriousisland/mineralcatalog.py +++ b/tungston/modpack/mysteriousisland/mineralcatalog.py @@ -16,27 +16,27 @@ def makeMineral(name:str, blockId:str, deepslateBlockId:None|str=None) -> Minera deepslateBlockId = deepslateBlockId if deepslateBlockId else blockId return Mineral(name, [ - R.inStone(blockId), - R.inDeepslate(blockId) + Replacement.inStone(blockId), + Replacement.inDeepslate(blockId) ]) def makeOreMineral(name:str) -> Mineral: return Mineral(name, [ - R.inStone(f"{name}_ore"), - R.inDeepslate(f"deepslate_{name}_ore") + Replacement.inStone(f"{name}_ore"), + Replacement.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}") - ]), + Replacement.inStone(f"{IE}:ore_{name}"), + Replacement.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") - ]), + Replacement.inStone(f"{RC}:{name}_ore"), + Replacement.inDeepslate("{RC}:deepslate_{name}_ore") + ]) # Catalog ########################################################################################## @@ -56,7 +56,7 @@ 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("quartz", f"{OQ}:quartz_ore", f"{OQ}:deepslate_quartz_ore")) C.add(makeMineral("salt", "butcher:saltblock")) # Earth, gravel, etc. diff --git a/tungston/modpack/mysteriousisland/mobcatalog.py b/tungston/modpack/mysteriousisland/mobcatalog.py index 1368d31..e462dcf 100644 --- a/tungston/modpack/mysteriousisland/mobcatalog.py +++ b/tungston/modpack/mysteriousisland/mobcatalog.py @@ -1,9 +1,9 @@ from tungston.core.ecology.biomefilter import BiomeFilter as BF +from tungston.core.habitat import Habitat from tungston.core.fauna.mob import Mob -from tungston.core.fauna.mobplacement import MobPlacement from tungston.core.fauna.mobcatalog import MobCatalog +from tungston.core.fauna.mobplacement import MobPlacement -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 @@ -11,6 +11,7 @@ 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.active as AC import tungston.core.fauna.group as GR import tungston.core.fauna.location as LO import tungston.core.scarcity as SC @@ -22,17 +23,17 @@ import tungston.core.season as SE CATALOG = MobCatalog([ MobPlacement(Mob("armadillo", "minecraft:armadillo", AC.NOCTURNAL), Habitat( - altitude = AL.LOWLANDS, + altitudes = 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, + altitudes = AL.UPLANDS, scarcity = SC.SPARSE, ).derive( - altitude = AL.LOWLANDS, SE.excluding(SE.SUMMER), scarcity = SC.UNCOMMON, + altitudes = AL.LOWLANDS, seasons = SE.excluding(SE.SUMMER), scarcity = SC.UNCOMMON, ).derive( - altitude = AL.UPLANDS, scarcity = SC.UNUSUAL, + altitudes = AL.UPLANDS, scarcity = SC.UNUSUAL, ) ), MobPlacement(Mob("black_bear", "bearminimum:black_bear"), @@ -47,7 +48,7 @@ CATALOG = MobCatalog([ ).derive( seasons = SE.WINTER, scarcity = SC.UNUSUAL ).derive( - biomeFilter = BF([HE.BOREAL, (HE.CANOPY, HE.FOREST)]), + biomeFilter = BF([HE.BOREAL, (FL.CANOPY, FL.FOREST)]), seasons = SE.AUTUMN, scarcity = SC.SPARSE ).derive( @@ -65,7 +66,7 @@ CATALOG = MobCatalog([ ) ), MobPlacement(Mob("bogged", "minecraft:bogged")), - MobPlacement(Mob("brown_bear", "bearminimum:brown_bear") + MobPlacement(Mob("brown_bear", "bearminimum:brown_bear"), Habitat( altitudes = AL.span(AL.LOWLANDS, AL.ALPINE), biomeFilter = BF([HE.BOREAL, (FL.CANOPY, FL.FOREST)]), @@ -93,7 +94,7 @@ CATALOG = MobCatalog([ MobPlacement(Mob("cat", "minecraft:cat")), MobPlacement(Mob("cave_spider", "minecraft:cave_spider"), Habitat( - altitudes = AL.SPAN(AL.OVERBURDEN, AL.HILLS), + altitudes = AL.span(AL.OVERBURDEN, AL.HILLS), location = LO.CAVE, group = GR.SOLO, scarcity = SC.UNCOMMON @@ -102,27 +103,27 @@ CATALOG = MobCatalog([ MobPlacement(Mob("chameleon", "cold_sweat:chameleon"), Habitat( altitudes = AL.span(AL.DUNES, AL.UPLANDS), - biomeFilters = BF([HE.TROPICAL, HU.WET, [FL.CANOPY, FL.FOREST]]), + biomeFilter = BF([HE.TROPICAL, HU.WET, [FL.CANOPY, FL.FOREST]]), seasons = SE.WET, - groups = GR.merge(GR.SOLO, GR.FAMILY), + group = 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]), + biomeFilter = 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") + 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)]), + biomeFilter = BF([HE.TROPICAL, HU.WET, FL.within(FL.CANOPY, FL.CLEARING)]), seasons = SE.SUMMER, - groups = GR.TROUP, - scarcity.COMMON, + group = GR.TROUP, + scarcity = SC.COMMON, ).derive( seasons = SE.excluding(SE.SUMMER), scarcity = SC.UNCOMMON ) diff --git a/tungston/modpack/mysteriousisland/runner.py b/tungston/modpack/mysteriousisland/runner.py new file mode 100644 index 0000000..cf2cfdb --- /dev/null +++ b/tungston/modpack/mysteriousisland/runner.py @@ -0,0 +1,35 @@ +from tungston.interface.runner import Runner as BaseRunner +from tungston.core.world import World +from tungston.modpack.mysteriousisland.biomecatalog import CATALOG as biomes +from tungston.modpack.mysteriousisland.depositcatalog import CATALOG as deposits +from tungston.modpack.mysteriousisland.mineralcatalog import CATALOG as minerals +from tungston.modpack.mysteriousisland.mobcatalog import CATALOG as mobs +from tungston.generator.markdown.reportwriter import ReportWriter +from tungston.generator.markdown.biomereport import BiomeReport +from tungston.generator.markdown.mineralreport import MineralReport + +import sys + + +# Constants ######################################################################################## + +REPORT_PATH = "./output/markdown/mysteriousisland" + + +# Class ############################################################################################ + +class Runner(BaseRunner): + + def _command_writeReports(self): + writer = ReportWriter([ + BiomeReport(self.world), + MineralReport(self.world) + ]) + writer.write(REPORT_PATH) + + + +# Script ########################################################################################### + +if __name__ == "__main__": + Runner(World(biomes, deposits, minerals, mobs)).run(sys.argv)