mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-02-11 04:45:01 +01:00
merge mc1.15/dev into mc1.16/dev
This commit is contained in:
commit
1a4814e724
77 changed files with 1929 additions and 1158 deletions
|
@ -1,6 +1,6 @@
|
||||||
<p align="center"><img src="https://i.imgur.com/35JmqWB.gif" alt="Logo" width="100"></p>
|
<p align="center"><img src="https://i.imgur.com/35JmqWB.gif" alt="Logo" width="100"></p>
|
||||||
<h1 align="center">Create<br>
|
<h1 align="center">Create<br>
|
||||||
<a href="https://www.patreon.com/simibubi"><img src="https://img.shields.io/badge/Supporters-29-ff5733" alt="Patreon"></a>
|
<a href="https://www.patreon.com/simibubi"><img src="https://img.shields.io/badge/Supporters-40-ff5733" alt="Patreon"></a>
|
||||||
<a href="https://www.curseforge.com/minecraft/mc-mods/create/files"><img src="https://img.shields.io/badge/Available%20for-MC%201.14,%201.15-c70039" alt="Supported Versions"></a>
|
<a href="https://www.curseforge.com/minecraft/mc-mods/create/files"><img src="https://img.shields.io/badge/Available%20for-MC%201.14,%201.15-c70039" alt="Supported Versions"></a>
|
||||||
<a href="https://github.com/Creators-of-Create/Create/blob/master/LICENSE"><img src="https://img.shields.io/github/license/Creators-of-Create/Create?style=flat&color=900c3f" alt="License"></a>
|
<a href="https://github.com/Creators-of-Create/Create/blob/master/LICENSE"><img src="https://img.shields.io/github/license/Creators-of-Create/Create?style=flat&color=900c3f" alt="License"></a>
|
||||||
<a href="https://discord.gg/hmaD7Se"><img src="https://img.shields.io/discord/620934202875183104?color=844685&label=Feedback%20%26%20Help&style=flat" alt="Discord"></a>
|
<a href="https://discord.gg/hmaD7Se"><img src="https://img.shields.io/discord/620934202875183104?color=844685&label=Feedback%20%26%20Help&style=flat" alt="Discord"></a>
|
||||||
|
@ -19,7 +19,7 @@ Check out the wiki and in-game Tool-tips for further info on how to use these fe
|
||||||
[<img src="https://i.imgur.com/xj8o2xC.jpg" width="210">](https://www.patreon.com/simibubi "Support Us")
|
[<img src="https://i.imgur.com/xj8o2xC.jpg" width="210">](https://www.patreon.com/simibubi "Support Us")
|
||||||
|
|
||||||
- Support for Minecraft 1.12: Not planned
|
- Support for Minecraft 1.12: Not planned
|
||||||
- Support for Minecraft 1.16: Porting efforts will begin soon.
|
- Support for Minecraft 1.16: Porting efforts are making good progress.
|
||||||
- Support for Fabric: Not planned
|
- Support for Fabric: Not planned
|
||||||
<hr>
|
<hr>
|
||||||
<h4 align="center">Find out more about Create on our <a href="https://www.curseforge.com/minecraft/mc-mods/create">Project Page</a></h4>
|
<h4 align="center">Find out more about Create on our <a href="https://www.curseforge.com/minecraft/mc-mods/create">Project Page</a></h4>
|
||||||
|
|
|
@ -368,6 +368,7 @@ a3a11524cd3515fc01d905767b4b7ea782adaf03 assets/create/blockstates/yellow_seat.j
|
||||||
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
|
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
|
||||||
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
|
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
|
||||||
c113d0a180880243538e9b1c3019c863df3fbdc1 assets/create/lang/en_ud.json
|
c113d0a180880243538e9b1c3019c863df3fbdc1 assets/create/lang/en_ud.json
|
||||||
|
<<<<<<< HEAD
|
||||||
a4cd12907a1ddfd60883077b2d11c5459d436016 assets/create/lang/en_us.json
|
a4cd12907a1ddfd60883077b2d11c5459d436016 assets/create/lang/en_us.json
|
||||||
063195daed96a4420588e6d6d13f4a9b1f099ff4 assets/create/lang/unfinished/de_de.json
|
063195daed96a4420588e6d6d13f4a9b1f099ff4 assets/create/lang/unfinished/de_de.json
|
||||||
30da89bafac8a5ea4d82903928ba4d2a63385117 assets/create/lang/unfinished/fr_fr.json
|
30da89bafac8a5ea4d82903928ba4d2a63385117 assets/create/lang/unfinished/fr_fr.json
|
||||||
|
@ -384,6 +385,24 @@ b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_windo
|
||||||
1358ff546e99004444fccca5355853d1738ef191 assets/create/models/block/acacia_window_pane_post.json
|
1358ff546e99004444fccca5355853d1738ef191 assets/create/models/block/acacia_window_pane_post.json
|
||||||
bd33b944ec6ad89850a1d275b3d2843fe6f831cc assets/create/models/block/acacia_window_pane_side.json
|
bd33b944ec6ad89850a1d275b3d2843fe6f831cc assets/create/models/block/acacia_window_pane_side.json
|
||||||
b272035cd746364a0bd3bf13061f51190e9b46d6 assets/create/models/block/acacia_window_pane_side_alt.json
|
b272035cd746364a0bd3bf13061f51190e9b46d6 assets/create/models/block/acacia_window_pane_side_alt.json
|
||||||
|
=======
|
||||||
|
ee39bea21ca57e7b61f1af0d609d63cbbf8c8425 assets/create/lang/en_us.json
|
||||||
|
233e7fae9df99bcb79d3e08f57e6d5e02bdf49ad assets/create/lang/unfinished/de_de.json
|
||||||
|
d56a40fa6097af1badd3ab24bbcfa191ea5074ca assets/create/lang/unfinished/fr_fr.json
|
||||||
|
1945bf0aebfc97e6f2ee1ac7e4dd754e7fd19fa5 assets/create/lang/unfinished/it_it.json
|
||||||
|
3f76057ebb1c0e9a5c285fb79c1ef72ddec83a32 assets/create/lang/unfinished/ja_jp.json
|
||||||
|
504d30d63a19e117c51be32f16c778bc1a7114c7 assets/create/lang/unfinished/ko_kr.json
|
||||||
|
654efcd49befcac96bd632e65f0a36247bd0fc2e assets/create/lang/unfinished/nl_nl.json
|
||||||
|
2c0f9c853b85a47b91877cd7b89faddc918f0170 assets/create/lang/unfinished/pt_br.json
|
||||||
|
7193bf2573473b3fa8ffd7c8a6dd58ce069201a7 assets/create/lang/unfinished/ru_ru.json
|
||||||
|
28b75a0dd8c021a7e385b3479b91b1edd47f13f4 assets/create/lang/unfinished/zh_cn.json
|
||||||
|
846200eb548d3bfa2e77b41039de159b4b6cfb45 assets/create/models/block/acacia_window.json
|
||||||
|
1930fa3a3c98d53dd19e4ee7f55bc27fd47aa281 assets/create/models/block/acacia_window_pane_noside.json
|
||||||
|
1763ea2c9b981d187f5031ba608f3d5d3be3986a assets/create/models/block/acacia_window_pane_noside_alt.json
|
||||||
|
7d23c8e4543108f5f53b78ccb4908f7a5bb76c54 assets/create/models/block/acacia_window_pane_post.json
|
||||||
|
3bdcc6bd616a179ffc22e66307aab538e9bcb75f assets/create/models/block/acacia_window_pane_side.json
|
||||||
|
7b5b6809e3ef685a497ba15b549d3918aeb6c135 assets/create/models/block/acacia_window_pane_side_alt.json
|
||||||
|
>>>>>>> mc1.15/dev
|
||||||
7c81658c8839fdb23429e54f847c2a0aee0e866e assets/create/models/block/adjustable_pulley_end_horizontal.json
|
7c81658c8839fdb23429e54f847c2a0aee0e866e assets/create/models/block/adjustable_pulley_end_horizontal.json
|
||||||
20cfb751fc395a0e07c66ce87ab035207f9d1e0e assets/create/models/block/adjustable_pulley_end_horizontal_powered.json
|
20cfb751fc395a0e07c66ce87ab035207f9d1e0e assets/create/models/block/adjustable_pulley_end_horizontal_powered.json
|
||||||
bb02f94b260be8fe1944b801cc4050b4d213f1df assets/create/models/block/adjustable_pulley_end_vertical.json
|
bb02f94b260be8fe1944b801cc4050b4d213f1df assets/create/models/block/adjustable_pulley_end_vertical.json
|
||||||
|
|
|
@ -646,6 +646,12 @@
|
||||||
"create.blockzapper.leftClickToSet": "Left-Click a Block to set Material",
|
"create.blockzapper.leftClickToSet": "Left-Click a Block to set Material",
|
||||||
"create.blockzapper.empty": "Out of Blocks!",
|
"create.blockzapper.empty": "Out of Blocks!",
|
||||||
|
|
||||||
|
"create.minecart_coupling.two_couplings_max": "Minecarts cannot have more than two couplings each",
|
||||||
|
"create.minecart_coupling.unloaded": "Parts of your train seem to be in unloaded chunks",
|
||||||
|
"create.minecart_coupling.no_loops": "Couplings cannot form a loop",
|
||||||
|
"create.minecart_coupling.removed": "Removed all couplings from minecart",
|
||||||
|
"create.minecart_coupling.too_far": "Minecarts are too far apart",
|
||||||
|
|
||||||
"create.contraptions.movement_mode": "Movement Mode",
|
"create.contraptions.movement_mode": "Movement Mode",
|
||||||
"create.contraptions.movement_mode.move_place": "Always Place when Stopped",
|
"create.contraptions.movement_mode.move_place": "Always Place when Stopped",
|
||||||
"create.contraptions.movement_mode.move_place_returned": "Place only in Starting Position",
|
"create.contraptions.movement_mode.move_place_returned": "Place only in Starting Position",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 853",
|
"_": "Missing Localizations: 858",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -647,6 +647,12 @@
|
||||||
"create.blockzapper.leftClickToSet": "Linksklick auf einen Block zum Auswählen",
|
"create.blockzapper.leftClickToSet": "Linksklick auf einen Block zum Auswählen",
|
||||||
"create.blockzapper.empty": "Keine Blöcke übrig!",
|
"create.blockzapper.empty": "Keine Blöcke übrig!",
|
||||||
|
|
||||||
|
"create.minecart_coupling.two_couplings_max": "UNLOCALIZED: Minecarts cannot have more than two couplings each",
|
||||||
|
"create.minecart_coupling.unloaded": "UNLOCALIZED: Parts of your train seem to be in unloaded chunks",
|
||||||
|
"create.minecart_coupling.no_loops": "UNLOCALIZED: Couplings cannot form a loop",
|
||||||
|
"create.minecart_coupling.removed": "UNLOCALIZED: Removed all couplings from minecart",
|
||||||
|
"create.minecart_coupling.too_far": "UNLOCALIZED: Minecarts are too far apart",
|
||||||
|
|
||||||
"create.contraptions.movement_mode": "UNLOCALIZED: Movement Mode",
|
"create.contraptions.movement_mode": "UNLOCALIZED: Movement Mode",
|
||||||
"create.contraptions.movement_mode.move_place": "UNLOCALIZED: Always Place when Stopped",
|
"create.contraptions.movement_mode.move_place": "UNLOCALIZED: Always Place when Stopped",
|
||||||
"create.contraptions.movement_mode.move_place_returned": "UNLOCALIZED: Place only in Starting Position",
|
"create.contraptions.movement_mode.move_place_returned": "UNLOCALIZED: Place only in Starting Position",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 477",
|
"_": "Missing Localizations: 482",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -647,6 +647,12 @@
|
||||||
"create.blockzapper.leftClickToSet": "Clic gauche sur un bloc pour en définir le matériau",
|
"create.blockzapper.leftClickToSet": "Clic gauche sur un bloc pour en définir le matériau",
|
||||||
"create.blockzapper.empty": "Plus de blocs!",
|
"create.blockzapper.empty": "Plus de blocs!",
|
||||||
|
|
||||||
|
"create.minecart_coupling.two_couplings_max": "UNLOCALIZED: Minecarts cannot have more than two couplings each",
|
||||||
|
"create.minecart_coupling.unloaded": "UNLOCALIZED: Parts of your train seem to be in unloaded chunks",
|
||||||
|
"create.minecart_coupling.no_loops": "UNLOCALIZED: Couplings cannot form a loop",
|
||||||
|
"create.minecart_coupling.removed": "UNLOCALIZED: Removed all couplings from minecart",
|
||||||
|
"create.minecart_coupling.too_far": "UNLOCALIZED: Minecarts are too far apart",
|
||||||
|
|
||||||
"create.contraptions.movement_mode": "Mode de mouvement",
|
"create.contraptions.movement_mode": "Mode de mouvement",
|
||||||
"create.contraptions.movement_mode.move_place": "Toujours placer à l'arrêt",
|
"create.contraptions.movement_mode.move_place": "Toujours placer à l'arrêt",
|
||||||
"create.contraptions.movement_mode.move_place_returned": "Placer uniquement en position de départ",
|
"create.contraptions.movement_mode.move_place_returned": "Placer uniquement en position de départ",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 461",
|
"_": "Missing Localizations: 466",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -647,6 +647,12 @@
|
||||||
"create.blockzapper.leftClickToSet": "Clic-Sinistro su un blocco per impostare il materiale",
|
"create.blockzapper.leftClickToSet": "Clic-Sinistro su un blocco per impostare il materiale",
|
||||||
"create.blockzapper.empty": "Fuori dai Blocchi!",
|
"create.blockzapper.empty": "Fuori dai Blocchi!",
|
||||||
|
|
||||||
|
"create.minecart_coupling.two_couplings_max": "UNLOCALIZED: Minecarts cannot have more than two couplings each",
|
||||||
|
"create.minecart_coupling.unloaded": "UNLOCALIZED: Parts of your train seem to be in unloaded chunks",
|
||||||
|
"create.minecart_coupling.no_loops": "UNLOCALIZED: Couplings cannot form a loop",
|
||||||
|
"create.minecart_coupling.removed": "UNLOCALIZED: Removed all couplings from minecart",
|
||||||
|
"create.minecart_coupling.too_far": "UNLOCALIZED: Minecarts are too far apart",
|
||||||
|
|
||||||
"create.contraptions.movement_mode": "Modalità Movimento",
|
"create.contraptions.movement_mode": "Modalità Movimento",
|
||||||
"create.contraptions.movement_mode.move_place": "Posizionare Sempre quando è Fermo",
|
"create.contraptions.movement_mode.move_place": "Posizionare Sempre quando è Fermo",
|
||||||
"create.contraptions.movement_mode.move_place_returned": "Posiziona solo nella Posizione Iniziale",
|
"create.contraptions.movement_mode.move_place_returned": "Posiziona solo nella Posizione Iniziale",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 456",
|
"_": "Missing Localizations: 461",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -647,6 +647,12 @@
|
||||||
"create.blockzapper.leftClickToSet": "ブロックをシフト-左クリックでマテリアルを選択",
|
"create.blockzapper.leftClickToSet": "ブロックをシフト-左クリックでマテリアルを選択",
|
||||||
"create.blockzapper.empty": "ブロック不足!",
|
"create.blockzapper.empty": "ブロック不足!",
|
||||||
|
|
||||||
|
"create.minecart_coupling.two_couplings_max": "UNLOCALIZED: Minecarts cannot have more than two couplings each",
|
||||||
|
"create.minecart_coupling.unloaded": "UNLOCALIZED: Parts of your train seem to be in unloaded chunks",
|
||||||
|
"create.minecart_coupling.no_loops": "UNLOCALIZED: Couplings cannot form a loop",
|
||||||
|
"create.minecart_coupling.removed": "UNLOCALIZED: Removed all couplings from minecart",
|
||||||
|
"create.minecart_coupling.too_far": "UNLOCALIZED: Minecarts are too far apart",
|
||||||
|
|
||||||
"create.contraptions.movement_mode": "移動モード",
|
"create.contraptions.movement_mode": "移動モード",
|
||||||
"create.contraptions.movement_mode.move_place": "停止時に常に配置",
|
"create.contraptions.movement_mode.move_place": "停止時に常に配置",
|
||||||
"create.contraptions.movement_mode.move_place_returned": "開始位置のみに配置",
|
"create.contraptions.movement_mode.move_place_returned": "開始位置のみに配置",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 461",
|
"_": "Missing Localizations: 466",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -647,6 +647,12 @@
|
||||||
"create.blockzapper.leftClickToSet": "좌클릭으로 블럭 설정하기",
|
"create.blockzapper.leftClickToSet": "좌클릭으로 블럭 설정하기",
|
||||||
"create.blockzapper.empty": "블럭이 없습니다!",
|
"create.blockzapper.empty": "블럭이 없습니다!",
|
||||||
|
|
||||||
|
"create.minecart_coupling.two_couplings_max": "UNLOCALIZED: Minecarts cannot have more than two couplings each",
|
||||||
|
"create.minecart_coupling.unloaded": "UNLOCALIZED: Parts of your train seem to be in unloaded chunks",
|
||||||
|
"create.minecart_coupling.no_loops": "UNLOCALIZED: Couplings cannot form a loop",
|
||||||
|
"create.minecart_coupling.removed": "UNLOCALIZED: Removed all couplings from minecart",
|
||||||
|
"create.minecart_coupling.too_far": "UNLOCALIZED: Minecarts are too far apart",
|
||||||
|
|
||||||
"create.contraptions.movement_mode": "이동 설정",
|
"create.contraptions.movement_mode": "이동 설정",
|
||||||
"create.contraptions.movement_mode.move_place": "멈췄을때 항상 블럭 설치하기",
|
"create.contraptions.movement_mode.move_place": "멈췄을때 항상 블럭 설치하기",
|
||||||
"create.contraptions.movement_mode.move_place_returned": "멈췄을떄 최초 위치에서만 블럭 설치하기",
|
"create.contraptions.movement_mode.move_place_returned": "멈췄을떄 최초 위치에서만 블럭 설치하기",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 791",
|
"_": "Missing Localizations: 796",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -647,6 +647,12 @@
|
||||||
"create.blockzapper.leftClickToSet": "Klik met links op een Blok om een Materiaal te kiezen",
|
"create.blockzapper.leftClickToSet": "Klik met links op een Blok om een Materiaal te kiezen",
|
||||||
"create.blockzapper.empty": "De Blokken zijn op!",
|
"create.blockzapper.empty": "De Blokken zijn op!",
|
||||||
|
|
||||||
|
"create.minecart_coupling.two_couplings_max": "UNLOCALIZED: Minecarts cannot have more than two couplings each",
|
||||||
|
"create.minecart_coupling.unloaded": "UNLOCALIZED: Parts of your train seem to be in unloaded chunks",
|
||||||
|
"create.minecart_coupling.no_loops": "UNLOCALIZED: Couplings cannot form a loop",
|
||||||
|
"create.minecart_coupling.removed": "UNLOCALIZED: Removed all couplings from minecart",
|
||||||
|
"create.minecart_coupling.too_far": "UNLOCALIZED: Minecarts are too far apart",
|
||||||
|
|
||||||
"create.contraptions.movement_mode": "UNLOCALIZED: Movement Mode",
|
"create.contraptions.movement_mode": "UNLOCALIZED: Movement Mode",
|
||||||
"create.contraptions.movement_mode.move_place": "UNLOCALIZED: Always Place when Stopped",
|
"create.contraptions.movement_mode.move_place": "UNLOCALIZED: Always Place when Stopped",
|
||||||
"create.contraptions.movement_mode.move_place_returned": "UNLOCALIZED: Place only in Starting Position",
|
"create.contraptions.movement_mode.move_place_returned": "UNLOCALIZED: Place only in Starting Position",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 860",
|
"_": "Missing Localizations: 865",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -647,6 +647,12 @@
|
||||||
"create.blockzapper.leftClickToSet": "Botão-Esquerdo em um Bloco para selecionar Material",
|
"create.blockzapper.leftClickToSet": "Botão-Esquerdo em um Bloco para selecionar Material",
|
||||||
"create.blockzapper.empty": "Sem Blocos!",
|
"create.blockzapper.empty": "Sem Blocos!",
|
||||||
|
|
||||||
|
"create.minecart_coupling.two_couplings_max": "UNLOCALIZED: Minecarts cannot have more than two couplings each",
|
||||||
|
"create.minecart_coupling.unloaded": "UNLOCALIZED: Parts of your train seem to be in unloaded chunks",
|
||||||
|
"create.minecart_coupling.no_loops": "UNLOCALIZED: Couplings cannot form a loop",
|
||||||
|
"create.minecart_coupling.removed": "UNLOCALIZED: Removed all couplings from minecart",
|
||||||
|
"create.minecart_coupling.too_far": "UNLOCALIZED: Minecarts are too far apart",
|
||||||
|
|
||||||
"create.contraptions.movement_mode": "UNLOCALIZED: Movement Mode",
|
"create.contraptions.movement_mode": "UNLOCALIZED: Movement Mode",
|
||||||
"create.contraptions.movement_mode.move_place": "UNLOCALIZED: Always Place when Stopped",
|
"create.contraptions.movement_mode.move_place": "UNLOCALIZED: Always Place when Stopped",
|
||||||
"create.contraptions.movement_mode.move_place_returned": "UNLOCALIZED: Place only in Starting Position",
|
"create.contraptions.movement_mode.move_place_returned": "UNLOCALIZED: Place only in Starting Position",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 854",
|
"_": "Missing Localizations: 859",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -647,6 +647,12 @@
|
||||||
"create.blockzapper.leftClickToSet": "ЛКМ на блок, чтобы выбрать материал",
|
"create.blockzapper.leftClickToSet": "ЛКМ на блок, чтобы выбрать материал",
|
||||||
"create.blockzapper.empty": "Закончились блоки!",
|
"create.blockzapper.empty": "Закончились блоки!",
|
||||||
|
|
||||||
|
"create.minecart_coupling.two_couplings_max": "UNLOCALIZED: Minecarts cannot have more than two couplings each",
|
||||||
|
"create.minecart_coupling.unloaded": "UNLOCALIZED: Parts of your train seem to be in unloaded chunks",
|
||||||
|
"create.minecart_coupling.no_loops": "UNLOCALIZED: Couplings cannot form a loop",
|
||||||
|
"create.minecart_coupling.removed": "UNLOCALIZED: Removed all couplings from minecart",
|
||||||
|
"create.minecart_coupling.too_far": "UNLOCALIZED: Minecarts are too far apart",
|
||||||
|
|
||||||
"create.contraptions.movement_mode": "UNLOCALIZED: Movement Mode",
|
"create.contraptions.movement_mode": "UNLOCALIZED: Movement Mode",
|
||||||
"create.contraptions.movement_mode.move_place": "UNLOCALIZED: Always Place when Stopped",
|
"create.contraptions.movement_mode.move_place": "UNLOCALIZED: Always Place when Stopped",
|
||||||
"create.contraptions.movement_mode.move_place_returned": "UNLOCALIZED: Place only in Starting Position",
|
"create.contraptions.movement_mode.move_place_returned": "UNLOCALIZED: Place only in Starting Position",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 141",
|
"_": "Missing Localizations: 146",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -647,6 +647,12 @@
|
||||||
"create.blockzapper.leftClickToSet": "左键点击方块以设定方块",
|
"create.blockzapper.leftClickToSet": "左键点击方块以设定方块",
|
||||||
"create.blockzapper.empty": "方块不足!",
|
"create.blockzapper.empty": "方块不足!",
|
||||||
|
|
||||||
|
"create.minecart_coupling.two_couplings_max": "UNLOCALIZED: Minecarts cannot have more than two couplings each",
|
||||||
|
"create.minecart_coupling.unloaded": "UNLOCALIZED: Parts of your train seem to be in unloaded chunks",
|
||||||
|
"create.minecart_coupling.no_loops": "UNLOCALIZED: Couplings cannot form a loop",
|
||||||
|
"create.minecart_coupling.removed": "UNLOCALIZED: Removed all couplings from minecart",
|
||||||
|
"create.minecart_coupling.too_far": "UNLOCALIZED: Minecarts are too far apart",
|
||||||
|
|
||||||
"create.contraptions.movement_mode": "运动模式",
|
"create.contraptions.movement_mode": "运动模式",
|
||||||
"create.contraptions.movement_mode.move_place": "停止时总是实体化方块",
|
"create.contraptions.movement_mode.move_place": "停止时总是实体化方块",
|
||||||
"create.contraptions.movement_mode.move_place_returned": "停止时只在初始位置实体化方块",
|
"create.contraptions.movement_mode.move_place_returned": "停止时只在初始位置实体化方块",
|
||||||
|
|
|
@ -49,6 +49,7 @@ public class AllShapes {
|
||||||
.forDirectional(),
|
.forDirectional(),
|
||||||
CART_ASSEMBLER = shape(0, 12, 0, 16, 16, 16).add(-2, 0, 1, 18, 14, 15)
|
CART_ASSEMBLER = shape(0, 12, 0, 16, 16, 16).add(-2, 0, 1, 18, 14, 15)
|
||||||
.forHorizontalAxis(),
|
.forHorizontalAxis(),
|
||||||
|
CART_ASSEMBLER_PLAYER_COLLISION = shape(0, 0, 1, 16, 16, 15).forHorizontalAxis(),
|
||||||
STOCKPILE_SWITCH = shape(0, 0, 0, 16, 2, 16).add(1, 0, 1, 15, 16, 15)
|
STOCKPILE_SWITCH = shape(0, 0, 0, 16, 2, 16).add(1, 0, 1, 15, 16, 15)
|
||||||
.add(0, 14, 0, 16, 16, 16)
|
.add(0, 14, 0, 16, 16, 16)
|
||||||
.add(3, 3, -2, 13, 13, 2)
|
.add(3, 3, -2, 13, 13, 2)
|
||||||
|
|
|
@ -9,6 +9,7 @@ import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.simibubi.create.content.CreateItemGroup;
|
import com.simibubi.create.content.CreateItemGroup;
|
||||||
import com.simibubi.create.content.contraptions.TorquePropagator;
|
import com.simibubi.create.content.contraptions.TorquePropagator;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController;
|
||||||
import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler;
|
import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler;
|
||||||
import com.simibubi.create.content.palettes.AllPaletteBlocks;
|
import com.simibubi.create.content.palettes.AllPaletteBlocks;
|
||||||
import com.simibubi.create.content.palettes.PalettesItemGroup;
|
import com.simibubi.create.content.palettes.PalettesItemGroup;
|
||||||
|
@ -98,6 +99,7 @@ public class Create {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void init(final FMLCommonSetupEvent event) {
|
public static void init(final FMLCommonSetupEvent event) {
|
||||||
|
CapabilityMinecartController.register();
|
||||||
schematicReceiver = new ServerSchematicLoader();
|
schematicReceiver = new ServerSchematicLoader();
|
||||||
redstoneLinkNetworkHandler = new RedstoneLinkNetworkHandler();
|
redstoneLinkNetworkHandler = new RedstoneLinkNetworkHandler();
|
||||||
torquePropagator = new TorquePropagator();
|
torquePropagator = new TorquePropagator();
|
||||||
|
|
|
@ -200,7 +200,7 @@ public class RotationPropagator {
|
||||||
* @param pos
|
* @param pos
|
||||||
*/
|
*/
|
||||||
public static void handleAdded(World worldIn, BlockPos pos, KineticTileEntity addedTE) {
|
public static void handleAdded(World worldIn, BlockPos pos, KineticTileEntity addedTE) {
|
||||||
if (worldIn.isRemote || isFrozen())
|
if (worldIn.isRemote)
|
||||||
return;
|
return;
|
||||||
if (!worldIn.isBlockPresent(pos))
|
if (!worldIn.isBlockPresent(pos))
|
||||||
return;
|
return;
|
||||||
|
@ -297,7 +297,7 @@ public class RotationPropagator {
|
||||||
* @param removedTE
|
* @param removedTE
|
||||||
*/
|
*/
|
||||||
public static void handleRemoved(World worldIn, BlockPos pos, KineticTileEntity removedTE) {
|
public static void handleRemoved(World worldIn, BlockPos pos, KineticTileEntity removedTE) {
|
||||||
if (worldIn.isRemote || isFrozen())
|
if (worldIn.isRemote)
|
||||||
return;
|
return;
|
||||||
if (removedTE == null)
|
if (removedTE == null)
|
||||||
return;
|
return;
|
||||||
|
@ -454,8 +454,4 @@ public class RotationPropagator {
|
||||||
return neighbours;
|
return neighbours;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isFrozen() {
|
|
||||||
return AllConfigs.SERVER.control.freezeRotationPropagator.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,7 @@ public class BellMovementBehaviour extends MovementBehaviour {
|
||||||
public void onSpeedChanged(MovementContext context, Vector3d oldMotion, Vector3d motion) {
|
public void onSpeedChanged(MovementContext context, Vector3d oldMotion, Vector3d motion) {
|
||||||
double dotProduct = oldMotion.dotProduct(motion);
|
double dotProduct = oldMotion.dotProduct(motion);
|
||||||
|
|
||||||
if (dotProduct <= 0 && (context.relativeMotion.length() != 0 || context.rotation.length() == 0)
|
if (dotProduct <= 0 && (context.relativeMotion.length() != 0) || context.firstMovement)
|
||||||
|| context.firstMovement)
|
|
||||||
context.world.playSound(null, new BlockPos(context.position), SoundEvents.BLOCK_BELL_USE,
|
context.world.playSound(null, new BlockPos(context.position), SoundEvents.BLOCK_BELL_USE,
|
||||||
SoundCategory.BLOCKS, 2.0F, 1.0F);
|
SoundCategory.BLOCKS, 2.0F, 1.0F);
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,7 +138,7 @@ public class PortableStorageInterfaceMovement extends MovementBehaviour {
|
||||||
private Optional<Direction> getCurrentFacingIfValid(MovementContext context) {
|
private Optional<Direction> getCurrentFacingIfValid(MovementContext context) {
|
||||||
Vector3d directionVec = Vector3d.of(context.state.get(PortableStorageInterfaceBlock.FACING)
|
Vector3d directionVec = Vector3d.of(context.state.get(PortableStorageInterfaceBlock.FACING)
|
||||||
.getDirectionVec());
|
.getDirectionVec());
|
||||||
directionVec = VecHelper.rotate(directionVec, context.rotation.x, context.rotation.y, context.rotation.z);
|
directionVec = context.rotation.apply(directionVec);
|
||||||
Direction facingFromVector = Direction.getFacingFromVector(directionVec.x, directionVec.y, directionVec.z);
|
Direction facingFromVector = Direction.getFacingFromVector(directionVec.x, directionVec.y, directionVec.z);
|
||||||
if (directionVec.distanceTo(Vector3d.of(facingFromVector.getDirectionVec())) > 1 / 8f)
|
if (directionVec.distanceTo(Vector3d.of(facingFromVector.getDirectionVec())) > 1 / 8f)
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
|
|
|
@ -5,7 +5,6 @@ import java.util.HashMap;
|
||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
|
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
|
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
|
||||||
|
|
||||||
import mcp.MethodsReturnNonnullByDefault;
|
import mcp.MethodsReturnNonnullByDefault;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
|
@ -63,7 +62,7 @@ public class DispenserMovementBehaviour extends DropperMovementBehaviour {
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3d facingVec = Vector3d.of(context.state.get(DispenserBlock.FACING).getDirectionVec());
|
Vector3d facingVec = Vector3d.of(context.state.get(DispenserBlock.FACING).getDirectionVec());
|
||||||
facingVec = VecHelper.rotate(facingVec, context.rotation.x, context.rotation.y, context.rotation.z);
|
facingVec = context.rotation.apply(facingVec);
|
||||||
facingVec.normalize();
|
facingVec.normalize();
|
||||||
Direction clostestFacing = Direction.getFacingFromVector(facingVec.x, facingVec.y, facingVec.z);
|
Direction clostestFacing = Direction.getFacingFromVector(facingVec.x, facingVec.y, facingVec.z);
|
||||||
ContraptionBlockSource blockSource = new ContraptionBlockSource(context, pos, clostestFacing);
|
ContraptionBlockSource blockSource = new ContraptionBlockSource(context, pos, clostestFacing);
|
||||||
|
|
|
@ -35,6 +35,7 @@ import net.minecraft.world.IWorld;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraft.world.server.ServerWorld;
|
import net.minecraft.world.server.ServerWorld;
|
||||||
|
|
||||||
|
|
||||||
public interface IMovedDispenseItemBehaviour {
|
public interface IMovedDispenseItemBehaviour {
|
||||||
static void init() {
|
static void init() {
|
||||||
MovedProjectileDispenserBehaviour movedPotionDispenseItemBehaviour = new MovedProjectileDispenserBehaviour() {
|
MovedProjectileDispenserBehaviour movedPotionDispenseItemBehaviour = new MovedProjectileDispenserBehaviour() {
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class MovedDefaultDispenseItemBehaviour implements IMovedDispenseItemBeha
|
||||||
@Override
|
@Override
|
||||||
public ItemStack dispense(ItemStack itemStack, MovementContext context, BlockPos pos) {
|
public ItemStack dispense(ItemStack itemStack, MovementContext context, BlockPos pos) {
|
||||||
Vector3d facingVec = Vector3d.of(context.state.get(DispenserBlock.FACING).getDirectionVec());
|
Vector3d facingVec = Vector3d.of(context.state.get(DispenserBlock.FACING).getDirectionVec());
|
||||||
facingVec = VecHelper.rotate(facingVec, context.rotation.x, context.rotation.y, context.rotation.z);
|
facingVec = context.rotation.apply(facingVec);
|
||||||
facingVec.normalize();
|
facingVec.normalize();
|
||||||
|
|
||||||
Direction closestToFacing = getClosestFacingDirection(facingVec);
|
Direction closestToFacing = getClosestFacingDirection(facingVec);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package com.simibubi.create.content.contraptions.components.crank;
|
package com.simibubi.create.content.contraptions.components.crank;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
|
|
||||||
import com.simibubi.create.AllBlockPartials;
|
import com.simibubi.create.AllBlockPartials;
|
||||||
|
|
||||||
import net.minecraft.item.ItemGroup;
|
import net.minecraft.item.ItemGroup;
|
||||||
|
@ -8,8 +10,6 @@ import net.minecraft.util.NonNullList;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
|
||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
||||||
|
|
||||||
@ParametersAreNonnullByDefault
|
@ParametersAreNonnullByDefault
|
||||||
public class ValveHandleBlock extends HandCrankBlock {
|
public class ValveHandleBlock extends HandCrankBlock {
|
||||||
private final boolean inCreativeTab;
|
private final boolean inCreativeTab;
|
||||||
|
|
|
@ -69,7 +69,7 @@ public class CrushingWheelControllerBlock extends Block
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onEntityCollision(BlockState state, World worldIn, BlockPos pos, Entity entityIn) {
|
public void onEntityCollision(BlockState state, World worldIn, BlockPos pos, Entity entityIn) {
|
||||||
if (!state.get(VALID) || CrushingWheelControllerTileEntity.isFrozen())
|
if (!state.get(VALID))
|
||||||
return;
|
return;
|
||||||
withTileEntityDo(worldIn, pos, te -> {
|
withTileEntityDo(worldIn, pos, te -> {
|
||||||
if (te.processingEntity == entityIn)
|
if (te.processingEntity == entityIn)
|
||||||
|
@ -80,9 +80,6 @@ public class CrushingWheelControllerBlock extends Block
|
||||||
@Override
|
@Override
|
||||||
public void onLanded(IBlockReader worldIn, Entity entityIn) {
|
public void onLanded(IBlockReader worldIn, Entity entityIn) {
|
||||||
super.onLanded(worldIn, entityIn);
|
super.onLanded(worldIn, entityIn);
|
||||||
if (CrushingWheelControllerTileEntity.isFrozen())
|
|
||||||
return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
CrushingWheelControllerTileEntity te = getTileEntity(worldIn, entityIn.getBlockPos().down());
|
CrushingWheelControllerTileEntity te = getTileEntity(worldIn, entityIn.getBlockPos().down());
|
||||||
if (te.crushingspeed == 0)
|
if (te.crushingspeed == 0)
|
||||||
|
@ -122,7 +119,7 @@ public class CrushingWheelControllerBlock extends Block
|
||||||
|
|
||||||
public void updateSpeed(BlockState state, IWorld world, BlockPos pos) {
|
public void updateSpeed(BlockState state, IWorld world, BlockPos pos) {
|
||||||
withTileEntityDo(world, pos, te -> {
|
withTileEntityDo(world, pos, te -> {
|
||||||
if (!state.get(VALID) || CrushingWheelControllerTileEntity.isFrozen()) {
|
if (!state.get(VALID)) {
|
||||||
if (te.crushingspeed != 0) {
|
if (te.crushingspeed != 0) {
|
||||||
te.crushingspeed = 0;
|
te.crushingspeed = 0;
|
||||||
te.sendData();
|
te.sendData();
|
||||||
|
|
|
@ -70,8 +70,6 @@ public class CrushingWheelControllerTileEntity extends SmartTileEntity {
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
super.tick();
|
super.tick();
|
||||||
if (isFrozen())
|
|
||||||
return;
|
|
||||||
if (searchForEntity) {
|
if (searchForEntity) {
|
||||||
searchForEntity = false;
|
searchForEntity = false;
|
||||||
List<Entity> search = world.getEntitiesInAABBexcluding(null, new AxisAlignedBB(getPos()),
|
List<Entity> search = world.getEntitiesInAABBexcluding(null, new AxisAlignedBB(getPos()),
|
||||||
|
@ -225,7 +223,7 @@ public class CrushingWheelControllerTileEntity extends SmartTileEntity {
|
||||||
@Override
|
@Override
|
||||||
protected void fromTag(BlockState state, CompoundNBT compound, boolean clientPacket) {
|
protected void fromTag(BlockState state, CompoundNBT compound, boolean clientPacket) {
|
||||||
super.fromTag(state, compound, clientPacket);
|
super.fromTag(state, compound, clientPacket);
|
||||||
if (compound.contains("Entity") && !isFrozen() && !isOccupied()) {
|
if (compound.contains("Entity") && !isOccupied()) {
|
||||||
entityUUID = NBTUtil.readUniqueId(compound.getCompound("Entity"));
|
entityUUID = NBTUtil.readUniqueId(compound.getCompound("Entity"));
|
||||||
this.searchForEntity = true;
|
this.searchForEntity = true;
|
||||||
}
|
}
|
||||||
|
@ -265,8 +263,4 @@ public class CrushingWheelControllerTileEntity extends SmartTileEntity {
|
||||||
return processingEntity != null;
|
return processingEntity != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isFrozen() {
|
|
||||||
return AllConfigs.SERVER.control.freezeCrushing.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Mov
|
||||||
import com.simibubi.create.content.logistics.item.filter.FilterItem;
|
import com.simibubi.create.content.logistics.item.filter.FilterItem;
|
||||||
import com.simibubi.create.foundation.item.ItemHelper;
|
import com.simibubi.create.foundation.item.ItemHelper;
|
||||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
|
||||||
|
|
||||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||||
import net.minecraft.entity.player.PlayerInventory;
|
import net.minecraft.entity.player.PlayerInventory;
|
||||||
|
@ -52,7 +51,7 @@ public class DeployerMovementBehaviour extends MovementBehaviour {
|
||||||
public void activate(MovementContext context, BlockPos pos, DeployerFakePlayer player, Mode mode) {
|
public void activate(MovementContext context, BlockPos pos, DeployerFakePlayer player, Mode mode) {
|
||||||
Vector3d facingVec = Vector3d.of(context.state.get(DeployerBlock.FACING)
|
Vector3d facingVec = Vector3d.of(context.state.get(DeployerBlock.FACING)
|
||||||
.getDirectionVec());
|
.getDirectionVec());
|
||||||
facingVec = VecHelper.rotate(facingVec, context.rotation.x, context.rotation.y, context.rotation.z);
|
facingVec = context.rotation.apply(facingVec);
|
||||||
Vector3d vec = context.position.subtract(facingVec.scale(2));
|
Vector3d vec = context.position.subtract(facingVec.scale(2));
|
||||||
player.rotationYaw = ContraptionEntity.yawFromVector(facingVec);
|
player.rotationYaw = ContraptionEntity.yawFromVector(facingVec);
|
||||||
player.rotationPitch = ContraptionEntity.pitchFromVector(facingVec) - 90;
|
player.rotationPitch = ContraptionEntity.pitchFromVector(facingVec) - 90;
|
||||||
|
|
|
@ -105,9 +105,6 @@ public class AirCurrent {
|
||||||
if (entity instanceof ServerPlayerEntity)
|
if (entity instanceof ServerPlayerEntity)
|
||||||
((ServerPlayerEntity) entity).connection.floatingTickCount = 0;
|
((ServerPlayerEntity) entity).connection.floatingTickCount = 0;
|
||||||
|
|
||||||
if (InWorldProcessing.isFrozen())
|
|
||||||
return;
|
|
||||||
|
|
||||||
entityDistance -= .5f;
|
entityDistance -= .5f;
|
||||||
InWorldProcessing.Type processingType = getSegmentAt((float) entityDistance);
|
InWorldProcessing.Type processingType = getSegmentAt((float) entityDistance);
|
||||||
if (processingType != null) {
|
if (processingType != null) {
|
||||||
|
|
|
@ -142,10 +142,6 @@ public abstract class Contraption {
|
||||||
return contraption;
|
return contraption;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isFrozen() {
|
|
||||||
return AllConfigs.SERVER.control.freezeContraptions.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static MovementBehaviour getMovement(BlockState state) {
|
protected static MovementBehaviour getMovement(BlockState state) {
|
||||||
Block block = state.getBlock();
|
Block block = state.getBlock();
|
||||||
if (!AllMovementBehaviours.hasMovementBehaviour(block))
|
if (!AllMovementBehaviours.hasMovementBehaviour(block))
|
||||||
|
@ -337,9 +333,14 @@ public abstract class Contraption {
|
||||||
frontier.add(otherPartPos);
|
frontier.add(otherPartPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cart assemblers attach themselves
|
||||||
|
BlockState stateBelow = world.getBlockState(pos.down());
|
||||||
|
if (!visited.contains(pos.down()) && AllBlocks.CART_ASSEMBLER.has(stateBelow))
|
||||||
|
frontier.add(pos.down());
|
||||||
|
|
||||||
Map<Direction, SuperGlueEntity> superglue = SuperGlueHandler.gatherGlue(world, pos);
|
Map<Direction, SuperGlueEntity> superglue = SuperGlueHandler.gatherGlue(world, pos);
|
||||||
|
|
||||||
// Slime blocks drag adjacent blocks if possible
|
// Slime blocks and super glue drag adjacent blocks if possible
|
||||||
boolean isSlimeBlock = state.getBlock() instanceof SlimeBlock;
|
boolean isSlimeBlock = state.getBlock() instanceof SlimeBlock;
|
||||||
for (Direction offset : Direction.values()) {
|
for (Direction offset : Direction.values()) {
|
||||||
BlockPos offsetPos = pos.offset(offset);
|
BlockPos offsetPos = pos.offset(offset);
|
||||||
|
@ -360,7 +361,6 @@ public abstract class Contraption {
|
||||||
|
|
||||||
if (!wasVisited && ((isSlimeBlock && !brittle) || blockAttachedTowardsFace || faceHasGlue))
|
if (!wasVisited && ((isSlimeBlock && !brittle) || blockAttachedTowardsFace || faceHasGlue))
|
||||||
frontier.add(offsetPos);
|
frontier.add(offsetPos);
|
||||||
|
|
||||||
if (faceHasGlue)
|
if (faceHasGlue)
|
||||||
addGlue(superglue.get(offset));
|
addGlue(superglue.get(offset));
|
||||||
}
|
}
|
||||||
|
@ -764,7 +764,7 @@ public abstract class Contraption {
|
||||||
ctx.position = null;
|
ctx.position = null;
|
||||||
ctx.motion = Vector3d.ZERO;
|
ctx.motion = Vector3d.ZERO;
|
||||||
ctx.relativeMotion = Vector3d.ZERO;
|
ctx.relativeMotion = Vector3d.ZERO;
|
||||||
ctx.rotation = Vector3d.ZERO;
|
ctx.rotation = v -> v;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,7 @@ package com.simibubi.create.content.contraptions.components.structureMovement;
|
||||||
import static net.minecraft.entity.Entity.collideBoundingBoxHeuristically;
|
import static net.minecraft.entity.Entity.collideBoundingBoxHeuristically;
|
||||||
import static net.minecraft.entity.Entity.horizontalMag;
|
import static net.minecraft.entity.Entity.horizontalMag;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@ -33,6 +31,7 @@ import net.minecraft.entity.EntityType;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
|
import net.minecraft.util.Direction.Axis;
|
||||||
import net.minecraft.util.Direction.AxisDirection;
|
import net.minecraft.util.Direction.AxisDirection;
|
||||||
import net.minecraft.util.ReuseableStream;
|
import net.minecraft.util.ReuseableStream;
|
||||||
import net.minecraft.util.math.AxisAlignedBB;
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
|
@ -51,28 +50,11 @@ import net.minecraftforge.fml.DistExecutor;
|
||||||
|
|
||||||
public class ContraptionCollider {
|
public class ContraptionCollider {
|
||||||
|
|
||||||
public static void runCollisions(World world) {
|
|
||||||
List<WeakReference<ContraptionEntity>> list = ContraptionHandler.activeContraptions.getIfPresent(world);
|
|
||||||
if (list == null)
|
|
||||||
return;
|
|
||||||
for (Iterator<WeakReference<ContraptionEntity>> iterator = list.iterator(); iterator.hasNext();) {
|
|
||||||
WeakReference<ContraptionEntity> weakReference = iterator.next();
|
|
||||||
ContraptionEntity contraptionEntity = weakReference.get();
|
|
||||||
if (contraptionEntity == null) {
|
|
||||||
iterator.remove();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!contraptionEntity.isAlive())
|
|
||||||
continue;
|
|
||||||
collideEntities(contraptionEntity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum PlayerType {
|
enum PlayerType {
|
||||||
NONE, CLIENT, REMOTE, SERVER
|
NONE, CLIENT, REMOTE, SERVER
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void collideEntities(ContraptionEntity contraptionEntity) {
|
static void collideEntities(ContraptionEntity contraptionEntity) {
|
||||||
World world = contraptionEntity.getEntityWorld();
|
World world = contraptionEntity.getEntityWorld();
|
||||||
Contraption contraption = contraptionEntity.getContraption();
|
Contraption contraption = contraptionEntity.getContraption();
|
||||||
AxisAlignedBB bounds = contraptionEntity.getBoundingBox();
|
AxisAlignedBB bounds = contraptionEntity.getBoundingBox();
|
||||||
|
@ -89,8 +71,18 @@ public class ContraptionCollider {
|
||||||
|
|
||||||
Vector3d centerOfBlock = VecHelper.getCenterOf(BlockPos.ZERO);
|
Vector3d centerOfBlock = VecHelper.getCenterOf(BlockPos.ZERO);
|
||||||
double conRotX = contraptionRotation.x;
|
double conRotX = contraptionRotation.x;
|
||||||
double conRotY = contraptionRotation.y;
|
double conRotY = contraptionRotation.y + contraptionEntity.getInitialYaw();
|
||||||
double conRotZ = contraptionRotation.z;
|
double conRotZ = contraptionRotation.z;
|
||||||
|
|
||||||
|
double reverseYaw = 0;
|
||||||
|
|
||||||
|
// Collision algorithm does not support rotation around two axes -> rotate
|
||||||
|
// entities manually
|
||||||
|
if (conRotZ != 0 && contraptionRotation.y != 0) {
|
||||||
|
reverseYaw = contraptionRotation.y;
|
||||||
|
conRotY = contraptionEntity.getInitialYaw();
|
||||||
|
}
|
||||||
|
|
||||||
Vector3d contraptionCentreOffset = contraptionEntity.stationary ? centerOfBlock : Vector3d.ZERO.add(0, 0.5, 0);
|
Vector3d contraptionCentreOffset = contraptionEntity.stationary ? centerOfBlock : Vector3d.ZERO.add(0, 0.5, 0);
|
||||||
boolean axisAlignedCollision = contraptionRotation.equals(Vector3d.ZERO);
|
boolean axisAlignedCollision = contraptionRotation.equals(Vector3d.ZERO);
|
||||||
Matrix3d rotation = null;
|
Matrix3d rotation = null;
|
||||||
|
@ -118,13 +110,15 @@ public class ContraptionCollider {
|
||||||
Vector3d centerY = new Vector3d(0, entityBounds.getYSize() / 2, 0);
|
Vector3d centerY = new Vector3d(0, entityBounds.getYSize() / 2, 0);
|
||||||
Vector3d motion = entity.getMotion();
|
Vector3d motion = entity.getMotion();
|
||||||
|
|
||||||
Vector3d position = entityPosition.subtract(contraptionCentreOffset)
|
Vector3d position = entityPosition;
|
||||||
.add(centerY);
|
position = position.subtract(contraptionCentreOffset);
|
||||||
|
position = position.add(centerY);
|
||||||
position = position.subtract(contraptionPosition);
|
position = position.subtract(contraptionPosition);
|
||||||
|
position = VecHelper.rotate(position, -reverseYaw, Axis.Y);
|
||||||
position = rotation.transform(position);
|
position = rotation.transform(position);
|
||||||
position = position.add(centerOfBlock)
|
position = position.add(centerOfBlock);
|
||||||
.subtract(centerY)
|
position = position.subtract(centerY);
|
||||||
.subtract(entityPosition);
|
position = position.subtract(entityPosition);
|
||||||
|
|
||||||
// Find all potential block shapes to collide with
|
// Find all potential block shapes to collide with
|
||||||
AxisAlignedBB localBB = entityBounds.offset(position)
|
AxisAlignedBB localBB = entityBounds.offset(position)
|
||||||
|
@ -209,6 +203,7 @@ public class ContraptionCollider {
|
||||||
motionResponse = rotation.transform(motionResponse)
|
motionResponse = rotation.transform(motionResponse)
|
||||||
.add(contraptionMotion);
|
.add(contraptionMotion);
|
||||||
totalResponse = rotation.transform(totalResponse);
|
totalResponse = rotation.transform(totalResponse);
|
||||||
|
totalResponse = VecHelper.rotate(totalResponse, reverseYaw, Axis.Y);
|
||||||
rotation.transpose();
|
rotation.transpose();
|
||||||
|
|
||||||
if (futureCollision.isTrue() && playerType != PlayerType.SERVER) {
|
if (futureCollision.isTrue() && playerType != PlayerType.SERVER) {
|
||||||
|
@ -224,7 +219,7 @@ public class ContraptionCollider {
|
||||||
entity.fallDistance = 0;
|
entity.fallDistance = 0;
|
||||||
entity.setOnGround(true);
|
entity.setOnGround(true);
|
||||||
contraptionEntity.collidingEntities.add(entity);
|
contraptionEntity.collidingEntities.add(entity);
|
||||||
if (playerType != PlayerType.SERVER)
|
if (playerType != PlayerType.SERVER)
|
||||||
contactPointMotion = contraptionEntity.getContactPointMotion(entityPosition);
|
contactPointMotion = contraptionEntity.getContactPointMotion(entityPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +248,7 @@ public class ContraptionCollider {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
totalResponse = totalResponse.add(contactPointMotion);
|
totalResponse = totalResponse.add(contactPointMotion);
|
||||||
Vector3d allowedMovement = getAllowedMovement(totalResponse, entity);
|
Vector3d allowedMovement = getAllowedMovement(totalResponse, entity);
|
||||||
contraptionEntity.collidingEntities.add(entity);
|
contraptionEntity.collidingEntities.add(entity);
|
||||||
|
@ -263,7 +259,7 @@ public class ContraptionCollider {
|
||||||
|
|
||||||
if (playerType != PlayerType.CLIENT)
|
if (playerType != PlayerType.CLIENT)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
double d0 = entity.getX() - entity.prevPosX - contactPointMotion.x;
|
double d0 = entity.getX() - entity.prevPosX - contactPointMotion.x;
|
||||||
double d1 = entity.getZ() - entity.prevPosZ - contactPointMotion.z;
|
double d1 = entity.getZ() - entity.prevPosZ - contactPointMotion.z;
|
||||||
float limbSwing = MathHelper.sqrt(d0 * d0 + d1 * d1) * 4.0F;
|
float limbSwing = MathHelper.sqrt(d0 * d0 + d1 * d1) * 4.0F;
|
||||||
|
@ -357,8 +353,6 @@ public class ContraptionCollider {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean collideBlocks(ContraptionEntity contraptionEntity) {
|
public static boolean collideBlocks(ContraptionEntity contraptionEntity) {
|
||||||
if (Contraption.isFrozen())
|
|
||||||
return true;
|
|
||||||
if (!contraptionEntity.collisionEnabled())
|
if (!contraptionEntity.collisionEnabled())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -20,11 +20,13 @@ import com.simibubi.create.content.contraptions.components.structureMovement.glu
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode;
|
import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MountedContraption;
|
import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MountedContraption;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionSeatMappingPacket;
|
import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionSeatMappingPacket;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCoupling;
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCouplingHandler;
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController;
|
||||||
import com.simibubi.create.foundation.item.ItemHelper;
|
import com.simibubi.create.foundation.item.ItemHelper;
|
||||||
import com.simibubi.create.foundation.networking.AllPackets;
|
import com.simibubi.create.foundation.networking.AllPackets;
|
||||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||||
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
|
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
@ -49,10 +51,12 @@ import net.minecraft.network.PacketBuffer;
|
||||||
import net.minecraft.network.datasync.DataParameter;
|
import net.minecraft.network.datasync.DataParameter;
|
||||||
import net.minecraft.network.datasync.DataSerializers;
|
import net.minecraft.network.datasync.DataSerializers;
|
||||||
import net.minecraft.network.datasync.EntityDataManager;
|
import net.minecraft.network.datasync.EntityDataManager;
|
||||||
|
import net.minecraft.network.datasync.IDataSerializer;
|
||||||
import net.minecraft.tags.BlockTags;
|
import net.minecraft.tags.BlockTags;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
import net.minecraft.util.DamageSource;
|
import net.minecraft.util.DamageSource;
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
|
import net.minecraft.util.Direction.Axis;
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
import net.minecraft.util.math.AxisAlignedBB;
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
@ -62,32 +66,55 @@ import net.minecraft.world.World;
|
||||||
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
|
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
|
||||||
import net.minecraftforge.fml.network.NetworkHooks;
|
import net.minecraftforge.fml.network.NetworkHooks;
|
||||||
import net.minecraftforge.fml.network.PacketDistributor;
|
import net.minecraftforge.fml.network.PacketDistributor;
|
||||||
|
|
||||||
public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnData {
|
public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnData {
|
||||||
|
|
||||||
|
public static final IDataSerializer<Optional<Direction>> OPTIONAL_DIRECTION =
|
||||||
|
new IDataSerializer<Optional<Direction>>() {
|
||||||
|
|
||||||
|
public void write(PacketBuffer buffer, Optional<Direction> opt) {
|
||||||
|
buffer.writeVarInt(opt.map(Direction::ordinal)
|
||||||
|
.orElse(-1) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Direction> read(PacketBuffer buffer) {
|
||||||
|
int i = buffer.readVarInt();
|
||||||
|
return i == 0 ? Optional.empty() : Optional.of(Direction.values()[i - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Direction> copyValue(Optional<Direction> opt) {
|
||||||
|
return Optional.ofNullable(opt.orElse(null));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static {
|
||||||
|
DataSerializers.registerSerializer(OPTIONAL_DIRECTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Entity> collidingEntities = new ArrayList<>();
|
||||||
|
|
||||||
protected Contraption contraption;
|
protected Contraption contraption;
|
||||||
protected float initialAngle;
|
|
||||||
protected float forcedAngle;
|
|
||||||
protected BlockPos controllerPos;
|
protected BlockPos controllerPos;
|
||||||
protected Vector3d motionBeforeStall;
|
protected Vector3d motionBeforeStall;
|
||||||
|
protected boolean forceAngle;
|
||||||
protected boolean stationary;
|
protected boolean stationary;
|
||||||
protected boolean initialized;
|
protected boolean initialized;
|
||||||
final List<Entity> collidingEntities = new ArrayList<>();
|
|
||||||
private boolean isSerializingFurnaceCart;
|
private boolean isSerializingFurnaceCart;
|
||||||
private boolean attachedExtraInventories;
|
private boolean attachedExtraInventories;
|
||||||
private boolean prevPosInvalid;
|
private boolean prevPosInvalid;
|
||||||
|
|
||||||
private static final Ingredient FUEL_ITEMS = Ingredient.fromItems(Items.COAL, Items.CHARCOAL);
|
private static final Ingredient FUEL_ITEMS = Ingredient.fromItems(Items.COAL, Items.CHARCOAL);
|
||||||
|
|
||||||
private static final DataParameter<Boolean> STALLED =
|
private static final DataParameter<Boolean> STALLED =
|
||||||
EntityDataManager.createKey(ContraptionEntity.class, DataSerializers.BOOLEAN);
|
EntityDataManager.createKey(ContraptionEntity.class, DataSerializers.BOOLEAN);
|
||||||
|
|
||||||
private static final DataParameter<Optional<UUID>> COUPLING =
|
private static final DataParameter<Optional<UUID>> COUPLING =
|
||||||
EntityDataManager.createKey(ContraptionEntity.class, DataSerializers.OPTIONAL_UNIQUE_ID);
|
EntityDataManager.createKey(ContraptionEntity.class, DataSerializers.OPTIONAL_UNIQUE_ID);
|
||||||
private static final DataParameter<Optional<UUID>> COUPLED_CART =
|
private static final DataParameter<Optional<Direction>> INITIAL_ORIENTATION =
|
||||||
EntityDataManager.createKey(ContraptionEntity.class, DataSerializers.OPTIONAL_UNIQUE_ID);
|
EntityDataManager.createKey(ContraptionEntity.class, ContraptionEntity.OPTIONAL_DIRECTION);
|
||||||
|
|
||||||
public float prevYaw;
|
public float prevYaw;
|
||||||
public float prevPitch;
|
public float prevPitch;
|
||||||
|
@ -107,23 +134,15 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
stationary = entityTypeIn == AllEntityTypes.STATIONARY_CONTRAPTION.get();
|
stationary = entityTypeIn == AllEntityTypes.STATIONARY_CONTRAPTION.get();
|
||||||
isSerializingFurnaceCart = false;
|
isSerializingFurnaceCart = false;
|
||||||
attachedExtraInventories = false;
|
attachedExtraInventories = false;
|
||||||
forcedAngle = -1;
|
|
||||||
prevPosInvalid = true;
|
prevPosInvalid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ContraptionEntity createMounted(World world, Contraption contraption, float initialAngle) {
|
public static ContraptionEntity createMounted(World world, Contraption contraption,
|
||||||
|
Optional<Direction> initialOrientation) {
|
||||||
ContraptionEntity entity = new ContraptionEntity(AllEntityTypes.CONTRAPTION.get(), world);
|
ContraptionEntity entity = new ContraptionEntity(AllEntityTypes.CONTRAPTION.get(), world);
|
||||||
entity.contraptionCreated(contraption);
|
entity.contraptionCreated(contraption);
|
||||||
entity.initialAngle = initialAngle;
|
initialOrientation.ifPresent(entity::setInitialOrientation);
|
||||||
entity.forceYaw(initialAngle);
|
entity.startAtInitialYaw();
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ContraptionEntity createMounted(World world, Contraption contraption, float initialAngle,
|
|
||||||
Direction facing) {
|
|
||||||
ContraptionEntity entity = createMounted(world, contraption, initialAngle);
|
|
||||||
entity.forcedAngle = facing.getHorizontalAngle();
|
|
||||||
entity.forceYaw(entity.forcedAngle);
|
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +152,10 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reOrientate(Direction newInitialAngle) {
|
||||||
|
setInitialOrientation(newInitialAngle);
|
||||||
|
}
|
||||||
|
|
||||||
protected void contraptionCreated(Contraption contraption) {
|
protected void contraptionCreated(Contraption contraption) {
|
||||||
this.contraption = contraption;
|
this.contraption = contraption;
|
||||||
if (contraption == null)
|
if (contraption == null)
|
||||||
|
@ -219,7 +242,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
BlockPos seat = contraption.getSeat(passenger.getUniqueID());
|
BlockPos seat = contraption.getSeat(passenger.getUniqueID());
|
||||||
if (seat == null)
|
if (seat == null)
|
||||||
return null;
|
return null;
|
||||||
Vector3d transformedVector = toGlobalVector(Vector3d.of(seat).add(.5, passenger.getYOffset() + ySize - .15f, .5))
|
Vector3d transformedVector = toGlobalVector(Vector3d.of(seat).add(.5, passenger.getYOffset() + ySize - .15f, .5), 1)
|
||||||
.add(VecHelper.getCenterOf(BlockPos.ZERO))
|
.add(VecHelper.getCenterOf(BlockPos.ZERO))
|
||||||
.subtract(0.5, ySize, 0.5);
|
.subtract(0.5, ySize, 0.5);
|
||||||
return transformedVector;
|
return transformedVector;
|
||||||
|
@ -267,20 +290,21 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3d toGlobalVector(Vector3d localVec) {
|
public Vector3d toGlobalVector(Vector3d localVec, float partialTicks) {
|
||||||
Vector3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
|
Vector3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
|
||||||
localVec = localVec.subtract(rotationOffset);
|
localVec = localVec.subtract(rotationOffset);
|
||||||
localVec = VecHelper.rotate(localVec, getRotationVec());
|
localVec = applyRotation(localVec, partialTicks);
|
||||||
localVec = localVec.add(rotationOffset)
|
localVec = localVec.add(rotationOffset)
|
||||||
.add(getAnchorVec());
|
.add(getAnchorVec());
|
||||||
return localVec;
|
return localVec;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3d toLocalVector(Vector3d globalVec) {
|
|
||||||
|
public Vector3d toLocalVector(Vector3d globalVec, float partialTicks) {
|
||||||
Vector3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
|
Vector3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
|
||||||
globalVec = globalVec.subtract(getAnchorVec())
|
globalVec = globalVec.subtract(getAnchorVec())
|
||||||
.subtract(rotationOffset);
|
.subtract(rotationOffset);
|
||||||
globalVec = VecHelper.rotate(globalVec, getRotationVec().scale(-1));
|
globalVec = reverseRotation(globalVec, partialTicks);
|
||||||
globalVec = globalVec.add(rotationOffset);
|
globalVec = globalVec.add(rotationOffset);
|
||||||
return globalVec;
|
return globalVec;
|
||||||
}
|
}
|
||||||
|
@ -291,7 +315,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
remove();
|
remove();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
prevPosX = getX();
|
prevPosX = getX();
|
||||||
prevPosY = getY();
|
prevPosY = getY();
|
||||||
prevPosZ = getZ();
|
prevPosZ = getZ();
|
||||||
|
@ -315,29 +339,41 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
if (ContraptionCollider.collideBlocks(this))
|
if (ContraptionCollider.collideBlocks(this))
|
||||||
getController().collided();
|
getController().collided();
|
||||||
|
|
||||||
Vector3d movement = getPositionVec().subtract(prevPosX, prevPosY, prevPosZ);
|
tickActors();
|
||||||
tickActors(movement);
|
|
||||||
|
|
||||||
prevYaw = yaw;
|
prevYaw = yaw;
|
||||||
prevPitch = pitch;
|
prevPitch = pitch;
|
||||||
prevRoll = roll;
|
prevRoll = roll;
|
||||||
|
|
||||||
super.tick();
|
super.tick();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tickAsPassenger(Entity e) {
|
public void tickAsPassenger(Entity e) {
|
||||||
boolean rotationLock = false;
|
boolean rotationLock = false;
|
||||||
boolean pauseWhileRotating = false;
|
boolean pauseWhileRotating = false;
|
||||||
boolean rotating = false;
|
boolean rotating = false;
|
||||||
|
boolean wasStalled = isStalled();
|
||||||
|
if (contraption instanceof MountedContraption) {
|
||||||
|
MountedContraption mountedContraption = (MountedContraption) contraption;
|
||||||
|
rotationLock = mountedContraption.rotationMode == CartMovementMode.ROTATION_LOCKED;
|
||||||
|
pauseWhileRotating = mountedContraption.rotationMode == CartMovementMode.ROTATE_PAUSED;
|
||||||
|
}
|
||||||
|
|
||||||
Entity riding = e;
|
Entity riding = e;
|
||||||
while (riding.getRidingEntity() != null)
|
while (riding.getRidingEntity() != null)
|
||||||
riding = riding.getRidingEntity();
|
riding = riding.getRidingEntity();
|
||||||
|
|
||||||
|
boolean isOnCoupling = false;
|
||||||
|
UUID couplingId = getCouplingId();
|
||||||
|
isOnCoupling = couplingId != null && riding instanceof AbstractMinecartEntity;
|
||||||
|
|
||||||
if (!attachedExtraInventories) {
|
if (!attachedExtraInventories) {
|
||||||
contraption.addExtraInventories(riding);
|
attachInventoriesFromRidingCarts(riding, isOnCoupling, couplingId);
|
||||||
attachedExtraInventories = true;
|
attachedExtraInventories = true;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
<<<<<<< HEAD
|
||||||
boolean isOnCoupling = false;
|
boolean isOnCoupling = false;
|
||||||
if (contraption instanceof MountedContraption) {
|
if (contraption instanceof MountedContraption) {
|
||||||
MountedContraption mountedContraption = (MountedContraption) contraption;
|
MountedContraption mountedContraption = (MountedContraption) contraption;
|
||||||
|
@ -362,19 +398,49 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
if (notOnMainCart) {
|
if (notOnMainCart) {
|
||||||
yaw += 180;
|
yaw += 180;
|
||||||
}
|
}
|
||||||
|
=======*/
|
||||||
|
if (isOnCoupling) {
|
||||||
|
Couple<MinecartController> coupledCarts = getCoupledCartsIfPresent();
|
||||||
|
if (coupledCarts != null) {
|
||||||
|
|
||||||
|
Vector3d positionVec = coupledCarts.getFirst()
|
||||||
|
.cart()
|
||||||
|
.getPositionVec();
|
||||||
|
Vector3d coupledVec = coupledCarts.getSecond()
|
||||||
|
.cart()
|
||||||
|
.getPositionVec();
|
||||||
|
|
||||||
|
double diffX = positionVec.x - coupledVec.x;
|
||||||
|
double diffY = positionVec.y - coupledVec.y;
|
||||||
|
double diffZ = positionVec.z - coupledVec.z;
|
||||||
|
|
||||||
|
prevYaw = yaw;
|
||||||
|
prevPitch = pitch;
|
||||||
|
yaw = (float) (MathHelper.atan2(diffZ, diffX) * 180 / Math.PI);
|
||||||
|
pitch = (float) (Math.atan2(diffY, Math.sqrt(diffX * diffX + diffZ * diffZ)) * 180 / Math.PI);
|
||||||
|
|
||||||
|
if (couplingId.equals(riding.getUniqueID())) {
|
||||||
|
pitch *= -1;
|
||||||
|
yaw += 180;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} else if (!wasStalled) {
|
||||||
rotationLock = mountedContraption.rotationMode == CartMovementMode.ROTATION_LOCKED;
|
Vector3d movementVector = riding.getMotion();
|
||||||
pauseWhileRotating = mountedContraption.rotationMode == CartMovementMode.ROTATE_PAUSED;
|
if (!(riding instanceof AbstractMinecartEntity))
|
||||||
}
|
|
||||||
|
|
||||||
Vector3d movementVector = riding.getMotion();
|
|
||||||
if (!isOnCoupling) {
|
|
||||||
if (riding instanceof BoatEntity)
|
|
||||||
movementVector = getPositionVec().subtract(prevPosX, prevPosY, prevPosZ);
|
movementVector = getPositionVec().subtract(prevPosX, prevPosY, prevPosZ);
|
||||||
Vector3d motion = movementVector.normalize();
|
Vector3d motion = movementVector.normalize();
|
||||||
|
|
||||||
|
if (!dataManager.get(INITIAL_ORIENTATION)
|
||||||
|
.isPresent() && !world.isRemote) {
|
||||||
|
if (motion.length() > 0) {
|
||||||
|
Direction facingFromVector = Direction.getFacingFromVector(motion.x, motion.y, motion.z);
|
||||||
|
if (facingFromVector.getAxis()
|
||||||
|
.isHorizontal())
|
||||||
|
setInitialOrientation(facingFromVector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!rotationLock) {
|
if (!rotationLock) {
|
||||||
if (motion.length() > 0) {
|
if (motion.length() > 0) {
|
||||||
targetYaw = yawFromVector(motion);
|
targetYaw = yawFromVector(motion);
|
||||||
|
@ -393,66 +459,131 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean wasStalled = isStalled();
|
|
||||||
if (!rotating || !pauseWhileRotating)
|
if (!rotating || !pauseWhileRotating)
|
||||||
tickActors(movementVector);
|
tickActors();
|
||||||
if (isStalled()) {
|
boolean isStalled = isStalled();
|
||||||
if (!wasStalled)
|
|
||||||
motionBeforeStall = riding.getMotion();
|
LazyOptional<MinecartController> capability =
|
||||||
riding.setMotion(0, 0, 0);
|
riding.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY);
|
||||||
|
if (capability.isPresent()) {
|
||||||
|
if (!world.isRemote())
|
||||||
|
capability.orElse(null)
|
||||||
|
.setStalledExternally(isStalled);
|
||||||
|
} else {
|
||||||
|
if (isStalled) {
|
||||||
|
if (!wasStalled)
|
||||||
|
motionBeforeStall = riding.getMotion();
|
||||||
|
riding.setMotion(0, 0, 0);
|
||||||
|
}
|
||||||
|
if (wasStalled && !isStalled) {
|
||||||
|
riding.setMotion(motionBeforeStall);
|
||||||
|
motionBeforeStall = Vector3d.ZERO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wasStalled && !isStalled()) {
|
if (world.isRemote)
|
||||||
riding.setMotion(motionBeforeStall);
|
return;
|
||||||
motionBeforeStall = Vector3d.ZERO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isStalled() && (riding instanceof FurnaceMinecartEntity)) {
|
if (!isStalled()) {
|
||||||
FurnaceMinecartEntity furnaceCart = (FurnaceMinecartEntity) riding;
|
if (isOnCoupling) {
|
||||||
|
Couple<MinecartController> coupledCarts = getCoupledCartsIfPresent();
|
||||||
// Notify to not trigger serialization side-effects
|
if (coupledCarts == null)
|
||||||
isSerializingFurnaceCart = true;
|
return;
|
||||||
CompoundNBT nbt = furnaceCart.serializeNBT();
|
coupledCarts.map(MinecartController::cart)
|
||||||
isSerializingFurnaceCart = false;
|
.forEach(this::powerFurnaceCartWithFuelFromStorage);
|
||||||
|
return;
|
||||||
int fuel = nbt.getInt("Fuel");
|
|
||||||
int fuelBefore = fuel;
|
|
||||||
double pushX = nbt.getDouble("PushX");
|
|
||||||
double pushZ = nbt.getDouble("PushZ");
|
|
||||||
|
|
||||||
int i = MathHelper.floor(furnaceCart.getX());
|
|
||||||
int j = MathHelper.floor(furnaceCart.getY());
|
|
||||||
int k = MathHelper.floor(furnaceCart.getZ());
|
|
||||||
if (furnaceCart.world.getBlockState(new BlockPos(i, j - 1, k))
|
|
||||||
.isIn(BlockTags.RAILS))
|
|
||||||
--j;
|
|
||||||
|
|
||||||
BlockPos blockpos = new BlockPos(i, j, k);
|
|
||||||
BlockState blockstate = this.world.getBlockState(blockpos);
|
|
||||||
if (furnaceCart.canUseRail() && blockstate.isIn(BlockTags.RAILS))
|
|
||||||
if (fuel > 1)
|
|
||||||
riding.setMotion(riding.getMotion()
|
|
||||||
.normalize()
|
|
||||||
.scale(1));
|
|
||||||
if (fuel < 5 && contraption != null) {
|
|
||||||
ItemStack coal = ItemHelper.extract(contraption.inventory, FUEL_ITEMS, 1, false);
|
|
||||||
if (!coal.isEmpty())
|
|
||||||
fuel += 3600;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fuel != fuelBefore || pushX != 0 || pushZ != 0) {
|
|
||||||
nbt.putInt("Fuel", fuel);
|
|
||||||
nbt.putDouble("PushX", 0);
|
|
||||||
nbt.putDouble("PushZ", 0);
|
|
||||||
furnaceCart.deserializeNBT(nbt);
|
|
||||||
}
|
}
|
||||||
|
powerFurnaceCartWithFuelFromStorage(riding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tickActors(Vector3d movementVector) {
|
protected void powerFurnaceCartWithFuelFromStorage(Entity riding) {
|
||||||
Vector3d rotationVec = getRotationVec();
|
if (!(riding instanceof FurnaceMinecartEntity))
|
||||||
Vector3d reversedRotationVec = rotationVec.scale(-1);
|
return;
|
||||||
Vector3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
|
FurnaceMinecartEntity furnaceCart = (FurnaceMinecartEntity) riding;
|
||||||
|
|
||||||
|
// Notify to not trigger serialization side-effects
|
||||||
|
isSerializingFurnaceCart = true;
|
||||||
|
CompoundNBT nbt = furnaceCart.serializeNBT();
|
||||||
|
isSerializingFurnaceCart = false;
|
||||||
|
|
||||||
|
int fuel = nbt.getInt("Fuel");
|
||||||
|
int fuelBefore = fuel;
|
||||||
|
double pushX = nbt.getDouble("PushX");
|
||||||
|
double pushZ = nbt.getDouble("PushZ");
|
||||||
|
|
||||||
|
int i = MathHelper.floor(furnaceCart.getX());
|
||||||
|
int j = MathHelper.floor(furnaceCart.getY());
|
||||||
|
int k = MathHelper.floor(furnaceCart.getZ());
|
||||||
|
if (furnaceCart.world.getBlockState(new BlockPos(i, j - 1, k))
|
||||||
|
.isIn(BlockTags.RAILS))
|
||||||
|
--j;
|
||||||
|
|
||||||
|
BlockPos blockpos = new BlockPos(i, j, k);
|
||||||
|
BlockState blockstate = this.world.getBlockState(blockpos);
|
||||||
|
if (furnaceCart.canUseRail() && blockstate.isIn(BlockTags.RAILS))
|
||||||
|
if (fuel > 1)
|
||||||
|
riding.setMotion(riding.getMotion()
|
||||||
|
.normalize()
|
||||||
|
.scale(1));
|
||||||
|
if (fuel < 5 && contraption != null) {
|
||||||
|
ItemStack coal = ItemHelper.extract(contraption.inventory, FUEL_ITEMS, 1, false);
|
||||||
|
if (!coal.isEmpty())
|
||||||
|
fuel += 3600;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fuel != fuelBefore || pushX != 0 || pushZ != 0) {
|
||||||
|
nbt.putInt("Fuel", fuel);
|
||||||
|
nbt.putDouble("PushX", 0);
|
||||||
|
nbt.putDouble("PushZ", 0);
|
||||||
|
furnaceCart.deserializeNBT(nbt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Couple<MinecartController> getCoupledCartsIfPresent() {
|
||||||
|
UUID couplingId = getCouplingId();
|
||||||
|
if (couplingId == null)
|
||||||
|
return null;
|
||||||
|
MinecartController controller = CapabilityMinecartController.getIfPresent(world, couplingId);
|
||||||
|
if (controller == null || !controller.isPresent())
|
||||||
|
return null;
|
||||||
|
UUID coupledCart = controller.getCoupledCart(true);
|
||||||
|
MinecartController coupledController = CapabilityMinecartController.getIfPresent(world, coupledCart);
|
||||||
|
if (coupledController == null || !coupledController.isPresent())
|
||||||
|
return null;
|
||||||
|
return Couple.create(controller, coupledController);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void attachInventoriesFromRidingCarts(Entity riding, boolean isOnCoupling, UUID couplingId) {
|
||||||
|
if (isOnCoupling) {
|
||||||
|
Couple<MinecartController> coupledCarts = getCoupledCartsIfPresent();
|
||||||
|
if (coupledCarts == null)
|
||||||
|
return;
|
||||||
|
coupledCarts.map(MinecartController::cart)
|
||||||
|
.forEach(contraption::addExtraInventories);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
contraption.addExtraInventories(riding);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3d applyRotation(Vector3d localPos, float partialTicks) {
|
||||||
|
localPos = VecHelper.rotate(localPos, getRoll(partialTicks), Axis.X);
|
||||||
|
localPos = VecHelper.rotate(localPos, getInitialYaw(), Axis.Y);
|
||||||
|
localPos = VecHelper.rotate(localPos, getPitch(partialTicks), Axis.Z);
|
||||||
|
localPos = VecHelper.rotate(localPos, getYaw(partialTicks), Axis.Y);
|
||||||
|
return localPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3d reverseRotation(Vector3d localPos, float partialTicks) {
|
||||||
|
localPos = VecHelper.rotate(localPos, -getYaw(partialTicks), Axis.Y);
|
||||||
|
localPos = VecHelper.rotate(localPos, -getPitch(partialTicks), Axis.Z);
|
||||||
|
localPos = VecHelper.rotate(localPos, -getInitialYaw(), Axis.Y);
|
||||||
|
localPos = VecHelper.rotate(localPos, -getRoll(partialTicks), Axis.X);
|
||||||
|
return localPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tickActors() {
|
||||||
boolean stalledPreviously = contraption.stalled;
|
boolean stalledPreviously = contraption.stalled;
|
||||||
|
|
||||||
if (!world.isRemote)
|
if (!world.isRemote)
|
||||||
|
@ -462,13 +593,8 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
MovementContext context = pair.right;
|
MovementContext context = pair.right;
|
||||||
BlockInfo blockInfo = pair.left;
|
BlockInfo blockInfo = pair.left;
|
||||||
MovementBehaviour actor = Contraption.getMovement(blockInfo.state);
|
MovementBehaviour actor = Contraption.getMovement(blockInfo.state);
|
||||||
|
Vector3d actorPosition = toGlobalVector(VecHelper.getCenterOf(blockInfo.pos)
|
||||||
Vector3d actorPosition = Vector3d.of(blockInfo.pos);
|
.add(actor.getActiveAreaOffset(context)), 1);
|
||||||
actorPosition = actorPosition.add(actor.getActiveAreaOffset(context));
|
|
||||||
actorPosition = VecHelper.rotate(actorPosition, rotationVec);
|
|
||||||
actorPosition = actorPosition.add(rotationOffset)
|
|
||||||
.add(getAnchorVec());
|
|
||||||
|
|
||||||
boolean newPosVisited = false;
|
boolean newPosVisited = false;
|
||||||
BlockPos gridPosition = new BlockPos(actorPosition);
|
BlockPos gridPosition = new BlockPos(actorPosition);
|
||||||
Vector3d oldMotion = context.motion;
|
Vector3d oldMotion = context.motion;
|
||||||
|
@ -478,7 +604,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
if (previousPosition != null) {
|
if (previousPosition != null) {
|
||||||
context.motion = actorPosition.subtract(previousPosition);
|
context.motion = actorPosition.subtract(previousPosition);
|
||||||
Vector3d relativeMotion = context.motion;
|
Vector3d relativeMotion = context.motion;
|
||||||
relativeMotion = VecHelper.rotate(relativeMotion, reversedRotationVec);
|
relativeMotion = reverseRotation(relativeMotion, 1);
|
||||||
context.relativeMotion = relativeMotion;
|
context.relativeMotion = relativeMotion;
|
||||||
newPosVisited = !new BlockPos(previousPosition).equals(gridPosition)
|
newPosVisited = !new BlockPos(previousPosition).equals(gridPosition)
|
||||||
|| context.relativeMotion.length() > 0 && context.firstMovement;
|
|| context.relativeMotion.length() > 0 && context.firstMovement;
|
||||||
|
@ -506,8 +632,9 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.rotation = rotationVec;
|
context.rotation = v -> applyRotation(v, 1);
|
||||||
context.position = actorPosition;
|
context.position = actorPosition;
|
||||||
|
|
||||||
if (actor.isActive(context)) {
|
if (actor.isActive(context)) {
|
||||||
if (newPosVisited && !context.stall) {
|
if (newPosVisited && !context.stall) {
|
||||||
actor.visitNewPosition(context, gridPosition);
|
actor.visitNewPosition(context, gridPosition);
|
||||||
|
@ -552,6 +679,8 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
@Override
|
@Override
|
||||||
public void notifyDataManagerChange(DataParameter<?> key) {
|
public void notifyDataManagerChange(DataParameter<?> key) {
|
||||||
super.notifyDataManagerChange(key);
|
super.notifyDataManagerChange(key);
|
||||||
|
if (key == INITIAL_ORIENTATION)
|
||||||
|
startAtInitialYaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void rotate(double roll, double yaw, double pitch) {
|
public void rotate(double roll, double yaw, double pitch) {
|
||||||
|
@ -590,7 +719,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
|
|
||||||
public float getYaw(float partialTicks) {
|
public float getYaw(float partialTicks) {
|
||||||
return (getRidingEntity() == null ? 1 : -1)
|
return (getRidingEntity() == null ? 1 : -1)
|
||||||
* (partialTicks == 1.0F ? yaw : angleLerp(partialTicks, prevYaw, yaw)) + initialAngle;
|
* (partialTicks == 1.0F ? yaw : angleLerp(partialTicks, prevYaw, yaw));
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getPitch(float partialTicks) {
|
public float getPitch(float partialTicks) {
|
||||||
|
@ -611,16 +740,20 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
protected void registerData() {
|
protected void registerData() {
|
||||||
this.dataManager.register(STALLED, false);
|
this.dataManager.register(STALLED, false);
|
||||||
this.dataManager.register(COUPLING, Optional.empty());
|
this.dataManager.register(COUPLING, Optional.empty());
|
||||||
this.dataManager.register(COUPLED_CART, Optional.empty());
|
this.dataManager.register(INITIAL_ORIENTATION, Optional.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void readAdditional(CompoundNBT compound) {
|
protected void readAdditional(CompoundNBT compound) {
|
||||||
initialized = compound.getBoolean("Initialized");
|
initialized = compound.getBoolean("Initialized");
|
||||||
contraption = Contraption.fromNBT(world, compound.getCompound("Contraption"));
|
contraption = Contraption.fromNBT(world, compound.getCompound("Contraption"));
|
||||||
initialAngle = compound.getFloat("InitialAngle");
|
|
||||||
forceYaw(compound.contains("ForcedYaw") ? compound.getFloat("ForcedYaw") : initialAngle);
|
|
||||||
dataManager.set(STALLED, compound.getBoolean("Stalled"));
|
dataManager.set(STALLED, compound.getBoolean("Stalled"));
|
||||||
|
|
||||||
|
if (compound.contains("InitialOrientation"))
|
||||||
|
setInitialOrientation(NBTHelper.readEnum(compound, "InitialOrientation", Direction.class));
|
||||||
|
if (compound.contains("ForceYaw"))
|
||||||
|
startAtYaw(compound.getFloat("ForceYaw"));
|
||||||
|
|
||||||
ListNBT vecNBT = compound.getList("CachedMotion", 6);
|
ListNBT vecNBT = compound.getList("CachedMotion", 6);
|
||||||
if (!vecNBT.isEmpty()) {
|
if (!vecNBT.isEmpty()) {
|
||||||
motionBeforeStall = new Vector3d(vecNBT.getDouble(0), vecNBT.getDouble(1), vecNBT.getDouble(2));
|
motionBeforeStall = new Vector3d(vecNBT.getDouble(0), vecNBT.getDouble(1), vecNBT.getDouble(2));
|
||||||
|
@ -628,20 +761,20 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
targetYaw = prevYaw = yaw += yawFromVector(motionBeforeStall);
|
targetYaw = prevYaw = yaw += yawFromVector(motionBeforeStall);
|
||||||
setMotion(Vector3d.ZERO);
|
setMotion(Vector3d.ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compound.contains("Controller"))
|
if (compound.contains("Controller"))
|
||||||
controllerPos = NBTUtil.readBlockPos(compound.getCompound("Controller"));
|
controllerPos = NBTUtil.readBlockPos(compound.getCompound("Controller"));
|
||||||
|
setCouplingId(
|
||||||
if (compound.contains("OnCoupling")) {
|
compound.contains("OnCoupling") ? NBTUtil.readUniqueId(compound.getCompound("OnCoupling")) : null);
|
||||||
setCouplingId(NBTUtil.readUniqueId(compound.getCompound("OnCoupling")));
|
|
||||||
setCoupledCart(NBTUtil.readUniqueId(compound.getCompound("CoupledCart")));
|
|
||||||
} else {
|
|
||||||
setCouplingId(null);
|
|
||||||
setCoupledCart(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void forceYaw(float forcedYaw) {
|
public void startAtInitialYaw() {
|
||||||
targetYaw = yaw = prevYaw = forcedYaw;
|
startAtYaw(getInitialYaw());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startAtYaw(float yaw) {
|
||||||
|
targetYaw = this.yaw = prevYaw = yaw;
|
||||||
|
forceAngle = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkController() {
|
public void checkController() {
|
||||||
|
@ -670,17 +803,20 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
newDoubleNBTList(motionBeforeStall.x, motionBeforeStall.y, motionBeforeStall.z));
|
newDoubleNBTList(motionBeforeStall.x, motionBeforeStall.y, motionBeforeStall.z));
|
||||||
if (controllerPos != null)
|
if (controllerPos != null)
|
||||||
compound.put("Controller", NBTUtil.writeBlockPos(controllerPos));
|
compound.put("Controller", NBTUtil.writeBlockPos(controllerPos));
|
||||||
if (forcedAngle != -1)
|
|
||||||
compound.putFloat("ForcedYaw", forcedAngle);
|
|
||||||
|
|
||||||
compound.putFloat("InitialAngle", initialAngle);
|
Optional<Direction> optional = dataManager.get(INITIAL_ORIENTATION);
|
||||||
|
if (optional.isPresent())
|
||||||
|
NBTHelper.writeEnum(compound, "InitialOrientation", optional.get());
|
||||||
|
if (forceAngle) {
|
||||||
|
compound.putFloat("ForceYaw", yaw);
|
||||||
|
forceAngle = false;
|
||||||
|
}
|
||||||
|
|
||||||
compound.putBoolean("Stalled", isStalled());
|
compound.putBoolean("Stalled", isStalled());
|
||||||
compound.putBoolean("Initialized", initialized);
|
compound.putBoolean("Initialized", initialized);
|
||||||
|
|
||||||
if (getCouplingId() != null) {
|
if (getCouplingId() != null)
|
||||||
compound.put("OnCoupling", NBTUtil.fromUuid(getCouplingId()));
|
compound.put("OnCoupling", NBTUtil.fromUuid(getCouplingId()));
|
||||||
compound.put("CoupledCart", NBTUtil.fromUuid(getCoupledCart()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -706,7 +842,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
if (getContraption() != null) {
|
if (getContraption() != null) {
|
||||||
remove();
|
remove();
|
||||||
BlockPos offset = new BlockPos(getAnchorVec().add(.5, .5, .5));
|
BlockPos offset = new BlockPos(getAnchorVec().add(.5, .5, .5));
|
||||||
Vector3d rotation = getRotationVec();
|
Vector3d rotation = getRotationVec().add(0, getInitialYaw(), 0);
|
||||||
StructureTransform transform = new StructureTransform(offset, rotation);
|
StructureTransform transform = new StructureTransform(offset, rotation);
|
||||||
contraption.addBlocksToWorld(world, transform);
|
contraption.addBlocksToWorld(world, transform);
|
||||||
contraption.addPassengersToWorld(world, transform, getPassengers());
|
contraption.addPassengersToWorld(world, transform, getPassengers());
|
||||||
|
@ -716,7 +852,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
Vector3d positionVec = getPositionVec();
|
Vector3d positionVec = getPositionVec();
|
||||||
Vector3d localVec = entity.getPositionVec()
|
Vector3d localVec = entity.getPositionVec()
|
||||||
.subtract(positionVec);
|
.subtract(positionVec);
|
||||||
localVec = VecHelper.rotate(localVec, getRotationVec().scale(-1));
|
localVec = VecHelper.rotate(localVec, rotation.scale(-1));
|
||||||
Vector3d transformed = transform.apply(localVec);
|
Vector3d transformed = transform.apply(localVec);
|
||||||
entity.setPositionAndUpdate(transformed.x, transformed.y, transformed.z);
|
entity.setPositionAndUpdate(transformed.x, transformed.y, transformed.z);
|
||||||
}
|
}
|
||||||
|
@ -835,8 +971,18 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getInitialAngle() {
|
public void setInitialOrientation(Direction direction) {
|
||||||
return initialAngle;
|
dataManager.set(INITIAL_ORIENTATION, Optional.of(direction));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Direction> getInitialOrientation() {
|
||||||
|
return dataManager.get(INITIAL_ORIENTATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getInitialYaw() {
|
||||||
|
return dataManager.get(INITIAL_ORIENTATION)
|
||||||
|
.orElse(Direction.SOUTH)
|
||||||
|
.getHorizontalAngle();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3d getRotationVec() {
|
public Vector3d getRotationVec() {
|
||||||
|
@ -854,18 +1000,9 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
public Vector3d getContactPointMotion(Vector3d globalContactPoint) {
|
public Vector3d getContactPointMotion(Vector3d globalContactPoint) {
|
||||||
if (prevPosInvalid)
|
if (prevPosInvalid)
|
||||||
return Vector3d.ZERO;
|
return Vector3d.ZERO;
|
||||||
|
Vector3d contactPoint = toGlobalVector(toLocalVector(globalContactPoint, 0), 1);
|
||||||
Vector3d positionVec = getPositionVec();
|
return contactPoint.subtract(globalContactPoint)
|
||||||
Vector3d conMotion = positionVec.subtract(getPrevPositionVec());
|
.add(getPositionVec().subtract(getPrevPositionVec()));
|
||||||
Vector3d conAngularMotion = getRotationVec().subtract(getPrevRotationVec());
|
|
||||||
Vector3d contraptionCentreOffset = stationary ? VecHelper.getCenterOf(BlockPos.ZERO) : Vector3d.ZERO.add(0, 0.5, 0);
|
|
||||||
Vector3d contactPoint = globalContactPoint.subtract(contraptionCentreOffset)
|
|
||||||
.subtract(positionVec);
|
|
||||||
contactPoint = VecHelper.rotate(contactPoint, conAngularMotion.x, conAngularMotion.y, conAngularMotion.z);
|
|
||||||
contactPoint = contactPoint.add(positionVec)
|
|
||||||
.add(contraptionCentreOffset)
|
|
||||||
.add(conMotion);
|
|
||||||
return contactPoint.subtract(globalContactPoint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canCollideWith(Entity e) {
|
public boolean canCollideWith(Entity e) {
|
||||||
|
@ -906,16 +1043,6 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
dataManager.set(COUPLING, Optional.ofNullable(id));
|
dataManager.set(COUPLING, Optional.ofNullable(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public UUID getCoupledCart() {
|
|
||||||
Optional<UUID> uuid = dataManager.get(COUPLED_CART);
|
|
||||||
return uuid.isPresent() ? uuid.get() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCoupledCart(UUID id) {
|
|
||||||
dataManager.set(COUPLED_CART, Optional.ofNullable(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOnePlayerRiding() {
|
public boolean isOnePlayerRiding() {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -39,13 +39,10 @@ public class ContraptionEntityRenderer extends EntityRenderer<ContraptionEntity>
|
||||||
MatrixStack msLocal = getLocalTransform(entity);
|
MatrixStack msLocal = getLocalTransform(entity);
|
||||||
MatrixStack[] matrixStacks = new MatrixStack[] { ms, msLocal };
|
MatrixStack[] matrixStacks = new MatrixStack[] { ms, msLocal };
|
||||||
|
|
||||||
float degYaw = entity.getYaw(partialTicks);
|
float angleInitialYaw = entity.getInitialYaw();
|
||||||
float degPitch = entity.getPitch(partialTicks);
|
float angleYaw = entity.getYaw(partialTicks);
|
||||||
float degRoll = entity.getRoll(partialTicks);
|
float anglePitch = entity.getPitch(partialTicks);
|
||||||
|
float angleRoll = entity.getRoll(partialTicks);
|
||||||
float angleYaw = (float) (degYaw / 180 * Math.PI);
|
|
||||||
float anglePitch = (float) (degPitch / 180 * Math.PI);
|
|
||||||
float angleRoll = (float) (degRoll / 180 * Math.PI);
|
|
||||||
|
|
||||||
ms.push();
|
ms.push();
|
||||||
Entity ridingEntity = entity.getRidingEntity();
|
Entity ridingEntity = entity.getRidingEntity();
|
||||||
|
@ -80,7 +77,10 @@ public class ContraptionEntityRenderer extends EntityRenderer<ContraptionEntity>
|
||||||
MatrixStacker.of(stack)
|
MatrixStacker.of(stack)
|
||||||
.nudge(entity.getEntityId())
|
.nudge(entity.getEntityId())
|
||||||
.centre()
|
.centre()
|
||||||
.rotateRadians(angleRoll, angleYaw, anglePitch)
|
.rotateY(angleYaw)
|
||||||
|
.rotateZ(anglePitch)
|
||||||
|
.rotateY(angleInitialYaw)
|
||||||
|
.rotateX(angleRoll)
|
||||||
.unCentre();
|
.unCentre();
|
||||||
ContraptionRenderer.render(entity.world, entity.getContraption(), ms, msLocal, buffers);
|
ContraptionRenderer.render(entity.world, entity.getContraption(), ms, msLocal, buffers);
|
||||||
ms.pop();
|
ms.pop();
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
package com.simibubi.create.content.contraptions.components.structureMovement;
|
package com.simibubi.create.content.contraptions.components.structureMovement;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
|
|
||||||
import com.google.common.cache.Cache;
|
|
||||||
import com.google.common.cache.CacheBuilder;
|
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
|
import com.simibubi.create.foundation.utility.WorldAttached;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectLists;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.nbt.CompoundNBT;
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
@ -21,21 +19,39 @@ import net.minecraftforge.common.util.Constants.NBT;
|
||||||
|
|
||||||
public class ContraptionHandler {
|
public class ContraptionHandler {
|
||||||
|
|
||||||
public static Cache<World, List<WeakReference<ContraptionEntity>>> activeContraptions = CacheBuilder.newBuilder()
|
/* Global map of loaded contraptions */
|
||||||
.expireAfterAccess(400, SECONDS)
|
|
||||||
.build();
|
public static WorldAttached<List<WeakReference<ContraptionEntity>>> loadedContraptions;
|
||||||
|
static WorldAttached<List<ContraptionEntity>> queuedAdditions;
|
||||||
|
|
||||||
|
static {
|
||||||
|
loadedContraptions = new WorldAttached<>(ArrayList::new);
|
||||||
|
queuedAdditions = new WorldAttached<>(() -> ObjectLists.synchronize(new ObjectArrayList<>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void tick(World world) {
|
||||||
|
List<WeakReference<ContraptionEntity>> list = loadedContraptions.get(world);
|
||||||
|
List<ContraptionEntity> queued = queuedAdditions.get(world);
|
||||||
|
|
||||||
|
for (ContraptionEntity contraptionEntity : queued)
|
||||||
|
list.add(new WeakReference<>(contraptionEntity));
|
||||||
|
queued.clear();
|
||||||
|
|
||||||
|
for (Iterator<WeakReference<ContraptionEntity>> iterator = list.iterator(); iterator.hasNext();) {
|
||||||
|
WeakReference<ContraptionEntity> weakReference = iterator.next();
|
||||||
|
ContraptionEntity contraptionEntity = weakReference.get();
|
||||||
|
if (contraptionEntity == null || !contraptionEntity.isAlive()) {
|
||||||
|
iterator.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ContraptionCollider.collideEntities(contraptionEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void addSpawnedContraptionsToCollisionList(Entity entity, World world) {
|
public static void addSpawnedContraptionsToCollisionList(Entity entity, World world) {
|
||||||
if (!(entity instanceof ContraptionEntity))
|
if (entity instanceof ContraptionEntity)
|
||||||
return;
|
queuedAdditions.get(world)
|
||||||
try {
|
.add((ContraptionEntity) entity);
|
||||||
List<WeakReference<ContraptionEntity>> list =
|
|
||||||
activeContraptions.get(world, () -> Collections.synchronizedList(new ArrayList<>()));
|
|
||||||
ContraptionEntity contraption = (ContraptionEntity) entity;
|
|
||||||
list.add(new WeakReference<>(contraption));
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void entitiesWhoJustDismountedGetSentToTheRightLocation(LivingEntity entityLiving, World world) {
|
public static void entitiesWhoJustDismountedGetSentToTheRightLocation(LivingEntity entityLiving, World world) {
|
||||||
|
|
|
@ -78,8 +78,8 @@ public class ContraptionHandlerClient {
|
||||||
for (ContraptionEntity contraptionEntity : mc.world.getEntitiesWithinAABB(ContraptionEntity.class,
|
for (ContraptionEntity contraptionEntity : mc.world.getEntitiesWithinAABB(ContraptionEntity.class,
|
||||||
new AxisAlignedBB(origin, target))) {
|
new AxisAlignedBB(origin, target))) {
|
||||||
|
|
||||||
Vector3d localOrigin = contraptionEntity.toLocalVector(origin);
|
Vector3d localOrigin = contraptionEntity.toLocalVector(origin, 1);
|
||||||
Vector3d localTarget = contraptionEntity.toLocalVector(target);
|
Vector3d localTarget = contraptionEntity.toLocalVector(target, 1);
|
||||||
Contraption contraption = contraptionEntity.getContraption();
|
Contraption contraption = contraptionEntity.getContraption();
|
||||||
|
|
||||||
MutableObject<BlockRayTraceResult> mutableResult = new MutableObject<>();
|
MutableObject<BlockRayTraceResult> mutableResult = new MutableObject<>();
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package com.simibubi.create.content.contraptions.components.structureMovement;
|
package com.simibubi.create.content.contraptions.components.structureMovement;
|
||||||
|
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
@ -15,7 +17,8 @@ public class MovementContext {
|
||||||
public Vector3d position;
|
public Vector3d position;
|
||||||
public Vector3d motion;
|
public Vector3d motion;
|
||||||
public Vector3d relativeMotion;
|
public Vector3d relativeMotion;
|
||||||
public Vector3d rotation;
|
public UnaryOperator<Vector3d> rotation;
|
||||||
|
|
||||||
public World world;
|
public World world;
|
||||||
public BlockState state;
|
public BlockState state;
|
||||||
public BlockPos localPos;
|
public BlockPos localPos;
|
||||||
|
@ -36,7 +39,7 @@ public class MovementContext {
|
||||||
firstMovement = true;
|
firstMovement = true;
|
||||||
motion = Vector3d.ZERO;
|
motion = Vector3d.ZERO;
|
||||||
relativeMotion = Vector3d.ZERO;
|
relativeMotion = Vector3d.ZERO;
|
||||||
rotation = Vector3d.ZERO;
|
rotation = v -> v;
|
||||||
position = null;
|
position = null;
|
||||||
data = new CompoundNBT();
|
data = new CompoundNBT();
|
||||||
stall = false;
|
stall = false;
|
||||||
|
@ -56,7 +59,6 @@ public class MovementContext {
|
||||||
MovementContext context = new MovementContext(world, info);
|
MovementContext context = new MovementContext(world, info);
|
||||||
context.motion = VecHelper.readNBT(nbt.getList("Motion", NBT.TAG_DOUBLE));
|
context.motion = VecHelper.readNBT(nbt.getList("Motion", NBT.TAG_DOUBLE));
|
||||||
context.relativeMotion = VecHelper.readNBT(nbt.getList("RelativeMotion", NBT.TAG_DOUBLE));
|
context.relativeMotion = VecHelper.readNBT(nbt.getList("RelativeMotion", NBT.TAG_DOUBLE));
|
||||||
context.rotation = VecHelper.readNBT(nbt.getList("Rotation", NBT.TAG_DOUBLE));
|
|
||||||
if (nbt.contains("Position"))
|
if (nbt.contains("Position"))
|
||||||
context.position = VecHelper.readNBT(nbt.getList("Position", NBT.TAG_DOUBLE));
|
context.position = VecHelper.readNBT(nbt.getList("Position", NBT.TAG_DOUBLE));
|
||||||
context.stall = nbt.getBoolean("Stall");
|
context.stall = nbt.getBoolean("Stall");
|
||||||
|
@ -68,7 +70,6 @@ public class MovementContext {
|
||||||
public CompoundNBT writeToNBT(CompoundNBT nbt) {
|
public CompoundNBT writeToNBT(CompoundNBT nbt) {
|
||||||
nbt.put("Motion", VecHelper.writeNBT(motion));
|
nbt.put("Motion", VecHelper.writeNBT(motion));
|
||||||
nbt.put("RelativeMotion", VecHelper.writeNBT(relativeMotion));
|
nbt.put("RelativeMotion", VecHelper.writeNBT(relativeMotion));
|
||||||
nbt.put("Rotation", VecHelper.writeNBT(rotation));
|
|
||||||
if (position != null)
|
if (position != null)
|
||||||
nbt.put("Position", VecHelper.writeNBT(position));
|
nbt.put("Position", VecHelper.writeNBT(position));
|
||||||
nbt.putBoolean("Stall", stall);
|
nbt.putBoolean("Stall", stall);
|
||||||
|
|
|
@ -24,8 +24,6 @@ public class BearingContraption extends Contraption {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BearingContraption assembleBearingAt(World world, BlockPos pos, Direction direction) {
|
public static BearingContraption assembleBearingAt(World world, BlockPos pos, Direction direction) {
|
||||||
if (isFrozen())
|
|
||||||
return null;
|
|
||||||
BearingContraption construct = new BearingContraption();
|
BearingContraption construct = new BearingContraption();
|
||||||
construct.facing = direction;
|
construct.facing = direction;
|
||||||
BlockPos offset = pos.offset(direction);
|
BlockPos offset = pos.offset(direction);
|
||||||
|
|
|
@ -3,7 +3,6 @@ package com.simibubi.create.content.contraptions.components.structureMovement.be
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
|
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
|
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkContraption.HandType;
|
import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkContraption.HandType;
|
||||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||||
|
@ -46,9 +45,6 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe
|
||||||
clientHourAngleDiff /= 2;
|
clientHourAngleDiff /= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (running && Contraption.isFrozen())
|
|
||||||
disassemble();
|
|
||||||
|
|
||||||
if (!world.isRemote && assembleNextTick) {
|
if (!world.isRemote && assembleNextTick) {
|
||||||
assembleNextTick = false;
|
assembleNextTick = false;
|
||||||
if (running) {
|
if (running) {
|
||||||
|
|
|
@ -39,9 +39,6 @@ public class ClockworkContraption extends Contraption {
|
||||||
|
|
||||||
public static Pair<ClockworkContraption, ClockworkContraption> assembleClockworkAt(World world, BlockPos pos,
|
public static Pair<ClockworkContraption, ClockworkContraption> assembleClockworkAt(World world, BlockPos pos,
|
||||||
Direction direction) {
|
Direction direction) {
|
||||||
if (isFrozen())
|
|
||||||
return null;
|
|
||||||
|
|
||||||
int hourArmBlocks = 0;
|
int hourArmBlocks = 0;
|
||||||
|
|
||||||
ClockworkContraption hourArm = new ClockworkContraption();
|
ClockworkContraption hourArm = new ClockworkContraption();
|
||||||
|
|
|
@ -5,7 +5,6 @@ import static net.minecraft.state.properties.BlockStateProperties.FACING;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity;
|
import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
|
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
|
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.DirectionalExtenderScrollOptionSlot;
|
import com.simibubi.create.content.contraptions.components.structureMovement.DirectionalExtenderScrollOptionSlot;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
|
@ -207,8 +206,6 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
|
||||||
|
|
||||||
if (world.isRemote)
|
if (world.isRemote)
|
||||||
clientAngleDiff /= 2;
|
clientAngleDiff /= 2;
|
||||||
if (running && Contraption.isFrozen())
|
|
||||||
disassemble();
|
|
||||||
|
|
||||||
if (!world.isRemote && assembleNextTick) {
|
if (!world.isRemote && assembleNextTick) {
|
||||||
assembleNextTick = false;
|
assembleNextTick = false;
|
||||||
|
|
|
@ -2,6 +2,8 @@ package com.simibubi.create.content.contraptions.components.structureMovement.mo
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -11,12 +13,16 @@ import com.simibubi.create.AllShapes;
|
||||||
import com.simibubi.create.AllTileEntities;
|
import com.simibubi.create.AllTileEntities;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
|
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode;
|
import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCouplingHandler;
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandler;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController;
|
||||||
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
|
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
|
||||||
import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement;
|
import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement;
|
||||||
import com.simibubi.create.content.schematics.ItemRequirement;
|
import com.simibubi.create.content.schematics.ItemRequirement;
|
||||||
import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType;
|
import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType;
|
||||||
import com.simibubi.create.foundation.block.ITE;
|
import com.simibubi.create.foundation.block.ITE;
|
||||||
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
|
|
||||||
import net.minecraft.block.AbstractRailBlock;
|
import net.minecraft.block.AbstractRailBlock;
|
||||||
|
@ -58,6 +64,7 @@ import net.minecraft.world.IBlockReader;
|
||||||
import net.minecraft.world.IWorldReader;
|
import net.minecraft.world.IWorldReader;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraft.world.server.ServerWorld;
|
import net.minecraft.world.server.ServerWorld;
|
||||||
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
|
|
||||||
public class CartAssemblerBlock extends AbstractRailBlock
|
public class CartAssemblerBlock extends AbstractRailBlock
|
||||||
implements ITE<CartAssemblerTileEntity>, IWrenchable, ISpecialBlockItemRequirement {
|
implements ITE<CartAssemblerTileEntity>, IWrenchable, ISpecialBlockItemRequirement {
|
||||||
|
@ -116,8 +123,13 @@ public class CartAssemblerBlock extends AbstractRailBlock
|
||||||
AbstractMinecartEntity cart) {
|
AbstractMinecartEntity cart) {
|
||||||
if (!canAssembleTo(cart))
|
if (!canAssembleTo(cart))
|
||||||
return;
|
return;
|
||||||
|
if (world.isRemote)
|
||||||
|
return;
|
||||||
|
|
||||||
withTileEntityDo(world, pos, te -> {
|
withTileEntityDo(world, pos, te -> {
|
||||||
|
/*
|
||||||
|
}
|
||||||
|
<<<<<<< HEAD
|
||||||
if (te.isMinecartUpdateValid()) {
|
if (te.isMinecartUpdateValid()) {
|
||||||
switch (state.get(RAIL_TYPE)) {
|
switch (state.get(RAIL_TYPE)) {
|
||||||
case POWERED_RAIL:
|
case POWERED_RAIL:
|
||||||
|
@ -162,10 +174,61 @@ public class CartAssemblerBlock extends AbstractRailBlock
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
te.resetTicksSinceMinecartUpdate();
|
te.resetTicksSinceMinecartUpdate();
|
||||||
|
=======*/
|
||||||
|
if (!te.isMinecartUpdateValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
CartAssemblerAction action = getActionForCart(state, cart);
|
||||||
|
if (action.shouldAssemble())
|
||||||
|
assemble(world, pos, cart);
|
||||||
|
if (action.shouldDisassemble())
|
||||||
|
disassemble(world, pos, cart);
|
||||||
|
if (action == CartAssemblerAction.ASSEMBLE_ACCELERATE) {
|
||||||
|
Direction facing = cart.getAdjustedHorizontalFacing();
|
||||||
|
float speed = getRailMaxSpeed(state, world, pos, cart);
|
||||||
|
cart.setMotion(facing.getXOffset() * speed, facing.getYOffset() * speed, facing.getZOffset() * speed);
|
||||||
}
|
}
|
||||||
|
if (action == CartAssemblerAction.DISASSEMBLE_BRAKE) {
|
||||||
|
Vector3d diff = VecHelper.getCenterOf(pos)
|
||||||
|
.subtract(cart.getPositionVec());
|
||||||
|
cart.setMotion(diff.x / 16f, 0, diff.z / 16f);
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum CartAssemblerAction {
|
||||||
|
ASSEMBLE, DISASSEMBLE, ASSEMBLE_ACCELERATE, DISASSEMBLE_BRAKE, PASS;
|
||||||
|
|
||||||
|
public boolean shouldAssemble() {
|
||||||
|
return this == ASSEMBLE || this == ASSEMBLE_ACCELERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldDisassemble() {
|
||||||
|
return this == DISASSEMBLE || this == DISASSEMBLE_BRAKE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CartAssemblerAction getActionForCart(BlockState state, AbstractMinecartEntity cart) {
|
||||||
|
CartAssembleRailType type = state.get(RAIL_TYPE);
|
||||||
|
boolean powered = state.get(POWERED);
|
||||||
|
|
||||||
|
if (type == CartAssembleRailType.REGULAR)
|
||||||
|
return powered ? CartAssemblerAction.ASSEMBLE : CartAssemblerAction.DISASSEMBLE;
|
||||||
|
|
||||||
|
if (type == CartAssembleRailType.ACTIVATOR_RAIL)
|
||||||
|
return powered ? CartAssemblerAction.DISASSEMBLE : CartAssemblerAction.PASS;
|
||||||
|
|
||||||
|
if (type == CartAssembleRailType.POWERED_RAIL)
|
||||||
|
return powered ? CartAssemblerAction.ASSEMBLE_ACCELERATE : CartAssemblerAction.DISASSEMBLE_BRAKE;
|
||||||
|
|
||||||
|
if (type == CartAssembleRailType.DETECTOR_RAIL)
|
||||||
|
return cart.getPassengers()
|
||||||
|
.isEmpty() ? CartAssemblerAction.ASSEMBLE_ACCELERATE : CartAssemblerAction.DISASSEMBLE;
|
||||||
|
|
||||||
|
return CartAssemblerAction.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean canAssembleTo(AbstractMinecartEntity cart) {
|
public static boolean canAssembleTo(AbstractMinecartEntity cart) {
|
||||||
return cart.canBeRidden() || cart instanceof FurnaceMinecartEntity || cart instanceof ChestMinecartEntity;
|
return cart.canBeRidden() || cart instanceof FurnaceMinecartEntity || cart instanceof ChestMinecartEntity;
|
||||||
}
|
}
|
||||||
|
@ -204,34 +267,44 @@ public class CartAssemblerBlock extends AbstractRailBlock
|
||||||
.isEmpty())
|
.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
LazyOptional<MinecartController> optional =
|
||||||
|
cart.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY);
|
||||||
|
if (optional.isPresent() && optional.orElse(null)
|
||||||
|
.isCoupledThroughContraption())
|
||||||
|
return;
|
||||||
|
|
||||||
MountedContraption contraption = MountedContraption.assembleMinecart(world, pos);
|
MountedContraption contraption = MountedContraption.assembleMinecart(world, pos);
|
||||||
if (contraption == null)
|
if (contraption == null)
|
||||||
return;
|
return;
|
||||||
if (contraption.blocks.size() == 1)
|
if (contraption.blocks.size() == 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Direction facing = cart.getAdjustedHorizontalFacing();
|
|
||||||
float initialAngle = facing.getHorizontalAngle();
|
|
||||||
|
|
||||||
withTileEntityDo(world, pos, te -> contraption.rotationMode = CartMovementMode.values()[te.movementMode.value]);
|
withTileEntityDo(world, pos, te -> contraption.rotationMode = CartMovementMode.values()[te.movementMode.value]);
|
||||||
|
|
||||||
boolean couplingFound = contraption.connectedCart != null;
|
boolean couplingFound = contraption.connectedCart != null;
|
||||||
|
Optional<Direction> initialOrientation = cart.getMotion()
|
||||||
|
.length() < 1 / 512f ? Optional.empty() : Optional.of(cart.getAdjustedHorizontalFacing());
|
||||||
|
|
||||||
|
if (couplingFound) {
|
||||||
|
cart.setPosition(pos.getX() + .5f, pos.getY(), pos.getZ() + .5f);
|
||||||
|
if (!CouplingHandler.tryToCoupleCarts(null, world, cart.getEntityId(),
|
||||||
|
contraption.connectedCart.getEntityId()))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
contraption.removeBlocksFromWorld(world, BlockPos.ZERO);
|
||||||
|
contraption.initActors(world);
|
||||||
|
contraption.expandBoundsAroundAxis(Axis.Y);
|
||||||
|
|
||||||
if (couplingFound) {
|
if (couplingFound) {
|
||||||
MinecartCouplingHandler.connectCarts(null, world, cart.getEntityId(),
|
|
||||||
contraption.connectedCart.getEntityId());
|
|
||||||
Vector3d diff = contraption.connectedCart.getPositionVec()
|
Vector3d diff = contraption.connectedCart.getPositionVec()
|
||||||
.subtract(cart.getPositionVec());
|
.subtract(cart.getPositionVec());
|
||||||
initialAngle = Direction.fromAngle(MathHelper.atan2(diff.z, diff.x) * 180 / Math.PI)
|
initialOrientation = Optional.of(Direction.fromAngle(MathHelper.atan2(diff.z, diff.x) * 180 / Math.PI));
|
||||||
.getHorizontalAngle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ContraptionEntity entity = ContraptionEntity.createMounted(world, contraption, initialAngle, facing);
|
ContraptionEntity entity = ContraptionEntity.createMounted(world, contraption, initialOrientation);
|
||||||
|
if (couplingFound)
|
||||||
if (couplingFound) {
|
|
||||||
entity.setCouplingId(cart.getUniqueID());
|
entity.setCouplingId(cart.getUniqueID());
|
||||||
entity.setCoupledCart(contraption.connectedCart.getUniqueID());
|
|
||||||
}
|
|
||||||
|
|
||||||
entity.setPosition(pos.getX(), pos.getY(), pos.getZ());
|
entity.setPosition(pos.getX(), pos.getY(), pos.getZ());
|
||||||
world.addEntity(entity);
|
world.addEntity(entity);
|
||||||
entity.startRiding(cart);
|
entity.startRiding(cart);
|
||||||
|
@ -248,11 +321,44 @@ public class CartAssemblerBlock extends AbstractRailBlock
|
||||||
if (cart.getPassengers()
|
if (cart.getPassengers()
|
||||||
.isEmpty())
|
.isEmpty())
|
||||||
return;
|
return;
|
||||||
if (!(cart.getPassengers()
|
Entity entity = cart.getPassengers()
|
||||||
.get(0) instanceof ContraptionEntity))
|
.get(0);
|
||||||
|
if (!(entity instanceof ContraptionEntity))
|
||||||
return;
|
return;
|
||||||
cart.removePassengers();
|
ContraptionEntity contraption = (ContraptionEntity) entity;
|
||||||
|
UUID couplingId = contraption.getCouplingId();
|
||||||
|
|
||||||
|
if (couplingId == null) {
|
||||||
|
disassembleCart(cart);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Couple<MinecartController> coupledCarts = contraption.getCoupledCartsIfPresent();
|
||||||
|
if (coupledCarts == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Make sure connected cart is present and being disassembled
|
||||||
|
for (boolean current : Iterate.trueAndFalse) {
|
||||||
|
MinecartController minecartController = coupledCarts.get(current);
|
||||||
|
if (minecartController.cart() == cart)
|
||||||
|
continue;
|
||||||
|
BlockPos otherPos = minecartController.cart()
|
||||||
|
.getBlockPos();
|
||||||
|
BlockState blockState = world.getBlockState(otherPos);
|
||||||
|
if (!AllBlocks.CART_ASSEMBLER.has(blockState))
|
||||||
|
return;
|
||||||
|
if (!getActionForCart(blockState, minecartController.cart()).shouldDisassemble())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (boolean current : Iterate.trueAndFalse)
|
||||||
|
coupledCarts.get(current)
|
||||||
|
.removeConnection(current);
|
||||||
|
disassembleCart(cart);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void disassembleCart(AbstractMinecartEntity cart) {
|
||||||
|
cart.removePassengers();
|
||||||
if (cart instanceof FurnaceMinecartEntity) {
|
if (cart instanceof FurnaceMinecartEntity) {
|
||||||
CompoundNBT nbt = cart.serializeNBT();
|
CompoundNBT nbt = cart.serializeNBT();
|
||||||
nbt.putDouble("PushZ", cart.getMotion().x);
|
nbt.putDouble("PushZ", cart.getMotion().x);
|
||||||
|
@ -285,16 +391,22 @@ public class CartAssemblerBlock extends AbstractRailBlock
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public VoxelShape getShape(BlockState state, @Nonnull IBlockReader worldIn, @Nonnull BlockPos pos,
|
public VoxelShape getShape(BlockState state, @Nonnull IBlockReader worldIn, @Nonnull BlockPos pos,
|
||||||
@Nonnull ISelectionContext context) {
|
@Nonnull ISelectionContext context) {
|
||||||
return AllShapes.CART_ASSEMBLER
|
return AllShapes.CART_ASSEMBLER.get(getRailAxis(state));
|
||||||
.get(state.get(RAIL_SHAPE) == RailShape.NORTH_SOUTH ? Direction.Axis.Z : Direction.Axis.X);
|
}
|
||||||
|
|
||||||
|
protected Axis getRailAxis(BlockState state) {
|
||||||
|
return state.get(RAIL_SHAPE) == RailShape.NORTH_SOUTH ? Direction.Axis.Z : Direction.Axis.X;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public VoxelShape getCollisionShape(@Nonnull BlockState state, @Nonnull IBlockReader worldIn, @Nonnull BlockPos pos,
|
public VoxelShape getCollisionShape(@Nonnull BlockState state, @Nonnull IBlockReader worldIn, @Nonnull BlockPos pos,
|
||||||
ISelectionContext context) {
|
ISelectionContext context) {
|
||||||
if (context.getEntity() instanceof AbstractMinecartEntity)
|
Entity entity = context.getEntity();
|
||||||
|
if (entity instanceof AbstractMinecartEntity)
|
||||||
return VoxelShapes.empty();
|
return VoxelShapes.empty();
|
||||||
|
if (entity instanceof PlayerEntity)
|
||||||
|
return AllShapes.CART_ASSEMBLER_PLAYER_COLLISION.get(getRailAxis(state));
|
||||||
return VoxelShapes.fullCube();
|
return VoxelShapes.fullCube();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package com.simibubi.create.content.contraptions.components.structureMovement.mounted;
|
package com.simibubi.create.content.contraptions.components.structureMovement.mounted;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.simibubi.create.AllItems;
|
import com.simibubi.create.AllItems;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
|
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
|
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
|
||||||
|
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||||
|
|
||||||
import net.minecraft.block.AbstractRailBlock;
|
import net.minecraft.block.AbstractRailBlock;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
@ -27,6 +29,7 @@ import net.minecraft.state.properties.RailShape;
|
||||||
import net.minecraft.tags.BlockTags;
|
import net.minecraft.tags.BlockTags;
|
||||||
import net.minecraft.util.ActionResultType;
|
import net.minecraft.util.ActionResultType;
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
|
import net.minecraft.util.Direction.Axis;
|
||||||
import net.minecraft.util.NonNullList;
|
import net.minecraft.util.NonNullList;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
@ -154,18 +157,21 @@ public class MinecartContraptionItem extends Item {
|
||||||
CompoundNBT tag = itemstack.getOrCreateTag();
|
CompoundNBT tag = itemstack.getOrCreateTag();
|
||||||
if (tag.contains("Contraption")) {
|
if (tag.contains("Contraption")) {
|
||||||
CompoundNBT contraptionTag = tag.getCompound("Contraption");
|
CompoundNBT contraptionTag = tag.getCompound("Contraption");
|
||||||
float initialAngle = contraptionTag.getFloat("InitialAngle");
|
|
||||||
|
Direction initialOrientation = Direction.SOUTH;
|
||||||
|
if (contraptionTag.contains("InitialOrientation"))
|
||||||
|
initialOrientation = NBTHelper.readEnum(contraptionTag, "InitialOrientation", Direction.class);
|
||||||
|
|
||||||
Contraption mountedContraption = Contraption.fromNBT(world, contraptionTag);
|
Contraption mountedContraption = Contraption.fromNBT(world, contraptionTag);
|
||||||
ContraptionEntity contraption;
|
ContraptionEntity contraptionEntity =
|
||||||
|
ContraptionEntity.createMounted(world, mountedContraption, Optional.of(initialOrientation));
|
||||||
|
|
||||||
if (newFacing != null)
|
if (newFacing != null)
|
||||||
contraption = ContraptionEntity.createMounted(world, mountedContraption, initialAngle, newFacing);
|
contraptionEntity.reOrientate(newFacing.getAxis() == Axis.X ? newFacing : newFacing.getOpposite());
|
||||||
else
|
|
||||||
contraption = ContraptionEntity.createMounted(world, mountedContraption, initialAngle);
|
|
||||||
|
|
||||||
contraption.startRiding(cart);
|
contraptionEntity.startRiding(cart);
|
||||||
contraption.setPosition(cart.getX(), cart.getY(), cart.getZ());
|
contraptionEntity.setPosition(cart.getX(), cart.getY(), cart.getZ());
|
||||||
world.addEntity(contraption);
|
world.addEntity(contraptionEntity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +224,11 @@ public class MinecartContraptionItem extends Item {
|
||||||
tag.remove("UUID");
|
tag.remove("UUID");
|
||||||
tag.remove("Pos");
|
tag.remove("Pos");
|
||||||
tag.remove("Motion");
|
tag.remove("Motion");
|
||||||
tag.putFloat("InitialAngle", entity.getInitialAngle());
|
|
||||||
|
Optional<Direction> initialOrientation = entity.getInitialOrientation();
|
||||||
|
if (initialOrientation.isPresent())
|
||||||
|
NBTHelper.writeEnum(tag, "InitialOrientation", initialOrientation.orElse(null));
|
||||||
|
|
||||||
stack.getOrCreateTag()
|
stack.getOrCreateTag()
|
||||||
.put("Contraption", tag);
|
.put("Contraption", tag);
|
||||||
return stack;
|
return stack;
|
||||||
|
|
|
@ -30,7 +30,9 @@ import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.IWorld;
|
import net.minecraft.world.IWorld;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
||||||
|
import net.minecraftforge.items.IItemHandlerModifiable;
|
||||||
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
|
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
|
||||||
|
import net.minecraftforge.items.wrapper.InvWrapper;
|
||||||
|
|
||||||
public class MountedContraption extends Contraption {
|
public class MountedContraption extends Contraption {
|
||||||
|
|
||||||
|
@ -47,9 +49,6 @@ public class MountedContraption extends Contraption {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MountedContraption assembleMinecart(World world, BlockPos pos) {
|
public static MountedContraption assembleMinecart(World world, BlockPos pos) {
|
||||||
if (isFrozen())
|
|
||||||
return null;
|
|
||||||
|
|
||||||
BlockState state = world.getBlockState(pos);
|
BlockState state = world.getBlockState(pos);
|
||||||
if (!BlockHelper.hasBlockStateProperty(state, RAIL_SHAPE))
|
if (!BlockHelper.hasBlockStateProperty(state, RAIL_SHAPE))
|
||||||
return null;
|
return null;
|
||||||
|
@ -61,10 +60,6 @@ public class MountedContraption extends Contraption {
|
||||||
Axis axis = state.get(RAIL_SHAPE) == RailShape.EAST_WEST ? Axis.X : Axis.Z;
|
Axis axis = state.get(RAIL_SHAPE) == RailShape.EAST_WEST ? Axis.X : Axis.Z;
|
||||||
contraption.add(pos, Pair.of(new BlockInfo(pos, AllBlocks.MINECART_ANCHOR.getDefaultState()
|
contraption.add(pos, Pair.of(new BlockInfo(pos, AllBlocks.MINECART_ANCHOR.getDefaultState()
|
||||||
.with(BlockStateProperties.HORIZONTAL_AXIS, axis), null), null));
|
.with(BlockStateProperties.HORIZONTAL_AXIS, axis), null), null));
|
||||||
contraption.removeBlocksFromWorld(world, BlockPos.ZERO);
|
|
||||||
contraption.initActors(world);
|
|
||||||
contraption.expandBoundsAroundAxis(Axis.Y);
|
|
||||||
|
|
||||||
return contraption;
|
return contraption;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,35 +74,51 @@ public class MountedContraption extends Contraption {
|
||||||
protected Pair<BlockInfo, TileEntity> capture(World world, BlockPos pos) {
|
protected Pair<BlockInfo, TileEntity> capture(World world, BlockPos pos) {
|
||||||
Pair<BlockInfo, TileEntity> pair = super.capture(world, pos);
|
Pair<BlockInfo, TileEntity> pair = super.capture(world, pos);
|
||||||
BlockInfo capture = pair.getKey();
|
BlockInfo capture = pair.getKey();
|
||||||
if (AllBlocks.CART_ASSEMBLER.has(capture.state)) {
|
if (!AllBlocks.CART_ASSEMBLER.has(capture.state))
|
||||||
if (!pos.equals(anchor)) {
|
return pair;
|
||||||
for (Axis axis : Iterate.axes) {
|
|
||||||
if (axis.isVertical())
|
Pair<BlockInfo, TileEntity> anchorSwap =
|
||||||
continue;
|
Pair.of(new BlockInfo(pos, CartAssemblerBlock.createAnchor(capture.state), null), pair.getValue());
|
||||||
if (VecHelper.onSameAxis(anchor, pos, axis) && connectedCart == null) {
|
if (pos.equals(anchor) || connectedCart != null)
|
||||||
for (AbstractMinecartEntity abstractMinecartEntity : world
|
return anchorSwap;
|
||||||
.getEntitiesWithinAABB(AbstractMinecartEntity.class, new AxisAlignedBB(pos))) {
|
|
||||||
if (!CartAssemblerBlock.canAssembleTo(abstractMinecartEntity))
|
for (Axis axis : Iterate.axes) {
|
||||||
break;
|
if (axis.isVertical() || !VecHelper.onSameAxis(anchor, pos, axis))
|
||||||
connectedCart = abstractMinecartEntity;
|
continue;
|
||||||
addExtraInventories(abstractMinecartEntity);
|
for (AbstractMinecartEntity abstractMinecartEntity : world
|
||||||
}
|
.getEntitiesWithinAABB(AbstractMinecartEntity.class, new AxisAlignedBB(pos))) {
|
||||||
}
|
if (!CartAssemblerBlock.canAssembleTo(abstractMinecartEntity))
|
||||||
}
|
break;
|
||||||
|
connectedCart = abstractMinecartEntity;
|
||||||
|
connectedCart.setPosition(pos.getX() + .5, pos.getY(), pos.getZ() + .5f);
|
||||||
}
|
}
|
||||||
return Pair.of(new BlockInfo(pos, CartAssemblerBlock.createAnchor(capture.state), null), pair.getValue());
|
|
||||||
}
|
}
|
||||||
return pair;
|
|
||||||
|
return anchorSwap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean movementAllowed(World world, BlockPos pos) {
|
protected boolean movementAllowed(World world, BlockPos pos) {
|
||||||
BlockState blockState = world.getBlockState(pos);
|
BlockState blockState = world.getBlockState(pos);
|
||||||
if (!pos.equals(anchor) && AllBlocks.CART_ASSEMBLER.has(blockState))
|
if (!pos.equals(anchor) && AllBlocks.CART_ASSEMBLER.has(blockState))
|
||||||
return true;
|
return testSecondaryCartAssembler(world, blockState, pos);
|
||||||
return super.movementAllowed(world, pos);
|
return super.movementAllowed(world, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean testSecondaryCartAssembler(World world, BlockState state, BlockPos pos) {
|
||||||
|
for (Axis axis : Iterate.axes) {
|
||||||
|
if (axis.isVertical() || !VecHelper.onSameAxis(anchor, pos, axis))
|
||||||
|
continue;
|
||||||
|
for (AbstractMinecartEntity abstractMinecartEntity : world
|
||||||
|
.getEntitiesWithinAABB(AbstractMinecartEntity.class, new AxisAlignedBB(pos))) {
|
||||||
|
if (!CartAssemblerBlock.canAssembleTo(abstractMinecartEntity))
|
||||||
|
break;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT writeNBT() {
|
public CompoundNBT writeNBT() {
|
||||||
CompoundNBT writeNBT = super.writeNBT();
|
CompoundNBT writeNBT = super.writeNBT();
|
||||||
|
@ -133,7 +144,9 @@ public class MountedContraption extends Contraption {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addExtraInventories(Entity cart) {
|
public void addExtraInventories(Entity cart) {
|
||||||
if (cart instanceof IInventory)
|
if (!(cart instanceof IInventory))
|
||||||
inventory = new CombinedInvWrapper(new ItemHandlerModifiableFromIInventory((IInventory) cart), inventory);
|
return;
|
||||||
|
IItemHandlerModifiable handlerFromInv = new InvWrapper((IInventory) cart);
|
||||||
|
inventory = new CombinedInvWrapper(handlerFromInv, inventory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,8 +49,6 @@ public class PistonContraption extends Contraption {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PistonContraption movePistonAt(World world, BlockPos pos, Direction direction, boolean retract) {
|
public static PistonContraption movePistonAt(World world, BlockPos pos, Direction direction, boolean retract) {
|
||||||
if (isFrozen())
|
|
||||||
return null;
|
|
||||||
PistonContraption construct = new PistonContraption();
|
PistonContraption construct = new PistonContraption();
|
||||||
construct.orientation = direction;
|
construct.orientation = direction;
|
||||||
if (!construct.collectExtensions(world, pos, direction))
|
if (!construct.collectExtensions(world, pos, direction))
|
||||||
|
|
|
@ -17,8 +17,6 @@ public class PulleyContraption extends Contraption {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PulleyContraption assemblePulleyAt(World world, BlockPos pos, int initialOffset) {
|
public static PulleyContraption assemblePulleyAt(World world, BlockPos pos, int initialOffset) {
|
||||||
if (isFrozen())
|
|
||||||
return null;
|
|
||||||
PulleyContraption construct = new PulleyContraption();
|
PulleyContraption construct = new PulleyContraption();
|
||||||
construct.initialOffset = initialOffset;
|
construct.initialOffset = initialOffset;
|
||||||
if (!construct.searchMovedStructure(world, pos, null))
|
if (!construct.searchMovedStructure(world, pos, null))
|
||||||
|
|
|
@ -9,16 +9,16 @@ import net.minecraft.entity.player.ServerPlayerEntity;
|
||||||
import net.minecraft.network.PacketBuffer;
|
import net.minecraft.network.PacketBuffer;
|
||||||
import net.minecraftforge.fml.network.NetworkEvent.Context;
|
import net.minecraftforge.fml.network.NetworkEvent.Context;
|
||||||
|
|
||||||
public class MinecartCouplingCreationPacket extends SimplePacketBase {
|
public class CouplingCreationPacket extends SimplePacketBase {
|
||||||
|
|
||||||
int id1, id2;
|
int id1, id2;
|
||||||
|
|
||||||
public MinecartCouplingCreationPacket(AbstractMinecartEntity cart1, AbstractMinecartEntity cart2) {
|
public CouplingCreationPacket(AbstractMinecartEntity cart1, AbstractMinecartEntity cart2) {
|
||||||
id1 = cart1.getEntityId();
|
id1 = cart1.getEntityId();
|
||||||
id2 = cart2.getEntityId();
|
id2 = cart2.getEntityId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public MinecartCouplingCreationPacket(PacketBuffer buffer) {
|
public CouplingCreationPacket(PacketBuffer buffer) {
|
||||||
id1 = buffer.readInt();
|
id1 = buffer.readInt();
|
||||||
id2 = buffer.readInt();
|
id2 = buffer.readInt();
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ public class MinecartCouplingCreationPacket extends SimplePacketBase {
|
||||||
ServerPlayerEntity sender = context.get()
|
ServerPlayerEntity sender = context.get()
|
||||||
.getSender();
|
.getSender();
|
||||||
if (sender != null)
|
if (sender != null)
|
||||||
MinecartCouplingHandler.connectCarts(sender, sender.world, id1, id2);
|
CouplingHandler.tryToCoupleCarts(sender, sender.world, id1, id2);
|
||||||
});
|
});
|
||||||
context.get()
|
context.get()
|
||||||
.setPacketHandled(true);
|
.setPacketHandled(true);
|
|
@ -0,0 +1,184 @@
|
||||||
|
package com.simibubi.create.content.contraptions.components.structureMovement.train;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.simibubi.create.AllItems;
|
||||||
|
import com.simibubi.create.Create;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController;
|
||||||
|
import com.simibubi.create.foundation.config.AllConfigs;
|
||||||
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
import com.simibubi.create.foundation.utility.Lang;
|
||||||
|
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.text.StringTextComponent;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
|
import net.minecraftforge.event.entity.EntityMountEvent;
|
||||||
|
import net.minecraftforge.eventbus.api.Event.Result;
|
||||||
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||||
|
|
||||||
|
@EventBusSubscriber
|
||||||
|
public class CouplingHandler {
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void preventEntitiesFromMoutingOccupiedCart(EntityMountEvent event) {
|
||||||
|
Entity e = event.getEntityBeingMounted();
|
||||||
|
LazyOptional<MinecartController> optional = e.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY);
|
||||||
|
if (!optional.isPresent())
|
||||||
|
return;
|
||||||
|
if (event.getEntityMounting() instanceof ContraptionEntity)
|
||||||
|
return;
|
||||||
|
MinecartController controller = optional.orElse(null);
|
||||||
|
if (controller.isCoupledThroughContraption()) {
|
||||||
|
event.setCanceled(true);
|
||||||
|
event.setResult(Result.DENY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void forEachLoadedCoupling(World world, Consumer<Couple<MinecartController>> consumer) {
|
||||||
|
if (world == null)
|
||||||
|
return;
|
||||||
|
Set<UUID> cartsWithCoupling = CapabilityMinecartController.loadedMinecartsWithCoupling.get(world);
|
||||||
|
if (cartsWithCoupling == null)
|
||||||
|
return;
|
||||||
|
cartsWithCoupling.forEach(id -> {
|
||||||
|
MinecartController controller = CapabilityMinecartController.getIfPresent(world, id);
|
||||||
|
if (controller == null)
|
||||||
|
return;
|
||||||
|
if (!controller.isLeadingCoupling())
|
||||||
|
return;
|
||||||
|
UUID coupledCart = controller.getCoupledCart(true);
|
||||||
|
MinecartController coupledController = CapabilityMinecartController.getIfPresent(world, coupledCart);
|
||||||
|
if (coupledController == null)
|
||||||
|
return;
|
||||||
|
consumer.accept(Couple.create(controller, coupledController));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean tryToCoupleCarts(@Nullable PlayerEntity player, World world, int cartId1, int cartId2) {
|
||||||
|
Entity entity1 = world.getEntityByID(cartId1);
|
||||||
|
Entity entity2 = world.getEntityByID(cartId2);
|
||||||
|
|
||||||
|
if (!(entity1 instanceof AbstractMinecartEntity))
|
||||||
|
return false;
|
||||||
|
if (!(entity2 instanceof AbstractMinecartEntity))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
String tooMany = "two_couplings_max";
|
||||||
|
String unloaded = "unloaded";
|
||||||
|
String noLoops = "no_loops";
|
||||||
|
String tooFar = "too_far";
|
||||||
|
|
||||||
|
int distanceTo = (int) entity1.getPositionVec()
|
||||||
|
.distanceTo(entity2.getPositionVec());
|
||||||
|
boolean contraptionCoupling = player == null;
|
||||||
|
|
||||||
|
if (distanceTo < 2) {
|
||||||
|
if (contraptionCoupling)
|
||||||
|
return false; // dont allow train contraptions with <2 distance
|
||||||
|
distanceTo = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distanceTo > AllConfigs.SERVER.kinetics.maxCartCouplingLength.get()) {
|
||||||
|
status(player, tooFar);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractMinecartEntity cart1 = (AbstractMinecartEntity) entity1;
|
||||||
|
AbstractMinecartEntity cart2 = (AbstractMinecartEntity) entity2;
|
||||||
|
UUID mainID = cart1.getUniqueID();
|
||||||
|
UUID connectedID = cart2.getUniqueID();
|
||||||
|
MinecartController mainController = CapabilityMinecartController.getIfPresent(world, mainID);
|
||||||
|
MinecartController connectedController = CapabilityMinecartController.getIfPresent(world, connectedID);
|
||||||
|
|
||||||
|
if (mainController == null || connectedController == null) {
|
||||||
|
status(player, unloaded);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mainController.isFullyCoupled() || connectedController.isFullyCoupled()) {
|
||||||
|
status(player, tooMany);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mainController.isLeadingCoupling() && mainController.getCoupledCart(true)
|
||||||
|
.equals(connectedID) || connectedController.isLeadingCoupling()
|
||||||
|
&& connectedController.getCoupledCart(true)
|
||||||
|
.equals(mainID))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (boolean main : Iterate.trueAndFalse) {
|
||||||
|
MinecartController current = main ? mainController : connectedController;
|
||||||
|
boolean forward = current.isLeadingCoupling();
|
||||||
|
int safetyCount = 1000;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (safetyCount-- <= 0) {
|
||||||
|
Create.logger.warn("Infinite loop in coupling iteration");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = getNextInCouplingChain(world, current, forward);
|
||||||
|
if (current == null) {
|
||||||
|
status(player, unloaded);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (current == connectedController) {
|
||||||
|
status(player, noLoops);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (current == MinecartController.EMPTY)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contraptionCoupling) {
|
||||||
|
for (Hand hand : Hand.values()) {
|
||||||
|
if (player.isCreative())
|
||||||
|
break;
|
||||||
|
ItemStack heldItem = player.getHeldItem(hand);
|
||||||
|
if (!AllItems.MINECART_COUPLING.isIn(heldItem))
|
||||||
|
continue;
|
||||||
|
heldItem.shrink(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mainController.prepareForCoupling(true);
|
||||||
|
connectedController.prepareForCoupling(false);
|
||||||
|
|
||||||
|
mainController.coupleWith(true, connectedID, distanceTo, contraptionCoupling);
|
||||||
|
connectedController.coupleWith(false, mainID, distanceTo, contraptionCoupling);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
/**
|
||||||
|
* MinecartController.EMPTY if none connected, null if not yet loaded
|
||||||
|
*/
|
||||||
|
public static MinecartController getNextInCouplingChain(World world, MinecartController controller,
|
||||||
|
boolean forward) {
|
||||||
|
UUID coupledCart = controller.getCoupledCart(forward);
|
||||||
|
if (coupledCart == null)
|
||||||
|
return MinecartController.empty();
|
||||||
|
return CapabilityMinecartController.getIfPresent(world, coupledCart);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void status(PlayerEntity player, String key) {
|
||||||
|
if (player == null)
|
||||||
|
return;
|
||||||
|
player.sendStatusMessage(new StringTextComponent(Lang.translate("minecart_coupling." + key)), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ import net.minecraft.particles.RedstoneParticleData;
|
||||||
import net.minecraft.util.math.AxisAlignedBB;
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
import net.minecraft.util.math.vector.Vector3d;
|
import net.minecraft.util.math.vector.Vector3d;
|
||||||
|
|
||||||
public class ClientMinecartCouplingHandler {
|
public class CouplingHandlerClient {
|
||||||
|
|
||||||
static AbstractMinecartEntity selectedCart;
|
static AbstractMinecartEntity selectedCart;
|
||||||
static Random r = new Random();
|
static Random r = new Random();
|
||||||
|
@ -44,7 +44,7 @@ public class ClientMinecartCouplingHandler {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
spawnSelectionParticles(entity.getBoundingBox(), true);
|
spawnSelectionParticles(entity.getBoundingBox(), true);
|
||||||
AllPackets.channel.sendToServer(new MinecartCouplingCreationPacket(selectedCart, entity));
|
AllPackets.channel.sendToServer(new CouplingCreationPacket(selectedCart, entity));
|
||||||
selectedCart = null;
|
selectedCart = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
package com.simibubi.create.content.contraptions.components.structureMovement.train;
|
||||||
|
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController;
|
||||||
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
|
|
||||||
|
import net.minecraft.block.AbstractRailBlock;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.MoverType;
|
||||||
|
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
||||||
|
import net.minecraft.state.properties.RailShape;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Vector3d;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
public class CouplingPhysics {
|
||||||
|
|
||||||
|
public static void tick(World world) {
|
||||||
|
CouplingHandler.forEachLoadedCoupling(world, c -> tickCoupling(world, c));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void tickCoupling(World world, Couple<MinecartController> c) {
|
||||||
|
Couple<AbstractMinecartEntity> carts = c.map(MinecartController::cart);
|
||||||
|
float couplingLength = c.getFirst().getCouplingLength(true);
|
||||||
|
softCollisionStep(world, carts, couplingLength);
|
||||||
|
hardCollisionStep(world, carts, couplingLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void hardCollisionStep(World world, Couple<AbstractMinecartEntity> carts, double couplingLength) {
|
||||||
|
Couple<Vector3d> corrections = Couple.create(null, null);
|
||||||
|
Couple<Float> maxSpeed = carts.map(AbstractMinecartEntity::getMaxCartSpeedOnRail);
|
||||||
|
boolean firstLoop = true;
|
||||||
|
for (boolean current : new boolean[] { true, false, true }) {
|
||||||
|
AbstractMinecartEntity cart = carts.get(current);
|
||||||
|
AbstractMinecartEntity otherCart = carts.get(!current);
|
||||||
|
|
||||||
|
float stress = (float) (couplingLength - cart.getPositionVec()
|
||||||
|
.distanceTo(otherCart.getPositionVec()));
|
||||||
|
|
||||||
|
RailShape shape = null;
|
||||||
|
BlockPos railPosition = cart.getCurrentRailPosition();
|
||||||
|
BlockState railState = world.getBlockState(railPosition.up());
|
||||||
|
|
||||||
|
if (railState.getBlock() instanceof AbstractRailBlock) {
|
||||||
|
AbstractRailBlock block = (AbstractRailBlock) railState.getBlock();
|
||||||
|
shape = block.getRailDirection(railState, world, railPosition, cart);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3d correction = Vector3d.ZERO;
|
||||||
|
Vector3d pos = cart.getPositionVec();
|
||||||
|
Vector3d link = otherCart.getPositionVec()
|
||||||
|
.subtract(pos);
|
||||||
|
float correctionMagnitude = firstLoop ? -stress / 2f : -stress;
|
||||||
|
correction = shape != null ? followLinkOnRail(link, pos, correctionMagnitude, shape).subtract(pos)
|
||||||
|
: link.normalize()
|
||||||
|
.scale(correctionMagnitude);
|
||||||
|
|
||||||
|
float maxResolveSpeed = 1.75f;
|
||||||
|
correction = VecHelper.clamp(correction, Math.min(maxResolveSpeed, maxSpeed.get(current)));
|
||||||
|
|
||||||
|
if (corrections.get(current) == null)
|
||||||
|
corrections.set(current, correction);
|
||||||
|
|
||||||
|
if (shape != null)
|
||||||
|
MinecartSim2020.moveCartAlongTrack(cart, correction, railPosition, railState);
|
||||||
|
else {
|
||||||
|
cart.move(MoverType.SELF, correction);
|
||||||
|
cart.setMotion(cart.getMotion()
|
||||||
|
.scale(0.5f));
|
||||||
|
}
|
||||||
|
firstLoop = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void softCollisionStep(World world, Couple<AbstractMinecartEntity> carts, double couplingLength) {
|
||||||
|
|
||||||
|
Couple<Vector3d> positions = carts.map(Entity::getPositionVector);
|
||||||
|
Couple<Float> maxSpeed = carts.map(AbstractMinecartEntity::getMaxCartSpeedOnRail);
|
||||||
|
Couple<Boolean> canAddmotion = carts.map(MinecartSim2020::canAddMotion);
|
||||||
|
|
||||||
|
Couple<RailShape> shapes = carts.map(current -> {
|
||||||
|
BlockPos railPosition = current.getCurrentRailPosition();
|
||||||
|
BlockState railState = world.getBlockState(railPosition.up());
|
||||||
|
if (!(railState.getBlock() instanceof AbstractRailBlock))
|
||||||
|
return null;
|
||||||
|
AbstractRailBlock block = (AbstractRailBlock) railState.getBlock();
|
||||||
|
return block.getRailDirection(railState, world, railPosition, current);
|
||||||
|
});
|
||||||
|
|
||||||
|
Couple<Vector3d> motions = carts.map(MinecartSim2020::predictMotionOf);
|
||||||
|
Couple<Vector3d> nextPositions = positions.copy();
|
||||||
|
nextPositions.replaceWithParams(Vector3d::add, motions);
|
||||||
|
|
||||||
|
float futureStress = (float) (couplingLength - nextPositions.getFirst()
|
||||||
|
.distanceTo(nextPositions.getSecond()));
|
||||||
|
if (Math.abs(futureStress) < 1 / 128f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (boolean current : Iterate.trueAndFalse) {
|
||||||
|
Vector3d correction = Vector3d.ZERO;
|
||||||
|
Vector3d pos = nextPositions.get(current);
|
||||||
|
Vector3d link = nextPositions.get(!current)
|
||||||
|
.subtract(pos);
|
||||||
|
float correctionMagnitude = -futureStress / 2f;
|
||||||
|
|
||||||
|
if (canAddmotion.get(current) != canAddmotion.get(!current))
|
||||||
|
correctionMagnitude = !canAddmotion.get(current) ? 0 : correctionMagnitude * 2;
|
||||||
|
|
||||||
|
RailShape shape = shapes.get(current);
|
||||||
|
correction = shape != null ? followLinkOnRail(link, pos, correctionMagnitude, shape).subtract(pos)
|
||||||
|
: link.normalize()
|
||||||
|
.scale(correctionMagnitude);
|
||||||
|
correction = VecHelper.clamp(correction, maxSpeed.get(current));
|
||||||
|
motions.set(current, motions.get(current)
|
||||||
|
.add(correction));
|
||||||
|
}
|
||||||
|
|
||||||
|
motions.replaceWithParams(VecHelper::clamp, maxSpeed);
|
||||||
|
carts.forEachWithParams(Entity::setMotion, motions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3d followLinkOnRail(Vector3d link, Vector3d cart, float diffToReduce, RailShape shape) {
|
||||||
|
Vector3d railAxis = MinecartSim2020.getRailVec(shape);
|
||||||
|
double dotProduct = railAxis.dotProduct(link);
|
||||||
|
if (Double.isNaN(dotProduct) || dotProduct == 0 || diffToReduce == 0)
|
||||||
|
return cart;
|
||||||
|
|
||||||
|
Vector3d axis = railAxis.scale(-Math.signum(dotProduct));
|
||||||
|
Vector3d center = cart.add(link);
|
||||||
|
double radius = link.length() - diffToReduce;
|
||||||
|
Vector3d intersectSphere = VecHelper.intersectSphere(cart, axis, center, radius);
|
||||||
|
|
||||||
|
// Cannot satisfy on current rail vector
|
||||||
|
if (intersectSphere == null)
|
||||||
|
return cart.add(VecHelper.project(link, axis));
|
||||||
|
|
||||||
|
return intersectSphere;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,6 +5,10 @@ import static net.minecraft.util.math.MathHelper.lerp;
|
||||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||||
import com.simibubi.create.AllBlockPartials;
|
import com.simibubi.create.AllBlockPartials;
|
||||||
|
import com.simibubi.create.CreateClient;
|
||||||
|
import com.simibubi.create.content.contraptions.KineticDebugger;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController;
|
||||||
|
import com.simibubi.create.foundation.utility.ColorHelper;
|
||||||
import com.simibubi.create.foundation.utility.Couple;
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
import com.simibubi.create.foundation.utility.MatrixStacker;
|
import com.simibubi.create.foundation.utility.MatrixStacker;
|
||||||
import com.simibubi.create.foundation.utility.SuperByteBuffer;
|
import com.simibubi.create.foundation.utility.SuperByteBuffer;
|
||||||
|
@ -24,13 +28,24 @@ import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraft.util.math.vector.Vector3d;
|
import net.minecraft.util.math.vector.Vector3d;
|
||||||
import net.minecraft.util.math.vector.Vector3f;
|
import net.minecraft.util.math.vector.Vector3f;
|
||||||
|
|
||||||
public class MinecartCouplingRenderer {
|
public class CouplingRenderer {
|
||||||
|
|
||||||
public static void renderCoupling(MatrixStack ms, IRenderTypeBuffer buffer, MinecartCoupling coupling) {
|
public static void renderAll(MatrixStack ms, IRenderTypeBuffer buffer) {
|
||||||
if (!coupling.areBothEndsPresent())
|
CouplingHandler.forEachLoadedCoupling(Minecraft.getInstance().world,
|
||||||
return;
|
c -> {
|
||||||
|
if (c.getFirst().hasContraptionCoupling(true))
|
||||||
|
return;
|
||||||
|
CouplingRenderer.renderCoupling(ms, buffer, c.map(MinecartController::cart));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void tickDebugModeRenders() {
|
||||||
|
if (KineticDebugger.isActive())
|
||||||
|
CouplingHandler.forEachLoadedCoupling(Minecraft.getInstance().world, CouplingRenderer::doDebugRender);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void renderCoupling(MatrixStack ms, IRenderTypeBuffer buffer, Couple<AbstractMinecartEntity> carts) {
|
||||||
ClientWorld world = Minecraft.getInstance().world;
|
ClientWorld world = Minecraft.getInstance().world;
|
||||||
Couple<AbstractMinecartEntity> carts = coupling.asCouple();
|
|
||||||
Couple<Integer> lightValues =
|
Couple<Integer> lightValues =
|
||||||
carts.map(c -> WorldRenderer.getLightmapCoordinates(world, new BlockPos(c.getBoundingBox()
|
carts.map(c -> WorldRenderer.getLightmapCoordinates(world, new BlockPos(c.getBoundingBox()
|
||||||
.getCenter())));
|
.getCenter())));
|
||||||
|
@ -194,4 +209,29 @@ public class MinecartCouplingRenderer {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void doDebugRender(Couple<MinecartController> c) {
|
||||||
|
int yOffset = 1;
|
||||||
|
MinecartController first = c.getFirst();
|
||||||
|
AbstractMinecartEntity mainCart = first.cart();
|
||||||
|
Vector3d mainCenter = mainCart.getPositionVec()
|
||||||
|
.add(0, yOffset, 0);
|
||||||
|
Vector3d connectedCenter = c.getSecond()
|
||||||
|
.cart()
|
||||||
|
.getPositionVec()
|
||||||
|
.add(0, yOffset, 0);
|
||||||
|
|
||||||
|
int color = ColorHelper.mixColors(0xabf0e9, 0xee8572, (float) MathHelper
|
||||||
|
.clamp(Math.abs(first.getCouplingLength(true) - connectedCenter.distanceTo(mainCenter)) * 8, 0, 1));
|
||||||
|
|
||||||
|
CreateClient.outliner.showLine(mainCart.getEntityId() + "", mainCenter, connectedCenter)
|
||||||
|
.colored(color)
|
||||||
|
.lineWidth(1 / 8f);
|
||||||
|
|
||||||
|
Vector3d point = mainCart.getPositionVec()
|
||||||
|
.add(0, yOffset, 0);
|
||||||
|
CreateClient.outliner.showLine(mainCart.getEntityId() + "_dot", point, point.add(0, 1 / 128f, 0))
|
||||||
|
.colored(0xffffff)
|
||||||
|
.lineWidth(1 / 4f);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,117 +0,0 @@
|
||||||
package com.simibubi.create.content.contraptions.components.structureMovement.train;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCouplingSerializer.CouplingData;
|
|
||||||
import com.simibubi.create.foundation.utility.Couple;
|
|
||||||
|
|
||||||
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
|
||||||
import net.minecraft.world.World;
|
|
||||||
|
|
||||||
public class MinecartCoupling {
|
|
||||||
|
|
||||||
WeakReference<AbstractMinecartEntity> mainCart;
|
|
||||||
WeakReference<AbstractMinecartEntity> connectedCart;
|
|
||||||
double length;
|
|
||||||
|
|
||||||
private MinecartCoupling(AbstractMinecartEntity mainCart, AbstractMinecartEntity connectedCart, double length) {
|
|
||||||
this.mainCart = new WeakReference<>(mainCart);
|
|
||||||
this.connectedCart = new WeakReference<>(connectedCart);
|
|
||||||
this.length = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MinecartCoupling create(AbstractMinecartEntity mainCart, AbstractMinecartEntity connectedCart) {
|
|
||||||
return new MinecartCoupling(mainCart, connectedCart,
|
|
||||||
Math.max(2, getDistanceBetweenCarts(mainCart, connectedCart)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static List<MinecartCoupling> loadAllAttached(World world, AbstractMinecartEntity minecart) {
|
|
||||||
List<MinecartCoupling> loaded = new ArrayList<>(2);
|
|
||||||
List<AbstractMinecartEntity> otherCartsInRange =
|
|
||||||
world.getEntitiesWithinAABB(AbstractMinecartEntity.class, minecart.getBoundingBox()
|
|
||||||
.grow(MinecartCouplingHandler.maxDistance()), c -> c != minecart);
|
|
||||||
|
|
||||||
List<CouplingData> couplingData = MinecartCouplingSerializer.getCouplingData(minecart);
|
|
||||||
Connections: for (CouplingData connection : couplingData) {
|
|
||||||
boolean cartIsMain = connection.main;
|
|
||||||
UUID cartCouplingUUID = connection.id;
|
|
||||||
|
|
||||||
for (AbstractMinecartEntity otherCart : otherCartsInRange) {
|
|
||||||
List<CouplingData> otherCouplingData = MinecartCouplingSerializer.getCouplingData(otherCart);
|
|
||||||
for (CouplingData otherConnection : otherCouplingData) {
|
|
||||||
boolean otherIsMain = otherConnection.main;
|
|
||||||
UUID otherCouplingUUID = otherConnection.id;
|
|
||||||
|
|
||||||
if (cartIsMain == otherIsMain)
|
|
||||||
continue;
|
|
||||||
if (!otherCouplingUUID.equals(cartCouplingUUID))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
AbstractMinecartEntity mainCart = cartIsMain ? minecart : otherCart;
|
|
||||||
AbstractMinecartEntity connectedCart = cartIsMain ? otherCart : minecart;
|
|
||||||
loaded.add(new MinecartCoupling(mainCart, connectedCart, connection.length));
|
|
||||||
continue Connections;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeToCarts() {
|
|
||||||
MinecartCouplingSerializer.removeCouplingFromCart(mainCart.get(), this);
|
|
||||||
MinecartCouplingSerializer.removeCouplingFromCart(connectedCart.get(), this);
|
|
||||||
|
|
||||||
MinecartCouplingSerializer.addCouplingToCart(mainCart.get(), this);
|
|
||||||
MinecartCouplingSerializer.addCouplingToCart(connectedCart.get(), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Swap main and connected cart for aliging couplings of a train.<br>
|
|
||||||
* Changes are written to the carts' nbt data!<br>
|
|
||||||
* Id of this coupling will change!
|
|
||||||
*/
|
|
||||||
public void flip() {
|
|
||||||
MinecartCouplingSerializer.removeCouplingFromCart(mainCart.get(), this);
|
|
||||||
MinecartCouplingSerializer.removeCouplingFromCart(connectedCart.get(), this);
|
|
||||||
|
|
||||||
WeakReference<AbstractMinecartEntity> oldMain = mainCart;
|
|
||||||
mainCart = connectedCart;
|
|
||||||
connectedCart = oldMain;
|
|
||||||
|
|
||||||
MinecartCouplingSerializer.addCouplingToCart(mainCart.get(), this);
|
|
||||||
MinecartCouplingSerializer.addCouplingToCart(connectedCart.get(), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double getDistanceBetweenCarts(AbstractMinecartEntity mainCart,
|
|
||||||
AbstractMinecartEntity connectedCart) {
|
|
||||||
return mainCart.getBoundingBox()
|
|
||||||
.getCenter()
|
|
||||||
.subtract(connectedCart.getBoundingBox()
|
|
||||||
.getCenter())
|
|
||||||
.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean areBothEndsPresent() {
|
|
||||||
return (mainCart.get() != null && mainCart.get()
|
|
||||||
.isAlive()) && (connectedCart.get() != null
|
|
||||||
&& connectedCart.get()
|
|
||||||
.isAlive());
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getId() {
|
|
||||||
return mainCart.get()
|
|
||||||
.getUniqueID();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Couple<AbstractMinecartEntity> asCouple() {
|
|
||||||
return Couple.create(mainCart.get(), connectedCart.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,404 +0,0 @@
|
||||||
package com.simibubi.create.content.contraptions.components.structureMovement.train;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
|
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCouplingSerializer.CouplingData;
|
|
||||||
import com.simibubi.create.foundation.config.AllConfigs;
|
|
||||||
import com.simibubi.create.foundation.networking.AllPackets;
|
|
||||||
import com.simibubi.create.foundation.utility.Couple;
|
|
||||||
import com.simibubi.create.foundation.utility.WorldAttached;
|
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectLists;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
|
||||||
import net.minecraft.client.world.ClientWorld;
|
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
|
||||||
import net.minecraft.nbt.CompoundNBT;
|
|
||||||
import net.minecraft.world.World;
|
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
||||||
import net.minecraftforge.fml.network.PacketDistributor;
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Couplings are a directional connection of two Minecart entities
|
|
||||||
* - ID and Key is the UUID of the main cart
|
|
||||||
* - They are immediately written to both minecarts' nbt tags upon creation.
|
|
||||||
* {Main: true, Id: {L: ", M: "}, Length: 5}
|
|
||||||
*
|
|
||||||
* Trains are an ordered list of Couplings
|
|
||||||
* - ID and Key is the UUID of the main coupling
|
|
||||||
* - Every coupling is part of exactly one train, lonely couplings are still treated as such
|
|
||||||
* - When two trains are merged, the couplings have to be re-oriented to always point towards the main coupling
|
|
||||||
*
|
|
||||||
* Loaded carts are queued to be dealt with on world tick,
|
|
||||||
* so that the world functions are not accessed during the chunk deserialization
|
|
||||||
*
|
|
||||||
* Challenges:
|
|
||||||
* - Minecarts can only be corrected by changing their motion or their position
|
|
||||||
* - A Minecarts' motion vector does not represent its actual movement next tick
|
|
||||||
* - There is no accessible simulation step (can be copied / at'd)
|
|
||||||
* - It is not always known which cart is ahead/behind
|
|
||||||
* - If both ends keep a contant momentum, the link stress is not necessarily satisfied
|
|
||||||
* - Carts cannot be "dragged" directly towards resolving link stress;
|
|
||||||
* It is not entirely predictable how motions outside of the rail vector get projected
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Day III, couplings still too unstable. Why is that? What causes the instability, is it the general approach or a specific issue
|
|
||||||
* Explored strategies:
|
|
||||||
*
|
|
||||||
* Acellerate against violation diff -> perpetual motion, Jittering, bouncyness
|
|
||||||
* Brake and correct towards violation diff -> quick loss of momentum
|
|
||||||
* Move against diff -> de-rails carts on tricky paths
|
|
||||||
*
|
|
||||||
* Not yet explored: running an actual simulation step for the minecarts' movement.
|
|
||||||
*
|
|
||||||
* - satisfied link
|
|
||||||
* -- stretched link
|
|
||||||
* . shortened link
|
|
||||||
* ? not visible in ctx
|
|
||||||
* = cart
|
|
||||||
* => moving cart
|
|
||||||
*
|
|
||||||
* Create algorithm to find a tick order which maximizes resolved stress
|
|
||||||
*
|
|
||||||
* => ? <= ? = - => (@t)
|
|
||||||
* ^ tick here first
|
|
||||||
*
|
|
||||||
* cart[], motion[], position[]
|
|
||||||
* Predict through simulation + motion, that without any intervention, this happens:
|
|
||||||
*
|
|
||||||
* => ? <= ? = -- => (@t+1)
|
|
||||||
*
|
|
||||||
* Decision: Accelerate trailing? (free motion)
|
|
||||||
* Brake leading? (loss of momentum)
|
|
||||||
* -> Both?
|
|
||||||
*
|
|
||||||
* Soft collisions can always be resolved. Just have to adjust motions accordingly.
|
|
||||||
* Hard collisions should never be resolved by the soft/motion resolver, as it would generate or void momentum!
|
|
||||||
*
|
|
||||||
* Approach: Hard pass then soft pass. two iterations of the coupling list
|
|
||||||
*
|
|
||||||
* find starting point of hard resolve: the center of balance
|
|
||||||
* i from left, j from right
|
|
||||||
* compare and approach the exact center of the resolved chain.
|
|
||||||
*
|
|
||||||
* -3 -2-10v 0
|
|
||||||
* 0-----0-0-0-0
|
|
||||||
* 0--0--0--0--0
|
|
||||||
* 2 1
|
|
||||||
* 0---0-0---0---0--0--0-0-0-0-0
|
|
||||||
* 0--0--0--0--0--0--0--0--0--0--0
|
|
||||||
*
|
|
||||||
* v
|
|
||||||
* 0-0-0
|
|
||||||
* 0--0--0
|
|
||||||
*
|
|
||||||
* v
|
|
||||||
* 0---0---0---0
|
|
||||||
* 0-0-0-0
|
|
||||||
*
|
|
||||||
* -1 0 -1 0
|
|
||||||
* 0-0---0--0---0-0
|
|
||||||
* 0--0--0--0--0--0
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* iterate both ways from the center and resolve hard collisions.
|
|
||||||
*
|
|
||||||
* <HARD Resolve>
|
|
||||||
* if coupling is NOT ok @t {
|
|
||||||
* Something unpredictable happened.
|
|
||||||
* Try to reach soft state asap. every lost cycle in hard will act strangely and render inconsistently
|
|
||||||
* Using motion to hard resolve is probably a bad idea
|
|
||||||
*
|
|
||||||
* if cart on rail -> force move along rail away from collision
|
|
||||||
* else straight-up push it
|
|
||||||
* use simulation to test if movements are possible
|
|
||||||
*
|
|
||||||
* hard resolves are usually quite tiny. If they go beyond 1m then something really messed up
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* if coupling could not be fixed {
|
|
||||||
* clear all motion of the two carts (?)
|
|
||||||
* A failed hard collision implies that the Minecarts cannot be forced together/apart, might aswell not make things worse
|
|
||||||
* }
|
|
||||||
* </HARD Resolve>
|
|
||||||
*
|
|
||||||
* Soft collisions only mess with motion values. It is still good to find a good order of iteration-
|
|
||||||
* that way predictions of earlier couplings in the loop are still accurate
|
|
||||||
*
|
|
||||||
* =>>> - = - <= - =>>
|
|
||||||
*
|
|
||||||
* left to right
|
|
||||||
* =>> - = - => - =>
|
|
||||||
* right to left
|
|
||||||
* =>> - => - = - =>
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* if now coupling is ok @t {
|
|
||||||
* <Soft Resolve>
|
|
||||||
* Run Prediction I
|
|
||||||
* if (coupling is ok @t+1)
|
|
||||||
* my job here is done; return
|
|
||||||
*
|
|
||||||
* get required force to resolve (front or back)
|
|
||||||
* distribute equally over both carts
|
|
||||||
*
|
|
||||||
* Run Prediction II
|
|
||||||
* if (coupling is ok @t+1*)
|
|
||||||
* looks good; return
|
|
||||||
*
|
|
||||||
* re-distribute force to other cart
|
|
||||||
* all collisions should be fixed at this point. return;
|
|
||||||
* (in case of sudden changes/ bad predictions, the next cycle can handle the hard resolve)
|
|
||||||
* </Soft Resolve>
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* NEXT STEPS
|
|
||||||
* 1. normalize diagonal rail vectors and debug all possible rail motion transfers. The required tools have to work properly
|
|
||||||
* 2. implement a prediction step
|
|
||||||
* 3. find a suitable hard collision resolver
|
|
||||||
* 4. find a suitable soft collision order
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class MinecartCouplingHandler {
|
|
||||||
|
|
||||||
static WorldAttached<Map<UUID, MinecartCoupling>> loadedCouplings = new WorldAttached<>(HashMap::new);
|
|
||||||
static WorldAttached<Map<UUID, MinecartTrain>> loadedTrains = new WorldAttached<>(HashMap::new);
|
|
||||||
|
|
||||||
static WorldAttached<List<AbstractMinecartEntity>> queuedCarts =
|
|
||||||
new WorldAttached<>(() -> ObjectLists.synchronize(new ObjectArrayList<>()));
|
|
||||||
|
|
||||||
public static void connectCarts(@Nullable PlayerEntity player, World world, int cartId1, int cartId2) {
|
|
||||||
Entity entity1 = world.getEntityByID(cartId1);
|
|
||||||
Entity entity2 = world.getEntityByID(cartId2);
|
|
||||||
|
|
||||||
if (!(entity1 instanceof AbstractMinecartEntity))
|
|
||||||
return;
|
|
||||||
if (!(entity2 instanceof AbstractMinecartEntity))
|
|
||||||
return;
|
|
||||||
if ((int) entity1.getPositionVec()
|
|
||||||
.distanceTo(entity2.getPositionVec()) > maxDistance())
|
|
||||||
return;
|
|
||||||
|
|
||||||
AbstractMinecartEntity cart1 = (AbstractMinecartEntity) entity1;
|
|
||||||
AbstractMinecartEntity cart2 = (AbstractMinecartEntity) entity2;
|
|
||||||
|
|
||||||
if (alreadyCoupled(world, cart1, cart2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
addCoupling(world, MinecartCoupling.create(cart1, cart2), false);
|
|
||||||
|
|
||||||
if (world.isRemote)
|
|
||||||
return;
|
|
||||||
AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> cart1),
|
|
||||||
new MinecartCouplingSyncPacket(cart1, cart2));
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
public static void render(MatrixStack ms, IRenderTypeBuffer buffer) {
|
|
||||||
ClientWorld world = Minecraft.getInstance().world;
|
|
||||||
if (world == null)
|
|
||||||
return;
|
|
||||||
loadedCouplings.get(world)
|
|
||||||
.values()
|
|
||||||
.forEach(c -> MinecartCouplingRenderer.renderCoupling(ms, buffer, c));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void tick(World world) {
|
|
||||||
initQueuedCarts(world);
|
|
||||||
removeUnloadedCouplings(world);
|
|
||||||
loadedTrains.get(world)
|
|
||||||
.values()
|
|
||||||
.forEach(t -> t.tickCouplings(world));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void initQueuedCarts(World world) {
|
|
||||||
List<AbstractMinecartEntity> queued = queuedCarts.get(world);
|
|
||||||
if (queued == null)
|
|
||||||
return;
|
|
||||||
for (AbstractMinecartEntity minecart : queued)
|
|
||||||
MinecartCoupling.loadAllAttached(world, minecart)
|
|
||||||
.forEach(c -> addCoupling(world, c, true));
|
|
||||||
queued.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void removeUnloadedCouplings(World world) {
|
|
||||||
List<UUID> toRemove = new ArrayList<>();
|
|
||||||
Map<UUID, MinecartCoupling> couplings = loadedCouplings.get(world);
|
|
||||||
if (couplings == null)
|
|
||||||
return;
|
|
||||||
for (Entry<UUID, MinecartCoupling> entry : couplings.entrySet())
|
|
||||||
if (!entry.getValue()
|
|
||||||
.areBothEndsPresent())
|
|
||||||
toRemove.add(entry.getKey());
|
|
||||||
couplings.keySet()
|
|
||||||
.removeAll(toRemove);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void handleAddedMinecart(Entity entity, World world) {
|
|
||||||
if (!(entity instanceof AbstractMinecartEntity))
|
|
||||||
return;
|
|
||||||
if (world.isRemote)
|
|
||||||
queueLoadedMinecartClient(entity, world);
|
|
||||||
else
|
|
||||||
queueLoadedMinecart(entity, world);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void queueLoadedMinecartClient(Entity entity, World world) {
|
|
||||||
AllPackets.channel.sendToServer(new PersistantDataPacketRequest(entity));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void queueLoadedMinecart(Entity entity, World world) {
|
|
||||||
AbstractMinecartEntity minecart = (AbstractMinecartEntity) entity;
|
|
||||||
CompoundNBT nbt = minecart.getPersistentData();
|
|
||||||
if (!nbt.contains("Couplings"))
|
|
||||||
return;
|
|
||||||
queuedCarts.get(world)
|
|
||||||
.add(minecart);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int maxDistance() {
|
|
||||||
return AllConfigs.SERVER.kinetics.maxCartCouplingLength.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Pair<UUID, Boolean> getTrainIfComplete(World world, AbstractMinecartEntity minecart,
|
|
||||||
@Nullable UUID ignore) {
|
|
||||||
AbstractMinecartEntity current = minecart;
|
|
||||||
UUID trainId = current.getUniqueID();
|
|
||||||
for (int i = 0; i < 100; i++) {
|
|
||||||
List<CouplingData> couplingData = MinecartCouplingSerializer.getCouplingData(current);
|
|
||||||
for (CouplingData data : couplingData) {
|
|
||||||
if (data.main)
|
|
||||||
continue;
|
|
||||||
if (ignore != null && ignore.equals(data.id))
|
|
||||||
continue;
|
|
||||||
trainId = data.id;
|
|
||||||
MinecartCoupling coupling = loadedCouplings.get(world)
|
|
||||||
.get(trainId);
|
|
||||||
|
|
||||||
// Not fully loaded in
|
|
||||||
if (coupling == null)
|
|
||||||
return Pair.of(trainId, false);
|
|
||||||
|
|
||||||
current = coupling.mainCart.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Complete
|
|
||||||
return Pair.of(trainId, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean alreadyCoupled(World world, AbstractMinecartEntity cart1, AbstractMinecartEntity cart2) {
|
|
||||||
Pair<UUID, Boolean> trainOf = getTrainIfComplete(world, cart1, null);
|
|
||||||
Pair<UUID, Boolean> trainOf2 = getTrainIfComplete(world, cart2, null);
|
|
||||||
return trainOf.getRight() && trainOf2.getRight() && trainOf.getLeft()
|
|
||||||
.equals(trainOf2.getLeft());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addCoupling(World world, MinecartCoupling coupling, boolean loadedFromChunk) {
|
|
||||||
MinecartTrain train = new MinecartTrain(coupling);
|
|
||||||
Pair<UUID, Boolean> trainIdOfMain = getTrainIfComplete(world, coupling.mainCart.get(), null);
|
|
||||||
Pair<UUID, Boolean> trainIdOfConnected =
|
|
||||||
getTrainIfComplete(world, coupling.connectedCart.get(), loadedFromChunk ? coupling.getId() : null);
|
|
||||||
|
|
||||||
// Something is not loaded
|
|
||||||
if (!loadedFromChunk && !(trainIdOfMain.getValue() && trainIdOfConnected.getValue()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Coupling was already loaded in
|
|
||||||
if (loadedFromChunk && loadedCouplings.get(world)
|
|
||||||
.containsKey(coupling.getId()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!world.isRemote) {
|
|
||||||
Map<UUID, MinecartTrain> trains = loadedTrains.get(world);
|
|
||||||
MinecartTrain trainOfMain = trains.get(trainIdOfMain.getKey());
|
|
||||||
MinecartTrain trainOfConnected = trains.get(trainIdOfConnected.getKey());
|
|
||||||
|
|
||||||
// Connected cart is part of a train, merge it onto the newly created one
|
|
||||||
if (trainOfConnected != null)
|
|
||||||
trains.remove(trainIdOfConnected.getKey())
|
|
||||||
.mergeOnto(world, train);
|
|
||||||
|
|
||||||
// Main cart is part of a train, merge the newly created one onto it
|
|
||||||
boolean mainCartHasTrain = trainOfMain != null && trainIdOfMain.getKey()
|
|
||||||
.equals(coupling.getId());
|
|
||||||
if (trainOfMain != null) {
|
|
||||||
if (mainCartHasTrain && !loadedFromChunk)
|
|
||||||
flipTrain(world, trainOfMain);
|
|
||||||
train.mergeOnto(world, trainOfMain);
|
|
||||||
train = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...add the new train otherwise
|
|
||||||
if (train != null)
|
|
||||||
trains.put(train.getId(), train);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadedCouplings.get(world)
|
|
||||||
.put(coupling.getId(), coupling);
|
|
||||||
if (!loadedFromChunk)
|
|
||||||
coupling.writeToCarts();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void flipTrain(World world, MinecartTrain train) {
|
|
||||||
Map<UUID, MinecartTrain> map = loadedTrains.get(world);
|
|
||||||
map.remove(train.getId());
|
|
||||||
train.flip(world);
|
|
||||||
map.put(train.getId(), train);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MinecartCoupling getCoupling(World world, UUID id) {
|
|
||||||
Map<UUID, MinecartCoupling> map = loadedCouplings.get(world);
|
|
||||||
return map.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void flipCoupling(World world, MinecartCoupling coupling) {
|
|
||||||
Map<UUID, MinecartCoupling> map = loadedCouplings.get(world);
|
|
||||||
map.remove(coupling.getId());
|
|
||||||
|
|
||||||
if (coupling.areBothEndsPresent()) {
|
|
||||||
Couple<AbstractMinecartEntity> carts = coupling.asCouple();
|
|
||||||
Couple<UUID> ids = carts.map(Entity::getUniqueID);
|
|
||||||
carts.map(c -> c.isBeingRidden() ? c.getPassengers()
|
|
||||||
.get(0) : null)
|
|
||||||
.map(c -> c instanceof ContraptionEntity ? (ContraptionEntity) c : null)
|
|
||||||
.forEachWithContext((contraption, current) -> {
|
|
||||||
if (contraption == null || contraption.getCouplingId() == null)
|
|
||||||
return;
|
|
||||||
boolean switchTo = contraption.getCouplingId()
|
|
||||||
.equals(ids.get(current)) ? !current : current;
|
|
||||||
if (!carts.get(switchTo).getUniqueID().equals(contraption.getCoupledCart()))
|
|
||||||
return;
|
|
||||||
contraption.setCouplingId(ids.get(switchTo));
|
|
||||||
contraption.setCoupledCart(ids.get(!switchTo));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
coupling.flip();
|
|
||||||
map.put(coupling.getId(), coupling);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +1,8 @@
|
||||||
package com.simibubi.create.content.contraptions.components.structureMovement.train;
|
package com.simibubi.create.content.contraptions.components.structureMovement.train;
|
||||||
|
|
||||||
import com.simibubi.create.AllItems;
|
import com.simibubi.create.AllItems;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController;
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
||||||
|
@ -11,7 +13,10 @@ import net.minecraft.util.ActionResultType;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||||
|
import net.minecraftforge.event.entity.player.PlayerInteractEvent.EntityInteract;
|
||||||
|
import net.minecraftforge.eventbus.api.EventPriority;
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.DistExecutor;
|
import net.minecraftforge.fml.DistExecutor;
|
||||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||||
|
@ -23,8 +28,8 @@ public class MinecartCouplingItem extends Item {
|
||||||
super(p_i48487_1_);
|
super(p_i48487_1_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||||
public static void couplingItemCanBeUsedOnMinecarts(PlayerInteractEvent.EntityInteract event) {
|
public static void handleInteractionWithMinecart(PlayerInteractEvent.EntityInteract event) {
|
||||||
Entity interacted = event.getTarget();
|
Entity interacted = event.getTarget();
|
||||||
if (!(interacted instanceof AbstractMinecartEntity))
|
if (!(interacted instanceof AbstractMinecartEntity))
|
||||||
return;
|
return;
|
||||||
|
@ -32,23 +37,58 @@ public class MinecartCouplingItem extends Item {
|
||||||
PlayerEntity player = event.getPlayer();
|
PlayerEntity player = event.getPlayer();
|
||||||
if (player == null)
|
if (player == null)
|
||||||
return;
|
return;
|
||||||
ItemStack heldItem = player.getHeldItem(event.getHand());
|
LazyOptional<MinecartController> capability =
|
||||||
if (!AllItems.MINECART_COUPLING.isIn(heldItem))
|
minecart.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY);
|
||||||
|
if (!capability.isPresent())
|
||||||
return;
|
return;
|
||||||
|
MinecartController controller = capability.orElse(null);
|
||||||
World world = event.getWorld();
|
|
||||||
if (MinecartCouplingSerializer.getCouplingData(minecart).size() < 2) {
|
ItemStack heldItem = player.getHeldItem(event.getHand());
|
||||||
if (world != null && world.isRemote)
|
if (AllItems.MINECART_COUPLING.isIn(heldItem)) {
|
||||||
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> cartClicked(player, minecart));
|
if (!onCouplingInteractOnMinecart(event, minecart, player, controller))
|
||||||
}
|
return;
|
||||||
|
} else if (AllItems.WRENCH.isIn(heldItem)) {
|
||||||
|
if (!onWrenchInteractOnMinecart(event, minecart, player, controller))
|
||||||
|
return;
|
||||||
|
} else
|
||||||
|
return;
|
||||||
|
|
||||||
event.setCanceled(true);
|
event.setCanceled(true);
|
||||||
event.setCancellationResult(ActionResultType.SUCCESS);
|
event.setCancellationResult(ActionResultType.SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static boolean onCouplingInteractOnMinecart(PlayerInteractEvent.EntityInteract event,
|
||||||
|
AbstractMinecartEntity minecart, PlayerEntity player, MinecartController controller) {
|
||||||
|
World world = event.getWorld();
|
||||||
|
if (controller.isFullyCoupled()) {
|
||||||
|
if (!world.isRemote)
|
||||||
|
CouplingHandler.status(player, "two_couplings_max");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (world != null && world.isRemote)
|
||||||
|
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> cartClicked(player, minecart));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean onWrenchInteractOnMinecart(EntityInteract event, AbstractMinecartEntity minecart,
|
||||||
|
PlayerEntity player, MinecartController controller) {
|
||||||
|
int couplings = (controller.isConnectedToCoupling() ? 1 : 0) + (controller.isLeadingCoupling() ? 1 : 0);
|
||||||
|
if (couplings == 0)
|
||||||
|
return false;
|
||||||
|
if (event.getWorld().isRemote)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
CouplingHandler.status(player, "removed");
|
||||||
|
controller.decouple();
|
||||||
|
if (!player.isCreative())
|
||||||
|
player.inventory.placeItemBackInInventory(event.getWorld(),
|
||||||
|
new ItemStack(AllItems.MINECART_COUPLING.get(), couplings));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
@OnlyIn(Dist.CLIENT)
|
||||||
private static void cartClicked(PlayerEntity player, AbstractMinecartEntity interacted) {
|
private static void cartClicked(PlayerEntity player, AbstractMinecartEntity interacted) {
|
||||||
ClientMinecartCouplingHandler.onCartClicked(player, (AbstractMinecartEntity) interacted);
|
CouplingHandlerClient.onCartClicked(player, (AbstractMinecartEntity) interacted);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
package com.simibubi.create.content.contraptions.components.structureMovement.train;
|
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
|
||||||
import net.minecraft.network.PacketBuffer;
|
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
||||||
import net.minecraftforge.fml.network.NetworkEvent.Context;
|
|
||||||
|
|
||||||
public class MinecartCouplingSyncPacket extends MinecartCouplingCreationPacket {
|
|
||||||
|
|
||||||
public MinecartCouplingSyncPacket(AbstractMinecartEntity cart1, AbstractMinecartEntity cart2) {
|
|
||||||
super(cart1, cart2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MinecartCouplingSyncPacket(PacketBuffer buffer) {
|
|
||||||
super(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
public void handle(Supplier<Context> context) {
|
|
||||||
context.get()
|
|
||||||
.enqueueWork(() -> MinecartCouplingHandler.connectCarts(null, Minecraft.getInstance().world, id1, id2));
|
|
||||||
context.get()
|
|
||||||
.setPacketHandled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -2,16 +2,15 @@ package com.simibubi.create.content.contraptions.components.structureMovement.tr
|
||||||
|
|
||||||
import static net.minecraft.entity.Entity.horizontalMag;
|
import static net.minecraft.entity.Entity.horizontalMag;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController;
|
||||||
|
|
||||||
import net.minecraft.block.AbstractRailBlock;
|
import net.minecraft.block.AbstractRailBlock;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
||||||
import net.minecraft.entity.item.minecart.FurnaceMinecartEntity;
|
import net.minecraft.entity.item.minecart.FurnaceMinecartEntity;
|
||||||
import net.minecraft.state.properties.RailShape;
|
import net.minecraft.state.properties.RailShape;
|
||||||
|
@ -21,37 +20,37 @@ import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraft.util.math.vector.Vector3d;
|
import net.minecraft.util.math.vector.Vector3d;
|
||||||
import net.minecraft.util.math.vector.Vector3i;
|
import net.minecraft.util.math.vector.Vector3i;
|
||||||
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Useful methods for dealing with Minecarts
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class MinecartSim2020 {
|
public class MinecartSim2020 {
|
||||||
|
|
||||||
private static final Map<RailShape, Pair<Vector3i, Vector3i>> MATRIX =
|
private static final Map<RailShape, Pair<Vector3i, Vector3i>> MATRIX =
|
||||||
Util.make(Maps.newEnumMap(RailShape.class), (p_226574_0_) -> {
|
Util.make(Maps.newEnumMap(RailShape.class), (map) -> {
|
||||||
Vector3i vec3i = Direction.WEST.getDirectionVec();
|
Vector3i west = Direction.WEST.getDirectionVec();
|
||||||
Vector3i vec3i1 = Direction.EAST.getDirectionVec();
|
Vector3i east = Direction.EAST.getDirectionVec();
|
||||||
Vector3i vec3i2 = Direction.NORTH.getDirectionVec();
|
Vector3i north = Direction.NORTH.getDirectionVec();
|
||||||
Vector3i vec3i3 = Direction.SOUTH.getDirectionVec();
|
Vector3i south = Direction.SOUTH.getDirectionVec();
|
||||||
Vector3i vec3i4 = vec3i.down();
|
map.put(RailShape.NORTH_SOUTH, Pair.of(north, south));
|
||||||
Vector3i vec3i5 = vec3i1.down();
|
map.put(RailShape.EAST_WEST, Pair.of(west, east));
|
||||||
Vector3i vec3i6 = vec3i2.down();
|
map.put(RailShape.ASCENDING_EAST, Pair.of(west.down(), east));
|
||||||
Vector3i vec3i7 = vec3i3.down();
|
map.put(RailShape.ASCENDING_WEST, Pair.of(west, east.down()));
|
||||||
p_226574_0_.put(RailShape.NORTH_SOUTH, Pair.of(vec3i2, vec3i3));
|
map.put(RailShape.ASCENDING_NORTH, Pair.of(north, south.down()));
|
||||||
p_226574_0_.put(RailShape.EAST_WEST, Pair.of(vec3i, vec3i1));
|
map.put(RailShape.ASCENDING_SOUTH, Pair.of(north.down(), south));
|
||||||
p_226574_0_.put(RailShape.ASCENDING_EAST, Pair.of(vec3i4, vec3i1));
|
map.put(RailShape.SOUTH_EAST, Pair.of(south, east));
|
||||||
p_226574_0_.put(RailShape.ASCENDING_WEST, Pair.of(vec3i, vec3i5));
|
map.put(RailShape.SOUTH_WEST, Pair.of(south, west));
|
||||||
p_226574_0_.put(RailShape.ASCENDING_NORTH, Pair.of(vec3i2, vec3i7));
|
map.put(RailShape.NORTH_WEST, Pair.of(north, west));
|
||||||
p_226574_0_.put(RailShape.ASCENDING_SOUTH, Pair.of(vec3i6, vec3i3));
|
map.put(RailShape.NORTH_EAST, Pair.of(north, east));
|
||||||
p_226574_0_.put(RailShape.SOUTH_EAST, Pair.of(vec3i3, vec3i1));
|
|
||||||
p_226574_0_.put(RailShape.SOUTH_WEST, Pair.of(vec3i3, vec3i));
|
|
||||||
p_226574_0_.put(RailShape.NORTH_WEST, Pair.of(vec3i2, vec3i));
|
|
||||||
p_226574_0_.put(RailShape.NORTH_EAST, Pair.of(vec3i2, vec3i1));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
public static Vector3d predictMotionOf(AbstractMinecartEntity cart) {
|
public static Vector3d predictMotionOf(AbstractMinecartEntity cart) {
|
||||||
if (cart instanceof FurnaceMinecartEntity) {
|
// if (cart instanceof FurnaceMinecartEntity) {
|
||||||
return cart.getPositionVec()
|
// return cart.getPositionVec()
|
||||||
.subtract(cart.lastTickPosX, cart.lastTickPosY, cart.lastTickPosZ);
|
// .subtract(cart.lastTickPosX, cart.lastTickPosY, cart.lastTickPosZ);
|
||||||
}
|
// }
|
||||||
return cart.getMotion().scale(1.03f);
|
return cart.getMotion().scale(1f);
|
||||||
// if (cart instanceof ContainerMinecartEntity) {
|
// if (cart instanceof ContainerMinecartEntity) {
|
||||||
// ContainerMinecartEntity containerCart = (ContainerMinecartEntity) cart;
|
// ContainerMinecartEntity containerCart = (ContainerMinecartEntity) cart;
|
||||||
// float f = 0.98F;
|
// float f = 0.98F;
|
||||||
|
@ -71,15 +70,9 @@ public class MinecartSim2020 {
|
||||||
if (c instanceof FurnaceMinecartEntity)
|
if (c instanceof FurnaceMinecartEntity)
|
||||||
return MathHelper.epsilonEquals(((FurnaceMinecartEntity) c).pushX, 0)
|
return MathHelper.epsilonEquals(((FurnaceMinecartEntity) c).pushX, 0)
|
||||||
&& MathHelper.epsilonEquals(((FurnaceMinecartEntity) c).pushZ, 0);
|
&& MathHelper.epsilonEquals(((FurnaceMinecartEntity) c).pushZ, 0);
|
||||||
List<Entity> passengers = c.getPassengers();
|
LazyOptional<MinecartController> capability = c.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY);
|
||||||
if (passengers.isEmpty())
|
if (capability.isPresent() && capability.orElse(null).isStalled())
|
||||||
return true;
|
return false;
|
||||||
for (Entity entity : passengers) {
|
|
||||||
if (entity instanceof ContraptionEntity) {
|
|
||||||
ContraptionEntity contraptionEntity = (ContraptionEntity) entity;
|
|
||||||
return !contraptionEntity.isStalled();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,4 +212,25 @@ public class MinecartSim2020 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Vector3d getRailVec(RailShape shape) {
|
||||||
|
switch (shape) {
|
||||||
|
case ASCENDING_NORTH:
|
||||||
|
case ASCENDING_SOUTH:
|
||||||
|
case NORTH_SOUTH:
|
||||||
|
return new Vector3d(0, 0, 1);
|
||||||
|
case ASCENDING_EAST:
|
||||||
|
case ASCENDING_WEST:
|
||||||
|
case EAST_WEST:
|
||||||
|
return new Vector3d(1, 0, 0);
|
||||||
|
case NORTH_EAST:
|
||||||
|
case SOUTH_WEST:
|
||||||
|
return new Vector3d(1, 0, 1).normalize();
|
||||||
|
case NORTH_WEST:
|
||||||
|
case SOUTH_EAST:
|
||||||
|
return new Vector3d(1, 0, -1).normalize();
|
||||||
|
default:
|
||||||
|
return new Vector3d(0, 1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
package com.simibubi.create.content.contraptions.components.structureMovement.train;
|
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.world.ClientWorld;
|
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.nbt.CompoundNBT;
|
|
||||||
import net.minecraft.network.PacketBuffer;
|
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
||||||
import net.minecraftforge.fml.network.NetworkEvent.Context;
|
|
||||||
|
|
||||||
public class PersistantDataPacket extends PersistantDataPacketRequest {
|
|
||||||
|
|
||||||
CompoundNBT persistentData;
|
|
||||||
|
|
||||||
public PersistantDataPacket(Entity entity) {
|
|
||||||
super(entity);
|
|
||||||
persistentData = entity.getPersistentData();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PersistantDataPacket(PacketBuffer buffer) {
|
|
||||||
super(buffer);
|
|
||||||
persistentData = buffer.readCompoundTag();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(PacketBuffer buffer) {
|
|
||||||
super.write(buffer);
|
|
||||||
buffer.writeCompoundTag(persistentData);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
public void handle(Supplier<Context> context) {
|
|
||||||
context.get()
|
|
||||||
.enqueueWork(() -> {
|
|
||||||
ClientWorld world = Minecraft.getInstance().world;
|
|
||||||
if (world == null)
|
|
||||||
return;
|
|
||||||
Entity entityByID = world.getEntityByID(entityId);
|
|
||||||
if (entityByID == null)
|
|
||||||
return;
|
|
||||||
CompoundNBT persistentData = entityByID.getPersistentData();
|
|
||||||
persistentData.merge(this.persistentData);
|
|
||||||
MinecartCouplingHandler.queueLoadedMinecart(entityByID, world);
|
|
||||||
});
|
|
||||||
context.get()
|
|
||||||
.setPacketHandled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
package com.simibubi.create.content.contraptions.components.structureMovement.train;
|
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import com.simibubi.create.foundation.networking.AllPackets;
|
|
||||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
|
||||||
import net.minecraft.network.PacketBuffer;
|
|
||||||
import net.minecraftforge.fml.network.NetworkEvent.Context;
|
|
||||||
import net.minecraftforge.fml.network.PacketDistributor;
|
|
||||||
|
|
||||||
public class PersistantDataPacketRequest extends SimplePacketBase {
|
|
||||||
|
|
||||||
int entityId;
|
|
||||||
|
|
||||||
public PersistantDataPacketRequest(Entity entity) {
|
|
||||||
entityId = entity.getEntityId();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PersistantDataPacketRequest(PacketBuffer buffer) {
|
|
||||||
entityId = buffer.readInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(PacketBuffer buffer) {
|
|
||||||
buffer.writeInt(entityId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handle(Supplier<Context> context) {
|
|
||||||
context.get()
|
|
||||||
.enqueueWork(() -> {
|
|
||||||
ServerPlayerEntity sender = context.get()
|
|
||||||
.getSender();
|
|
||||||
if (sender == null || sender.world == null)
|
|
||||||
return;
|
|
||||||
Entity entityByID = sender.world.getEntityByID(entityId);
|
|
||||||
if (entityByID == null)
|
|
||||||
return;
|
|
||||||
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> sender),
|
|
||||||
new PersistantDataPacket(entityByID));
|
|
||||||
});
|
|
||||||
context.get()
|
|
||||||
.setPacketHandled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
package com.simibubi.create.content.contraptions.components.structureMovement.train.capability;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.simibubi.create.AllItems;
|
||||||
|
import com.simibubi.create.Create;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandler;
|
||||||
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
import com.simibubi.create.foundation.utility.WorldAttached;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectLists;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.item.ItemEntity;
|
||||||
|
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.nbt.INBT;
|
||||||
|
import net.minecraft.util.Direction;
|
||||||
|
import net.minecraft.util.math.ChunkPos;
|
||||||
|
import net.minecraft.util.math.Vector3d;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.capabilities.Capability;
|
||||||
|
import net.minecraftforge.common.capabilities.CapabilityInject;
|
||||||
|
import net.minecraftforge.common.capabilities.CapabilityManager;
|
||||||
|
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
|
||||||
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
|
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||||
|
import net.minecraftforge.event.world.ChunkEvent;
|
||||||
|
|
||||||
|
public class CapabilityMinecartController implements ICapabilitySerializable<CompoundNBT> {
|
||||||
|
|
||||||
|
/* Global map of loaded carts */
|
||||||
|
|
||||||
|
public static WorldAttached<Map<UUID, MinecartController>> loadedMinecartsByUUID;
|
||||||
|
public static WorldAttached<Set<UUID>> loadedMinecartsWithCoupling;
|
||||||
|
static WorldAttached<List<AbstractMinecartEntity>> queuedAdditions;
|
||||||
|
static WorldAttached<List<UUID>> queuedUnloads;
|
||||||
|
|
||||||
|
static {
|
||||||
|
loadedMinecartsByUUID = new WorldAttached<>(HashMap::new);
|
||||||
|
loadedMinecartsWithCoupling = new WorldAttached<>(HashSet::new);
|
||||||
|
queuedAdditions = new WorldAttached<>(() -> ObjectLists.synchronize(new ObjectArrayList<>()));
|
||||||
|
queuedUnloads = new WorldAttached<>(() -> ObjectLists.synchronize(new ObjectArrayList<>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void tick(World world) {
|
||||||
|
List<UUID> toRemove = new ArrayList<>();
|
||||||
|
Map<UUID, MinecartController> carts = loadedMinecartsByUUID.get(world);
|
||||||
|
List<AbstractMinecartEntity> queued = queuedAdditions.get(world);
|
||||||
|
List<UUID> queuedRemovals = queuedUnloads.get(world);
|
||||||
|
Set<UUID> cartsWithCoupling = loadedMinecartsWithCoupling.get(world);
|
||||||
|
Set<UUID> keySet = carts.keySet();
|
||||||
|
|
||||||
|
keySet.removeAll(queuedRemovals);
|
||||||
|
cartsWithCoupling.removeAll(queuedRemovals);
|
||||||
|
|
||||||
|
for (AbstractMinecartEntity cart : queued) {
|
||||||
|
UUID uniqueID = cart.getUniqueID();
|
||||||
|
cartsWithCoupling.remove(uniqueID);
|
||||||
|
LazyOptional<MinecartController> capability = cart.getCapability(MINECART_CONTROLLER_CAPABILITY);
|
||||||
|
MinecartController controller = capability.orElse(null);
|
||||||
|
capability.addListener(cap -> onCartRemoved(world, cart));
|
||||||
|
carts.put(uniqueID, controller);
|
||||||
|
capability.ifPresent(mc -> {
|
||||||
|
if (mc.isLeadingCoupling())
|
||||||
|
cartsWithCoupling.add(uniqueID);
|
||||||
|
});
|
||||||
|
if (!world.isRemote && controller != null)
|
||||||
|
controller.sendData();
|
||||||
|
}
|
||||||
|
|
||||||
|
queuedRemovals.clear();
|
||||||
|
queued.clear();
|
||||||
|
|
||||||
|
for (Entry<UUID, MinecartController> entry : carts.entrySet()) {
|
||||||
|
MinecartController controller = entry.getValue();
|
||||||
|
if (controller != null) {
|
||||||
|
if (controller.isPresent()) {
|
||||||
|
controller.tick();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
toRemove.add(entry.getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
cartsWithCoupling.removeAll(toRemove);
|
||||||
|
keySet.removeAll(toRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void onChunkUnloaded(ChunkEvent.Unload event) {
|
||||||
|
ChunkPos chunkPos = event.getChunk()
|
||||||
|
.getPos();
|
||||||
|
Map<UUID, MinecartController> carts = loadedMinecartsByUUID.get(event.getWorld());
|
||||||
|
for (MinecartController minecartController : carts.values()) {
|
||||||
|
if (!minecartController.isPresent())
|
||||||
|
continue;
|
||||||
|
AbstractMinecartEntity cart = minecartController.cart();
|
||||||
|
if (cart.chunkCoordX == chunkPos.x && cart.chunkCoordZ == chunkPos.z)
|
||||||
|
queuedUnloads.get(event.getWorld())
|
||||||
|
.add(cart.getUniqueID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void onCartRemoved(World world, AbstractMinecartEntity entity) {
|
||||||
|
Map<UUID, MinecartController> carts = loadedMinecartsByUUID.get(world);
|
||||||
|
List<UUID> unloads = queuedUnloads.get(world);
|
||||||
|
UUID uniqueID = entity.getUniqueID();
|
||||||
|
if (!carts.containsKey(uniqueID) || unloads.contains(uniqueID))
|
||||||
|
return;
|
||||||
|
if (world.isRemote)
|
||||||
|
return;
|
||||||
|
handleKilledMinecart(world, carts.get(uniqueID), entity.getPositionVec());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void handleKilledMinecart(World world, MinecartController controller, Vector3d removedPos) {
|
||||||
|
if (controller == null)
|
||||||
|
return;
|
||||||
|
for (boolean forward : Iterate.trueAndFalse) {
|
||||||
|
MinecartController next = CouplingHandler.getNextInCouplingChain(world, controller, forward);
|
||||||
|
if (next == null || next == MinecartController.EMPTY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
next.removeConnection(!forward);
|
||||||
|
if (controller.hasContraptionCoupling(forward))
|
||||||
|
continue;
|
||||||
|
AbstractMinecartEntity cart = next.cart();
|
||||||
|
if (cart == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Vector3d itemPos = cart.getPositionVec()
|
||||||
|
.add(removedPos)
|
||||||
|
.scale(.5f);
|
||||||
|
ItemEntity itemEntity =
|
||||||
|
new ItemEntity(world, itemPos.x, itemPos.y, itemPos.z, AllItems.MINECART_COUPLING.asStack());
|
||||||
|
itemEntity.setDefaultPickupDelay();
|
||||||
|
world.addEntity(itemEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static MinecartController getIfPresent(World world, UUID cartId) {
|
||||||
|
Map<UUID, MinecartController> carts = loadedMinecartsByUUID.get(world);
|
||||||
|
if (carts == null)
|
||||||
|
return null;
|
||||||
|
if (!carts.containsKey(cartId))
|
||||||
|
return null;
|
||||||
|
return carts.get(cartId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Capability management */
|
||||||
|
|
||||||
|
@CapabilityInject(MinecartController.class)
|
||||||
|
public static Capability<MinecartController> MINECART_CONTROLLER_CAPABILITY = null;
|
||||||
|
|
||||||
|
public static void attach(AttachCapabilitiesEvent<Entity> event) {
|
||||||
|
Entity entity = event.getObject();
|
||||||
|
if (!(entity instanceof AbstractMinecartEntity))
|
||||||
|
return;
|
||||||
|
event.addCapability(Create.asResource("minecart_controller"),
|
||||||
|
new CapabilityMinecartController((AbstractMinecartEntity) entity));
|
||||||
|
queuedAdditions.get(entity.getEntityWorld())
|
||||||
|
.add((AbstractMinecartEntity) entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register() {
|
||||||
|
CapabilityManager.INSTANCE.register(MinecartController.class, new Capability.IStorage<MinecartController>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public INBT writeNBT(Capability<MinecartController> capability, MinecartController instance,
|
||||||
|
Direction side) {
|
||||||
|
return instance.serializeNBT();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readNBT(Capability<MinecartController> capability, MinecartController instance, Direction side,
|
||||||
|
INBT base) {
|
||||||
|
instance.deserializeNBT((CompoundNBT) base);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, MinecartController::empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Capability provider */
|
||||||
|
|
||||||
|
private final LazyOptional<MinecartController> cap;
|
||||||
|
private MinecartController handler;
|
||||||
|
|
||||||
|
public CapabilityMinecartController(AbstractMinecartEntity minecart) {
|
||||||
|
handler = new MinecartController(minecart);
|
||||||
|
cap = LazyOptional.of(() -> handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) {
|
||||||
|
if (cap == MINECART_CONTROLLER_CAPABILITY)
|
||||||
|
return this.cap.cast();
|
||||||
|
return LazyOptional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundNBT serializeNBT() {
|
||||||
|
return handler.serializeNBT();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deserializeNBT(CompoundNBT nbt) {
|
||||||
|
handler.deserializeNBT(nbt);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,392 @@
|
||||||
|
package com.simibubi.create.content.contraptions.components.structureMovement.train.capability;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||||
|
|
||||||
|
import com.simibubi.create.Create;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandler;
|
||||||
|
import com.simibubi.create.foundation.networking.AllPackets;
|
||||||
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
|
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.nbt.NBTUtil;
|
||||||
|
import net.minecraft.util.math.Vector3d;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.util.Constants.NBT;
|
||||||
|
import net.minecraftforge.common.util.INBTSerializable;
|
||||||
|
import net.minecraftforge.fml.network.PacketDistributor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extended code for Minecarts, this allows for handling stalled carts and
|
||||||
|
* coupled trains
|
||||||
|
*/
|
||||||
|
public class MinecartController implements INBTSerializable<CompoundNBT> {
|
||||||
|
|
||||||
|
public static MinecartController EMPTY;
|
||||||
|
private boolean needsEntryRefresh;
|
||||||
|
private WeakReference<AbstractMinecartEntity> weakRef;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stall information, <Internal (waiting couplings), External (stalled
|
||||||
|
* contraptions)>
|
||||||
|
*/
|
||||||
|
private Couple<Optional<StallData>> stallData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Coupling information, <Main (helmed by this cart), Connected (handled by
|
||||||
|
* other cart)>
|
||||||
|
*/
|
||||||
|
private Couple<Optional<CouplingData>> couplings;
|
||||||
|
|
||||||
|
public MinecartController(AbstractMinecartEntity minecart) {
|
||||||
|
weakRef = new WeakReference<>(minecart);
|
||||||
|
stallData = Couple.create(Optional::empty);
|
||||||
|
couplings = Couple.create(Optional::empty);
|
||||||
|
needsEntryRefresh = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
AbstractMinecartEntity cart = cart();
|
||||||
|
World world = getWorld();
|
||||||
|
|
||||||
|
if (needsEntryRefresh) {
|
||||||
|
List<AbstractMinecartEntity> list = CapabilityMinecartController.queuedAdditions.get(world);
|
||||||
|
if (list != null)
|
||||||
|
list.add(cart);
|
||||||
|
}
|
||||||
|
|
||||||
|
stallData.forEach(opt -> opt.ifPresent(sd -> sd.tick(cart)));
|
||||||
|
|
||||||
|
MutableBoolean internalStall = new MutableBoolean(false);
|
||||||
|
couplings.forEachWithContext((opt, main) -> opt.ifPresent(cd -> {
|
||||||
|
|
||||||
|
UUID idOfOther = cd.idOfCart(!main);
|
||||||
|
MinecartController otherCart = CapabilityMinecartController.getIfPresent(world, idOfOther);
|
||||||
|
internalStall.setValue(
|
||||||
|
internalStall.booleanValue() || otherCart == null || !otherCart.isPresent() || otherCart.isStalled(false));
|
||||||
|
|
||||||
|
}));
|
||||||
|
if (!world.isRemote)
|
||||||
|
setStalled(internalStall.booleanValue(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFullyCoupled() {
|
||||||
|
return isLeadingCoupling() && isConnectedToCoupling();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLeadingCoupling() {
|
||||||
|
return couplings.get(true)
|
||||||
|
.isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnectedToCoupling() {
|
||||||
|
return couplings.get(false)
|
||||||
|
.isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCoupledThroughContraption() {
|
||||||
|
for (boolean current : Iterate.trueAndFalse)
|
||||||
|
if (hasContraptionCoupling(current))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasContraptionCoupling(boolean current) {
|
||||||
|
Optional<CouplingData> optional = couplings.get(current);
|
||||||
|
return optional.isPresent() && optional.get().contraption;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getCouplingLength(boolean leading) {
|
||||||
|
Optional<CouplingData> optional = couplings.get(leading);
|
||||||
|
if (optional.isPresent())
|
||||||
|
return optional.get().length;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decouple() {
|
||||||
|
couplings.forEachWithContext((opt, main) -> opt.ifPresent(cd -> {
|
||||||
|
UUID idOfOther = cd.idOfCart(!main);
|
||||||
|
MinecartController otherCart = CapabilityMinecartController.getIfPresent(getWorld(), idOfOther);
|
||||||
|
if (otherCart == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
removeConnection(main);
|
||||||
|
otherCart.removeConnection(!main);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeConnection(boolean main) {
|
||||||
|
if (hasContraptionCoupling(main) && !getWorld().isRemote) {
|
||||||
|
List<Entity> passengers = cart().getPassengers();
|
||||||
|
if (!passengers.isEmpty()) {
|
||||||
|
Entity entity = passengers.get(0);
|
||||||
|
if (entity instanceof ContraptionEntity)
|
||||||
|
((ContraptionEntity) entity).disassemble();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
couplings.set(main, Optional.empty());
|
||||||
|
needsEntryRefresh |= main;
|
||||||
|
sendData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void prepareForCoupling(boolean isLeading) {
|
||||||
|
// reverse existing chain if necessary
|
||||||
|
if (isLeading && isLeadingCoupling() || !isLeading && isConnectedToCoupling()) {
|
||||||
|
|
||||||
|
List<MinecartController> cartsToFlip = new ArrayList<>();
|
||||||
|
MinecartController current = this;
|
||||||
|
boolean forward = current.isLeadingCoupling();
|
||||||
|
int safetyCount = 1000;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (safetyCount-- <= 0) {
|
||||||
|
Create.logger.warn("Infinite loop in coupling iteration");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cartsToFlip.add(current);
|
||||||
|
current = CouplingHandler.getNextInCouplingChain(getWorld(), current, forward);
|
||||||
|
if (current == null || current == MinecartController.EMPTY)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (MinecartController minecartController : cartsToFlip) {
|
||||||
|
MinecartController mc = minecartController;
|
||||||
|
mc.couplings.forEachWithContext((opt, leading) -> opt.ifPresent(cd -> {
|
||||||
|
cd.flip();
|
||||||
|
if (!cd.contraption)
|
||||||
|
return;
|
||||||
|
List<Entity> passengers = mc.cart()
|
||||||
|
.getPassengers();
|
||||||
|
if (passengers.isEmpty())
|
||||||
|
return;
|
||||||
|
Entity entity = passengers.get(0);
|
||||||
|
if (!(entity instanceof ContraptionEntity))
|
||||||
|
return;
|
||||||
|
ContraptionEntity contraption = (ContraptionEntity) entity;
|
||||||
|
UUID couplingId = contraption.getCouplingId();
|
||||||
|
if (couplingId == cd.mainCartID) {
|
||||||
|
contraption.setCouplingId(cd.connectedCartID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (couplingId == cd.connectedCartID) {
|
||||||
|
contraption.setCouplingId(cd.mainCartID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
mc.couplings = mc.couplings.swap();
|
||||||
|
if (mc == this)
|
||||||
|
continue;
|
||||||
|
mc.needsEntryRefresh = true;
|
||||||
|
mc.sendData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void coupleWith(boolean isLeading, UUID coupled, float length, boolean contraption) {
|
||||||
|
UUID mainID = isLeading ? cart().getUniqueID() : coupled;
|
||||||
|
UUID connectedID = isLeading ? coupled : cart().getUniqueID();
|
||||||
|
couplings.set(isLeading, Optional.of(new CouplingData(mainID, connectedID, length, contraption)));
|
||||||
|
needsEntryRefresh |= isLeading;
|
||||||
|
sendData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public UUID getCoupledCart(boolean asMain) {
|
||||||
|
Optional<CouplingData> optional = couplings.get(asMain);
|
||||||
|
if (!optional.isPresent())
|
||||||
|
return null;
|
||||||
|
CouplingData couplingData = optional.get();
|
||||||
|
return asMain ? couplingData.connectedCartID : couplingData.mainCartID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStalled() {
|
||||||
|
return isStalled(true) || isStalled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isStalled(boolean internal) {
|
||||||
|
return stallData.get(internal)
|
||||||
|
.isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStalledExternally(boolean stall) {
|
||||||
|
setStalled(stall, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setStalled(boolean stall, boolean internal) {
|
||||||
|
if (isStalled(internal) == stall)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AbstractMinecartEntity cart = cart();
|
||||||
|
if (stall) {
|
||||||
|
stallData.set(internal, Optional.of(new StallData(cart)));
|
||||||
|
sendData();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isStalled(!internal))
|
||||||
|
stallData.get(internal)
|
||||||
|
.get()
|
||||||
|
.release(cart);
|
||||||
|
stallData.set(internal, Optional.empty());
|
||||||
|
|
||||||
|
sendData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendData() {
|
||||||
|
if (getWorld().isRemote)
|
||||||
|
return;
|
||||||
|
AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(this::cart),
|
||||||
|
new MinecartControllerUpdatePacket(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundNBT serializeNBT() {
|
||||||
|
CompoundNBT compoundNBT = new CompoundNBT();
|
||||||
|
|
||||||
|
stallData.forEachWithContext((opt, internal) -> opt
|
||||||
|
.ifPresent(sd -> compoundNBT.put(internal ? "InternalStallData" : "StallData", sd.serialize())));
|
||||||
|
couplings.forEachWithContext((opt, main) -> opt
|
||||||
|
.ifPresent(cd -> compoundNBT.put(main ? "MainCoupling" : "ConnectedCoupling", cd.serialize())));
|
||||||
|
|
||||||
|
return compoundNBT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deserializeNBT(CompoundNBT nbt) {
|
||||||
|
Optional<StallData> internalSD = Optional.empty();
|
||||||
|
Optional<StallData> externalSD = Optional.empty();
|
||||||
|
Optional<CouplingData> mainCD = Optional.empty();
|
||||||
|
Optional<CouplingData> connectedCD = Optional.empty();
|
||||||
|
|
||||||
|
if (nbt.contains("InternalStallData"))
|
||||||
|
internalSD = Optional.of(StallData.read(nbt.getCompound("InternalStallData")));
|
||||||
|
if (nbt.contains("StallData"))
|
||||||
|
externalSD = Optional.of(StallData.read(nbt.getCompound("StallData")));
|
||||||
|
if (nbt.contains("MainCoupling"))
|
||||||
|
mainCD = Optional.of(CouplingData.read(nbt.getCompound("MainCoupling")));
|
||||||
|
if (nbt.contains("ConnectedCoupling"))
|
||||||
|
connectedCD = Optional.of(CouplingData.read(nbt.getCompound("ConnectedCoupling")));
|
||||||
|
|
||||||
|
stallData = Couple.create(internalSD, externalSD);
|
||||||
|
couplings = Couple.create(mainCD, connectedCD);
|
||||||
|
needsEntryRefresh = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPresent() {
|
||||||
|
return weakRef.get() != null && cart().isAlive();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractMinecartEntity cart() {
|
||||||
|
return weakRef.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MinecartController empty() {
|
||||||
|
return EMPTY != null ? EMPTY : (EMPTY = new MinecartController(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
private World getWorld() {
|
||||||
|
return cart().getEntityWorld();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CouplingData {
|
||||||
|
|
||||||
|
private UUID mainCartID;
|
||||||
|
private UUID connectedCartID;
|
||||||
|
private float length;
|
||||||
|
private boolean contraption;
|
||||||
|
|
||||||
|
public CouplingData(UUID mainCartID, UUID connectedCartID, float length, boolean contraption) {
|
||||||
|
this.mainCartID = mainCartID;
|
||||||
|
this.connectedCartID = connectedCartID;
|
||||||
|
this.length = length;
|
||||||
|
this.contraption = contraption;
|
||||||
|
}
|
||||||
|
|
||||||
|
void flip() {
|
||||||
|
UUID swap = mainCartID;
|
||||||
|
mainCartID = connectedCartID;
|
||||||
|
connectedCartID = swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompoundNBT serialize() {
|
||||||
|
CompoundNBT nbt = new CompoundNBT();
|
||||||
|
nbt.put("Main", NBTUtil.writeUniqueId(mainCartID));
|
||||||
|
nbt.put("Connected", NBTUtil.writeUniqueId(connectedCartID));
|
||||||
|
nbt.putFloat("Length", length);
|
||||||
|
nbt.putBoolean("Contraption", contraption);
|
||||||
|
return nbt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CouplingData read(CompoundNBT nbt) {
|
||||||
|
UUID mainCartID = NBTUtil.readUniqueId(nbt.getCompound("Main"));
|
||||||
|
UUID connectedCartID = NBTUtil.readUniqueId(nbt.getCompound("Connected"));
|
||||||
|
float length = nbt.getFloat("Length");
|
||||||
|
boolean contraption = nbt.getBoolean("Contraption");
|
||||||
|
return new CouplingData(mainCartID, connectedCartID, length, contraption);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID idOfCart(boolean main) {
|
||||||
|
return main ? mainCartID : connectedCartID;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class StallData {
|
||||||
|
Vector3d position;
|
||||||
|
Vector3d motion;
|
||||||
|
float yaw, pitch;
|
||||||
|
|
||||||
|
private StallData() {}
|
||||||
|
|
||||||
|
StallData(AbstractMinecartEntity entity) {
|
||||||
|
position = entity.getPositionVec();
|
||||||
|
motion = entity.getMotion();
|
||||||
|
yaw = entity.rotationYaw;
|
||||||
|
pitch = entity.rotationPitch;
|
||||||
|
tick(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tick(AbstractMinecartEntity entity) {
|
||||||
|
entity.setPosition(position.x, position.y, position.z);
|
||||||
|
entity.setMotion(Vector3d.ZERO);
|
||||||
|
entity.rotationYaw = yaw;
|
||||||
|
entity.rotationPitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void release(AbstractMinecartEntity entity) {
|
||||||
|
entity.setMotion(motion);
|
||||||
|
}
|
||||||
|
|
||||||
|
CompoundNBT serialize() {
|
||||||
|
CompoundNBT nbt = new CompoundNBT();
|
||||||
|
nbt.put("Pos", VecHelper.writeNBT(position));
|
||||||
|
nbt.put("Motion", VecHelper.writeNBT(motion));
|
||||||
|
nbt.putFloat("Yaw", yaw);
|
||||||
|
nbt.putFloat("Pitch", pitch);
|
||||||
|
return nbt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static StallData read(CompoundNBT nbt) {
|
||||||
|
StallData stallData = new StallData();
|
||||||
|
stallData.position = VecHelper.readNBT(nbt.getList("Pos", NBT.TAG_DOUBLE));
|
||||||
|
stallData.motion = VecHelper.readNBT(nbt.getList("Motion", NBT.TAG_DOUBLE));
|
||||||
|
stallData.yaw = nbt.getFloat("Yaw");
|
||||||
|
stallData.pitch = nbt.getFloat("Pitch");
|
||||||
|
return stallData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package com.simibubi.create.content.contraptions.components.structureMovement.train.capability;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.world.ClientWorld;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.network.PacketBuffer;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.fml.DistExecutor;
|
||||||
|
import net.minecraftforge.fml.network.NetworkEvent.Context;
|
||||||
|
|
||||||
|
public class MinecartControllerUpdatePacket extends SimplePacketBase {
|
||||||
|
|
||||||
|
int entityID;
|
||||||
|
CompoundNBT nbt;
|
||||||
|
|
||||||
|
public MinecartControllerUpdatePacket(MinecartController controller) {
|
||||||
|
entityID = controller.cart()
|
||||||
|
.getEntityId();
|
||||||
|
nbt = controller.serializeNBT();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MinecartControllerUpdatePacket(PacketBuffer buffer) {
|
||||||
|
entityID = buffer.readInt();
|
||||||
|
nbt = buffer.readCompoundTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(PacketBuffer buffer) {
|
||||||
|
buffer.writeInt(entityID);
|
||||||
|
buffer.writeCompoundTag(nbt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(Supplier<Context> context) {
|
||||||
|
context.get()
|
||||||
|
.enqueueWork(() -> DistExecutor.runWhenOn(Dist.CLIENT, () -> this::handleCL));
|
||||||
|
context.get()
|
||||||
|
.setPacketHandled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
private void handleCL() {
|
||||||
|
ClientWorld world = Minecraft.getInstance().world;
|
||||||
|
if (world == null)
|
||||||
|
return;
|
||||||
|
Entity entityByID = world.getEntityByID(entityID);
|
||||||
|
if (entityByID == null)
|
||||||
|
return;
|
||||||
|
entityByID.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY)
|
||||||
|
.ifPresent(mc -> mc.deserializeNBT(nbt));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ import java.util.Map;
|
||||||
|
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
|
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
|
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
|
||||||
|
|
||||||
import net.minecraft.entity.item.ItemEntity;
|
import net.minecraft.entity.item.ItemEntity;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
@ -31,7 +30,7 @@ public class BasinMovementBehaviour extends MovementBehaviour {
|
||||||
public void tick(MovementContext context) {
|
public void tick(MovementContext context) {
|
||||||
super.tick(context);
|
super.tick(context);
|
||||||
if (context.temporaryData == null || (boolean) context.temporaryData) {
|
if (context.temporaryData == null || (boolean) context.temporaryData) {
|
||||||
Vector3d facingVec = VecHelper.rotate(Vector3d.of(Direction.UP.getDirectionVec()), context.rotation.x, context.rotation.y, context.rotation.z);
|
Vector3d facingVec = context.rotation.apply(Vector3d.of(Direction.UP.getDirectionVec()));
|
||||||
facingVec.normalize();
|
facingVec.normalize();
|
||||||
if (Direction.getFacingFromVector(facingVec.x, facingVec.y, facingVec.z) == Direction.DOWN)
|
if (Direction.getFacingFromVector(facingVec.x, facingVec.y, facingVec.z) == Direction.DOWN)
|
||||||
dump(context, facingVec);
|
dump(context, facingVec);
|
||||||
|
@ -41,16 +40,21 @@ public class BasinMovementBehaviour extends MovementBehaviour {
|
||||||
private void dump(MovementContext context, Vector3d facingVec) {
|
private void dump(MovementContext context, Vector3d facingVec) {
|
||||||
getOrReadInventory(context).forEach((key, itemStackHandler) -> {
|
getOrReadInventory(context).forEach((key, itemStackHandler) -> {
|
||||||
for (int i = 0; i < itemStackHandler.getSlots(); i++) {
|
for (int i = 0; i < itemStackHandler.getSlots(); i++) {
|
||||||
if (itemStackHandler.getStackInSlot(i).isEmpty())
|
if (itemStackHandler.getStackInSlot(i)
|
||||||
|
.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
ItemEntity itemEntity = new ItemEntity(context.world, context.position.x, context.position.y, context.position.z, itemStackHandler.getStackInSlot(i));
|
ItemEntity itemEntity = new ItemEntity(context.world, context.position.x, context.position.y,
|
||||||
|
context.position.z, itemStackHandler.getStackInSlot(i));
|
||||||
itemEntity.setMotion(facingVec.scale(.05));
|
itemEntity.setMotion(facingVec.scale(.05));
|
||||||
context.world.addEntity(itemEntity);
|
context.world.addEntity(itemEntity);
|
||||||
itemStackHandler.setStackInSlot(i, ItemStack.EMPTY);
|
itemStackHandler.setStackInSlot(i, ItemStack.EMPTY);
|
||||||
}
|
}
|
||||||
context.tileData.put(key, itemStackHandler.serializeNBT());
|
context.tileData.put(key, itemStackHandler.serializeNBT());
|
||||||
});
|
});
|
||||||
context.contraption.customRenderTEs.stream().filter(te -> te.getPos().equals(context.localPos) && te instanceof BasinTileEntity).forEach(te -> ((BasinTileEntity) te).readOnlyItems(context.tileData));
|
context.contraption.customRenderTEs.stream()
|
||||||
|
.filter(te -> te.getPos()
|
||||||
|
.equals(context.localPos) && te instanceof BasinTileEntity)
|
||||||
|
.forEach(te -> ((BasinTileEntity) te).readOnlyItems(context.tileData));
|
||||||
context.temporaryData = false; // did already dump, so can't any more
|
context.temporaryData = false; // did already dump, so can't any more
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,18 @@ package com.simibubi.create.content.contraptions.wrench;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import com.simibubi.create.AllItems;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.item.ItemUseContext;
|
import net.minecraft.item.ItemUseContext;
|
||||||
import net.minecraft.util.ActionResultType;
|
import net.minecraft.util.ActionResultType;
|
||||||
|
import net.minecraft.util.DamageSource;
|
||||||
|
import net.minecraftforge.event.entity.player.AttackEntityEvent;
|
||||||
|
|
||||||
public class WrenchItem extends Item {
|
public class WrenchItem extends Item {
|
||||||
|
|
||||||
|
@ -31,4 +38,19 @@ public class WrenchItem extends Item {
|
||||||
return actor.onSneakWrenched(state, context);
|
return actor.onSneakWrenched(state, context);
|
||||||
return actor.onWrenched(state, context);
|
return actor.onWrenched(state, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void wrenchInstaKillsMinecarts(AttackEntityEvent event) {
|
||||||
|
Entity target = event.getTarget();
|
||||||
|
if (!(target instanceof AbstractMinecartEntity))
|
||||||
|
return;
|
||||||
|
PlayerEntity player = event.getPlayer();
|
||||||
|
ItemStack heldItem = player.getHeldItemMainhand();
|
||||||
|
if (!AllItems.WRENCH.isIn(heldItem))
|
||||||
|
return;
|
||||||
|
if (player.isCreative())
|
||||||
|
return;
|
||||||
|
AbstractMinecartEntity minecart = (AbstractMinecartEntity) target;
|
||||||
|
minecart.attackEntityFrom(DamageSource.causePlayerDamage(player), 100);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import java.util.Random;
|
||||||
import com.simibubi.create.AllItems;
|
import com.simibubi.create.AllItems;
|
||||||
import com.simibubi.create.foundation.advancement.AllTriggers;
|
import com.simibubi.create.foundation.advancement.AllTriggers;
|
||||||
import com.simibubi.create.foundation.config.AllConfigs;
|
import com.simibubi.create.foundation.config.AllConfigs;
|
||||||
import com.simibubi.create.foundation.config.CCuriosities;
|
import com.simibubi.create.foundation.config.CRecipes;
|
||||||
import com.simibubi.create.foundation.utility.ColorHelper;
|
import com.simibubi.create.foundation.utility.ColorHelper;
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ public class ChromaticCompoundItem extends Item {
|
||||||
public double getDurabilityForDisplay(ItemStack stack) {
|
public double getDurabilityForDisplay(ItemStack stack) {
|
||||||
int light = stack.getOrCreateTag()
|
int light = stack.getOrCreateTag()
|
||||||
.getInt("CollectingLight");
|
.getInt("CollectingLight");
|
||||||
return 1 - light / (float) AllConfigs.SERVER.curiosities.lightSourceCountForRefinedRadiance.get();
|
return 1 - light / (float) AllConfigs.SERVER.recipes.lightSourceCountForRefinedRadiance.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -76,7 +76,7 @@ public class ChromaticCompoundItem extends Item {
|
||||||
.getOrCreateTag();
|
.getOrCreateTag();
|
||||||
|
|
||||||
Vector3d positionVec = entity.getPositionVec();
|
Vector3d positionVec = entity.getPositionVec();
|
||||||
CCuriosities config = AllConfigs.SERVER.curiosities;
|
CRecipes config = AllConfigs.SERVER.recipes;
|
||||||
if (world.isRemote) {
|
if (world.isRemote) {
|
||||||
int light = itemData.getInt("CollectingLight");
|
int light = itemData.getInt("CollectingLight");
|
||||||
if (random.nextInt(config.lightSourceCountForRefinedRadiance.get() + 20) < light) {
|
if (random.nextInt(config.lightSourceCountForRefinedRadiance.get() + 20) < light) {
|
||||||
|
|
|
@ -4,8 +4,6 @@ import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.simibubi.create.foundation.config.AllConfigs;
|
|
||||||
|
|
||||||
import net.minecraft.tileentity.TileEntity;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
@ -30,8 +28,8 @@ public class ZapperLog {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void record(World world, List<BlockPos> positions) {
|
public void record(World world, List<BlockPos> positions) {
|
||||||
if (maxLogLength() == 0)
|
// if (maxLogLength() == 0)
|
||||||
return;
|
// return;
|
||||||
if (world != activeWorld)
|
if (world != activeWorld)
|
||||||
log.clear();
|
log.clear();
|
||||||
activeWorld = world;
|
activeWorld = world;
|
||||||
|
@ -44,13 +42,13 @@ public class ZapperLog {
|
||||||
log.add(0, blocks);
|
log.add(0, blocks);
|
||||||
// redoIndex = 0;
|
// redoIndex = 0;
|
||||||
|
|
||||||
if (maxLogLength() < log.size())
|
// if (maxLogLength() < log.size())
|
||||||
log.remove(log.size() - 1);
|
// log.remove(log.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Integer maxLogLength() {
|
// protected Integer maxLogLength() {
|
||||||
return AllConfigs.SERVER.curiosities.zapperUndoLogLength.get();
|
// return AllConfigs.SERVER.curiosities.zapperUndoLogLength.get();
|
||||||
}
|
// }
|
||||||
|
|
||||||
public void undo() {
|
public void undo() {
|
||||||
|
|
||||||
|
|
|
@ -322,8 +322,4 @@ public class InWorldProcessing {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isFrozen() {
|
|
||||||
return AllConfigs.SERVER.control.freezeInWorldProcessing.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package com.simibubi.create.content.logistics.block.redstone;
|
||||||
import com.simibubi.create.AllBlocks;
|
import com.simibubi.create.AllBlocks;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
|
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
|
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.nbt.NBTUtil;
|
import net.minecraft.nbt.NBTUtil;
|
||||||
|
@ -36,7 +35,7 @@ public class ContactMovementBehaviour extends MovementBehaviour {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Vector3d contact = Vector3d.of(block.get(RedstoneContactBlock.FACING).getDirectionVec());
|
Vector3d contact = Vector3d.of(block.get(RedstoneContactBlock.FACING).getDirectionVec());
|
||||||
contact = VecHelper.rotate(contact, context.rotation.x, context.rotation.y, context.rotation.z);
|
contact = context.rotation.apply(contact);
|
||||||
Direction direction = Direction.getFacingFromVector(contact.x, contact.y, contact.z);
|
Direction direction = Direction.getFacingFromVector(contact.x, contact.y, contact.z);
|
||||||
|
|
||||||
if (!RedstoneContactBlock.hasValidContact(world, pos.offset(direction.getOpposite()), direction))
|
if (!RedstoneContactBlock.hasValidContact(world, pos.offset(direction.getOpposite()), direction))
|
||||||
|
|
|
@ -29,6 +29,7 @@ import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraft.util.text.ITextComponent;
|
import net.minecraft.util.text.ITextComponent;
|
||||||
import net.minecraft.util.text.StringTextComponent;
|
import net.minecraft.util.text.StringTextComponent;
|
||||||
|
|
||||||
|
|
||||||
public class SchematicTableScreen extends AbstractSimiContainerScreen<SchematicTableContainer>
|
public class SchematicTableScreen extends AbstractSimiContainerScreen<SchematicTableContainer>
|
||||||
implements IHasContainer<SchematicTableContainer> {
|
implements IHasContainer<SchematicTableContainer> {
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
package com.simibubi.create.content.schematics.block;
|
package com.simibubi.create.content.schematics.block;
|
||||||
|
|
||||||
|
import static net.minecraft.util.text.TextFormatting.GRAY;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
import com.simibubi.create.AllBlocks;
|
import com.simibubi.create.AllBlocks;
|
||||||
|
@ -26,13 +33,7 @@ import net.minecraft.util.text.StringTextComponent;
|
||||||
import net.minecraft.util.text.TextFormatting;
|
import net.minecraft.util.text.TextFormatting;
|
||||||
import net.minecraft.util.text.TranslationTextComponent;
|
import net.minecraft.util.text.TranslationTextComponent;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
import static net.minecraft.util.text.TextFormatting.*;
|
import static net.minecraft.util.text.TextFormatting.*;
|
||||||
|
|
||||||
public class SchematicannonScreen extends AbstractSimiContainerScreen<SchematicannonContainer> {
|
public class SchematicannonScreen extends AbstractSimiContainerScreen<SchematicannonContainer> {
|
||||||
|
|
||||||
private static final AllGuiTextures BG_BOTTOM = AllGuiTextures.SCHEMATICANNON_BOTTOM;
|
private static final AllGuiTextures BG_BOTTOM = AllGuiTextures.SCHEMATICANNON_BOTTOM;
|
||||||
|
|
|
@ -7,10 +7,12 @@ import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
import com.simibubi.create.Create;
|
import com.simibubi.create.Create;
|
||||||
import com.simibubi.create.CreateClient;
|
import com.simibubi.create.CreateClient;
|
||||||
import com.simibubi.create.content.contraptions.KineticDebugger;
|
import com.simibubi.create.content.contraptions.KineticDebugger;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionCollider;
|
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandler;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisRangeDisplay;
|
import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisRangeDisplay;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.ClientMinecartCouplingHandler;
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandlerClient;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCouplingHandler;
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingPhysics;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingRenderer;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController;
|
||||||
import com.simibubi.create.content.contraptions.components.turntable.TurntableHandler;
|
import com.simibubi.create.content.contraptions.components.turntable.TurntableHandler;
|
||||||
import com.simibubi.create.content.contraptions.relays.belt.item.BeltConnectorHandler;
|
import com.simibubi.create.content.contraptions.relays.belt.item.BeltConnectorHandler;
|
||||||
import com.simibubi.create.content.curiosities.tools.ExtendoGripRenderHandler;
|
import com.simibubi.create.content.curiosities.tools.ExtendoGripRenderHandler;
|
||||||
|
@ -80,8 +82,10 @@ public class ClientEvents {
|
||||||
CreateClient.schematicAndQuillHandler.tick();
|
CreateClient.schematicAndQuillHandler.tick();
|
||||||
CreateClient.schematicHandler.tick();
|
CreateClient.schematicHandler.tick();
|
||||||
|
|
||||||
ContraptionCollider.runCollisions(world);
|
ContraptionHandler.tick(world);
|
||||||
MinecartCouplingHandler.tick(world);
|
CapabilityMinecartController.tick(world);
|
||||||
|
CouplingPhysics.tick(world);
|
||||||
|
|
||||||
ScreenOpener.tick();
|
ScreenOpener.tick();
|
||||||
ServerSpeedProvider.clientTick();
|
ServerSpeedProvider.clientTick();
|
||||||
BeltConnectorHandler.tick();
|
BeltConnectorHandler.tick();
|
||||||
|
@ -92,7 +96,8 @@ public class ClientEvents {
|
||||||
EdgeInteractionRenderer.tick();
|
EdgeInteractionRenderer.tick();
|
||||||
WorldshaperRenderHandler.tick();
|
WorldshaperRenderHandler.tick();
|
||||||
BlockzapperRenderHandler.tick();
|
BlockzapperRenderHandler.tick();
|
||||||
ClientMinecartCouplingHandler.tick();
|
CouplingHandlerClient.tick();
|
||||||
|
CouplingRenderer.tickDebugModeRenders();
|
||||||
KineticDebugger.tick();
|
KineticDebugger.tick();
|
||||||
ZapperRenderHandler.tick();
|
ZapperRenderHandler.tick();
|
||||||
ExtendoGripRenderHandler.tick();
|
ExtendoGripRenderHandler.tick();
|
||||||
|
@ -115,7 +120,7 @@ public class ClientEvents {
|
||||||
ms.translate(-view.getX(), -view.getY(), -view.getZ());
|
ms.translate(-view.getX(), -view.getY(), -view.getZ());
|
||||||
SuperRenderTypeBuffer buffer = SuperRenderTypeBuffer.getInstance();
|
SuperRenderTypeBuffer buffer = SuperRenderTypeBuffer.getInstance();
|
||||||
|
|
||||||
MinecartCouplingHandler.render(ms, buffer);
|
CouplingRenderer.renderAll(ms, buffer);
|
||||||
CreateClient.schematicHandler.render(ms, buffer);
|
CreateClient.schematicHandler.render(ms, buffer);
|
||||||
CreateClient.outliner.renderOutlines(ms, buffer);
|
CreateClient.outliner.renderOutlines(ms, buffer);
|
||||||
// CollisionDebugger.render(ms, buffer);
|
// CollisionDebugger.render(ms, buffer);
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package com.simibubi.create.events;
|
package com.simibubi.create.events;
|
||||||
|
|
||||||
import com.simibubi.create.Create;
|
import com.simibubi.create.Create;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionCollider;
|
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandler;
|
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandler;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCouplingHandler;
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingPhysics;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController;
|
||||||
|
import com.simibubi.create.content.contraptions.wrench.WrenchItem;
|
||||||
import com.simibubi.create.content.schematics.ServerSchematicLoader;
|
import com.simibubi.create.content.schematics.ServerSchematicLoader;
|
||||||
import com.simibubi.create.foundation.command.AllCommands;
|
import com.simibubi.create.foundation.command.AllCommands;
|
||||||
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
|
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
|
||||||
|
@ -16,11 +17,14 @@ import net.minecraft.resources.IReloadableResourceManager;
|
||||||
import net.minecraft.resources.IResourceManager;
|
import net.minecraft.resources.IResourceManager;
|
||||||
import net.minecraft.world.IWorld;
|
import net.minecraft.world.IWorld;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||||
import net.minecraftforge.event.TickEvent.Phase;
|
import net.minecraftforge.event.TickEvent.Phase;
|
||||||
import net.minecraftforge.event.TickEvent.ServerTickEvent;
|
import net.minecraftforge.event.TickEvent.ServerTickEvent;
|
||||||
import net.minecraftforge.event.TickEvent.WorldTickEvent;
|
import net.minecraftforge.event.TickEvent.WorldTickEvent;
|
||||||
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
|
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
|
||||||
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
|
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
|
||||||
|
import net.minecraftforge.event.entity.player.AttackEntityEvent;
|
||||||
|
import net.minecraftforge.event.world.ChunkEvent;
|
||||||
import net.minecraftforge.event.world.WorldEvent;
|
import net.minecraftforge.event.world.WorldEvent;
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||||
|
@ -41,14 +45,20 @@ public class CommonEvents {
|
||||||
Create.lagger.tick();
|
Create.lagger.tick();
|
||||||
ServerSpeedProvider.serverTick();
|
ServerSpeedProvider.serverTick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void onChunkUnloaded(ChunkEvent.Unload event) {
|
||||||
|
CapabilityMinecartController.onChunkUnloaded(event);
|
||||||
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onWorldTick(WorldTickEvent event) {
|
public static void onWorldTick(WorldTickEvent event) {
|
||||||
if (event.phase == Phase.START)
|
if (event.phase == Phase.START)
|
||||||
return;
|
return;
|
||||||
World world = event.world;
|
World world = event.world;
|
||||||
ContraptionCollider.runCollisions(world);
|
ContraptionHandler.tick(world);
|
||||||
MinecartCouplingHandler.tick(world);
|
CapabilityMinecartController.tick(world);
|
||||||
|
CouplingPhysics.tick(world);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
|
@ -65,7 +75,11 @@ public class CommonEvents {
|
||||||
Entity entity = event.getEntity();
|
Entity entity = event.getEntity();
|
||||||
World world = event.getWorld();
|
World world = event.getWorld();
|
||||||
ContraptionHandler.addSpawnedContraptionsToCollisionList(entity, world);
|
ContraptionHandler.addSpawnedContraptionsToCollisionList(entity, world);
|
||||||
MinecartCouplingHandler.handleAddedMinecart(entity, world);
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void onEntityAttackedByPlayer(AttackEntityEvent event) {
|
||||||
|
WrenchItem.wrenchInstaKillsMinecarts(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
|
@ -99,5 +113,10 @@ public class CommonEvents {
|
||||||
Create.torquePropagator.onUnloadWorld(world);
|
Create.torquePropagator.onUnloadWorld(world);
|
||||||
WorldAttached.invalidateWorld(world);
|
WorldAttached.invalidateWorld(world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void attachCapabilities(AttachCapabilitiesEvent<Entity> event) {
|
||||||
|
CapabilityMinecartController.attach(event);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,7 @@ package com.simibubi.create.foundation.config;
|
||||||
public class CCuriosities extends ConfigBase {
|
public class CCuriosities extends ConfigBase {
|
||||||
|
|
||||||
public ConfigInt maxSymmetryWandRange = i(50, 10, "maxSymmetryWandRange", Comments.symmetryRange);
|
public ConfigInt maxSymmetryWandRange = i(50, 10, "maxSymmetryWandRange", Comments.symmetryRange);
|
||||||
public ConfigInt zapperUndoLogLength = i(10, 0, "zapperUndoLogLength", Comments.zapperUndoLogLength);
|
// public ConfigInt zapperUndoLogLength = i(10, 0, "zapperUndoLogLength", Comments.zapperUndoLogLength); NYI
|
||||||
public ConfigInt lightSourceCountForRefinedRadiance = i(10, 1, "lightSourceCountForRefinedRadiance",
|
|
||||||
Comments.refinedRadiance);
|
|
||||||
public ConfigBool allowGlassPanesInPartialBlocks = b(true, "allowGlassPanesInPartialBlocks",
|
|
||||||
Comments.windowsInBlocks);
|
|
||||||
public ConfigBool enableRefinedRadianceRecipe = b(true, "enableRefinedRadianceRecipe",
|
|
||||||
Comments.refinedRadianceRecipe);
|
|
||||||
public ConfigBool enableShadowSteelRecipe = b(true, "enableShadowSteelRecipe", Comments.shadowSteelRecipe);
|
|
||||||
public ConfigFloat cocoaLogGrowthSpeed = f(20, 0, 100, "cocoaLogGrowthSpeed", Comments.cocoa);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -20,12 +12,7 @@ public class CCuriosities extends ConfigBase {
|
||||||
|
|
||||||
private static class Comments {
|
private static class Comments {
|
||||||
static String symmetryRange = "The Maximum Distance to an active mirror for the symmetry wand to trigger.";
|
static String symmetryRange = "The Maximum Distance to an active mirror for the symmetry wand to trigger.";
|
||||||
static String refinedRadiance = "The amount of Light sources destroyed before Chromatic Compound turns into Refined Radiance.";
|
// static String zapperUndoLogLength = "The maximum amount of operations, a blockzapper can remember for undoing. (0 to disable undo)";
|
||||||
static String refinedRadianceRecipe = "Allow the standard Refined Radiance recipes.";
|
|
||||||
static String shadowSteelRecipe = "Allow the standard Shadow Steel recipe.";
|
|
||||||
static String windowsInBlocks = "Allow Glass Panes to be put inside Blocks like Stairs, Slabs, Fences etc.";
|
|
||||||
static String cocoa = "% of random Ticks causing a Cocoa log to grow.";
|
|
||||||
static String zapperUndoLogLength = "The maximum amount of operations, a blockzapper can remember for undoing. (0 to disable undo)";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
package com.simibubi.create.foundation.config;
|
|
||||||
|
|
||||||
public class CDamageControl extends ConfigBase {
|
|
||||||
|
|
||||||
public ConfigBool freezeCrushing = b(false, "freezeCrushing", Comments.freezeCrushing);
|
|
||||||
public ConfigBool freezeExtractors = b(false, "freezeExtractors", Comments.freezeExtractors);
|
|
||||||
public ConfigBool freezeInWorldProcessing = b(false, "freezeInWorldProcessing", Comments.freezeInWorldProcessing);
|
|
||||||
public ConfigBool freezeRotationPropagator =
|
|
||||||
b(false, "freezeRotationPropagator", Comments.freezeRotationPropagator);
|
|
||||||
public ConfigBool freezeContraptions = b(false, "freezeContraptions", Comments.freezeContraptions);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "damageControl";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Comments {
|
|
||||||
static String freezeCrushing = "In case Crushing Wheels crushed your server.";
|
|
||||||
static String freezeExtractors = "In case Extractors pulled the plug.";
|
|
||||||
static String freezeInWorldProcessing = "In case Encased Fans tried smelting your hardware.";
|
|
||||||
static String freezeRotationPropagator =
|
|
||||||
"Pauses rotation logic altogether - Use if crash mentions RotationPropagators.";
|
|
||||||
static String freezeContraptions = "In case Moving contraptions pushed it too far.";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -12,8 +12,9 @@ public class CKinetics extends ConfigBase {
|
||||||
public ConfigEnum<DeployerAggroSetting> ignoreDeployerAttacks =
|
public ConfigEnum<DeployerAggroSetting> ignoreDeployerAttacks =
|
||||||
e(DeployerAggroSetting.CREEPERS, "ignoreDeployerAttacks", Comments.ignoreDeployerAttacks);
|
e(DeployerAggroSetting.CREEPERS, "ignoreDeployerAttacks", Comments.ignoreDeployerAttacks);
|
||||||
public ConfigInt kineticValidationFrequency = i(60, 5, "kineticValidationFrequency", Comments.kineticValidationFrequency);
|
public ConfigInt kineticValidationFrequency = i(60, 5, "kineticValidationFrequency", Comments.kineticValidationFrequency);
|
||||||
|
public ConfigFloat crankHungerMultiplier = f(.01f, 0, 1, "crankHungerMultiplier", Comments.crankHungerMultiplier);
|
||||||
|
|
||||||
public ConfigGroup fan = group(0, "encasedFan", "Encased Fan");
|
public ConfigGroup fan = group(1, "encasedFan", "Encased Fan");
|
||||||
public ConfigInt fanPushDistance = i(20, 5, "fanPushDistance", Comments.fanPushDistance);
|
public ConfigInt fanPushDistance = i(20, 5, "fanPushDistance", Comments.fanPushDistance);
|
||||||
public ConfigInt fanPullDistance = i(20, 5, "fanPullDistance", Comments.fanPullDistance);
|
public ConfigInt fanPullDistance = i(20, 5, "fanPullDistance", Comments.fanPullDistance);
|
||||||
public ConfigInt fanBlockCheckRate = i(30, 10, "fanBlockCheckRate", Comments.fanBlockCheckRate);
|
public ConfigInt fanBlockCheckRate = i(30, 10, "fanBlockCheckRate", Comments.fanBlockCheckRate);
|
||||||
|
@ -21,19 +22,16 @@ public class CKinetics extends ConfigBase {
|
||||||
public ConfigInt generatingFanSpeed = i(16, 0, "generatingFanSpeed", Comments.rpm, Comments.generatingFanSpeed);
|
public ConfigInt generatingFanSpeed = i(16, 0, "generatingFanSpeed", Comments.rpm, Comments.generatingFanSpeed);
|
||||||
public ConfigInt inWorldProcessingTime = i(150, 0, "inWorldProcessingTime", Comments.inWorldProcessingTime);
|
public ConfigInt inWorldProcessingTime = i(150, 0, "inWorldProcessingTime", Comments.inWorldProcessingTime);
|
||||||
|
|
||||||
public ConfigGroup crank = group(0, "handCrank", "Hand Crank & Valve Handles");
|
public ConfigGroup contraptions = group(1, "contraptions", "Moving Contraptions");
|
||||||
public ConfigFloat crankHungerMultiplier = f(.01f, 0, 1, "crankHungerMultiplier", Comments.crankHungerMultiplier);
|
|
||||||
|
|
||||||
public ConfigGroup contraptions = group(0, "contraptions", "Moving Contraptions");
|
|
||||||
public ConfigInt maxBlocksMoved = i(2048, 1, "maxBlocksMoved", Comments.maxBlocksMoved);
|
public ConfigInt maxBlocksMoved = i(2048, 1, "maxBlocksMoved", Comments.maxBlocksMoved);
|
||||||
public ConfigInt maxChassisRange = i(16, 1, "maxChassisRange", Comments.maxChassisRange);
|
public ConfigInt maxChassisRange = i(16, 1, "maxChassisRange", Comments.maxChassisRange);
|
||||||
public ConfigInt maxPistonPoles = i(64, 1, "maxPistonPoles", Comments.maxPistonPoles);
|
public ConfigInt maxPistonPoles = i(64, 1, "maxPistonPoles", Comments.maxPistonPoles);
|
||||||
public ConfigInt maxRopeLength = i(128, 1, "maxRopeLength", Comments.maxRopeLength);
|
public ConfigInt maxRopeLength = i(128, 1, "maxRopeLength", Comments.maxRopeLength);
|
||||||
public ConfigInt maxCartCouplingLength = i(32, 1, "maxCartCouplingLength", Comments.maxCartCouplingLength);
|
public ConfigInt maxCartCouplingLength = i(32, 1, "maxCartCouplingLength", Comments.maxCartCouplingLength);
|
||||||
|
|
||||||
public CStress stressValues = nested(0, CStress::new, Comments.stress);
|
public CStress stressValues = nested(1, CStress::new, Comments.stress);
|
||||||
|
|
||||||
public ConfigGroup state = group(0, "stats", Comments.stats);
|
public ConfigGroup state = group(1, "stats", Comments.stats);
|
||||||
public ConfigFloat mediumSpeed = f(30, 0, 4096, "mediumSpeed", Comments.rpm, Comments.mediumSpeed);
|
public ConfigFloat mediumSpeed = f(30, 0, 4096, "mediumSpeed", Comments.rpm, Comments.mediumSpeed);
|
||||||
public ConfigFloat fastSpeed = f(100, 0, 65535, "fastSpeed", Comments.rpm, Comments.fastSpeed);
|
public ConfigFloat fastSpeed = f(100, 0, 65535, "fastSpeed", Comments.rpm, Comments.fastSpeed);
|
||||||
public ConfigFloat mediumStressImpact =
|
public ConfigFloat mediumStressImpact =
|
||||||
|
|
|
@ -4,8 +4,14 @@ public class CRecipes extends ConfigBase {
|
||||||
|
|
||||||
public ConfigBool allowShapelessInMixer = b(true, "allowShapelessInMixer", Comments.allowShapelessInMixer);
|
public ConfigBool allowShapelessInMixer = b(true, "allowShapelessInMixer", Comments.allowShapelessInMixer);
|
||||||
public ConfigBool allowShapedSquareInPress = b(true, "allowShapedSquareInPress", Comments.allowShapedSquareInPress);
|
public ConfigBool allowShapedSquareInPress = b(true, "allowShapedSquareInPress", Comments.allowShapedSquareInPress);
|
||||||
public ConfigBool allowRegularCraftingInCrafter = b(true, "allowRegularCraftingInCrafter", Comments.allowRegularCraftingInCrafter);
|
public ConfigBool allowRegularCraftingInCrafter =
|
||||||
|
b(true, "allowRegularCraftingInCrafter", Comments.allowRegularCraftingInCrafter);
|
||||||
public ConfigBool allowStonecuttingOnSaw = b(true, "allowStonecuttingOnSaw", Comments.allowStonecuttingOnSaw);
|
public ConfigBool allowStonecuttingOnSaw = b(true, "allowStonecuttingOnSaw", Comments.allowStonecuttingOnSaw);
|
||||||
|
public ConfigInt lightSourceCountForRefinedRadiance =
|
||||||
|
i(10, 1, "lightSourceCountForRefinedRadiance", Comments.refinedRadiance);
|
||||||
|
public ConfigBool enableRefinedRadianceRecipe =
|
||||||
|
b(true, "enableRefinedRadianceRecipe", Comments.refinedRadianceRecipe);
|
||||||
|
public ConfigBool enableShadowSteelRecipe = b(true, "enableShadowSteelRecipe", Comments.shadowSteelRecipe);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -21,6 +27,10 @@ public class CRecipes extends ConfigBase {
|
||||||
"When true, allows any standard crafting recipes to be processed by Mechanical Crafters.";
|
"When true, allows any standard crafting recipes to be processed by Mechanical Crafters.";
|
||||||
static String allowStonecuttingOnSaw =
|
static String allowStonecuttingOnSaw =
|
||||||
"When true, allows any stonecutting recipes to be processed by a Mechanical Saw.";
|
"When true, allows any stonecutting recipes to be processed by a Mechanical Saw.";
|
||||||
|
static String refinedRadiance =
|
||||||
|
"The amount of Light sources destroyed before Chromatic Compound turns into Refined Radiance.";
|
||||||
|
static String refinedRadianceRecipe = "Allow the standard in-world Refined Radiance recipes.";
|
||||||
|
static String shadowSteelRecipe = "Allow the standard in-world Shadow Steel recipe.";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ public class CServer extends ConfigBase {
|
||||||
public CLogistics logistics = nested(0, CLogistics::new, Comments.logistics);
|
public CLogistics logistics = nested(0, CLogistics::new, Comments.logistics);
|
||||||
public CSchematics schematics = nested(0, CSchematics::new, Comments.schematics);
|
public CSchematics schematics = nested(0, CSchematics::new, Comments.schematics);
|
||||||
public CCuriosities curiosities = nested(0, CCuriosities::new, Comments.curiosities);
|
public CCuriosities curiosities = nested(0, CCuriosities::new, Comments.curiosities);
|
||||||
public CDamageControl control = nested(0, CDamageControl::new, Comments.control);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -26,7 +25,6 @@ public class CServer extends ConfigBase {
|
||||||
static String fluids = "Create's liquid manipulation tools";
|
static String fluids = "Create's liquid manipulation tools";
|
||||||
static String logistics = "Tweaks for logistical components";
|
static String logistics = "Tweaks for logistical components";
|
||||||
static String curiosities = "Gadgets and other Shenanigans added by Create";
|
static String curiosities = "Gadgets and other Shenanigans added by Create";
|
||||||
static String control = "You can try inhibiting related game mechanics for troubleshooting repeated crashes.";
|
|
||||||
static String infrastructure = "The Backbone of Create";
|
static String infrastructure = "The Backbone of Create";
|
||||||
static String tickrateSyncTimer =
|
static String tickrateSyncTimer =
|
||||||
"The amount of time a server waits before sending out tickrate synchronization packets.";
|
"The amount of time a server waits before sending out tickrate synchronization packets.";
|
||||||
|
|
|
@ -22,7 +22,7 @@ public abstract class ConfigBase {
|
||||||
protected List<ConfigBase> children;
|
protected List<ConfigBase> children;
|
||||||
|
|
||||||
protected void registerAll(final ForgeConfigSpec.Builder builder) {
|
protected void registerAll(final ForgeConfigSpec.Builder builder) {
|
||||||
for (CValue<?, ?> cValue : allValues)
|
for (CValue<?, ?> cValue : allValues)
|
||||||
cValue.register(builder);
|
cValue.register(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,9 +75,10 @@ public abstract class ConfigBase {
|
||||||
T config = constructor.get();
|
T config = constructor.get();
|
||||||
new ConfigGroup(config.getName(), depth, comment);
|
new ConfigGroup(config.getName(), depth, comment);
|
||||||
new CValue<Boolean, ForgeConfigSpec.BooleanValue>(config.getName(), builder -> {
|
new CValue<Boolean, ForgeConfigSpec.BooleanValue>(config.getName(), builder -> {
|
||||||
|
config.depth = depth;
|
||||||
config.registerAll(builder);
|
config.registerAll(builder);
|
||||||
if (config.depth > 0)
|
if (config.depth > depth)
|
||||||
builder.pop(config.depth);
|
builder.pop(config.depth - depth);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
if (children == null)
|
if (children == null)
|
||||||
|
@ -124,6 +125,10 @@ public abstract class ConfigBase {
|
||||||
public void set(V value) {
|
public void set(V value) {
|
||||||
this.value.set(value);
|
this.value.set(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -146,7 +151,7 @@ public abstract class ConfigBase {
|
||||||
builder.pop(depth - groupDepth);
|
builder.pop(depth - groupDepth);
|
||||||
depth = groupDepth;
|
depth = groupDepth;
|
||||||
addComments(builder, comment);
|
addComments(builder, comment);
|
||||||
builder.push(name);
|
builder.push(getName());
|
||||||
depth++;
|
depth++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,12 @@ import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.block.FireBlock;
|
import net.minecraft.block.FireBlock;
|
||||||
import net.minecraft.block.FlowingFluidBlock;
|
import net.minecraft.block.FlowingFluidBlock;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.*;
|
import net.minecraft.client.renderer.Atlases;
|
||||||
|
import net.minecraft.client.renderer.BlockRendererDispatcher;
|
||||||
|
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||||
|
import net.minecraft.client.renderer.RenderHelper;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.RenderTypeLookup;
|
||||||
import net.minecraft.client.renderer.model.IBakedModel;
|
import net.minecraft.client.renderer.model.IBakedModel;
|
||||||
import net.minecraft.client.renderer.model.ItemCameraTransforms;
|
import net.minecraft.client.renderer.model.ItemCameraTransforms;
|
||||||
import net.minecraft.client.renderer.texture.AtlasTexture;
|
import net.minecraft.client.renderer.texture.AtlasTexture;
|
||||||
|
|
|
@ -11,10 +11,8 @@ import com.simibubi.create.content.contraptions.components.structureMovement.syn
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionInteractionPacket;
|
import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionInteractionPacket;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionSeatMappingPacket;
|
import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionSeatMappingPacket;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.sync.LimbSwingUpdatePacket;
|
import com.simibubi.create.content.contraptions.components.structureMovement.sync.LimbSwingUpdatePacket;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCouplingCreationPacket;
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingCreationPacket;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCouplingSyncPacket;
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartControllerUpdatePacket;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.PersistantDataPacket;
|
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.PersistantDataPacketRequest;
|
|
||||||
import com.simibubi.create.content.contraptions.relays.advanced.sequencer.ConfigureSequencedGearshiftPacket;
|
import com.simibubi.create.content.contraptions.relays.advanced.sequencer.ConfigureSequencedGearshiftPacket;
|
||||||
import com.simibubi.create.content.curiosities.symmetry.SymmetryEffectPacket;
|
import com.simibubi.create.content.curiosities.symmetry.SymmetryEffectPacket;
|
||||||
import com.simibubi.create.content.curiosities.tools.ExtendoGripInteractionPacket;
|
import com.simibubi.create.content.curiosities.tools.ExtendoGripInteractionPacket;
|
||||||
|
@ -55,8 +53,7 @@ public enum AllPackets {
|
||||||
CONTRAPTION_INTERACT(ContraptionInteractionPacket.class, ContraptionInteractionPacket::new),
|
CONTRAPTION_INTERACT(ContraptionInteractionPacket.class, ContraptionInteractionPacket::new),
|
||||||
CLIENT_MOTION(ClientMotionPacket.class, ClientMotionPacket::new),
|
CLIENT_MOTION(ClientMotionPacket.class, ClientMotionPacket::new),
|
||||||
PLACE_ARM(ArmPlacementPacket.class, ArmPlacementPacket::new),
|
PLACE_ARM(ArmPlacementPacket.class, ArmPlacementPacket::new),
|
||||||
MINECART_COUPLING_CREATION(MinecartCouplingCreationPacket.class, MinecartCouplingCreationPacket::new),
|
MINECART_COUPLING_CREATION(CouplingCreationPacket.class, CouplingCreationPacket::new),
|
||||||
PERSISTANT_DATA_REQUEST(PersistantDataPacketRequest.class, PersistantDataPacketRequest::new),
|
|
||||||
INSTANT_SCHEMATIC(InstantSchematicPacket.class, InstantSchematicPacket::new),
|
INSTANT_SCHEMATIC(InstantSchematicPacket.class, InstantSchematicPacket::new),
|
||||||
|
|
||||||
// Server to Client
|
// Server to Client
|
||||||
|
@ -66,10 +63,9 @@ public enum AllPackets {
|
||||||
CONFIGURE_CONFIG(ConfigureConfigPacket.class, ConfigureConfigPacket::new),
|
CONFIGURE_CONFIG(ConfigureConfigPacket.class, ConfigureConfigPacket::new),
|
||||||
CONTRAPTION_STALL(ContraptionStallPacket.class, ContraptionStallPacket::new),
|
CONTRAPTION_STALL(ContraptionStallPacket.class, ContraptionStallPacket::new),
|
||||||
GLUE_EFFECT(GlueEffectPacket.class, GlueEffectPacket::new),
|
GLUE_EFFECT(GlueEffectPacket.class, GlueEffectPacket::new),
|
||||||
MINECART_COUPLING_SYNC(MinecartCouplingSyncPacket.class, MinecartCouplingSyncPacket::new),
|
|
||||||
CONTRAPTION_SEAT_MAPPING(ContraptionSeatMappingPacket.class, ContraptionSeatMappingPacket::new),
|
CONTRAPTION_SEAT_MAPPING(ContraptionSeatMappingPacket.class, ContraptionSeatMappingPacket::new),
|
||||||
PERSISTANT_DATA(PersistantDataPacket.class, PersistantDataPacket::new),
|
|
||||||
LIMBSWING_UPDATE(LimbSwingUpdatePacket.class, LimbSwingUpdatePacket::new),
|
LIMBSWING_UPDATE(LimbSwingUpdatePacket.class, LimbSwingUpdatePacket::new),
|
||||||
|
MINECART_CONTROLLER(MinecartControllerUpdatePacket.class, MinecartControllerUpdatePacket::new),
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import java.util.function.Predicate;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.common.base.Predicates;
|
import com.google.common.base.Predicates;
|
||||||
import com.simibubi.create.foundation.config.AllConfigs;
|
|
||||||
import com.simibubi.create.foundation.item.ItemHelper;
|
import com.simibubi.create.foundation.item.ItemHelper;
|
||||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
|
@ -104,8 +103,6 @@ public class InvManipulationBehaviour extends TileEntityBehaviour {
|
||||||
|
|
||||||
if (getWorld().isRemote)
|
if (getWorld().isRemote)
|
||||||
return ItemStack.EMPTY;
|
return ItemStack.EMPTY;
|
||||||
if (AllConfigs.SERVER.control.freezeExtractors.get())
|
|
||||||
return ItemStack.EMPTY;
|
|
||||||
IItemHandler inventory = targetCapability.orElse(null);
|
IItemHandler inventory = targetCapability.orElse(null);
|
||||||
if (inventory == null)
|
if (inventory == null)
|
||||||
return ItemStack.EMPTY;
|
return ItemStack.EMPTY;
|
||||||
|
|
|
@ -33,13 +33,6 @@ public class MatrixStacker {
|
||||||
return multiply(Vector3f.POSITIVE_Z, angle);
|
return multiply(Vector3f.POSITIVE_Z, angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MatrixStacker rotateRadians(double angleRoll, double angleYaw, double anglePitch) {
|
|
||||||
rotateX(AngleHelper.deg(angleRoll));
|
|
||||||
rotateY(AngleHelper.deg(angleYaw));
|
|
||||||
rotateZ(AngleHelper.deg(anglePitch));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MatrixStacker centre() {
|
public MatrixStacker centre() {
|
||||||
return translate(center);
|
return translate(center);
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,6 +121,12 @@
|
||||||
"create.blockzapper.componentTier.chromatic": "Chromatic",
|
"create.blockzapper.componentTier.chromatic": "Chromatic",
|
||||||
"create.blockzapper.leftClickToSet": "Left-Click a Block to set Material",
|
"create.blockzapper.leftClickToSet": "Left-Click a Block to set Material",
|
||||||
"create.blockzapper.empty": "Out of Blocks!",
|
"create.blockzapper.empty": "Out of Blocks!",
|
||||||
|
|
||||||
|
"create.minecart_coupling.two_couplings_max": "Minecarts cannot have more than two couplings each",
|
||||||
|
"create.minecart_coupling.unloaded": "Parts of your train seem to be in unloaded chunks",
|
||||||
|
"create.minecart_coupling.no_loops": "Couplings cannot form a loop",
|
||||||
|
"create.minecart_coupling.removed": "Removed all couplings from minecart",
|
||||||
|
"create.minecart_coupling.too_far": "Minecarts are too far apart",
|
||||||
|
|
||||||
"create.contraptions.movement_mode": "Movement Mode",
|
"create.contraptions.movement_mode": "Movement Mode",
|
||||||
"create.contraptions.movement_mode.move_place": "Always Place when Stopped",
|
"create.contraptions.movement_mode.move_place": "Always Place when Stopped",
|
||||||
|
|
Loading…
Reference in a new issue