Udržovat server v chodu je výzva sama pro sebe, natož ho udržovat při životě. Teď na to máme týpka, co dokáže udělat dost zábavy, ale na nějaké starání se o bezproblémový chod je zoufale málo času. V tuhle chvíli bylo asi nejhorší vyzjistit, jak nějak automagicky přejít s naším kouzelným resourcepackem na 1.21.4+. Je tam mnoho a mnoho změn, bohužel. Nakonec ale ne úplně k nejhoršímu. Já si to sem zapíšu, protože to bude třeba zajímavé do budoucnosti, až to zas přestane platit.
Před nějakou dobou jsme povýšili. To bylo poměrně logické. No a co se nestalo? Vypadly samozřejmě textury. V takových chvílích se ti prostě chce brečet a začneš mlátit hlavou o zeď, protože dokumentace na všechno nejsou na jednom místě a prostě na to není těch pár minut za měsíc, které by celou situaci zachránili. Každopádně teď jsme v éře AI, takže není vlastně tak složité si na tohle vytvořit lokálního agenta, který na to všechno přijde, upraví a při troše štěstí nic neshodí. V našem případě je to trochu komplikované, protože používáme klasický javovský plugin pro PaperMC API, resourcepack se všemi náležitostmi, ale také ještě upravený datapack pro zjednodušenou implementaci obrázkové funkcionality. Jestli by to chtělo sjednotit? Tak to každopádně.
No ale v první řadě, zaplaťpandu za to, se povedlo udělat alespoň nějaké sjednocení vývinu resourcepacku tak, aby šel v první řadě pohodlně verzovat, ale taky aby šel sestavit bez většího úsilí a ochechulí, tedy s odpovídajícím začarováním přes Makrfile a žádného dalšího zamýšlení. To počítá, že tam tedy bude adresář s kořenem RP (ten bude mít pack.mcmeta, pack.png a adresář assets) a target, do kterého se vychrlí hotový zip soubor a jemu spočítaný SHA1 součet.
SOURCE=respack
TARGET=respack
DEVTARGET=respack-dev
SHASUM=$(shell cat target/$(TARGET).sha1 | cut -d ' ' -f 1 )
include config.mk
#LOCAL=./minecraft/resourcepacks/
#MC_USER=minecraft
#MC_SERVER=mc-server
#PATH_WEB=/var/www/minecraft/
#PATH_SERVER=/srv/minecraft/
#PATH_INIT=/etc/init.d/mc-server
.PHONY: help
help: ## Show this help
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
awk -F ':.*?## ' '{printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' | sort
all: ## Build resourcepack and show its SHA1
cd $(SOURCE) ; zip -r ../target/$(TARGET).zip .
cd target ; shasum $(TARGET).zip > $(TARGET).sha1
SHASUM=$$(cut -d ' ' -f 1 target/$(TARGET).sha1)
echo $(SHASUM)
dev: clean all ## Create devel version
mv target/$(TARGET).zip target/$(DEVTARGET).zip
mv target/$(TARGET).sha1 target/$(DEVTARGET).sha1
local: ## Deploy to local dev server
rm -rf $(LOCAL)/$(SOURCE)
cp -r $(SOURCE) $(LOCAL)
deploy: clean all ## Deploy to live server and restart
SHASUM=$$(cut -d ' ' -f 1 target/$(TARGET).sha1)
scp -6 target/$(TARGET).zip $(MC_USER)@$(MC_SERVER):$(PATH_WEB)
ssh -6 $(MC_USER)@$(MC_SERVER) "sed -i 's/\(resource-pack-sha1=\)\([0-9a-f]\)\{40\}/\1${SHASUM}/g' $(PATH_SERVER)server.properties"
ssh -6 $(MC_USER)@$(MC_SERVER) "$(PATH_INIT) restart"
clean: ## Clean all artifacts and tmp files
find . -name '.DS_Store' -type f -delete
rm target/*.*
No a teď co s tím. Modernizovaný formát pro 1.21.4 říká, že formát balíčku bude 46, ale je tam taky ještě direktiva pro legacy použití, tedy supported_formats, což může být pole jiných verzí. Tož dejme tomu kromě 46 ještě třeba starší 42. Bohužel tohle samo o sobě nestačí pro zachování kompatibility z minulých verzí, takže v ideálním případě budou ze všech custom předmětů defaultní černo-fialové bloky. A tohle mě děsilo hodně dlouho, dokud to chytrý robot nezačal vysvětlovat. Ta změna hlavně spočívá v tom, že v assets/minecraft se původní předměty z modelů oddělují nově do items. Na první pohled je to haluz, ale ono to dává smysl. Takže pokud se do teď dělaly modely tak, že jsme měnili pouze mapovací ID, tak teď to funguje tak, že k původnímu existující předmětu nastavíme různé vstupy (entries) s parametry pro přepsání, což z kompatibility bude zahrnovat pole model, který bude definován už relativní cestou v models, a to libovolnou (konečně). Na ukázce s pírkem (feather) tady existuje pole s jedním přepsaným objektem, kterým je megabird s původním ID 1000, což je teď prahovou hodnotou pro použití konkrétního modelu item/megabird. Nakonec se přidává fallback zpět na pírko, a to se taky vyplatí.
{
"model": {
"type": "range_dispatch",
"property": "custom_model_data",
"entries": [
{
"threshold": 1000,
"model": {
"type": "model",
"model": "item\/megabird"
}
}
],
"fallback": {
"type": "model",
"model": "item\/feather"
}
}
} Došli jsme k tomu nakonec tak, že bylo nezbytně a nutně potřeba přidat možnost jíst včely. Aby se dala včela sníst, tak musí existovat nejprv její model, který se aplikuje na nějaké již existující jídlo, tady třeba na sušenku. Sušenka bude mít jeden z přepisů podobný tomu z pírka a bude odkazovat na konkrétní implementaci, tady třeba ručně spíchnutou zjednodušenou včelku, která sice nemá průhledná detailní křidýlka a nožičky, ale ujde to.
{
"credit": "Vcelicka k papani",
"ambientocclusion": false,
"texture_size": [
64,
64
],
"textures": {
"0": "item\/bee_edible",
"particle": "item\/bee_edible"
},
"elements": [
{
"from": [
4,
5,
4
],
"to": [
11,
12,
14
],
"rotation": {
"angle": 0,
"axis": "y",
"origin": [
4,
5,
4
]
},
"faces": {
"north": {
"uv": [
0,
3.5,
1.75,
5.25
],
"texture": "#0"
},
"east": {
"uv": [
0,
0,
2.5,
1.75
],
"texture": "#0"
},
"south": {
"uv": [
4.25,
0,
6,
1.75
],
"texture": "#0"
},
"west": {
"uv": [
0,
1.75,
2.5,
3.5
],
"texture": "#0"
},
"up": {
"uv": [
4.25,
2.5,
2.5,
0
],
"texture": "#0"
},
"down": {
"uv": [
4.25,
2.5,
2.5,
5
],
"texture": "#0"
}
}
},
{
"from": [
6.75,
7.75,
2
],
"to": [
8.25,
9.25,
5
],
"rotation": {
"angle": 0,
"axis": "y",
"origin": [
7,
8,
2
]
},
"faces": {
"north": {
"uv": [
4.25,
3.25,
4.75,
3.75
],
"texture": "#0"
},
"east": {
"uv": [
1.75,
3.5,
2.5,
4
],
"texture": "#0"
},
"south": {
"uv": [
4.25,
3.75,
4.75,
4.25
],
"texture": "#0"
},
"west": {
"uv": [
1.75,
4,
2.5,
4.5
],
"texture": "#0"
},
"up": {
"uv": [
4.75,
2.5,
4.25,
1.75
],
"texture": "#0"
},
"down": {
"uv": [
4.75,
2.5,
4.25,
3.25
],
"texture": "#0"
}
}
},
{
"from": [
7.25,
8.25,
1.5
],
"to": [
7.75,
8.75,
3.5
],
"rotation": {
"angle": 0,
"axis": "y",
"origin": [
7,
8,
1
]
},
"faces": {
"north": {
"uv": [
4.5,
4.5,
4.75,
4.75
],
"texture": "#0"
},
"east": {
"uv": [
4.25,
4.25,
4.75,
4.5
],
"texture": "#0"
},
"south": {
"uv": [
1.75,
4.75,
2,
5
],
"texture": "#0"
},
"west": {
"uv": [
1.75,
4.5,
2.25,
4.75
],
"texture": "#0"
},
"up": {
"uv": [
2.5,
5,
2.25,
4.5
],
"texture": "#0"
},
"down": {
"uv": [
4.5,
4.5,
4.25,
5
],
"texture": "#0"
}
}
},
{
"from": [
-1,
12.25,
6
],
"to": [
6,
12.5,
12
],
"rotation": {
"angle": 0,
"axis": "y",
"origin": [
-1,
13,
6
]
},
"faces": {
"north": {
"uv": [
5.25,
7.75,
7,
8
],
"texture": "#0"
},
"east": {
"uv": [
7.75,
6.5,
9.25,
6.75
],
"texture": "#0"
},
"south": {
"uv": [
7.75,
5.75,
9.5,
6
],
"texture": "#0"
},
"west": {
"uv": [
7.75,
6.75,
9.25,
7
],
"texture": "#0"
},
"up": {
"uv": [
3.5,
8.75,
1.75,
7.25
],
"texture": "#0"
},
"down": {
"uv": [
5.25,
7.75,
3.5,
9.25
],
"texture": "#0"
}
}
},
{
"from": [
9,
12.25,
6
],
"to": [
16,
12.5,
12
],
"rotation": {
"angle": 0,
"axis": "y",
"origin": [
9,
13,
6
]
},
"faces": {
"north": {
"uv": [
7,
5,
8.75,
5.25
],
"texture": "#0"
},
"east": {
"uv": [
7.75,
6,
9.25,
6.25
],
"texture": "#0"
},
"south": {
"uv": [
7,
5.25,
8.75,
5.5
],
"texture": "#0"
},
"west": {
"uv": [
7.75,
6.25,
9.25,
6.5
],
"texture": "#0"
},
"up": {
"uv": [
8.75,
5,
7,
3.5
],
"texture": "#0"
},
"down": {
"uv": [
1.75,
7.25,
0,
8.75
],
"texture": "#0"
}
}
},
{
"from": [
3.75,
4.75,
8
],
"to": [
11.25,
12.25,
9
],
"rotation": {
"angle": 0,
"axis": "y",
"origin": [
0,
4,
8
]
},
"faces": {
"north": {
"uv": [
1.75,
5,
3.75,
7
],
"texture": "#0"
},
"east": {
"uv": [
1,
5.25,
1.25,
7.25
],
"texture": "#0"
},
"south": {
"uv": [
3.75,
5.75,
5.75,
7.75
],
"texture": "#0"
},
"west": {
"uv": [
1.25,
5.25,
1.5,
7.25
],
"texture": "#0"
},
"up": {
"uv": [
8.75,
3.25,
6.75,
3
],
"texture": "#0"
},
"down": {
"uv": [
8.75,
3.25,
6.75,
3.5
],
"texture": "#0"
}
}
},
{
"from": [
3.75,
4.75,
6
],
"to": [
11.25,
12.25,
7
],
"rotation": {
"angle": 0,
"axis": "y",
"origin": [
0,
5,
6
]
},
"faces": {
"north": {
"uv": [
5.75,
5.75,
7.75,
7.75
],
"texture": "#0"
},
"east": {
"uv": [
1.5,
5.25,
1.75,
7.25
],
"texture": "#0"
},
"south": {
"uv": [
6.75,
0,
8.75,
2
],
"texture": "#0"
},
"west": {
"uv": [
6.75,
3.5,
7,
5.5
],
"texture": "#0"
},
"up": {
"uv": [
8.75,
5.75,
6.75,
5.5
],
"texture": "#0"
},
"down": {
"uv": [
3.75,
7,
1.75,
7.25
],
"texture": "#0"
}
}
},
{
"from": [
3.75,
4.75,
3
],
"to": [
11.25,
12.25,
5
],
"rotation": {
"angle": 0,
"axis": "y",
"origin": [
4,
5,
3
]
},
"faces": {
"north": {
"uv": [
4.75,
1.75,
6.75,
3.75
],
"texture": "#0"
},
"east": {
"uv": [
0,
5.25,
0.5,
7.25
],
"texture": "#0"
},
"south": {
"uv": [
4.75,
3.75,
6.75,
5.75
],
"texture": "#0"
},
"west": {
"uv": [
0.5,
5.25,
1,
7.25
],
"texture": "#0"
},
"up": {
"uv": [
8.75,
2.5,
6.75,
2
],
"texture": "#0"
},
"down": {
"uv": [
8.75,
2.5,
6.75,
3
],
"texture": "#0"
}
}
}
],
"display": {
"thirdperson_righthand": {
"rotation": [
28,
180,
-15
],
"translation": [
0,
-2,
0
],
"scale": [
0.6,
0.6,
0.6
]
},
"thirdperson_lefthand": {
"rotation": [
28,
180,
15
],
"translation": [
0,
-2,
0
],
"scale": [
0.6,
0.6,
0.6
]
},
"firstperson_righthand": {
"rotation": [
45,
180,
-36
],
"translation": [
0,
3.25,
0
],
"scale": [
0.6,
0.6,
0.6
]
},
"firstperson_lefthand": {
"rotation": [
45,
180,
33
],
"translation": [
-1.5,
1.25,
0.25
],
"scale": [
0.6,
0.6,
0.6
]
},
"gui": {
"rotation": [
39,
29,
15
],
"scale": [
0.86,
0.86,
0.86
]
},
"head": {
"rotation": [
0,
180,
26
],
"translation": [
6,
6.75,
-1.5
],
"scale": [
1.25,
1.25,
1.25
]
},
"fixed": {
"rotation": [
-90,
90,
0
],
"translation": [
0,
0,
-2.75
]
}
},
"groups": [
0,
1,
2,
{
"name": "kridylka",
"origin": [
4,
5,
3
],
"color": 0,
"children": [
3,
4
]
},
{
"name": "brisko",
"origin": [
7,
8,
1
],
"color": 0,
"children": [
5,
6,
7
]
}
]
} Když ji pak držíme v ruce, vypadá to hodně dobře. A dá se sníst. Jediný zádrhel je pak v tom, že kvůli mnoha změnám to nešlo úplně debugovat pomocí tradičního příkazu give, jelikož nějak nově pracuje s NBT vlastnostmi předmětu, ale přes API se to pomocí pluginu zařídit dalo jednoduše, takže včela se pak má k světu a dá se pohodlně sníst. Je to radost.
Díky tomuto zjištění se tedy povedlo opravit i další rozbité textury, zejména našeho blibeného magického regentskéto pivka – to má alikvótu! – a cukrových hůlek, které budou na Vánoce zase brzo velmi aktuální. Ještě jim bude potřeba tedy přidat nějaké super chování ve smyslu vytvoření ducha Vánoc, ale to snad přijde v budoucnosti. Jako nápad. Asi. Ale pro dnešek tedy hotovo, díky včelám byl průchod změnami poměrně snadný. Dokud tedy nové verze nepřinesou něco zase divočejšího. Ale to nevíme.