Skip to content

Commit

Permalink
feat: add generate.objective() and beet.contrib.scoreboard
Browse files Browse the repository at this point in the history
  • Loading branch information
vberlier committed Apr 17, 2021
1 parent 4429ff6 commit 6a5376a
Show file tree
Hide file tree
Showing 17 changed files with 208 additions and 0 deletions.
40 changes: 40 additions & 0 deletions beet/contrib/scoreboard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Plugin that adds generated scoreboards to the data pack."""


__all__ = [
"scoreboard",
]


from typing import Iterable, cast

from beet import Context, Function, Plugin
from beet.core.utils import JsonDict


def beet_default(ctx: Context):
config = ctx.meta.get("scoreboard", cast(JsonDict, {}))

function = config.get("function", "{namespace}:{path}scoreboard")
tags = config.get("tags", ["minecraft:load"])

ctx.require(scoreboard(function, tags))


def scoreboard(
function: str = "{namespace}:{path}scoreboard",
tags: Iterable[str] = ("minecraft:load",),
) -> Plugin:
"""Return a plugin that adds generated scoreboards to the data pack."""

def plugin(ctx: Context):
if scoreboard_data := ctx.meta.get("generate_scoreboard"):
commands = [
f"scoreboard objectives add {name} {criterion}"
for name, criterion in scoreboard_data.items()
]

ctx.generate(function, Function(commands, prepend_tags=list(tags)))
scoreboard_data.clear()

return plugin
24 changes: 24 additions & 0 deletions beet/library/data_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,21 @@ class Function(TextFileBase[List[str]], NamespaceFile):

content: TextFileContent[List[str]] = None
tags: Optional[List[str]] = extra_field(default=None)
prepend_tags: Optional[List[str]] = extra_field(default=None)

scope = ("functions",)
extension = ".mcfunction"

lines = FileDeserialize() # type: FileDeserialize[List[str]]

def append(self, other: "Function"):
"""Append lines from another function."""
self.lines.extend(other.lines)

def prepend(self, other: "Function"):
"""Prepend lines from another function."""
self.lines[0:0] = other.lines

@classmethod
def default(cls) -> List[str]:
return []
Expand All @@ -89,6 +98,10 @@ def bind(self, pack: "DataPack", namespace: str, path: str):
{tag_name: FunctionTag({"values": [f"{namespace}:{path}"]})}
)

for tag_name in self.prepend_tags or ():
function_tag = pack.function_tags.setdefault(tag_name, FunctionTag())
function_tag.prepend(FunctionTag({"values": [f"{namespace}:{path}"]}))


class LootTable(JsonFile, NamespaceFile):
"""Class representing a loot table."""
Expand Down Expand Up @@ -151,6 +164,17 @@ def merge(self: TagFileType, other: TagFileType) -> bool: # type: ignore
values.append(deepcopy(value))
return True

def prepend(self: TagFileType, other: TagFileType) -> bool: # type: ignore
"""Prepend values from another tag."""
if other.data.get("replace"):
self.data["replace"] = True

values = self.data.setdefault("values", [])

for value in other.data.get("values", []):
if value not in values:
values.insert(0, deepcopy(value))

@classmethod
def default(cls) -> JsonDict:
return {"values": []}
Expand Down
20 changes: 20 additions & 0 deletions beet/toolchain/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
]


import json
from collections import defaultdict
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Any, DefaultDict, Optional, Tuple, TypeVar, overload

from beet.core.utils import TextComponent
from beet.library.base import NamespaceFile

from .utils import LazyFormat, StableHashable, stable_hash
Expand Down Expand Up @@ -125,3 +127,21 @@ def hash(
"""Generate a scoped hash."""
template = self.ctx.meta.get("generate_hash", "{namespace}.{scope}")
return stable_hash(self.format(template + fmt, hash), short)

def objective(
self,
fmt: str = "{incr}",
hash: Optional[StableHashable] = None,
criterion: str = "dummy",
display: Optional[TextComponent] = None,
) -> str:
"""Generate a scoreboard objective."""
template = self.ctx.meta.get("generate_objective", "{namespace}.{scope}")
key = self.format(template + fmt, hash)
objective = stable_hash(key)
display = json.dumps(display or key)

scoreboard = self.ctx.meta.setdefault("generate_scoreboard", {})
scoreboard[objective] = f"{criterion} {display}"

return objective
8 changes: 8 additions & 0 deletions examples/code_scoreboard/beet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"pipeline": ["demo", "beet.contrib.scoreboard"],
"meta": {
"scoreboard": {
"function": "{namespace}:add_objectives"
}
}
}
18 changes: 18 additions & 0 deletions examples/code_scoreboard/demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from beet import Context


def beet_default(ctx: Context):
ctx.generate.objective()
ctx.generate.objective("{hash}", "something")
ctx.generate.objective("hello", criterion="playerKillCount")
ctx.generate.objective("world", display="Something")

generate = ctx.generate["foo"]["bar"]
generate.objective()
generate.objective("{hash}", "something")
generate.objective("hello", criterion="playerKillCount")
generate.objective("world", display="Something")

ctx.generate.objective(
"{hash}", "something", display={"text": "Update name", "color": "red"}
)
14 changes: 14 additions & 0 deletions examples/load_scoreboard/beet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"data_pack": {
"load": ["src"],
"render": {
"functions": ["*"]
}
},
"pipeline": ["beet.contrib.scoreboard"],
"meta": {
"generate_scoreboard": {
"from_config": "dummy"
}
}
}
10 changes: 10 additions & 0 deletions examples/load_scoreboard/src/data/demo/functions/foo.mcfunction
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!set obj1 = ctx.generate.objective()
#!set obj2 = ctx.generate.objective("foo")

scoreboard players operation @s {{ obj1 }} += @s {{ obj2 }}

#!set generate = ctx.generate["thing"]
#!set obj1 = generate.objective()
#!set obj2 = generate.objective("foo")

scoreboard players operation @s {{ obj1 }} += @s {{ obj2 }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
scoreboard objectives add 2ZVpgb8kGcG dummy "code_scoreboard.0"
scoreboard objectives add 7TSQihUbNLa dummy {"text": "Update name", "color": "red"}
scoreboard objectives add c27bB4cS5F6 playerKillCount "code_scoreboard.hello"
scoreboard objectives add 9WJtktDktnC dummy "Something"
scoreboard objectives add F3hNMFMkWK1 dummy "code_scoreboard.foo.bar.0"
scoreboard objectives add bCnEsPUVaU1 dummy "code_scoreboard.foo.bar.gJha1dTMehg"
scoreboard objectives add XFFrTkAcRD9 playerKillCount "code_scoreboard.foo.bar.hello"
scoreboard objectives add 5SYSLQGpc3D dummy "Something"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"values": [
"code_scoreboard:add_objectives"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"pack": {
"pack_format": 6,
"description": ""
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"pack": {
"pack_format": 6,
"description": ""
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
scoreboard players operation @s bT7PpNaNgfP += @s 9fP76NV5kv5

scoreboard players operation @s U466Vqh61Yo += @s baxdp7xLz9q
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
scoreboard objectives add from_config dummy
scoreboard objectives add bT7PpNaNgfP dummy "load_scoreboard.0"
scoreboard objectives add 9fP76NV5kv5 dummy "load_scoreboard.foo"
scoreboard objectives add U466Vqh61Yo dummy "load_scoreboard.thing.0"
scoreboard objectives add baxdp7xLz9q dummy "load_scoreboard.thing.foo"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"values": [
"load_scoreboard:scoreboard"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"pack": {
"pack_format": 6,
"description": ""
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"pack": {
"pack_format": 6,
"description": ""
}
}
24 changes: 24 additions & 0 deletions tests/test_data_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,22 @@ def test_vanilla_igloo_content(minecraft_data_pack: Path):
assert igloo_structure.data["size"] == [7, 5, 8]


def test_append_functions():
func1 = Function(["say foo"])
func2 = Function(["say bar"])
func1.append(func2)

assert func1 == Function(["say foo", "say bar"])


def test_prepend_functions():
func1 = Function(["say foo"])
func2 = Function(["say bar"])
func1.prepend(func2)

assert func1 == Function(["say bar", "say foo"])


def test_merge_tags():
p1 = DataPack()
p1["hello:func1"] = Function(["say foo"], tags=["minecraft:tick"])
Expand All @@ -155,6 +171,14 @@ def test_merge_tags():
}


def test_prepend_tags():
tag1 = FunctionTag({"values": ["hello:func1"]})
tag2 = FunctionTag({"values": ["hello:func2"]})
tag1.prepend(tag2)

assert tag1.data == {"values": ["hello:func2", "hello:func1"]}


def test_merge_block_tags():
p1 = DataPack()
p1["custom:blocks"] = BlockTag({"values": ["minecraft:stone"]})
Expand Down

0 comments on commit 6a5376a

Please sign in to comment.