Skip to content

Support minecraft 1.17 #22

New issue

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

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

Already on GitHub? Sign in to your account

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Added support for minecraft 1.17


## [0.3.1]
Expand Down Expand Up @@ -61,7 +64,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0


[Unreleased]: https://github.com/Le0Developer/mcfunction.py/compare/v0.3.1...HEAD
[0.3.0]: https://github.com/Le0Developer/mcfunction.py/compare/v0.3.0...v0.3.1
[0.3.1]: https://github.com/Le0Developer/mcfunction.py/compare/v0.3.0...v0.3.1
[0.3.0]: https://github.com/Le0Developer/mcfunction.py/compare/v0.2.1...v0.3.0
[0.2.1]: https://github.com/Le0Developer/mcfunction.py/compare/v0.2.0...v0.2.1
[0.2.0]: https://github.com/Le0Developer/mcfunction.py/compare/v0.1.0...v0.2.0
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

Command parser and reconstructor for minecraft commands in pure python (requires python3.7+).

This project currently supports [minecraft 1.8 - 1.16](<#versions>)
For version compatibility, read [versions](<#versions>).


## Installing
Expand Down Expand Up @@ -176,7 +176,7 @@ mcfunction.commands[2].command = '# '

## Versions

This library currently supports **1.8 - 1.16**.
This library currently supports **1.8 - 1.17**.

When using a parse function (`parse_command` and `parse_mcfunction`) you can
specfiy which version's syntax you want (defaults to the latest version).
Expand Down
8 changes: 8 additions & 0 deletions mcfunction/parser_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,14 @@ def parse(self, parts: t.Iterator[str]) -> nodes.ParticleNode:
match = NamespaceID.namespace.fullmatch(get(parts))
arguments = (nodes.NamespaceIDNode(*match.groups()),)

elif name == 'vibration':
arguments = (Position().parse(parts), Position().parse(parts),
Integer().parse(parts))

elif name == 'dust_color_transition':
arguments = tuple(nodes.DoubleNode(float(x))
for x in get(parts, 7))

return nodes.ParticleNode(namespace, name, arguments)


Expand Down
2 changes: 2 additions & 0 deletions mcfunction/versions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ def parse(self, command: str, version: MinecraftVersion = None):


VERSIONS = [
MinecraftVersion('1.17', 'mcfunction.versions.mc_1_17',
removed_commands={'replaceitem'}),
MinecraftVersion('1.16', 'mcfunction.versions.mc_1_16'),
MinecraftVersion('1.15', 'mcfunction.versions.mc_1_15'),
MinecraftVersion('1.14', 'mcfunction.versions.mc_1_14'),
Expand Down
Empty file.
110 changes: 110 additions & 0 deletions mcfunction/versions/mc_1_17/item.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@

from dataclasses import dataclass
import typing as t

from .. import Command, ParsedCommand, Parser
from ...exceptions import ConstructionException
from ...nodes import EntityNode, IntegerNode, ItemNode, PositionNode, RawNode
from ...parser_types import Any, Entity, Integer, Item, Literal, Position
from ...util import ensure_nodes


@dataclass()
class ParsedItemCommand(ParsedCommand):
command: str

target_type: RawNode
target: t.Union[PositionNode, EntityNode]
slot: RawNode
action: RawNode

source_type: RawNode = None
source: t.Union[PositionNode, EntityNode] = None
source_slot: RawNode = None
modifier: RawNode = None
item: ItemNode = None
count: IntegerNode = None

def __str__(self):
base = (f'{self.command} {self.target_type} {self.target} {self.slot} '
f'{self.action}')

if self.action.value == 'copy':
ensure_nodes(self, 'source_type', 'source', 'source_slot')
command = f'{base} {self.source_type} {self.source} ' \
f'{self.source_slot}'
if self.modifier is not None:
return f'{command} {self.modifier}'
return command

elif self.action.value == 'modify':
ensure_nodes(self, 'modifier')
return f'{base} {self.modifier}'

elif self.action.value == 'replace':
ensure_nodes(self, 'item')
if self.count is not None:
return f'{base} {self.item} {self.count}'
return f'{base} {self.item}'

else:
raise ConstructionException(
f'expected action to be \'copy\', \'modfiy\' or \'replace\', '
f'not {self.action.value!r}'
)


item = Command('item', parsed=ParsedItemCommand)

TYPES = (('block', Position()), ('entity', Entity()))

for target_type, target in TYPES:
# item <TARGET> <slot> copy <SOURCE> <slot> [<modifier>]
for source_type, source in TYPES:
# - item <TARGET> <slot> copy <SOURCE> <slot> <modifier>
item.add_variation(
Parser(Literal(target_type), 'target_type'),
Parser(target, 'target'),
Parser(Any(), 'slot'),
Parser(Literal('copy'), 'action'),
Parser(Literal(source_type), 'source_type'),
Parser(source, 'source'),
Parser(Any(), 'source_slot'),
Parser(Any(), 'modifier')
)
# - item <TARGET> <slot> copy <SOURCE> <slot>
item.add_variation(
Parser(Literal(target_type), 'target_type'),
Parser(target, 'target'),
Parser(Any(), 'slot'),
Parser(Literal('copy'), 'action'),
Parser(Literal(source_type), 'source_type'),
Parser(source, 'source'),
Parser(Any(), 'source_slot')
)
# item <TARGET> <slot> modify <modifier>
item.add_variation(
Parser(Literal(target_type), 'target_type'),
Parser(target, 'target'),
Parser(Any(), 'slot'),
Parser(Literal('modify'), 'action'),
Parser(Any(), 'modifier')
)
# item <TARGET> <slot> replace <item> [<count>]
# - item <TARGET> <slot> replace <item> <count>
item.add_variation(
Parser(Literal(target_type), 'target_type'),
Parser(target, 'target'),
Parser(Any(), 'slot'),
Parser(Literal('replace'), 'action'),
Parser(Item(), 'item'),
Parser(Integer(), 'count')
)
# - item <TARGET> <slot> replace <item>
item.add_variation(
Parser(Literal(target_type), 'target_type'),
Parser(target, 'target'),
Parser(Any(), 'slot'),
Parser(Literal('replace'), 'action'),
Parser(Item(), 'item')
)
77 changes: 77 additions & 0 deletions tests/commands/mc-1.17/test_item.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@

from mcfunction.versions.mc_1_17.item import item, ParsedItemCommand
from mcfunction.nodes import PositionNode


def test_item_copy():
parsed = item.parse('item block 0 0 0 slot copy block 1 1 1 slot')
parsed: ParsedItemCommand

assert parsed.target_type.value == 'block'
assert isinstance(parsed.target, PositionNode)
assert parsed.slot.value == 'slot'
assert parsed.action.value == 'copy'
assert parsed.source_type.value == 'block'
assert isinstance(parsed.source, PositionNode)
assert parsed.source_slot.value == 'slot'

assert str(parsed) == 'item block 0 0 0 slot copy block 1 1 1 slot'


def test_item_copy_modifier():
parsed = item.parse('item block 0 0 0 slot copy block 1 1 1 slot modifier')
parsed: ParsedItemCommand

assert parsed.target_type.value == 'block'
assert isinstance(parsed.target, PositionNode)
assert parsed.slot.value == 'slot'
assert parsed.action.value == 'copy'
assert parsed.source_type.value == 'block'
assert isinstance(parsed.source, PositionNode)
assert parsed.source_slot.value == 'slot'
assert parsed.modifier.value == 'modifier'

assert str(parsed) == 'item block 0 0 0 slot copy block 1 1 1 slot ' \
'modifier'


def test_item_modify():
parsed = item.parse('item block 0 0 0 slot modify modifier')
parsed: ParsedItemCommand

assert parsed.target_type.value == 'block'
assert isinstance(parsed.target, PositionNode)
assert parsed.slot.value == 'slot'
assert parsed.action.value == 'modify'
assert parsed.modifier.value == 'modifier'

assert str(parsed) == 'item block 0 0 0 slot modify modifier'


def test_item_replace():
parsed = item.parse('item block 0 0 0 slot replace test:item')
parsed: ParsedItemCommand

assert parsed.target_type.value == 'block'
assert isinstance(parsed.target, PositionNode)
assert parsed.slot.value == 'slot'
assert parsed.action.value == 'replace'
assert parsed.item.namespace == 'test'
assert parsed.item.name == 'item'

assert str(parsed) == 'item block 0 0 0 slot replace test:item'


def test_item_replace_count():
parsed = item.parse('item block 0 0 0 slot replace test:item 42')
parsed: ParsedItemCommand

assert parsed.target_type.value == 'block'
assert isinstance(parsed.target, PositionNode)
assert parsed.slot.value == 'slot'
assert parsed.action.value == 'replace'
assert parsed.item.namespace == 'test'
assert parsed.item.name == 'item'
assert parsed.count.value == 42

assert str(parsed) == 'item block 0 0 0 slot replace test:item 42'
14 changes: 14 additions & 0 deletions tests/test_parser_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ def test_particle():
'minecraft:block', 'test:block',
'minecraft:falling_dust', 'test:block',
'minecraft:item', 'test:item',
'minecraft:vibration', '0', '0', '0', '1', '1', '1', '2',
'minecraft:dust_color_transition', '0', '1', '2', '3', '4', '5', '6',
'invalid particle',
'minecraft:dust'
))
Expand Down Expand Up @@ -358,6 +360,18 @@ def test_particle():
assert node.name == 'item'
assert isinstance(node.arguments[0], nodes.NamespaceIDNode)

node = particle.parse(parts)
assert node.namespace == 'minecraft'
assert node.name == 'vibration'
assert isinstance(node.arguments[0], nodes.PositionNode)
assert isinstance(node.arguments[1], nodes.PositionNode)
assert isinstance(node.arguments[2], nodes.IntegerNode)

node = particle.parse(parts)
assert node.namespace == 'minecraft'
assert node.name == 'dust_color_transition'
assert [x.value for x in node.arguments] == [0, 1, 2, 3, 4, 5, 6]

with pytest.raises(ParserException,
match='expected valid particle, not .*'):
particle.parse(parts)
Expand Down