mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-11-10 20:11:35 +01:00
Couple things, Part I
- Added Foundation and POC of minecart couplings and carriage contraptions. highly unstable
This commit is contained in:
parent
ffe3cf4f71
commit
7e167f3b29
58 changed files with 2426 additions and 377 deletions
|
@ -357,17 +357,17 @@ c77b46d8b459e5c7cc495393546f3fcca8a1fa1d assets/create/blockstates/weathered_lim
|
|||
a3a11524cd3515fc01d905767b4b7ea782adaf03 assets/create/blockstates/yellow_seat.json
|
||||
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
|
||||
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
|
||||
da8ae8561b7827b4aca53ef32f2dd3860a39fba1 assets/create/lang/en_ud.json
|
||||
bf48621dfa7345a765c6a1e1c6a39689ddefd965 assets/create/lang/en_us.json
|
||||
bc1018ede1b186c9e7656e85a57682bfd8f13814 assets/create/lang/unfinished/de_de.json
|
||||
2b0ad2444e9c14c1ffcee91954940fef74061fb6 assets/create/lang/unfinished/fr_fr.json
|
||||
2b3595491cfc672f3d6da7bd9e3600f139445f2b assets/create/lang/unfinished/it_it.json
|
||||
3f559bd4e42159edea64e9f958901ee9c7049111 assets/create/lang/unfinished/ja_jp.json
|
||||
a9e22722c8b424bc3316b3d2c6d7f21da937a2d4 assets/create/lang/unfinished/ko_kr.json
|
||||
28c53f4ee00201fdf65e167c96affbcc72f3f585 assets/create/lang/unfinished/nl_nl.json
|
||||
12053da965398e50eccf5d549a2caa06d1555e5f assets/create/lang/unfinished/pt_br.json
|
||||
9d5f4355a84883b5e499d7af432431e0592f687b assets/create/lang/unfinished/ru_ru.json
|
||||
bf2894922ec5e14db2d516002d9be46e08461a58 assets/create/lang/unfinished/zh_cn.json
|
||||
a9bcfd546e95865633a97e4b29e39c4aec940338 assets/create/lang/en_ud.json
|
||||
aa14daef8d31ca69ace4e643ffdc5cc9aba22818 assets/create/lang/en_us.json
|
||||
b4435a02a94ae72032f3ffb8f9282e41b1dca953 assets/create/lang/unfinished/de_de.json
|
||||
4f9cc39db1e0de14e9aeabea93676b8fa8ba58ec assets/create/lang/unfinished/fr_fr.json
|
||||
a5a1d2d2e6154c07be187dfe2e33c203db1dd678 assets/create/lang/unfinished/it_it.json
|
||||
022fee71a855d3cd206c2c1d5c36c38f089f8120 assets/create/lang/unfinished/ja_jp.json
|
||||
07da262b3005fd53abd22b5da558e3494bbefa90 assets/create/lang/unfinished/ko_kr.json
|
||||
f1a7c021d2a48a56141ffe70ddec7128c5ad7261 assets/create/lang/unfinished/nl_nl.json
|
||||
5e10814eb0606a6bd20097067394a93842ef7957 assets/create/lang/unfinished/pt_br.json
|
||||
f1367be00730002ee0f233dfebb5e920eed56900 assets/create/lang/unfinished/ru_ru.json
|
||||
76928b7d9f7f41f4fa622824a872bec8e5635cea 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
|
||||
|
@ -1243,6 +1243,7 @@ f8d0d4b2a890ea7a69ab0c390947b48fe0478d3f assets/create/models/item/mechanical_pi
|
|||
bca99d467ec8ead10124becb60ac24b39be83de4 assets/create/models/item/mechanical_saw.json
|
||||
0eb5726c8c0de462f432411c210d6132b2c446a4 assets/create/models/item/millstone.json
|
||||
1134bc8ecdfefe5d30ee4973c37aa9a349c368b4 assets/create/models/item/minecart_contraption.json
|
||||
5f44acb8a784611c17913ddf64fb4098b3a8aee9 assets/create/models/item/minecart_coupling.json
|
||||
dc43c88dc8ae1f425e1c10f422b09d97719af5bc assets/create/models/item/mossy_andesite.json
|
||||
4ce9aabf9fa9e9e6af6b4339291e635708bdbcdf assets/create/models/item/mossy_dark_scoria.json
|
||||
d084f03d068d0b8c3b7c4d00014c168f61836770 assets/create/models/item/mossy_diorite.json
|
||||
|
|
|
@ -396,6 +396,7 @@
|
|||
"item.create.iron_sheet": "\u0287\u01DD\u01DD\u0265S uo\u0279I",
|
||||
"item.create.lapis_sheet": "\u0287\u01DD\u01DD\u0265S s\u0131d\u0250\uA780",
|
||||
"item.create.minecart_contraption": "uo\u0131\u0287d\u0250\u0279\u0287uo\u0186 \u0287\u0279\u0250\u0254\u01DDu\u0131W",
|
||||
"item.create.minecart_coupling": "bu\u0131\u05DFdno\u0186 \u0287\u0279\u0250\u0254\u01DDu\u0131W",
|
||||
"item.create.polished_rose_quartz": "z\u0287\u0279\u0250n\u1F49 \u01DDso\u1D1A p\u01DD\u0265s\u0131\u05DFo\u0500",
|
||||
"item.create.powdered_obsidian": "u\u0250\u0131p\u0131sqO p\u01DD\u0279\u01DDp\u028Do\u0500",
|
||||
"item.create.propeller": "\u0279\u01DD\u05DF\u05DF\u01DDdo\u0279\u0500",
|
||||
|
|
|
@ -401,6 +401,7 @@
|
|||
"item.create.iron_sheet": "Iron Sheet",
|
||||
"item.create.lapis_sheet": "Lapis Sheet",
|
||||
"item.create.minecart_contraption": "Minecart Contraption",
|
||||
"item.create.minecart_coupling": "Minecart Coupling",
|
||||
"item.create.polished_rose_quartz": "Polished Rose Quartz",
|
||||
"item.create.powdered_obsidian": "Powdered Obsidian",
|
||||
"item.create.propeller": "Propeller",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 813",
|
||||
"_": "Missing Localizations: 814",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -402,6 +402,7 @@
|
|||
"item.create.iron_sheet": "Eisenblech",
|
||||
"item.create.lapis_sheet": "UNLOCALIZED: Lapis Sheet",
|
||||
"item.create.minecart_contraption": "UNLOCALIZED: Minecart Contraption",
|
||||
"item.create.minecart_coupling": "UNLOCALIZED: Minecart Coupling",
|
||||
"item.create.polished_rose_quartz": "UNLOCALIZED: Polished Rose Quartz",
|
||||
"item.create.powdered_obsidian": "UNLOCALIZED: Powdered Obsidian",
|
||||
"item.create.propeller": "Propeller",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 416",
|
||||
"_": "Missing Localizations: 417",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -402,6 +402,7 @@
|
|||
"item.create.iron_sheet": "Plaque de Fer",
|
||||
"item.create.lapis_sheet": "UNLOCALIZED: Lapis Sheet",
|
||||
"item.create.minecart_contraption": "UNLOCALIZED: Minecart Contraption",
|
||||
"item.create.minecart_coupling": "UNLOCALIZED: Minecart Coupling",
|
||||
"item.create.polished_rose_quartz": "Quartz rose poli",
|
||||
"item.create.powdered_obsidian": "UNLOCALIZED: Powdered Obsidian",
|
||||
"item.create.propeller": "Hélice",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 400",
|
||||
"_": "Missing Localizations: 401",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -402,6 +402,7 @@
|
|||
"item.create.iron_sheet": "Lamiera di Ferro",
|
||||
"item.create.lapis_sheet": "UNLOCALIZED: Lapis Sheet",
|
||||
"item.create.minecart_contraption": "UNLOCALIZED: Minecart Contraption",
|
||||
"item.create.minecart_coupling": "UNLOCALIZED: Minecart Coupling",
|
||||
"item.create.polished_rose_quartz": "Quarzo Rosa Levigato",
|
||||
"item.create.powdered_obsidian": "UNLOCALIZED: Powdered Obsidian",
|
||||
"item.create.propeller": "Elica",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 395",
|
||||
"_": "Missing Localizations: 396",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -402,6 +402,7 @@
|
|||
"item.create.iron_sheet": "鉄板",
|
||||
"item.create.lapis_sheet": "UNLOCALIZED: Lapis Sheet",
|
||||
"item.create.minecart_contraption": "UNLOCALIZED: Minecart Contraption",
|
||||
"item.create.minecart_coupling": "UNLOCALIZED: Minecart Coupling",
|
||||
"item.create.polished_rose_quartz": "磨かれたローズクォーツ",
|
||||
"item.create.powdered_obsidian": "UNLOCALIZED: Powdered Obsidian",
|
||||
"item.create.propeller": "プロペラ",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 400",
|
||||
"_": "Missing Localizations: 401",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -402,6 +402,7 @@
|
|||
"item.create.iron_sheet": "철 판",
|
||||
"item.create.lapis_sheet": "UNLOCALIZED: Lapis Sheet",
|
||||
"item.create.minecart_contraption": "UNLOCALIZED: Minecart Contraption",
|
||||
"item.create.minecart_coupling": "UNLOCALIZED: Minecart Coupling",
|
||||
"item.create.polished_rose_quartz": "윤나는 장밋빛 석영",
|
||||
"item.create.powdered_obsidian": "UNLOCALIZED: Powdered Obsidian",
|
||||
"item.create.propeller": "프로펠러",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 750",
|
||||
"_": "Missing Localizations: 751",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -402,6 +402,7 @@
|
|||
"item.create.iron_sheet": "IJzeren Platen",
|
||||
"item.create.lapis_sheet": "UNLOCALIZED: Lapis Sheet",
|
||||
"item.create.minecart_contraption": "UNLOCALIZED: Minecart Contraption",
|
||||
"item.create.minecart_coupling": "UNLOCALIZED: Minecart Coupling",
|
||||
"item.create.polished_rose_quartz": "UNLOCALIZED: Polished Rose Quartz",
|
||||
"item.create.powdered_obsidian": "UNLOCALIZED: Powdered Obsidian",
|
||||
"item.create.propeller": "Propeller",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 820",
|
||||
"_": "Missing Localizations: 821",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -402,6 +402,7 @@
|
|||
"item.create.iron_sheet": "Placas de Ferro",
|
||||
"item.create.lapis_sheet": "UNLOCALIZED: Lapis Sheet",
|
||||
"item.create.minecart_contraption": "UNLOCALIZED: Minecart Contraption",
|
||||
"item.create.minecart_coupling": "UNLOCALIZED: Minecart Coupling",
|
||||
"item.create.polished_rose_quartz": "UNLOCALIZED: Polished Rose Quartz",
|
||||
"item.create.powdered_obsidian": "UNLOCALIZED: Powdered Obsidian",
|
||||
"item.create.propeller": "Hélice",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 814",
|
||||
"_": "Missing Localizations: 815",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -402,6 +402,7 @@
|
|||
"item.create.iron_sheet": "Железная пластина",
|
||||
"item.create.lapis_sheet": "UNLOCALIZED: Lapis Sheet",
|
||||
"item.create.minecart_contraption": "UNLOCALIZED: Minecart Contraption",
|
||||
"item.create.minecart_coupling": "UNLOCALIZED: Minecart Coupling",
|
||||
"item.create.polished_rose_quartz": "UNLOCALIZED: Polished Rose Quartz",
|
||||
"item.create.powdered_obsidian": "UNLOCALIZED: Powdered Obsidian",
|
||||
"item.create.propeller": "Пропеллер",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 76",
|
||||
"_": "Missing Localizations: 77",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -402,6 +402,7 @@
|
|||
"item.create.iron_sheet": "铁板",
|
||||
"item.create.lapis_sheet": "青金石板",
|
||||
"item.create.minecart_contraption": "装配过的矿车",
|
||||
"item.create.minecart_coupling": "UNLOCALIZED: Minecart Coupling",
|
||||
"item.create.polished_rose_quartz": "磨制玫瑰石英",
|
||||
"item.create.powdered_obsidian": "黑曜石粉末",
|
||||
"item.create.propeller": "扇叶",
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "item/generated",
|
||||
"textures": {
|
||||
"layer0": "create:item/minecart_coupling"
|
||||
}
|
||||
}
|
|
@ -94,7 +94,13 @@ public class AllBlockPartials {
|
|||
FLAG_LONG_IN = get("mechanical_arm/flag/long_in"), FLAG_LONG_OUT = get("mechanical_arm/flag/long_out"),
|
||||
|
||||
MECHANICAL_PUMP_ARROW = get("mechanical_pump/arrow"), MECHANICAL_PUMP_COG = get("mechanical_pump/cog"),
|
||||
FLUID_PIPE_CASING = get("fluid_pipe/casing");
|
||||
FLUID_PIPE_CASING = get("fluid_pipe/casing"),
|
||||
|
||||
COUPLING_ATTACHMENT = getEntity("minecart_coupling/attachment"),
|
||||
COUPLING_RING = getEntity("minecart_coupling/ring"),
|
||||
COUPLING_CONNECTOR = getEntity("minecart_coupling/connector")
|
||||
|
||||
;
|
||||
|
||||
public static final Map<Direction, AllBlockPartials> PIPE_RIMS = map();
|
||||
public static final Map<HeatLevel, AllBlockPartials> BLAZES = map();
|
||||
|
@ -124,6 +130,13 @@ public class AllBlockPartials {
|
|||
return new HashMap<>();
|
||||
}
|
||||
|
||||
private static AllBlockPartials getEntity(String path) {
|
||||
AllBlockPartials partials = new AllBlockPartials();
|
||||
partials.modelLocation = new ResourceLocation(Create.ID, "entity/" + path);
|
||||
all.add(partials);
|
||||
return partials;
|
||||
}
|
||||
|
||||
private static AllBlockPartials get(String path) {
|
||||
AllBlockPartials partials = new AllBlockPartials();
|
||||
partials.modelLocation = new ResourceLocation(Create.ID, "block/" + path);
|
||||
|
|
|
@ -13,6 +13,7 @@ import static com.simibubi.create.content.AllSections.SCHEMATICS;
|
|||
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueItem;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MinecartContraptionItem;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCouplingItem;
|
||||
import com.simibubi.create.content.contraptions.goggles.GogglesItem;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlockItem;
|
||||
import com.simibubi.create.content.contraptions.relays.belt.item.BeltConnectorItem;
|
||||
|
@ -122,15 +123,19 @@ public class AllItems {
|
|||
REGISTRATE.item("vertical_gearbox", VerticalGearboxItem::new)
|
||||
.model(AssetLookup.<VerticalGearboxItem>customItemModel("gearbox", "item_vertical"))
|
||||
.register();
|
||||
|
||||
|
||||
public static final ItemEntry<BlazeBurnerBlockItem> EMPTY_BLAZE_BURNER =
|
||||
REGISTRATE.item("empty_blaze_burner", BlazeBurnerBlockItem::empty)
|
||||
.model(AssetLookup.<BlazeBurnerBlockItem>customItemModel("blaze_burner", "block"))
|
||||
.register();
|
||||
.model(AssetLookup.<BlazeBurnerBlockItem>customItemModel("blaze_burner", "block"))
|
||||
.register();
|
||||
|
||||
public static final ItemEntry<SuperGlueItem> SUPER_GLUE = REGISTRATE.item("super_glue", SuperGlueItem::new)
|
||||
.register();
|
||||
|
||||
public static final ItemEntry<MinecartCouplingItem> MINECART_COUPLING =
|
||||
REGISTRATE.item("minecart_coupling", MinecartCouplingItem::new)
|
||||
.register();
|
||||
|
||||
public static final ItemEntry<SandPaperItem> SAND_PAPER = REGISTRATE.item("sand_paper", SandPaperItem::new)
|
||||
.transform(CreateRegistrate.customRenderedItem(() -> SandPaperModel::new))
|
||||
.register();
|
||||
|
|
|
@ -26,8 +26,10 @@ import net.minecraft.item.crafting.IRecipeSerializer;
|
|||
import net.minecraft.particles.ParticleType;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
import net.minecraftforge.fml.event.lifecycle.GatherDataEvent;
|
||||
|
@ -70,8 +72,10 @@ public class Create {
|
|||
modEventBus.addListener(AllConfigs::onLoad);
|
||||
modEventBus.addListener(AllConfigs::onReload);
|
||||
modEventBus.addListener(EventPriority.LOWEST, this::gatherData);
|
||||
CreateClient.addClientListeners(modEventBus);
|
||||
|
||||
AllConfigs.register();
|
||||
|
||||
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> CreateClient.addClientListeners(modEventBus));
|
||||
}
|
||||
|
||||
public static void init(final FMLCommonSetupEvent event) {
|
||||
|
@ -85,17 +89,6 @@ public class Create {
|
|||
AllWorldFeatures.reload();
|
||||
}
|
||||
|
||||
public static void tick() {
|
||||
if (schematicReceiver == null)
|
||||
schematicReceiver = new ServerSchematicLoader();
|
||||
schematicReceiver.tick();
|
||||
lagger.tick();
|
||||
}
|
||||
|
||||
public static void shutdown() {
|
||||
schematicReceiver.shutdown();
|
||||
}
|
||||
|
||||
public static CreateRegistrate registrate() {
|
||||
return registrate.get();
|
||||
}
|
||||
|
|
|
@ -5,16 +5,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.simibubi.create.content.contraptions.KineticDebugger;
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionRenderer;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisRangeDisplay;
|
||||
import com.simibubi.create.content.contraptions.relays.belt.item.BeltConnectorHandler;
|
||||
import com.simibubi.create.content.curiosities.tools.ExtendoGripRenderHandler;
|
||||
import com.simibubi.create.content.curiosities.zapper.ZapperRenderHandler;
|
||||
import com.simibubi.create.content.curiosities.zapper.blockzapper.BlockzapperRenderHandler;
|
||||
import com.simibubi.create.content.curiosities.zapper.terrainzapper.WorldshaperRenderHandler;
|
||||
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPointHandler;
|
||||
import com.simibubi.create.content.schematics.ClientSchematicLoader;
|
||||
import com.simibubi.create.content.schematics.client.SchematicAndQuillHandler;
|
||||
import com.simibubi.create.content.schematics.client.SchematicHandler;
|
||||
|
@ -23,10 +15,6 @@ import com.simibubi.create.foundation.block.render.CustomBlockModels;
|
|||
import com.simibubi.create.foundation.block.render.SpriteShifter;
|
||||
import com.simibubi.create.foundation.item.CustomItemModels;
|
||||
import com.simibubi.create.foundation.item.CustomRenderedItems;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction.EdgeInteractionRenderer;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringRenderer;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.linked.LinkRenderer;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueRenderer;
|
||||
import com.simibubi.create.foundation.utility.SuperByteBufferCache;
|
||||
import com.simibubi.create.foundation.utility.outliner.Outliner;
|
||||
|
||||
|
@ -40,14 +28,11 @@ import net.minecraft.item.Item;
|
|||
import net.minecraft.resources.IReloadableResourceManager;
|
||||
import net.minecraft.resources.IResourceManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.client.event.ModelBakeEvent;
|
||||
import net.minecraftforge.client.event.ModelRegistryEvent;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||
|
||||
public class CreateClient {
|
||||
|
@ -64,13 +49,11 @@ public class CreateClient {
|
|||
private static AllColorHandlers colorHandlers;
|
||||
|
||||
public static void addClientListeners(IEventBus modEventBus) {
|
||||
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> {
|
||||
modEventBus.addListener(CreateClient::clientInit);
|
||||
modEventBus.addListener(CreateClient::onModelBake);
|
||||
modEventBus.addListener(CreateClient::onModelRegistry);
|
||||
modEventBus.addListener(CreateClient::onTextureStitch);
|
||||
modEventBus.addListener(AllParticleTypes::registerFactories);
|
||||
});
|
||||
modEventBus.addListener(CreateClient::clientInit);
|
||||
modEventBus.addListener(CreateClient::onModelBake);
|
||||
modEventBus.addListener(CreateClient::onModelRegistry);
|
||||
modEventBus.addListener(CreateClient::onTextureStitch);
|
||||
modEventBus.addListener(AllParticleTypes::registerFactories);
|
||||
}
|
||||
|
||||
public static void clientInit(FMLClientSetupEvent event) {
|
||||
|
@ -95,27 +78,6 @@ public class CreateClient {
|
|||
((IReloadableResourceManager) resourceManager).addReloadListener(new ResourceReloadHandler());
|
||||
}
|
||||
|
||||
public static void gameTick() {
|
||||
schematicSender.tick();
|
||||
schematicAndQuillHandler.tick();
|
||||
schematicHandler.tick();
|
||||
BeltConnectorHandler.tick();
|
||||
FilteringRenderer.tick();
|
||||
LinkRenderer.tick();
|
||||
ScrollValueRenderer.tick();
|
||||
ChassisRangeDisplay.tick();
|
||||
EdgeInteractionRenderer.tick();
|
||||
WorldshaperRenderHandler.tick();
|
||||
BlockzapperRenderHandler.tick();
|
||||
KineticDebugger.tick();
|
||||
ZapperRenderHandler.tick();
|
||||
ExtendoGripRenderHandler.tick();
|
||||
// CollisionDebugger.tick();
|
||||
ArmInteractionPointHandler.tick();
|
||||
outliner.tickOutlines();
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void onTextureStitch(TextureStitchEvent.Pre event) {
|
||||
if (!event.getMap()
|
||||
.getId()
|
||||
|
@ -125,7 +87,6 @@ public class CreateClient {
|
|||
.forEach(event::addSprite);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void onModelBake(ModelBakeEvent event) {
|
||||
Map<ResourceLocation, IBakedModel> modelRegistry = event.getModelRegistry();
|
||||
AllBlockPartials.onModelBake(event);
|
||||
|
@ -140,7 +101,6 @@ public class CreateClient {
|
|||
});
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void onModelRegistry(ModelRegistryEvent event) {
|
||||
AllBlockPartials.onModelRegistry(event);
|
||||
|
||||
|
@ -149,12 +109,10 @@ public class CreateClient {
|
|||
.forEach(ModelLoader::addSpecialModel));
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
protected static ModelResourceLocation getItemModelLocation(Item item) {
|
||||
return new ModelResourceLocation(item.getRegistryName(), "inventory");
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
protected static List<ModelResourceLocation> getAllBlockStateModelLocations(Block block) {
|
||||
List<ModelResourceLocation> models = new ArrayList<>();
|
||||
block.getStateContainer()
|
||||
|
@ -165,20 +123,17 @@ public class CreateClient {
|
|||
return models;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
protected static ModelResourceLocation getBlockModelLocation(Block block, String suffix) {
|
||||
return new ModelResourceLocation(block.getRegistryName(), suffix);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
protected static <T extends IBakedModel> void swapModels(Map<ResourceLocation, IBakedModel> modelRegistry,
|
||||
List<ModelResourceLocation> locations, Function<IBakedModel, T> factory) {
|
||||
locations.forEach(location -> {
|
||||
swapModels(modelRegistry, location, factory);
|
||||
});
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
|
||||
protected static <T extends IBakedModel> void swapModels(Map<ResourceLocation, IBakedModel> modelRegistry,
|
||||
ModelResourceLocation location, Function<IBakedModel, T> factory) {
|
||||
modelRegistry.put(location, factory.apply(modelRegistry.get(location)));
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.simibubi.create.content.contraptions;
|
|||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.content.contraptions.base.IRotate;
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.utility.ColorHelper;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
@ -24,8 +25,14 @@ import net.minecraft.world.World;
|
|||
public class KineticDebugger {
|
||||
|
||||
public static void tick() {
|
||||
if (!isActive())
|
||||
if (!isActive()) {
|
||||
if (KineticTileEntityRenderer.rainbowMode) {
|
||||
KineticTileEntityRenderer.rainbowMode = false;
|
||||
CreateClient.bufferCache.invalidate();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
KineticTileEntity te = getSelectedTE();
|
||||
if (te == null)
|
||||
return;
|
||||
|
|
|
@ -234,7 +234,7 @@ public abstract class Contraption {
|
|||
return true;
|
||||
if (!BlockMovementTraits.movementNecessary(world, pos))
|
||||
return true;
|
||||
if (!BlockMovementTraits.movementAllowed(world, pos))
|
||||
if (!movementAllowed(world, pos))
|
||||
return false;
|
||||
BlockState state = world.getBlockState(pos);
|
||||
if (isChassis(state) && !moveChassis(world, pos, forcedDirection, frontier, visited))
|
||||
|
@ -344,7 +344,7 @@ public abstract class Contraption {
|
|||
BlockState blockState = world.getBlockState(offsetPos);
|
||||
if (isAnchoringBlockAt(offsetPos))
|
||||
continue;
|
||||
if (!BlockMovementTraits.movementAllowed(world, offsetPos)) {
|
||||
if (!movementAllowed(world, offsetPos)) {
|
||||
if (offset == forcedDirection && isSlimeBlock)
|
||||
return false;
|
||||
continue;
|
||||
|
@ -367,6 +367,10 @@ public abstract class Contraption {
|
|||
return blocks.size() <= AllConfigs.SERVER.kinetics.maxBlocksMoved.get();
|
||||
}
|
||||
|
||||
protected boolean movementAllowed(World world, BlockPos pos) {
|
||||
return BlockMovementTraits.movementAllowed(world, pos);
|
||||
}
|
||||
|
||||
protected boolean isAnchoringBlockAt(BlockPos pos) {
|
||||
return pos.equals(anchor);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static net.minecraft.entity.Entity.collideBoundingBoxHeuristically;
|
||||
import static net.minecraft.entity.Entity.horizontalMag;
|
||||
|
||||
|
@ -8,15 +7,12 @@ import java.lang.ref.WeakReference;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||
import org.apache.commons.lang3.mutable.MutableObject;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.content.contraptions.components.actors.BlockBreakingMovementBehaviour;
|
||||
|
@ -31,18 +27,11 @@ import com.simibubi.create.foundation.utility.VecHelper;
|
|||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.CocoaBlock;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.MoverType;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.Direction.AxisDirection;
|
||||
import net.minecraft.util.ReuseableStream;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
|
@ -54,78 +43,11 @@ import net.minecraft.util.math.shapes.VoxelShape;
|
|||
import net.minecraft.util.math.shapes.VoxelShapes;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
import net.minecraftforge.event.TickEvent.ClientTickEvent;
|
||||
import net.minecraftforge.event.TickEvent.Phase;
|
||||
import net.minecraftforge.event.TickEvent.WorldTickEvent;
|
||||
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
|
||||
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
|
||||
@EventBusSubscriber
|
||||
public class ContraptionCollider {
|
||||
|
||||
public static DamageSource damageSourceContraptionSuffocate =
|
||||
new DamageSource("create.contraption_suffocate").setDamageBypassesArmor();
|
||||
public static boolean wasClientPlayerGrounded;
|
||||
public static Cache<World, List<WeakReference<ContraptionEntity>>> activeContraptions = CacheBuilder.newBuilder()
|
||||
.expireAfterAccess(400, SECONDS)
|
||||
.build();
|
||||
|
||||
@SubscribeEvent
|
||||
public static void addSpawnedContraptionsToCollisionList(EntityJoinWorldEvent event) {
|
||||
Entity entity = event.getEntity();
|
||||
if (!(entity instanceof ContraptionEntity))
|
||||
return;
|
||||
try {
|
||||
List<WeakReference<ContraptionEntity>> list = activeContraptions.get(event.getWorld(), ArrayList::new);
|
||||
ContraptionEntity contraption = (ContraptionEntity) entity;
|
||||
list.add(new WeakReference<>(contraption));
|
||||
} catch (ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void playerCollisionHappensOnClientTick(ClientTickEvent event) {
|
||||
if (event.phase == Phase.START)
|
||||
return;
|
||||
ClientWorld world = Minecraft.getInstance().world;
|
||||
if (world == null)
|
||||
return;
|
||||
runCollisions(world);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void entityCollisionHappensPreWorldTick(WorldTickEvent event) {
|
||||
if (event.phase == Phase.END)
|
||||
return;
|
||||
World world = event.world;
|
||||
runCollisions(world);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void entitiesWhoJustDismountedGetSentToTheRightLocation(LivingUpdateEvent event) {
|
||||
LivingEntity entityLiving = event.getEntityLiving();
|
||||
if (entityLiving == null)
|
||||
return;
|
||||
if (entityLiving.world.isRemote)
|
||||
return;
|
||||
CompoundNBT data = entityLiving.getPersistentData();
|
||||
if (!data.contains("ContraptionDismountLocation"))
|
||||
return;
|
||||
Vec3d position = VecHelper.readNBT(data.getList("ContraptionDismountLocation", NBT.TAG_DOUBLE));
|
||||
if (entityLiving.getRidingEntity() == null)
|
||||
entityLiving.setPositionAndUpdate(position.x, position.y, position.z);
|
||||
data.remove("ContraptionDismountLocation");
|
||||
}
|
||||
|
||||
private static void runCollisions(World world) {
|
||||
List<WeakReference<ContraptionEntity>> list = activeContraptions.getIfPresent(world);
|
||||
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();) {
|
||||
|
@ -139,7 +61,7 @@ public class ContraptionCollider {
|
|||
}
|
||||
}
|
||||
|
||||
public static void collideEntities(ContraptionEntity contraptionEntity) {
|
||||
private static void collideEntities(ContraptionEntity contraptionEntity) {
|
||||
World world = contraptionEntity.getEntityWorld();
|
||||
Contraption contraption = contraptionEntity.getContraption();
|
||||
AxisAlignedBB bounds = contraptionEntity.getBoundingBox();
|
||||
|
@ -289,7 +211,7 @@ public class ContraptionCollider {
|
|||
entity.fallDistance = 0;
|
||||
entity.onGround = true;
|
||||
contraptionEntity.collidingEntities.add(entity);
|
||||
if (!serverPlayer)
|
||||
if (!serverPlayer)
|
||||
contactPointMotion = contraptionEntity.getContactPointMotion(entityPosition);
|
||||
}
|
||||
|
||||
|
@ -325,7 +247,7 @@ public class ContraptionCollider {
|
|||
entity.setPosition(entityPosition.x + allowedMovement.x, entityPosition.y + allowedMovement.y,
|
||||
entityPosition.z + allowedMovement.z);
|
||||
entity.setMotion(entityMotion);
|
||||
|
||||
|
||||
if (!serverPlayer && player)
|
||||
AllPackets.channel.sendToServer(new ClientMotionPacket(entityMotion, true));
|
||||
}
|
||||
|
@ -373,68 +295,7 @@ public class ContraptionCollider {
|
|||
return vec3d;
|
||||
}
|
||||
|
||||
public static void pushEntityOutOfShape(Entity entity, VoxelShape voxelShape, Vec3d positionOffset,
|
||||
Vec3d shapeMotion) {
|
||||
AxisAlignedBB entityBB = entity.getBoundingBox()
|
||||
.offset(positionOffset);
|
||||
Vec3d entityMotion = entity.getMotion();
|
||||
|
||||
if (!voxelShape.toBoundingBoxList()
|
||||
.stream()
|
||||
.anyMatch(entityBB::intersects))
|
||||
return;
|
||||
|
||||
AxisAlignedBB shapeBB = voxelShape.getBoundingBox();
|
||||
Direction bestSide = Direction.DOWN;
|
||||
double bestOffset = 100;
|
||||
double finalOffset = 0;
|
||||
|
||||
for (Direction face : Direction.values()) {
|
||||
Axis axis = face.getAxis();
|
||||
double d = axis == Axis.X ? entityBB.getXSize() + shapeBB.getXSize()
|
||||
: axis == Axis.Y ? entityBB.getYSize() + shapeBB.getYSize() : entityBB.getZSize() + shapeBB.getZSize();
|
||||
d = d + .5f;
|
||||
|
||||
Vec3d nudge = new Vec3d(face.getDirectionVec()).scale(d);
|
||||
AxisAlignedBB nudgedBB = entityBB.offset(nudge.getX(), nudge.getY(), nudge.getZ());
|
||||
double nudgeDistance = face.getAxisDirection() == AxisDirection.POSITIVE ? -d : d;
|
||||
double offset = voxelShape.getAllowedOffset(face.getAxis(), nudgedBB, nudgeDistance);
|
||||
double abs = Math.abs(nudgeDistance - offset);
|
||||
if (abs < Math.abs(bestOffset) && abs != 0) {
|
||||
bestOffset = abs;
|
||||
finalOffset = abs;
|
||||
bestSide = face;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestOffset != 0) {
|
||||
entity.move(MoverType.SELF, new Vec3d(bestSide.getDirectionVec()).scale(finalOffset));
|
||||
boolean positive = bestSide.getAxisDirection() == AxisDirection.POSITIVE;
|
||||
|
||||
double clamped;
|
||||
switch (bestSide.getAxis()) {
|
||||
case X:
|
||||
clamped = positive ? Math.max(shapeMotion.x, entityMotion.x) : Math.min(shapeMotion.x, entityMotion.x);
|
||||
entity.setMotion(clamped, entityMotion.y, entityMotion.z);
|
||||
break;
|
||||
case Y:
|
||||
clamped = positive ? Math.max(shapeMotion.y, entityMotion.y) : Math.min(shapeMotion.y, entityMotion.y);
|
||||
if (bestSide == Direction.UP)
|
||||
clamped = shapeMotion.y;
|
||||
entity.setMotion(entityMotion.x, clamped, entityMotion.z);
|
||||
entity.handleFallDamage(entity.fallDistance, 1);
|
||||
entity.fallDistance = 0;
|
||||
entity.onGround = true;
|
||||
break;
|
||||
case Z:
|
||||
clamped = positive ? Math.max(shapeMotion.z, entityMotion.z) : Math.min(shapeMotion.z, entityMotion.z);
|
||||
entity.setMotion(entityMotion.x, entityMotion.y, clamped);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ReuseableStream<VoxelShape> getPotentiallyCollidedShapes(World world, Contraption contraption,
|
||||
private static ReuseableStream<VoxelShape> getPotentiallyCollidedShapes(World world, Contraption contraption,
|
||||
AxisAlignedBB localBB) {
|
||||
|
||||
double height = localBB.getYSize();
|
||||
|
|
|
@ -17,6 +17,8 @@ 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.MountedContraption;
|
||||
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.MinecartCouplingHandler;
|
||||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
|
@ -30,6 +32,7 @@ import net.minecraft.entity.EntityType;
|
|||
import net.minecraft.entity.IProjectile;
|
||||
import net.minecraft.entity.item.BoatEntity;
|
||||
import net.minecraft.entity.item.HangingEntity;
|
||||
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
||||
import net.minecraft.entity.item.minecart.FurnaceMinecartEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
@ -69,6 +72,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
protected Vec3d motionBeforeStall;
|
||||
protected boolean stationary;
|
||||
protected boolean initialized;
|
||||
protected boolean onCoupling;
|
||||
final List<Entity> collidingEntities = new ArrayList<>();
|
||||
private boolean isSerializingFurnaceCart;
|
||||
|
||||
|
@ -105,10 +109,11 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
}
|
||||
|
||||
public static ContraptionEntity createMounted(World world, Contraption contraption, float initialAngle,
|
||||
Direction facing) {
|
||||
Direction facing, boolean onCoupling) {
|
||||
ContraptionEntity entity = createMounted(world, contraption, initialAngle);
|
||||
entity.forcedAngle = facing.getHorizontalAngle();
|
||||
entity.forceYaw(entity.forcedAngle);
|
||||
entity.onCoupling = onCoupling;
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
@ -197,7 +202,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
return;
|
||||
callback.accept(passenger, transformedVector.x, transformedVector.y, transformedVector.z);
|
||||
}
|
||||
|
||||
|
||||
protected Vec3d getPassengerPosition(Entity passenger) {
|
||||
AxisAlignedBB bb = passenger.getBoundingBox();
|
||||
double ySize = bb.getYSize();
|
||||
|
@ -308,14 +313,33 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
boolean rotationLock = false;
|
||||
boolean pauseWhileRotating = false;
|
||||
|
||||
if (contraption instanceof MountedContraption) {
|
||||
rotationLock = ((MountedContraption) contraption).rotationMode == CartMovementMode.ROTATION_LOCKED;
|
||||
pauseWhileRotating = ((MountedContraption) contraption).rotationMode == CartMovementMode.ROTATE_PAUSED;
|
||||
}
|
||||
|
||||
Entity riding = e;
|
||||
while (riding.getRidingEntity() != null)
|
||||
riding = riding.getRidingEntity();
|
||||
|
||||
if (contraption instanceof MountedContraption) {
|
||||
MountedContraption mountedContraption = (MountedContraption) contraption;
|
||||
if (onCoupling && riding instanceof AbstractMinecartEntity) {
|
||||
MinecartCoupling coupling = MinecartCouplingHandler.getCoupling(world, riding.getUniqueID());
|
||||
if (coupling != null && coupling.areBothEndsPresent()) {
|
||||
Vec3d positionVec = coupling.asCouple()
|
||||
.getSecond()
|
||||
.getPositionVec();
|
||||
prevYaw = yaw;
|
||||
prevPitch = pitch;
|
||||
double diffZ = positionVec.z - getZ();
|
||||
double diffX = positionVec.x - getX();
|
||||
yaw = 90 + (float) (MathHelper.atan2(diffZ, diffX) * 180 / Math.PI);
|
||||
pitch = (float) (Math.atan2(positionVec.y - getY(), Math.sqrt(diffX * diffX + diffZ * diffZ)) * 180
|
||||
/ Math.PI);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rotationLock = mountedContraption.rotationMode == CartMovementMode.ROTATION_LOCKED;
|
||||
pauseWhileRotating = mountedContraption.rotationMode == CartMovementMode.ROTATE_PAUSED;
|
||||
}
|
||||
|
||||
Vec3d movementVector = riding.getMotion();
|
||||
if (riding instanceof BoatEntity)
|
||||
movementVector = getPositionVec().subtract(prevPosX, prevPosY, prevPosZ);
|
||||
|
@ -355,12 +379,12 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
|
||||
if (!isStalled() && (riding instanceof FurnaceMinecartEntity)) {
|
||||
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");
|
||||
|
@ -560,6 +584,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
@Override
|
||||
protected void readAdditional(CompoundNBT compound) {
|
||||
initialized = compound.getBoolean("Initialized");
|
||||
onCoupling = compound.getBoolean("OnCoupling");
|
||||
contraption = Contraption.fromNBT(world, compound.getCompound("Contraption"));
|
||||
initialAngle = compound.getFloat("InitialAngle");
|
||||
forceYaw(compound.contains("ForcedYaw") ? compound.getFloat("ForcedYaw") : initialAngle);
|
||||
|
@ -611,6 +636,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
compound.putFloat("InitialAngle", initialAngle);
|
||||
compound.putBoolean("Stalled", isStalled());
|
||||
compound.putBoolean("Initialized", initialized);
|
||||
compound.putBoolean("OnCoupling", onCoupling);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -682,7 +708,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
public CompoundNBT writeWithoutTypeId(CompoundNBT nbt) {
|
||||
if (isSerializingFurnaceCart)
|
||||
return nbt;
|
||||
|
||||
|
||||
Vec3d vec = getPositionVec();
|
||||
List<Entity> passengers = getPassengers();
|
||||
|
||||
|
@ -802,6 +828,8 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
return false;
|
||||
if (e instanceof HangingEntity)
|
||||
return false;
|
||||
if (e instanceof AbstractMinecartEntity)
|
||||
return false;
|
||||
if (e instanceof SuperGlueEntity)
|
||||
return false;
|
||||
if (e instanceof SeatEntity)
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
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 net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
|
||||
public class ContraptionHandler {
|
||||
|
||||
public static Cache<World, List<WeakReference<ContraptionEntity>>> activeContraptions = CacheBuilder.newBuilder()
|
||||
.expireAfterAccess(400, SECONDS)
|
||||
.build();
|
||||
|
||||
public static void addSpawnedContraptionsToCollisionList(Entity entity, World world) {
|
||||
if (!(entity instanceof ContraptionEntity))
|
||||
return;
|
||||
try {
|
||||
List<WeakReference<ContraptionEntity>> list = activeContraptions.get(world, ArrayList::new);
|
||||
ContraptionEntity contraption = (ContraptionEntity) entity;
|
||||
list.add(new WeakReference<>(contraption));
|
||||
} catch (ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void entitiesWhoJustDismountedGetSentToTheRightLocation(LivingEntity entityLiving, World world) {
|
||||
if (world.isRemote)
|
||||
return;
|
||||
CompoundNBT data = entityLiving.getPersistentData();
|
||||
if (!data.contains("ContraptionDismountLocation"))
|
||||
return;
|
||||
Vec3d position = VecHelper.readNBT(data.getList("ContraptionDismountLocation", NBT.TAG_DOUBLE));
|
||||
if (entityLiving.getRidingEntity() == null)
|
||||
entityLiving.setPositionAndUpdate(position.x, position.y, position.z);
|
||||
data.remove("ContraptionDismountLocation");
|
||||
}
|
||||
|
||||
}
|
|
@ -11,6 +11,7 @@ import com.simibubi.create.AllShapes;
|
|||
import com.simibubi.create.AllTileEntities;
|
||||
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.train.MinecartCouplingHandler;
|
||||
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
|
||||
import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement;
|
||||
import com.simibubi.create.content.schematics.ItemRequirement;
|
||||
|
@ -111,7 +112,7 @@ public class CartAssemblerBlock extends AbstractRailBlock
|
|||
@Override
|
||||
public void onMinecartPass(@Nonnull BlockState state, @Nonnull World world, @Nonnull BlockPos pos,
|
||||
AbstractMinecartEntity cart) {
|
||||
if (!cart.canBeRidden() && !(cart instanceof FurnaceMinecartEntity))
|
||||
if (!canAssembleTo(cart))
|
||||
return;
|
||||
|
||||
withTileEntityDo(world, pos, te -> {
|
||||
|
@ -163,6 +164,10 @@ public class CartAssemblerBlock extends AbstractRailBlock
|
|||
});
|
||||
}
|
||||
|
||||
public static boolean canAssembleTo(AbstractMinecartEntity cart) {
|
||||
return cart.canBeRidden() || cart instanceof FurnaceMinecartEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public ActionResultType onUse(@Nonnull BlockState state, @Nonnull World world, @Nonnull BlockPos pos,
|
||||
|
@ -207,7 +212,12 @@ public class CartAssemblerBlock extends AbstractRailBlock
|
|||
float initialAngle = facing.getHorizontalAngle();
|
||||
|
||||
withTileEntityDo(world, pos, te -> contraption.rotationMode = CartMovementMode.values()[te.movementMode.value]);
|
||||
ContraptionEntity entity = ContraptionEntity.createMounted(world, contraption, initialAngle, facing);
|
||||
boolean couplingFound = contraption.connectedCart != null;
|
||||
if (couplingFound)
|
||||
MinecartCouplingHandler.connectCarts(null, world, cart.getEntityId(),
|
||||
contraption.connectedCart.getEntityId());
|
||||
ContraptionEntity entity =
|
||||
ContraptionEntity.createMounted(world, contraption, initialAngle, facing, couplingFound);
|
||||
entity.setPosition(pos.getX(), pos.getY(), pos.getZ());
|
||||
world.addEntity(entity);
|
||||
entity.startRiding(cart);
|
||||
|
|
|
@ -159,7 +159,8 @@ public class MinecartContraptionItem extends Item {
|
|||
ContraptionEntity contraption;
|
||||
|
||||
if (newFacing != null)
|
||||
contraption = ContraptionEntity.createMounted(world, mountedContraption, initialAngle, newFacing);
|
||||
contraption =
|
||||
ContraptionEntity.createMounted(world, mountedContraption, initialAngle, newFacing, false);
|
||||
else
|
||||
contraption = ContraptionEntity.createMounted(world, mountedContraption, initialAngle);
|
||||
|
||||
|
@ -212,8 +213,7 @@ public class MinecartContraptionItem extends Item {
|
|||
|
||||
public static ItemStack create(Type type, ContraptionEntity entity) {
|
||||
ItemStack stack =
|
||||
(type == Type.RIDEABLE ? AllItems.MINECART_CONTRAPTION : AllItems.FURNACE_MINECART_CONTRAPTION)
|
||||
.asStack();
|
||||
(type == Type.RIDEABLE ? AllItems.MINECART_CONTRAPTION : AllItems.FURNACE_MINECART_CONTRAPTION).asStack();
|
||||
CompoundNBT tag = entity.getContraption()
|
||||
.writeNBT();
|
||||
tag.remove("UUID");
|
||||
|
|
|
@ -10,15 +10,19 @@ import com.simibubi.create.AllBlocks;
|
|||
import com.simibubi.create.content.contraptions.components.structureMovement.AllContraptionTypes;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.state.properties.RailShape;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.World;
|
||||
|
@ -27,6 +31,7 @@ import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
|||
public class MountedContraption extends Contraption {
|
||||
|
||||
public CartMovementMode rotationMode;
|
||||
public AbstractMinecartEntity connectedCart;
|
||||
|
||||
public MountedContraption() {
|
||||
rotationMode = CartMovementMode.ROTATE;
|
||||
|
@ -70,12 +75,34 @@ public class MountedContraption extends Contraption {
|
|||
protected Pair<BlockInfo, TileEntity> capture(World world, BlockPos pos) {
|
||||
Pair<BlockInfo, TileEntity> pair = super.capture(world, pos);
|
||||
BlockInfo capture = pair.getKey();
|
||||
if (AllBlocks.CART_ASSEMBLER.has(capture.state))
|
||||
return Pair.of(new BlockInfo(capture.pos, CartAssemblerBlock.createAnchor(capture.state), null),
|
||||
pair.getValue());
|
||||
if (AllBlocks.CART_ASSEMBLER.has(capture.state)) {
|
||||
if (!pos.equals(anchor)) {
|
||||
for (Axis axis : Iterate.axes) {
|
||||
if (axis.isVertical())
|
||||
continue;
|
||||
if (VecHelper.onSameAxis(anchor, pos, axis) && connectedCart == null) {
|
||||
for (AbstractMinecartEntity abstractMinecartEntity : world
|
||||
.getEntitiesWithinAABB(AbstractMinecartEntity.class, new AxisAlignedBB(pos))) {
|
||||
if (!CartAssemblerBlock.canAssembleTo(abstractMinecartEntity))
|
||||
break;
|
||||
connectedCart = abstractMinecartEntity;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Pair.of(new BlockInfo(pos, CartAssemblerBlock.createAnchor(capture.state), null), pair.getValue());
|
||||
}
|
||||
return pair;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean movementAllowed(World world, BlockPos pos) {
|
||||
BlockState blockState = world.getBlockState(pos);
|
||||
if (!pos.equals(anchor) && AllBlocks.CART_ASSEMBLER.has(blockState))
|
||||
return true;
|
||||
return super.movementAllowed(world, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundNBT writeNBT() {
|
||||
CompoundNBT writeNBT = super.writeNBT();
|
||||
|
@ -93,7 +120,7 @@ public class MountedContraption extends Contraption {
|
|||
protected boolean customBlockPlacement(IWorld world, BlockPos pos, BlockState state) {
|
||||
return AllBlocks.MINECART_ANCHOR.has(state);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean customBlockRemoval(IWorld world, BlockPos pos, BlockState state) {
|
||||
return pos.equals(anchor);
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement.train;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.entity.player.ClientPlayerEntity;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.particles.IParticleData;
|
||||
import net.minecraft.particles.ParticleTypes;
|
||||
import net.minecraft.particles.RedstoneParticleData;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class ClientMinecartCouplingHandler {
|
||||
|
||||
static AbstractMinecartEntity selectedCart;
|
||||
static Random r = new Random();
|
||||
|
||||
public static void tick() {
|
||||
if (selectedCart == null)
|
||||
return;
|
||||
spawnSelectionParticles(selectedCart.getBoundingBox(), false);
|
||||
ClientPlayerEntity player = Minecraft.getInstance().player;
|
||||
ItemStack heldItemMainhand = player.getHeldItemMainhand();
|
||||
ItemStack heldItemOffhand = player.getHeldItemOffhand();
|
||||
if (AllItems.MINECART_COUPLING.isIn(heldItemMainhand) || AllItems.MINECART_COUPLING.isIn(heldItemOffhand))
|
||||
return;
|
||||
selectedCart = null;
|
||||
}
|
||||
|
||||
static void onCartClicked(PlayerEntity player, AbstractMinecartEntity entity) {
|
||||
if (Minecraft.getInstance().player != player)
|
||||
return;
|
||||
if (selectedCart == null || selectedCart == entity) {
|
||||
selectedCart = entity;
|
||||
spawnSelectionParticles(selectedCart.getBoundingBox(), true);
|
||||
return;
|
||||
}
|
||||
spawnSelectionParticles(entity.getBoundingBox(), true);
|
||||
AllPackets.channel.sendToServer(new MinecartCouplingCreationPacket(selectedCart, entity));
|
||||
selectedCart = null;
|
||||
}
|
||||
|
||||
static void sneakClick() {
|
||||
selectedCart = null;
|
||||
}
|
||||
|
||||
private static void spawnSelectionParticles(AxisAlignedBB axisAlignedBB, boolean highlight) {
|
||||
ClientWorld world = Minecraft.getInstance().world;
|
||||
Vec3d center = axisAlignedBB.getCenter();
|
||||
int amount = highlight ? 100 : 2;
|
||||
IParticleData particleData = highlight ? ParticleTypes.END_ROD : new RedstoneParticleData(1, 1, 1, 1);
|
||||
for (int i = 0; i < amount; i++) {
|
||||
Vec3d v = VecHelper.offsetRandomly(Vec3d.ZERO, r, 1);
|
||||
double yOffset = v.y;
|
||||
v = v.mul(1, 0, 1)
|
||||
.normalize()
|
||||
.add(0, yOffset / 8f, 0)
|
||||
.add(center);
|
||||
world.addParticle(particleData, v.x, v.y, v.z, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
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());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement.train;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||
|
||||
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraftforge.fml.network.NetworkEvent.Context;
|
||||
|
||||
public class MinecartCouplingCreationPacket extends SimplePacketBase {
|
||||
|
||||
int id1, id2;
|
||||
|
||||
public MinecartCouplingCreationPacket(AbstractMinecartEntity cart1, AbstractMinecartEntity cart2) {
|
||||
id1 = cart1.getEntityId();
|
||||
id2 = cart2.getEntityId();
|
||||
}
|
||||
|
||||
public MinecartCouplingCreationPacket(PacketBuffer buffer) {
|
||||
id1 = buffer.readInt();
|
||||
id2 = buffer.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(PacketBuffer buffer) {
|
||||
buffer.writeInt(id1);
|
||||
buffer.writeInt(id2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Supplier<Context> context) {
|
||||
context.get()
|
||||
.enqueueWork(() -> {
|
||||
ServerPlayerEntity sender = context.get()
|
||||
.getSender();
|
||||
if (sender != null)
|
||||
MinecartCouplingHandler.connectCarts(sender, sender.world, id1, id2);
|
||||
});
|
||||
context.get()
|
||||
.setPacketHandled(true);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,383 @@
|
|||
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.train.MinecartCouplingSerializer.CouplingData;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
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());
|
||||
coupling.flip();
|
||||
map.put(coupling.getId(), coupling);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement.train;
|
||||
|
||||
import com.simibubi.create.AllItems;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ActionResultType;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
|
||||
@EventBusSubscriber
|
||||
public class MinecartCouplingItem extends Item {
|
||||
|
||||
public MinecartCouplingItem(Properties p_i48487_1_) {
|
||||
super(p_i48487_1_);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void couplingItemCanBeUsedOnMinecarts(PlayerInteractEvent.EntityInteract event) {
|
||||
Entity interacted = event.getTarget();
|
||||
if (!(interacted instanceof AbstractMinecartEntity))
|
||||
return;
|
||||
AbstractMinecartEntity minecart = (AbstractMinecartEntity) interacted;
|
||||
PlayerEntity player = event.getPlayer();
|
||||
if (player == null)
|
||||
return;
|
||||
ItemStack heldItem = player.getHeldItem(event.getHand());
|
||||
if (!AllItems.MINECART_COUPLING.isIn(heldItem))
|
||||
return;
|
||||
|
||||
World world = event.getWorld();
|
||||
if (MinecartCouplingSerializer.getCouplingData(minecart).size() < 2) {
|
||||
if (world != null && world.isRemote)
|
||||
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> cartClicked(player, minecart));
|
||||
}
|
||||
|
||||
event.setCanceled(true);
|
||||
event.setCancellationResult(ActionResultType.SUCCESS);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private static void cartClicked(PlayerEntity player, AbstractMinecartEntity interacted) {
|
||||
ClientMinecartCouplingHandler.onCartClicked(player, (AbstractMinecartEntity) interacted);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement.train;
|
||||
|
||||
import static net.minecraft.util.math.MathHelper.lerp;
|
||||
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||
import com.simibubi.create.AllBlockPartials;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.MatrixStacker;
|
||||
import com.simibubi.create.foundation.utility.SuperByteBuffer;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.Vector3f;
|
||||
import net.minecraft.client.renderer.WorldRenderer;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class MinecartCouplingRenderer {
|
||||
|
||||
public static void renderCoupling(MatrixStack ms, IRenderTypeBuffer buffer, MinecartCoupling coupling) {
|
||||
if (!coupling.areBothEndsPresent())
|
||||
return;
|
||||
ClientWorld world = Minecraft.getInstance().world;
|
||||
Couple<AbstractMinecartEntity> carts = coupling.asCouple();
|
||||
Couple<Integer> lightValues =
|
||||
carts.map(c -> WorldRenderer.getLightmapCoordinates(world, new BlockPos(c.getBoundingBox()
|
||||
.getCenter())));
|
||||
|
||||
Vec3d center = carts.getFirst()
|
||||
.getPositionVec()
|
||||
.add(carts.getSecond()
|
||||
.getPositionVec())
|
||||
.scale(.5f);
|
||||
|
||||
Couple<CartEndpoint> transforms = carts.map(c -> getSuitableCartEndpoint(c, center));
|
||||
|
||||
BlockState renderState = Blocks.AIR.getDefaultState();
|
||||
IVertexBuilder builder = buffer.getBuffer(RenderType.getSolid());
|
||||
SuperByteBuffer attachment = AllBlockPartials.COUPLING_ATTACHMENT.renderOn(renderState);
|
||||
SuperByteBuffer ring = AllBlockPartials.COUPLING_RING.renderOn(renderState);
|
||||
SuperByteBuffer connector = AllBlockPartials.COUPLING_CONNECTOR.renderOn(renderState);
|
||||
|
||||
Vec3d zero = Vec3d.ZERO;
|
||||
Vec3d firstEndpoint = transforms.getFirst()
|
||||
.apply(zero);
|
||||
Vec3d secondEndpoint = transforms.getSecond()
|
||||
.apply(zero);
|
||||
Vec3d endPointDiff = secondEndpoint.subtract(firstEndpoint);
|
||||
double connectorYaw = -Math.atan2(endPointDiff.z, endPointDiff.x) * 180.0D / Math.PI;
|
||||
double connectorPitch = Math.atan2(endPointDiff.y, endPointDiff.mul(1, 0, 1)
|
||||
.length()) * 180 / Math.PI;
|
||||
|
||||
MatrixStacker msr = MatrixStacker.of(ms);
|
||||
carts.forEachWithContext((cart, isFirst) -> {
|
||||
CartEndpoint cartTransform = transforms.get(isFirst);
|
||||
|
||||
ms.push();
|
||||
cartTransform.apply(ms);
|
||||
attachment.light(lightValues.get(isFirst))
|
||||
.renderInto(ms, builder);
|
||||
msr.rotateY(connectorYaw - cartTransform.yaw);
|
||||
ring.light(lightValues.get(isFirst))
|
||||
.renderInto(ms, builder);
|
||||
ms.pop();
|
||||
});
|
||||
|
||||
int l1 = lightValues.getFirst();
|
||||
int l2 = lightValues.getSecond();
|
||||
int meanBlockLight = (((l1 >> 4) & 0xf) + ((l2 >> 4) & 0xf)) / 2;
|
||||
int meanSkyLight = (((l1 >> 20) & 0xf) + ((l2 >> 20) & 0xf)) / 2;
|
||||
|
||||
ms.push();
|
||||
msr.translate(firstEndpoint)
|
||||
.rotateY(connectorYaw)
|
||||
.rotateZ(connectorPitch);
|
||||
ms.scale((float) endPointDiff.length(), 1, 1);
|
||||
|
||||
connector.light(meanSkyLight << 20 | meanBlockLight << 4)
|
||||
.renderInto(ms, builder);
|
||||
ms.pop();
|
||||
}
|
||||
|
||||
private static CartEndpoint getSuitableCartEndpoint(AbstractMinecartEntity cart, Vec3d centerOfCoupling) {
|
||||
long i = cart.getEntityId() * 493286711L;
|
||||
i = i * i * 4392167121L + i * 98761L;
|
||||
float x = (((float) (i >> 16 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F;
|
||||
float y = (((float) (i >> 20 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F + 0.375F;
|
||||
float z = (((float) (i >> 24 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F;
|
||||
|
||||
float pt = Minecraft.getInstance()
|
||||
.getRenderPartialTicks();
|
||||
|
||||
double xIn = lerp(pt, cart.lastTickPosX, cart.getX());
|
||||
double yIn = lerp(pt, cart.lastTickPosY, cart.getY());
|
||||
double zIn = lerp(pt, cart.lastTickPosZ, cart.getZ());
|
||||
|
||||
float yaw = lerp(pt, cart.prevRotationYaw, cart.rotationYaw);
|
||||
float pitch = lerp(pt, cart.prevRotationPitch, cart.rotationPitch);
|
||||
float roll = cart.getRollingAmplitude() - pt;
|
||||
|
||||
float rollAmplifier = cart.getDamage() - pt;
|
||||
if (rollAmplifier < 0.0F)
|
||||
rollAmplifier = 0.0F;
|
||||
roll = roll > 0 ? MathHelper.sin(roll) * roll * rollAmplifier / 10.0F * cart.getRollingDirection() : 0;
|
||||
|
||||
Vec3d positionVec = new Vec3d(xIn, yIn, zIn);
|
||||
Vec3d frontVec = positionVec.add(VecHelper.rotate(new Vec3d(.5, 0, 0), 180 - yaw, Axis.Y));
|
||||
Vec3d backVec = positionVec.add(VecHelper.rotate(new Vec3d(-.5, 0, 0), 180 - yaw, Axis.Y));
|
||||
|
||||
Vec3d railVecOfPos = cart.getPos(xIn, yIn, zIn);
|
||||
boolean flip = false;
|
||||
|
||||
if (railVecOfPos != null) {
|
||||
frontVec = cart.getPosOffset(xIn, yIn, zIn, (double) 0.3F);
|
||||
backVec = cart.getPosOffset(xIn, yIn, zIn, (double) -0.3F);
|
||||
if (frontVec == null)
|
||||
frontVec = railVecOfPos;
|
||||
if (backVec == null)
|
||||
backVec = railVecOfPos;
|
||||
|
||||
x += railVecOfPos.x;
|
||||
y += (frontVec.y + backVec.y) / 2;
|
||||
z += railVecOfPos.z;
|
||||
|
||||
Vec3d endPointDiff = backVec.add(-frontVec.x, -frontVec.y, -frontVec.z);
|
||||
if (endPointDiff.length() != 0.0D) {
|
||||
endPointDiff = endPointDiff.normalize();
|
||||
yaw = (float) (Math.atan2(endPointDiff.z, endPointDiff.x) * 180.0D / Math.PI);
|
||||
pitch = (float) (Math.atan(endPointDiff.y) * 73.0D);
|
||||
}
|
||||
} else {
|
||||
x += xIn;
|
||||
y += yIn;
|
||||
z += zIn;
|
||||
}
|
||||
|
||||
final float offsetMagnitude = 13 / 16f;
|
||||
boolean isBackFaceCloser =
|
||||
frontVec.squareDistanceTo(centerOfCoupling) > backVec.squareDistanceTo(centerOfCoupling);
|
||||
flip = isBackFaceCloser;
|
||||
float offset = isBackFaceCloser ? -offsetMagnitude : offsetMagnitude;
|
||||
|
||||
return new CartEndpoint(x, y + 2 / 16f, z, 180 - yaw, -pitch, roll, offset, flip);
|
||||
}
|
||||
|
||||
static class CartEndpoint {
|
||||
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float yaw;
|
||||
float pitch;
|
||||
float roll;
|
||||
float offset;
|
||||
boolean flip;
|
||||
|
||||
public CartEndpoint(float x, float y, float z, float yaw, float pitch, float roll, float offset, boolean flip) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.yaw = yaw;
|
||||
this.pitch = pitch;
|
||||
this.roll = roll;
|
||||
this.offset = offset;
|
||||
this.flip = flip;
|
||||
}
|
||||
|
||||
public Vec3d apply(Vec3d vec) {
|
||||
vec = vec.add(offset, 0, 0);
|
||||
vec = VecHelper.rotate(vec, roll, Axis.X);
|
||||
vec = VecHelper.rotate(vec, pitch, Axis.Z);
|
||||
vec = VecHelper.rotate(vec, yaw, Axis.Y);
|
||||
return vec.add(x, y, z);
|
||||
}
|
||||
|
||||
public void apply(MatrixStack ms) {
|
||||
ms.translate(x, y, z);
|
||||
ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(yaw));
|
||||
ms.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(pitch));
|
||||
ms.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(roll));
|
||||
ms.translate(offset, 0, 0);
|
||||
if (flip)
|
||||
ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(180));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement.train;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
|
||||
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.nbt.NBTUtil;
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
|
||||
public class MinecartCouplingSerializer {
|
||||
|
||||
public static void addCouplingToCart(AbstractMinecartEntity minecart, MinecartCoupling coupling) {
|
||||
CompoundNBT nbt = minecart.getPersistentData();
|
||||
ListNBT couplingList = nbt.getList("Couplings", NBT.TAG_COMPOUND);
|
||||
boolean main = coupling.mainCart.get() == minecart;
|
||||
couplingList.add(createCouplingTag(main, coupling));
|
||||
nbt.put("Couplings", couplingList);
|
||||
}
|
||||
|
||||
public static void removeCouplingFromCart(AbstractMinecartEntity minecart, MinecartCoupling coupling) {
|
||||
CompoundNBT nbt = minecart.getPersistentData();
|
||||
ListNBT couplingList = nbt.getList("Couplings", NBT.TAG_COMPOUND);
|
||||
couplingList.removeIf(inbt -> coupling.getId()
|
||||
.equals(NBTUtil.readUniqueId(((CompoundNBT) inbt).getCompound("Id"))));
|
||||
nbt.put("Couplings", couplingList);
|
||||
}
|
||||
|
||||
private static CompoundNBT createCouplingTag(boolean main, MinecartCoupling coupling) {
|
||||
CompoundNBT nbt = new CompoundNBT();
|
||||
nbt.put("Id", NBTUtil.writeUniqueId(coupling.getId()));
|
||||
nbt.putBoolean("Main", main);
|
||||
nbt.putDouble("Length", coupling.length);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public static List<CouplingData> getCouplingData(AbstractMinecartEntity minecart) {
|
||||
List<CouplingData> list = new ArrayList<>();
|
||||
CompoundNBT nbt = minecart.getPersistentData();
|
||||
NBTHelper.iterateCompoundList(nbt.getList("Couplings", NBT.TAG_COMPOUND), c -> {
|
||||
boolean main = c.getBoolean("Main");
|
||||
UUID id = NBTUtil.readUniqueId(c.getCompound("Id"));
|
||||
double length = c.getDouble("Length");
|
||||
list.add(new CouplingData(main, id, length));
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
static class CouplingData {
|
||||
boolean main;
|
||||
UUID id;
|
||||
double length;
|
||||
|
||||
public CouplingData(boolean main, UUID id, double length) {
|
||||
this.main = main;
|
||||
this.id = id;
|
||||
this.length = length;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,224 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement.train;
|
||||
|
||||
import static net.minecraft.entity.Entity.horizontalMag;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
|
||||
|
||||
import net.minecraft.block.AbstractRailBlock;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
||||
import net.minecraft.entity.item.minecart.ContainerMinecartEntity;
|
||||
import net.minecraft.entity.item.minecart.FurnaceMinecartEntity;
|
||||
import net.minecraft.inventory.container.Container;
|
||||
import net.minecraft.state.properties.RailShape;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Util;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
|
||||
public class MinecartSim2020 {
|
||||
|
||||
private static final Map<RailShape, Pair<Vec3i, Vec3i>> MATRIX =
|
||||
Util.make(Maps.newEnumMap(RailShape.class), (p_226574_0_) -> {
|
||||
Vec3i vec3i = Direction.WEST.getDirectionVec();
|
||||
Vec3i vec3i1 = Direction.EAST.getDirectionVec();
|
||||
Vec3i vec3i2 = Direction.NORTH.getDirectionVec();
|
||||
Vec3i vec3i3 = Direction.SOUTH.getDirectionVec();
|
||||
Vec3i vec3i4 = vec3i.down();
|
||||
Vec3i vec3i5 = vec3i1.down();
|
||||
Vec3i vec3i6 = vec3i2.down();
|
||||
Vec3i vec3i7 = vec3i3.down();
|
||||
p_226574_0_.put(RailShape.NORTH_SOUTH, Pair.of(vec3i2, vec3i3));
|
||||
p_226574_0_.put(RailShape.EAST_WEST, Pair.of(vec3i, vec3i1));
|
||||
p_226574_0_.put(RailShape.ASCENDING_EAST, Pair.of(vec3i4, vec3i1));
|
||||
p_226574_0_.put(RailShape.ASCENDING_WEST, Pair.of(vec3i, vec3i5));
|
||||
p_226574_0_.put(RailShape.ASCENDING_NORTH, Pair.of(vec3i2, vec3i7));
|
||||
p_226574_0_.put(RailShape.ASCENDING_SOUTH, Pair.of(vec3i6, vec3i3));
|
||||
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 Vec3d predictMotionOf(AbstractMinecartEntity cart) {
|
||||
|
||||
if (cart instanceof FurnaceMinecartEntity) {
|
||||
return cart.getPositionVec()
|
||||
.subtract(cart.lastTickPosX, cart.lastTickPosY, cart.lastTickPosZ);
|
||||
}
|
||||
if (cart instanceof ContainerMinecartEntity) {
|
||||
ContainerMinecartEntity containerCart = (ContainerMinecartEntity) cart;
|
||||
float f = 0.98F;
|
||||
if (containerCart.isEmpty())
|
||||
return cart.getMotion()
|
||||
.mul(f, 0.0D, f);
|
||||
int i = 15 - Container.calcRedstoneFromInventory(containerCart);
|
||||
f += (float) i * 0.001F;
|
||||
return cart.getMotion()
|
||||
.mul(f, 0.0D, f);
|
||||
}
|
||||
return cart.getMotion()
|
||||
.scale(cart.isBeingRidden() ? 0.997D : 0.96D);
|
||||
}
|
||||
|
||||
public static boolean canAddMotion(AbstractMinecartEntity c) {
|
||||
if (c instanceof FurnaceMinecartEntity)
|
||||
return MathHelper.epsilonEquals(((FurnaceMinecartEntity) c).pushX, 0)
|
||||
&& MathHelper.epsilonEquals(((FurnaceMinecartEntity) c).pushZ, 0);
|
||||
List<Entity> passengers = c.getPassengers();
|
||||
if (passengers.isEmpty())
|
||||
return true;
|
||||
for (Entity entity : passengers) {
|
||||
if (entity instanceof ContraptionEntity) {
|
||||
ContraptionEntity contraptionEntity = (ContraptionEntity) entity;
|
||||
return !contraptionEntity.isStalled();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void moveCartAlongTrack(AbstractMinecartEntity cart, Vec3d forcedMovement, BlockPos cartPos,
|
||||
BlockState trackState) {
|
||||
|
||||
if (forcedMovement.equals(Vec3d.ZERO))
|
||||
return;
|
||||
|
||||
Vec3d previousMotion = cart.getMotion();
|
||||
cart.fallDistance = 0.0F;
|
||||
|
||||
double x = cart.getX();
|
||||
double y = cart.getY();
|
||||
double z = cart.getZ();
|
||||
|
||||
double actualX = x;
|
||||
double actualY = y;
|
||||
double actualZ = z;
|
||||
|
||||
Vec3d actualVec = cart.getPos(actualX, actualY, actualZ);
|
||||
actualY = cartPos.getY() + 1;
|
||||
|
||||
AbstractRailBlock abstractrailblock = (AbstractRailBlock) trackState.getBlock();
|
||||
RailShape railshape = abstractrailblock.getRailDirection(trackState, cart.world, cartPos, cart);
|
||||
switch (railshape) {
|
||||
case ASCENDING_EAST:
|
||||
forcedMovement = forcedMovement.add(-1 * cart.getSlopeAdjustment(), 0.0D, 0.0D);
|
||||
actualY++;
|
||||
break;
|
||||
case ASCENDING_WEST:
|
||||
forcedMovement = forcedMovement.add(cart.getSlopeAdjustment(), 0.0D, 0.0D);
|
||||
actualY++;
|
||||
break;
|
||||
case ASCENDING_NORTH:
|
||||
forcedMovement = forcedMovement.add(0.0D, 0.0D, cart.getSlopeAdjustment());
|
||||
actualY++;
|
||||
break;
|
||||
case ASCENDING_SOUTH:
|
||||
forcedMovement = forcedMovement.add(0.0D, 0.0D, -1 * cart.getSlopeAdjustment());
|
||||
actualY++;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Pair<Vec3i, Vec3i> pair = MATRIX.get(railshape);
|
||||
Vec3i vec3i = pair.getFirst();
|
||||
Vec3i vec3i1 = pair.getSecond();
|
||||
double d4 = (double) (vec3i1.getX() - vec3i.getX());
|
||||
double d5 = (double) (vec3i1.getZ() - vec3i.getZ());
|
||||
// double d6 = Math.sqrt(d4 * d4 + d5 * d5);
|
||||
double d7 = forcedMovement.x * d4 + forcedMovement.z * d5;
|
||||
if (d7 < 0.0D) {
|
||||
d4 = -d4;
|
||||
d5 = -d5;
|
||||
}
|
||||
|
||||
double d23 = (double) cartPos.getX() + 0.5D + (double) vec3i.getX() * 0.5D;
|
||||
double d10 = (double) cartPos.getZ() + 0.5D + (double) vec3i.getZ() * 0.5D;
|
||||
double d12 = (double) cartPos.getX() + 0.5D + (double) vec3i1.getX() * 0.5D;
|
||||
double d13 = (double) cartPos.getZ() + 0.5D + (double) vec3i1.getZ() * 0.5D;
|
||||
d4 = d12 - d23;
|
||||
d5 = d13 - d10;
|
||||
double d14;
|
||||
if (d4 == 0.0D) {
|
||||
d14 = actualZ - (double) cartPos.getZ();
|
||||
} else if (d5 == 0.0D) {
|
||||
d14 = actualX - (double) cartPos.getX();
|
||||
} else {
|
||||
double d15 = actualX - d23;
|
||||
double d16 = actualZ - d10;
|
||||
d14 = (d15 * d4 + d16 * d5) * 2.0D;
|
||||
}
|
||||
|
||||
actualX = d23 + d4 * d14;
|
||||
actualZ = d10 + d5 * d14;
|
||||
|
||||
cart.setPosition(actualX, actualY, actualZ);
|
||||
cart.setMotion(forcedMovement);
|
||||
cart.moveMinecartOnRail(cartPos);
|
||||
|
||||
x = cart.getX();
|
||||
y = cart.getY();
|
||||
z = cart.getZ();
|
||||
|
||||
if (vec3i.getY() != 0 && MathHelper.floor(x) - cartPos.getX() == vec3i.getX()
|
||||
&& MathHelper.floor(z) - cartPos.getZ() == vec3i.getZ()) {
|
||||
cart.setPosition(x, y + (double) vec3i.getY(), z);
|
||||
} else if (vec3i1.getY() != 0 && MathHelper.floor(x) - cartPos.getX() == vec3i1.getX()
|
||||
&& MathHelper.floor(z) - cartPos.getZ() == vec3i1.getZ()) {
|
||||
cart.setPosition(x, y + (double) vec3i1.getY(), z);
|
||||
}
|
||||
|
||||
x = cart.getX();
|
||||
y = cart.getY();
|
||||
z = cart.getZ();
|
||||
|
||||
Vec3d vec3d3 = cart.getPos(x, y, z);
|
||||
if (vec3d3 != null && actualVec != null) {
|
||||
double d17 = (actualVec.y - vec3d3.y) * 0.05D;
|
||||
Vec3d vec3d4 = cart.getMotion();
|
||||
double d18 = Math.sqrt(horizontalMag(vec3d4));
|
||||
if (d18 > 0.0D) {
|
||||
cart.setMotion(vec3d4.mul((d18 + d17) / d18, 1.0D, (d18 + d17) / d18));
|
||||
}
|
||||
|
||||
cart.setPosition(x, vec3d3.y, z);
|
||||
}
|
||||
|
||||
x = cart.getX();
|
||||
y = cart.getY();
|
||||
z = cart.getZ();
|
||||
|
||||
int j = MathHelper.floor(x);
|
||||
int i = MathHelper.floor(z);
|
||||
if (j != cartPos.getX() || i != cartPos.getZ()) {
|
||||
Vec3d vec3d5 = cart.getMotion();
|
||||
double d26 = Math.sqrt(horizontalMag(vec3d5));
|
||||
cart.setMotion(d26 * (double) (j - cartPos.getX()), vec3d5.y, d26 * (double) (i - cartPos.getZ()));
|
||||
}
|
||||
|
||||
cart.setMotion(previousMotion);
|
||||
|
||||
if (cart instanceof FurnaceMinecartEntity) {
|
||||
// FurnaceMinecartEntity furnaceCart = (FurnaceMinecartEntity) cart;
|
||||
// Vec3d vec3d = cart.getMotion();
|
||||
// double d2 = horizontalMag(vec3d);
|
||||
// double d3 = furnaceCart.pushX * furnaceCart.pushX + furnaceCart.pushZ * furnaceCart.pushZ;
|
||||
// if (d3 > 1.0E-4D && d2 > 0.001D) {
|
||||
// double d40 = (double) MathHelper.sqrt(d2);
|
||||
// double d50 = (double) MathHelper.sqrt(d3);
|
||||
// furnaceCart.pushX = vec3d.x / d40 * d50;
|
||||
// furnaceCart.pushZ = vec3d.z / d40 * d50;
|
||||
// furnaceCart.setMotion(vec3d.mul(0.8D, 0.0D, 0.8D)
|
||||
// .add(furnaceCart.pushX, 0.0D, furnaceCart.pushZ));
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,367 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement.train;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.foundation.utility.ColorHelper;
|
||||
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.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class MinecartTrain {
|
||||
|
||||
protected ArrayList<MinecartCoupling> couplings;
|
||||
protected double momentum;
|
||||
boolean complete;
|
||||
|
||||
public MinecartTrain(MinecartCoupling coupling) {
|
||||
couplings = new ArrayList<>();
|
||||
couplings.add(coupling);
|
||||
tickOrder = 1; // start at most stressed
|
||||
}
|
||||
|
||||
public void flip(World world) {
|
||||
Collections.reverse(couplings);
|
||||
couplings.forEach(c -> MinecartCouplingHandler.flipCoupling(world, c));
|
||||
}
|
||||
|
||||
public void mergeOnto(World world, MinecartTrain other) {
|
||||
AbstractMinecartEntity trailingOfOther = other.couplings.get(other.couplings.size() - 1).connectedCart.get();
|
||||
AbstractMinecartEntity leadingOfThis = couplings.get(0).mainCart.get();
|
||||
|
||||
if (trailingOfOther != leadingOfThis)
|
||||
flip(world);
|
||||
|
||||
other.couplings.addAll(couplings);
|
||||
}
|
||||
|
||||
public int tickOrder;
|
||||
|
||||
public void tickCouplings(World world) {
|
||||
|
||||
// SOFT collision - modify motion of carts with stressed links @t+1
|
||||
double sharedMotion = 0;
|
||||
int participants = 0;
|
||||
for (int i = 0; i < couplings.size(); i++) {
|
||||
MinecartCoupling minecartCoupling = couplings.get(i);
|
||||
boolean last = i + 1 == couplings.size();
|
||||
if (!minecartCoupling.areBothEndsPresent())
|
||||
continue;
|
||||
participants++;
|
||||
sharedMotion += minecartCoupling.mainCart.get()
|
||||
.getMotion()
|
||||
.length();
|
||||
|
||||
if (last) {
|
||||
participants++;
|
||||
sharedMotion += minecartCoupling.connectedCart.get()
|
||||
.getMotion()
|
||||
.length();
|
||||
}
|
||||
}
|
||||
|
||||
if (participants == 0)
|
||||
return;
|
||||
|
||||
sharedMotion /= participants;
|
||||
|
||||
/*
|
||||
* Tick order testing: 0: start from motion outlier 1: start at most stressed
|
||||
* coupling 2: start at front 3: start at back
|
||||
*/
|
||||
|
||||
if (tickOrder == 0) {
|
||||
// Iterate starting from biggest outlier in motion
|
||||
double maxDiff = 0;
|
||||
int argMax = 0;
|
||||
for (int i = 0; i < couplings.size(); i++) {
|
||||
MinecartCoupling minecartCoupling = couplings.get(i);
|
||||
boolean last = i + 1 == couplings.size();
|
||||
if (!minecartCoupling.areBothEndsPresent())
|
||||
continue;
|
||||
|
||||
double diff = Math.abs(minecartCoupling.mainCart.get()
|
||||
.getMotion()
|
||||
.length() - sharedMotion);
|
||||
if (diff > maxDiff) {
|
||||
maxDiff = diff;
|
||||
argMax = i;
|
||||
}
|
||||
|
||||
if (last) {
|
||||
diff = Math.abs(minecartCoupling.connectedCart.get()
|
||||
.getMotion()
|
||||
.length() - sharedMotion);
|
||||
if (diff > maxDiff) {
|
||||
maxDiff = diff;
|
||||
argMax = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (boolean hard : Iterate.trueAndFalse) {
|
||||
for (int i = argMax - 1; i >= 0; i--)
|
||||
if (couplings.get(i)
|
||||
.areBothEndsPresent())
|
||||
collisionStep(world, couplings.get(i)
|
||||
.asCouple()
|
||||
.swap(), couplings.get(i).length, hard);
|
||||
for (int i = argMax; i < couplings.size(); i++)
|
||||
if (couplings.get(i)
|
||||
.areBothEndsPresent())
|
||||
collisionStep(world, couplings.get(i)
|
||||
.asCouple()
|
||||
.swap(), couplings.get(i).length, hard);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (tickOrder == 1) {
|
||||
// Iterate starting from biggest stress
|
||||
double maxStress = 0;
|
||||
int argMax = 0;
|
||||
for (int i = 0; i < couplings.size(); i++) {
|
||||
MinecartCoupling minecartCoupling = couplings.get(i);
|
||||
if (!minecartCoupling.areBothEndsPresent())
|
||||
continue;
|
||||
double stress = getStressOfCoupling(minecartCoupling);
|
||||
if (stress > maxStress) {
|
||||
maxStress = stress;
|
||||
argMax = i;
|
||||
}
|
||||
}
|
||||
|
||||
for (boolean hard : Iterate.trueAndFalse) {
|
||||
for (int i = argMax - 1; i >= 0; i--)
|
||||
if (couplings.get(i)
|
||||
.areBothEndsPresent())
|
||||
collisionStep(world, couplings.get(i)
|
||||
.asCouple()
|
||||
.swap(), couplings.get(i).length, hard);
|
||||
for (int i = argMax; i < couplings.size(); i++)
|
||||
if (couplings.get(i)
|
||||
.areBothEndsPresent())
|
||||
collisionStep(world, couplings.get(i)
|
||||
.asCouple()
|
||||
.swap(), couplings.get(i).length, hard);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (momentum >= 0 == (tickOrder == 2)) {
|
||||
// Iterate front to back
|
||||
for (boolean hard : Iterate.trueAndFalse)
|
||||
for (int i = 0; i < couplings.size(); i++)
|
||||
if (couplings.get(i)
|
||||
.areBothEndsPresent())
|
||||
collisionStep(world, couplings.get(i)
|
||||
.asCouple()
|
||||
.swap(), couplings.get(i).length, hard);
|
||||
|
||||
} else {
|
||||
// Iterate back to front
|
||||
for (boolean hard : Iterate.trueAndFalse)
|
||||
for (int i = couplings.size() - 1; i >= 0; i--)
|
||||
if (couplings.get(i)
|
||||
.areBothEndsPresent())
|
||||
collisionStep(world, couplings.get(i)
|
||||
.asCouple()
|
||||
.swap(), couplings.get(i).length, hard);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private float getStressOfCoupling(MinecartCoupling coupling) {
|
||||
if (!coupling.areBothEndsPresent())
|
||||
return 0;
|
||||
return (float) (coupling.length - coupling.mainCart.get()
|
||||
.getPositionVec()
|
||||
.distanceTo(coupling.connectedCart.get()
|
||||
.getPositionVec()));
|
||||
}
|
||||
|
||||
public void collisionStep(World world, Couple<AbstractMinecartEntity> carts, double couplingLength, boolean hard) {
|
||||
if (hard)
|
||||
hardCollisionStep(world, carts, couplingLength);
|
||||
else
|
||||
softCollisionStep(world, carts, couplingLength);
|
||||
}
|
||||
|
||||
public void hardCollisionStep(World world, Couple<AbstractMinecartEntity> carts, double couplingLength) {
|
||||
Couple<Vec3d> 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);
|
||||
}
|
||||
|
||||
Vec3d correction = Vec3d.ZERO;
|
||||
Vec3d pos = cart.getPositionVec();
|
||||
Vec3d 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 void softCollisionStep(World world, Couple<AbstractMinecartEntity> carts, double couplingLength) {
|
||||
|
||||
Couple<Vec3d> 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<Vec3d> motions = carts.map(MinecartSim2020::predictMotionOf);
|
||||
Couple<Vec3d> nextPositions = positions.copy();
|
||||
nextPositions.replaceWithParams(Vec3d::add, motions);
|
||||
|
||||
float futureStress = (float) (couplingLength - nextPositions.getFirst()
|
||||
.distanceTo(nextPositions.getSecond()));
|
||||
if (Math.abs(futureStress) < 1 / 128f)
|
||||
return;
|
||||
|
||||
for (boolean current : Iterate.trueAndFalse) {
|
||||
Vec3d correction = Vec3d.ZERO;
|
||||
Vec3d pos = nextPositions.get(current);
|
||||
Vec3d 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 Vec3d followLinkOnRail(Vec3d link, Vec3d cart, float diffToReduce, RailShape shape) {
|
||||
Vec3d railAxis = getRailVec(shape);
|
||||
double dotProduct = railAxis.dotProduct(link);
|
||||
if (Double.isNaN(dotProduct) || dotProduct == 0 || diffToReduce == 0)
|
||||
return cart;
|
||||
|
||||
Vec3d axis = railAxis.scale(-Math.signum(dotProduct));
|
||||
Vec3d center = cart.add(link);
|
||||
double radius = link.length() - diffToReduce;
|
||||
Vec3d 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;
|
||||
}
|
||||
|
||||
private static Vec3d getRailVec(RailShape shape) {
|
||||
switch (shape) {
|
||||
case ASCENDING_NORTH:
|
||||
case ASCENDING_SOUTH:
|
||||
case NORTH_SOUTH:
|
||||
return new Vec3d(0, 0, 1);
|
||||
case ASCENDING_EAST:
|
||||
case ASCENDING_WEST:
|
||||
case EAST_WEST:
|
||||
return new Vec3d(1, 0, 0);
|
||||
case NORTH_EAST:
|
||||
case SOUTH_WEST:
|
||||
return new Vec3d(1, 0, 1).normalize();
|
||||
case NORTH_WEST:
|
||||
case SOUTH_EAST:
|
||||
return new Vec3d(1, 0, -1).normalize();
|
||||
default:
|
||||
return new Vec3d(0, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return couplings.get(0)
|
||||
.getId();
|
||||
}
|
||||
|
||||
public static void doDebugRender(World world, MinecartCoupling coupling, int index) {
|
||||
AbstractMinecartEntity mainCart = coupling.mainCart.get();
|
||||
AbstractMinecartEntity connectedCart = coupling.connectedCart.get();
|
||||
|
||||
if (!coupling.areBothEndsPresent())
|
||||
return;
|
||||
|
||||
int yOffset = 1;
|
||||
Vec3d mainCenter = mainCart.getPositionVec()
|
||||
.add(0, yOffset, 0);
|
||||
Vec3d connectedCenter = connectedCart.getPositionVec()
|
||||
.add(0, yOffset, 0);
|
||||
|
||||
int color = ColorHelper.mixColors(0xabf0e9, 0xee8572,
|
||||
(float) MathHelper.clamp(Math.abs(coupling.length - connectedCenter.distanceTo(mainCenter)) * 8, 0, 1));
|
||||
|
||||
CreateClient.outliner.showLine(coupling + "" + index, mainCenter, connectedCenter)
|
||||
.colored(color)
|
||||
.lineWidth(1 / 8f);
|
||||
|
||||
Vec3d point = mainCart.getPositionVec()
|
||||
.add(0, yOffset, 0);
|
||||
CreateClient.outliner.showLine(coupling.getId() + "" + index, point, point.add(0, 1 / 128f, 0))
|
||||
.colored(0xffffff)
|
||||
.lineWidth(1 / 4f);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -7,15 +7,27 @@ import com.mojang.blaze3d.matrix.MatrixStack;
|
|||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.content.contraptions.KineticDebugger;
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionCollider;
|
||||
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.MinecartCouplingHandler;
|
||||
import com.simibubi.create.content.contraptions.components.turntable.TurntableHandler;
|
||||
import com.simibubi.create.content.contraptions.relays.belt.item.BeltConnectorHandler;
|
||||
import com.simibubi.create.content.curiosities.tools.ExtendoGripRenderHandler;
|
||||
import com.simibubi.create.content.curiosities.zapper.ZapperRenderHandler;
|
||||
import com.simibubi.create.content.curiosities.zapper.blockzapper.BlockzapperRenderHandler;
|
||||
import com.simibubi.create.content.curiosities.zapper.terrainzapper.WorldshaperRenderHandler;
|
||||
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPointHandler;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.gui.ScreenOpener;
|
||||
import com.simibubi.create.foundation.item.TooltipHelper;
|
||||
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringHandler;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueHandler;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction.EdgeInteractionRenderer;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringRenderer;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.linked.LinkRenderer;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueRenderer;
|
||||
import com.simibubi.create.foundation.utility.AnimationTickHolder;
|
||||
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.ActiveRenderInfo;
|
||||
|
@ -24,10 +36,8 @@ import net.minecraft.client.renderer.texture.OverlayTexture;
|
|||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.InputEvent.KeyInputEvent;
|
||||
import net.minecraftforge.client.event.InputEvent.MouseInputEvent;
|
||||
import net.minecraftforge.client.event.InputEvent.MouseScrollEvent;
|
||||
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
||||
import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType;
|
||||
import net.minecraftforge.client.event.RenderWorldLastEvent;
|
||||
|
@ -35,6 +45,7 @@ import net.minecraftforge.event.TickEvent.ClientTickEvent;
|
|||
import net.minecraftforge.event.TickEvent.Phase;
|
||||
import net.minecraftforge.event.TickEvent.RenderTickEvent;
|
||||
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
|
||||
|
@ -46,6 +57,7 @@ public class ClientEvents {
|
|||
|
||||
@SubscribeEvent
|
||||
public static void onTick(ClientTickEvent event) {
|
||||
World world = Minecraft.getInstance().world;
|
||||
if (event.phase == Phase.START)
|
||||
return;
|
||||
|
||||
|
@ -54,13 +66,34 @@ public class ClientEvents {
|
|||
if (!isGameActive())
|
||||
return;
|
||||
|
||||
if (!KineticDebugger.isActive() && KineticTileEntityRenderer.rainbowMode) {
|
||||
KineticTileEntityRenderer.rainbowMode = false;
|
||||
CreateClient.bufferCache.invalidate();
|
||||
}
|
||||
|
||||
CreateClient.schematicSender.tick();
|
||||
CreateClient.schematicAndQuillHandler.tick();
|
||||
CreateClient.schematicHandler.tick();
|
||||
|
||||
ContraptionCollider.runCollisions(world);
|
||||
MinecartCouplingHandler.tick(world);
|
||||
ScreenOpener.tick();
|
||||
CreateClient.gameTick();
|
||||
ServerSpeedProvider.clientTick();
|
||||
BeltConnectorHandler.tick();
|
||||
FilteringRenderer.tick();
|
||||
LinkRenderer.tick();
|
||||
ScrollValueRenderer.tick();
|
||||
ChassisRangeDisplay.tick();
|
||||
EdgeInteractionRenderer.tick();
|
||||
WorldshaperRenderHandler.tick();
|
||||
BlockzapperRenderHandler.tick();
|
||||
ClientMinecartCouplingHandler.tick();
|
||||
KineticDebugger.tick();
|
||||
ZapperRenderHandler.tick();
|
||||
ExtendoGripRenderHandler.tick();
|
||||
// CollisionDebugger.tick();
|
||||
ArmInteractionPointHandler.tick();
|
||||
CreateClient.outliner.tickOutlines();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onLoadWorld(WorldEvent.Load event) {
|
||||
CreateClient.bufferCache.invalidate();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
@ -68,11 +101,11 @@ public class ClientEvents {
|
|||
MatrixStack ms = event.getMatrixStack();
|
||||
ActiveRenderInfo info = Minecraft.getInstance().gameRenderer.getActiveRenderInfo();
|
||||
Vec3d view = info.getProjectedView();
|
||||
|
||||
ms.push();
|
||||
ms.translate(-view.getX(), -view.getY(), -view.getZ());
|
||||
|
||||
SuperRenderTypeBuffer buffer = SuperRenderTypeBuffer.getInstance();
|
||||
|
||||
MinecartCouplingHandler.render(ms, buffer);
|
||||
CreateClient.schematicHandler.render(ms, buffer);
|
||||
CreateClient.outliner.renderOutlines(ms, buffer);
|
||||
// CollisionDebugger.render(ms, buffer);
|
||||
|
@ -95,42 +128,6 @@ public class ClientEvents {
|
|||
CreateClient.schematicHandler.renderOverlay(ms, buffer, light, overlay);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onKeyInput(KeyInputEvent event) {
|
||||
int key = event.getKey();
|
||||
boolean pressed = !(event.getAction() == 0);
|
||||
|
||||
if (Minecraft.getInstance().currentScreen != null)
|
||||
return;
|
||||
|
||||
CreateClient.schematicHandler.onKeyInput(key, pressed);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onMouseScrolled(MouseScrollEvent event) {
|
||||
if (Minecraft.getInstance().currentScreen != null)
|
||||
return;
|
||||
|
||||
double delta = event.getScrollDelta();
|
||||
// CollisionDebugger.onScroll(delta);
|
||||
boolean cancelled = CreateClient.schematicHandler.mouseScrolled(delta)
|
||||
|| CreateClient.schematicAndQuillHandler.mouseScrolled(delta) || FilteringHandler.onScroll(delta)
|
||||
|| ScrollValueHandler.onScroll(delta);
|
||||
event.setCanceled(cancelled);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onMouseInput(MouseInputEvent event) {
|
||||
if (Minecraft.getInstance().currentScreen != null)
|
||||
return;
|
||||
|
||||
int button = event.getButton();
|
||||
boolean pressed = !(event.getAction() == 0);
|
||||
|
||||
CreateClient.schematicHandler.onMouseInput(button, pressed);
|
||||
CreateClient.schematicAndQuillHandler.onMouseInput(button, pressed);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void addToItemTooltip(ItemTooltipEvent event) {
|
||||
if (!AllConfigs.CLIENT.tooltips.get())
|
||||
|
@ -159,7 +156,6 @@ public class ClientEvents {
|
|||
public static void onRenderTick(RenderTickEvent event) {
|
||||
if (!isGameActive())
|
||||
return;
|
||||
|
||||
TurntableHandler.gameRenderTick();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,25 @@
|
|||
package com.simibubi.create.events;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.foundation.command.CreateCommand;
|
||||
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.train.MinecartCouplingHandler;
|
||||
import com.simibubi.create.content.schematics.ServerSchematicLoader;
|
||||
import com.simibubi.create.foundation.command.AllCommands;
|
||||
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
|
||||
import com.simibubi.create.foundation.utility.WorldAttached;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.event.TickEvent.Phase;
|
||||
import net.minecraftforge.event.TickEvent.ServerTickEvent;
|
||||
import net.minecraftforge.event.TickEvent.WorldTickEvent;
|
||||
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
|
||||
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
|
||||
import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
|
||||
|
@ -19,20 +28,50 @@ import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
|
|||
public class CommonEvents {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onTick(ServerTickEvent event) {
|
||||
if (event.phase == Phase.END)
|
||||
public static void onServerTick(ServerTickEvent event) {
|
||||
if (event.phase == Phase.START)
|
||||
return;
|
||||
Create.tick();
|
||||
if (Create.schematicReceiver == null)
|
||||
Create.schematicReceiver = new ServerSchematicLoader();
|
||||
Create.schematicReceiver.tick();
|
||||
Create.lagger.tick();
|
||||
ServerSpeedProvider.serverTick();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onClose(FMLServerStoppingEvent event) {
|
||||
Create.shutdown();
|
||||
public static void onWorldTick(WorldTickEvent event) {
|
||||
if (event.phase == Phase.START)
|
||||
return;
|
||||
World world = event.world;
|
||||
ContraptionCollider.runCollisions(world);
|
||||
MinecartCouplingHandler.tick(world);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onUpdateLivingEntity(LivingUpdateEvent event) {
|
||||
LivingEntity entityLiving = event.getEntityLiving();
|
||||
World world = entityLiving.world;
|
||||
if (world == null)
|
||||
return;
|
||||
ContraptionHandler.entitiesWhoJustDismountedGetSentToTheRightLocation(entityLiving, world);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void serverStarting(FMLServerStartingEvent event) {
|
||||
new CreateCommand(event.getCommandDispatcher());
|
||||
public static void onEntityAdded(EntityJoinWorldEvent event) {
|
||||
Entity entity = event.getEntity();
|
||||
World world = event.getWorld();
|
||||
ContraptionHandler.addSpawnedContraptionsToCollisionList(entity, world);
|
||||
MinecartCouplingHandler.handleAddedMinecart(entity, world);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void serverStarted(FMLServerStartingEvent event) {
|
||||
AllCommands.register(event.getCommandDispatcher());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void serverStopped(FMLServerStoppingEvent event) {
|
||||
Create.schematicReceiver.shutdown();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
@ -40,8 +79,6 @@ public class CommonEvents {
|
|||
IWorld world = event.getWorld();
|
||||
Create.redstoneLinkNetworkHandler.onLoadWorld(world);
|
||||
Create.torquePropagator.onLoadWorld(world);
|
||||
if (event.getWorld().isRemote())
|
||||
DistExecutor.runWhenOn(Dist.CLIENT, () -> CreateClient.bufferCache::invalidate);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
@ -49,6 +86,7 @@ public class CommonEvents {
|
|||
IWorld world = event.getWorld();
|
||||
Create.redstoneLinkNetworkHandler.onUnloadWorld(world);
|
||||
Create.torquePropagator.onUnloadWorld(world);
|
||||
WorldAttached.invalidateWorld(world);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
54
src/main/java/com/simibubi/create/events/InputEvents.java
Normal file
54
src/main/java/com/simibubi/create/events/InputEvents.java
Normal file
|
@ -0,0 +1,54 @@
|
|||
package com.simibubi.create.events;
|
||||
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringHandler;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueHandler;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.InputEvent.KeyInputEvent;
|
||||
import net.minecraftforge.client.event.InputEvent.MouseInputEvent;
|
||||
import net.minecraftforge.client.event.InputEvent.MouseScrollEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
|
||||
@EventBusSubscriber(value = Dist.CLIENT)
|
||||
public class InputEvents {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onKeyInput(KeyInputEvent event) {
|
||||
int key = event.getKey();
|
||||
boolean pressed = !(event.getAction() == 0);
|
||||
|
||||
if (Minecraft.getInstance().currentScreen != null)
|
||||
return;
|
||||
|
||||
CreateClient.schematicHandler.onKeyInput(key, pressed);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onMouseScrolled(MouseScrollEvent event) {
|
||||
if (Minecraft.getInstance().currentScreen != null)
|
||||
return;
|
||||
|
||||
double delta = event.getScrollDelta();
|
||||
// CollisionDebugger.onScroll(delta);
|
||||
boolean cancelled = CreateClient.schematicHandler.mouseScrolled(delta)
|
||||
|| CreateClient.schematicAndQuillHandler.mouseScrolled(delta) || FilteringHandler.onScroll(delta)
|
||||
|| ScrollValueHandler.onScroll(delta);
|
||||
event.setCanceled(cancelled);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onMouseInput(MouseInputEvent event) {
|
||||
if (Minecraft.getInstance().currentScreen != null)
|
||||
return;
|
||||
|
||||
int button = event.getButton();
|
||||
boolean pressed = !(event.getAction() == 0);
|
||||
|
||||
CreateClient.schematicHandler.onMouseInput(button, pressed);
|
||||
CreateClient.schematicAndQuillHandler.onMouseInput(button, pressed);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.simibubi.create.foundation.command;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.command.Commands;
|
||||
|
||||
public class AllCommands {
|
||||
|
||||
public static void register(CommandDispatcher<CommandSource> dispatcher) {
|
||||
dispatcher.register(Commands.literal("create")
|
||||
.then(ToggleDebugCommand.register())
|
||||
.then(OverlayConfigCommand.register())
|
||||
.then(ClearBufferCacheCommand.register())
|
||||
// .then(KillTPSCommand.register()) //Commented out for release
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package com.simibubi.create.foundation.command;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.command.Commands;
|
||||
|
||||
public class CreateCommand {
|
||||
|
||||
public CreateCommand(CommandDispatcher<CommandSource> dispatcher) {
|
||||
dispatcher.register(Commands.literal("create")
|
||||
.then(ToggleDebugCommand.register())
|
||||
.then(OverlayConfigCommand.register())
|
||||
.then(ClearBufferCacheCommand.register())
|
||||
//.then(KillTPSCommand.register()) //Commented out for release
|
||||
);
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ public class CKinetics extends ConfigBase {
|
|||
public ConfigInt maxChassisRange = i(16, 1, "maxChassisRange", Comments.maxChassisRange);
|
||||
public ConfigInt maxPistonPoles = i(64, 1, "maxPistonPoles", Comments.maxPistonPoles);
|
||||
public ConfigInt maxRopeLength = i(128, 1, "maxRopeLength", Comments.maxRopeLength);
|
||||
public ConfigInt maxCartCouplingLength = i(32, 1, "maxCartCouplingLength", Comments.maxCartCouplingLength);
|
||||
|
||||
public ConfigGroup state = group(0, "stats", Comments.stats);
|
||||
public ConfigFloat mediumSpeed = f(30, 0, 4096, "mediumSpeed", Comments.rpm, Comments.mediumSpeed);
|
||||
|
@ -58,6 +59,7 @@ public class CKinetics extends ConfigBase {
|
|||
static String maxChassisRange = "Maximum value of a chassis attachment range.";
|
||||
static String maxPistonPoles = "Maximum amount of extension poles behind a Mechanical Piston.";
|
||||
static String maxRopeLength = "Max length of rope available off a Rope Pulley.";
|
||||
static String maxCartCouplingLength = "Maximum allowed distance of two coupled minecarts.";
|
||||
static String stats = "Configure speed/capacity levels for requirements and indicators.";
|
||||
static String rpm = "[in Revolutions per Minute]";
|
||||
static String su = "[in Stress Units]";
|
||||
|
|
|
@ -10,6 +10,10 @@ import com.simibubi.create.content.contraptions.components.structureMovement.glu
|
|||
import com.simibubi.create.content.contraptions.components.structureMovement.sync.ClientMotionPacket;
|
||||
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.train.MinecartCouplingCreationPacket;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCouplingSyncPacket;
|
||||
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.curiosities.symmetry.SymmetryEffectPacket;
|
||||
import com.simibubi.create.content.curiosities.tools.ExtendoGripInteractionPacket;
|
||||
|
@ -49,6 +53,8 @@ public enum AllPackets {
|
|||
CONTRAPTION_INTERACT(ContraptionInteractionPacket.class, ContraptionInteractionPacket::new),
|
||||
CLIENT_MOTION(ClientMotionPacket.class, ClientMotionPacket::new),
|
||||
PLACE_ARM(ArmPlacementPacket.class, ArmPlacementPacket::new),
|
||||
MINECART_COUPLING_CREATION(MinecartCouplingCreationPacket.class, MinecartCouplingCreationPacket::new),
|
||||
PERSISTANT_DATA_REQUEST(PersistantDataPacketRequest.class, PersistantDataPacketRequest::new),
|
||||
|
||||
// Server to Client
|
||||
SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new),
|
||||
|
@ -57,7 +63,9 @@ public enum AllPackets {
|
|||
CONFIGURE_CONFIG(ConfigureConfigPacket.class, ConfigureConfigPacket::new),
|
||||
CONTRAPTION_STALL(ContraptionStallPacket.class, ContraptionStallPacket::new),
|
||||
GLUE_EFFECT(GlueEffectPacket.class, GlueEffectPacket::new),
|
||||
MINECART_COUPLING_SYNC(MinecartCouplingSyncPacket.class, MinecartCouplingSyncPacket::new),
|
||||
CONTRAPTION_SEAT_MAPPING(ContraptionSeatMappingPacket.class, ContraptionSeatMappingPacket::new),
|
||||
PERSISTANT_DATA(PersistantDataPacket.class, PersistantDataPacket::new),
|
||||
|
||||
;
|
||||
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class Couple<T> extends Pair<T, T> {
|
||||
|
||||
private static Couple<Boolean> TRUE_AND_FALSE = Couple.create(true, false);
|
||||
|
||||
protected Couple(T first, T second) {
|
||||
super(first, second);
|
||||
}
|
||||
|
||||
public static <T> Couple<T> create(T first, T second) {
|
||||
return new Couple<>(first, second);
|
||||
}
|
||||
|
||||
public T get(boolean first) {
|
||||
return first ? getFirst() : getSecond();
|
||||
}
|
||||
|
||||
public void set(boolean first, T value) {
|
||||
if (first)
|
||||
setFirst(value);
|
||||
else
|
||||
setSecond(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Couple<T> copy() {
|
||||
return create(first, second);
|
||||
}
|
||||
|
||||
public <S> Couple<S> map(Function<T, S> function) {
|
||||
return Couple.create(function.apply(first), function.apply(second));
|
||||
}
|
||||
|
||||
public void replace(Function<T, T> function) {
|
||||
setFirst(function.apply(getFirst()));
|
||||
setSecond(function.apply(getSecond()));
|
||||
}
|
||||
|
||||
public void replaceWithContext(BiFunction<T, Boolean, T> function) {
|
||||
replaceWithParams(function, TRUE_AND_FALSE);
|
||||
}
|
||||
|
||||
public <S> void replaceWithParams(BiFunction<T, S, T> function, Couple<S> values) {
|
||||
setFirst(function.apply(getFirst(), values.getFirst()));
|
||||
setSecond(function.apply(getSecond(), values.getSecond()));
|
||||
}
|
||||
|
||||
public void forEach(Consumer<T> consumer) {
|
||||
consumer.accept(getFirst());
|
||||
consumer.accept(getSecond());
|
||||
}
|
||||
|
||||
public void forEachWithContext(BiConsumer<T, Boolean> consumer) {
|
||||
forEachWithParams(consumer, TRUE_AND_FALSE);
|
||||
}
|
||||
|
||||
public <S> void forEachWithParams(BiConsumer<T, S> function, Couple<S> values) {
|
||||
function.accept(getFirst(), values.getFirst());
|
||||
function.accept(getSecond(), values.getSecond());
|
||||
}
|
||||
|
||||
public Couple<T> swap() {
|
||||
return Couple.create(second, first);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Pair<F, S> {
|
||||
|
||||
F first;
|
||||
S second;
|
||||
|
||||
protected Pair(F first, S second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public static <F, S> Pair<F, S> of(F first, S second) {
|
||||
return new Pair<>(first, second);
|
||||
}
|
||||
|
||||
public F getFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
public S getSecond() {
|
||||
return second;
|
||||
}
|
||||
|
||||
public void setFirst(F first) {
|
||||
this.first = first;
|
||||
}
|
||||
|
||||
public void setSecond(S second) {
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public Pair<F, S> copy() {
|
||||
return Pair.of(first, second);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (obj instanceof Pair) {
|
||||
final Pair<?, ?> other = (Pair<?, ?>) obj;
|
||||
return Objects.equals(first, other.first) && Objects.equals(second, other.second);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + first + ", " + second + ")";
|
||||
}
|
||||
|
||||
public Pair<S, F> swap() {
|
||||
return Pair.of(second, first);
|
||||
}
|
||||
|
||||
}
|
|
@ -11,14 +11,9 @@ import net.minecraft.client.Minecraft;
|
|||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.event.TickEvent.Phase;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
import net.minecraftforge.fml.network.NetworkEvent.Context;
|
||||
import net.minecraftforge.fml.network.PacketDistributor;
|
||||
|
||||
@EventBusSubscriber
|
||||
public class ServerSpeedProvider {
|
||||
|
||||
static int clientTimer = 0;
|
||||
|
@ -26,33 +21,26 @@ public class ServerSpeedProvider {
|
|||
static boolean initialized = false;
|
||||
static InterpolatedChasingValue modifier = new InterpolatedChasingValue().withSpeed(.25f);
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onServerTick(TickEvent.ServerTickEvent event) {
|
||||
if (event.phase == Phase.START)
|
||||
return;
|
||||
public static void serverTick() {
|
||||
serverTimer++;
|
||||
if (serverTimer > getSyncInterval()) {
|
||||
AllPackets.channel.send(PacketDistributor.ALL.noArg(), new Packet());
|
||||
serverTimer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void clientTick() {
|
||||
if (Minecraft.getInstance().isSingleplayer() && Minecraft.getInstance().isGamePaused())
|
||||
return;
|
||||
modifier.tick();
|
||||
clientTimer++;
|
||||
}
|
||||
|
||||
public static Integer getSyncInterval() {
|
||||
return AllConfigs.SERVER.tickrateSyncTimer.get();
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@SubscribeEvent
|
||||
public static void onClientTick(TickEvent.ClientTickEvent event) {
|
||||
if (event.phase == Phase.START)
|
||||
return;
|
||||
if (Minecraft.getInstance().isSingleplayer() && Minecraft.getInstance().isGamePaused())
|
||||
return;
|
||||
|
||||
modifier.tick();
|
||||
clientTimer++;
|
||||
}
|
||||
|
||||
public static float get() {
|
||||
return modifier.value;
|
||||
}
|
||||
|
|
|
@ -52,17 +52,22 @@ public class SuperByteBufferCache {
|
|||
public SuperByteBuffer renderPartial(AllBlockPartials partial, BlockState referenceState) {
|
||||
return get(PARTIAL, partial, () -> standardModelRender(partial.get(), referenceState));
|
||||
}
|
||||
|
||||
public SuperByteBuffer renderPartial(AllBlockPartials partial, BlockState referenceState, MatrixStack modelTransform) {
|
||||
|
||||
public SuperByteBuffer renderPartial(AllBlockPartials partial, BlockState referenceState,
|
||||
MatrixStack modelTransform) {
|
||||
return get(PARTIAL, partial, () -> standardModelRender(partial.get(), referenceState, modelTransform));
|
||||
}
|
||||
|
||||
public SuperByteBuffer renderDirectionalPartial(AllBlockPartials partial, BlockState referenceState, Direction dir) {
|
||||
return get(DIRECTIONAL_PARTIAL, Pair.of(dir, partial), () -> standardModelRender(partial.get(), referenceState));
|
||||
|
||||
public SuperByteBuffer renderDirectionalPartial(AllBlockPartials partial, BlockState referenceState,
|
||||
Direction dir) {
|
||||
return get(DIRECTIONAL_PARTIAL, Pair.of(dir, partial),
|
||||
() -> standardModelRender(partial.get(), referenceState));
|
||||
}
|
||||
|
||||
public SuperByteBuffer renderDirectionalPartial(AllBlockPartials partial, BlockState referenceState, Direction dir, MatrixStack modelTransform) {
|
||||
return get(DIRECTIONAL_PARTIAL, Pair.of(dir, partial), () -> standardModelRender(partial.get(), referenceState, modelTransform));
|
||||
|
||||
public SuperByteBuffer renderDirectionalPartial(AllBlockPartials partial, BlockState referenceState, Direction dir,
|
||||
MatrixStack modelTransform) {
|
||||
return get(DIRECTIONAL_PARTIAL, Pair.of(dir, partial),
|
||||
() -> standardModelRender(partial.get(), referenceState, modelTransform));
|
||||
}
|
||||
|
||||
public SuperByteBuffer renderBlockIn(Compartment<BlockState> compartment, BlockState toRender) {
|
||||
|
@ -84,16 +89,19 @@ public class SuperByteBufferCache {
|
|||
}
|
||||
|
||||
public void registerCompartment(Compartment<?> instance) {
|
||||
cache.put(instance, CacheBuilder.newBuilder().build());
|
||||
cache.put(instance, CacheBuilder.newBuilder()
|
||||
.build());
|
||||
}
|
||||
|
||||
public void registerCompartment(Compartment<?> instance, long ticksTillExpired) {
|
||||
cache.put(instance,
|
||||
CacheBuilder.newBuilder().expireAfterAccess(ticksTillExpired * 50, TimeUnit.MILLISECONDS).build());
|
||||
public void registerCompartment(Compartment<?> instance, long ticksUntilExpired) {
|
||||
cache.put(instance, CacheBuilder.newBuilder()
|
||||
.expireAfterAccess(ticksUntilExpired * 50, TimeUnit.MILLISECONDS)
|
||||
.build());
|
||||
}
|
||||
|
||||
private SuperByteBuffer standardBlockRender(BlockState renderedState) {
|
||||
BlockRendererDispatcher dispatcher = Minecraft.getInstance().getBlockRendererDispatcher();
|
||||
BlockRendererDispatcher dispatcher = Minecraft.getInstance()
|
||||
.getBlockRendererDispatcher();
|
||||
return standardModelRender(dispatcher.getModelForState(renderedState), renderedState);
|
||||
}
|
||||
|
||||
|
@ -102,22 +110,21 @@ public class SuperByteBufferCache {
|
|||
}
|
||||
|
||||
private SuperByteBuffer standardModelRender(IBakedModel model, BlockState referenceState, MatrixStack ms) {
|
||||
BlockRendererDispatcher dispatcher = Minecraft.getInstance().getBlockRendererDispatcher();
|
||||
BlockRendererDispatcher dispatcher = Minecraft.getInstance()
|
||||
.getBlockRendererDispatcher();
|
||||
BlockModelRenderer blockRenderer = dispatcher.getBlockModelRenderer();
|
||||
BufferBuilder builder = new BufferBuilder(DefaultVertexFormats.BLOCK.getIntegerSize());
|
||||
Random random = new Random();
|
||||
builder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK);
|
||||
blockRenderer.renderModelFlat(Minecraft.getInstance().world, model, referenceState, BlockPos.ZERO.up(255), ms,
|
||||
builder, true, random, 42, OverlayTexture.DEFAULT_UV, EmptyModelData.INSTANCE);
|
||||
builder, true, random, 42, OverlayTexture.DEFAULT_UV, EmptyModelData.INSTANCE);
|
||||
builder.finishDrawing();
|
||||
|
||||
return new SuperByteBuffer(builder);
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
cache.forEach((comp, cache) -> {
|
||||
cache.invalidateAll();
|
||||
});
|
||||
cache.forEach((comp, cache) -> cache.invalidateAll());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.simibubi.create.foundation.utility;
|
|||
|
||||
import java.util.Random;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.nbt.DoubleNBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.util.Direction;
|
||||
|
@ -80,6 +82,8 @@ public class VecHelper {
|
|||
}
|
||||
|
||||
public static Vec3d readNBT(ListNBT list) {
|
||||
if (list.isEmpty())
|
||||
return Vec3d.ZERO;
|
||||
return new Vec3d(list.getDouble(0), list.getDouble(1), list.getDouble(2));
|
||||
}
|
||||
|
||||
|
@ -105,4 +109,31 @@ public class VecHelper {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static Vec3d clamp(Vec3d vec, float maxLength) {
|
||||
return vec.length() > maxLength ? vec.normalize()
|
||||
.scale(maxLength) : vec;
|
||||
}
|
||||
|
||||
public static Vec3d project(Vec3d vec, Vec3d ontoVec) {
|
||||
if (ontoVec.equals(Vec3d.ZERO))
|
||||
return Vec3d.ZERO;
|
||||
return ontoVec.scale(vec.dotProduct(ontoVec) / ontoVec.lengthSquared());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Vec3d intersectSphere(Vec3d origin, Vec3d lineDirection, Vec3d sphereCenter, double radius) {
|
||||
if (lineDirection.equals(Vec3d.ZERO))
|
||||
return null;
|
||||
if (lineDirection.length() != 1)
|
||||
lineDirection = lineDirection.normalize();
|
||||
|
||||
Vec3d diff = origin.subtract(sphereCenter);
|
||||
double lineDotDiff = lineDirection.dotProduct(diff);
|
||||
double delta = lineDotDiff * lineDotDiff - (diff.lengthSquared() - radius * radius);
|
||||
if (delta < 0)
|
||||
return null;
|
||||
double t = -lineDotDiff + MathHelper.sqrt(delta);
|
||||
return origin.add(lineDirection.scale(t));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.world.IWorld;
|
||||
|
||||
public class WorldAttached<T> {
|
||||
|
||||
static List<Map<IWorld, ?>> allMaps = new ArrayList<>();
|
||||
Map<IWorld, T> attached;
|
||||
private Supplier<T> factory;
|
||||
|
||||
public WorldAttached(Supplier<T> factory) {
|
||||
this.factory = factory;
|
||||
attached = new HashMap<>();
|
||||
allMaps.add(attached);
|
||||
}
|
||||
|
||||
public static void invalidateWorld(IWorld world) {
|
||||
allMaps.forEach(m -> m.remove(world));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public T get(IWorld world) {
|
||||
T t = attached.get(world);
|
||||
if (t != null)
|
||||
return t;
|
||||
T entry = factory.get();
|
||||
put(world, entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
public void put(IWorld world, T entry) {
|
||||
attached.put(world, entry);
|
||||
}
|
||||
|
||||
}
|
|
@ -20,7 +20,7 @@ public class LineOutline extends Outline {
|
|||
|
||||
@Override
|
||||
public void render(MatrixStack ms, SuperRenderTypeBuffer buffer) {
|
||||
renderAACuboidLine(ms, buffer, start, end);
|
||||
renderCuboidLine(ms, buffer, start, end);
|
||||
}
|
||||
|
||||
public static class EndChasingLineOutline extends LineOutline {
|
||||
|
@ -52,7 +52,7 @@ public class LineOutline extends Outline {
|
|||
float distanceToTarget = 1 - MathHelper.lerp(pt, prevProgress, progress);
|
||||
Vec3d start = end.add(this.start.subtract(end)
|
||||
.scale(distanceToTarget));
|
||||
renderAACuboidLine(ms, buffer, start, end);
|
||||
renderCuboidLine(ms, buffer, start, end);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,13 +10,16 @@ import com.mojang.blaze3d.vertex.IVertexBuilder;
|
|||
import com.simibubi.create.AllSpecialTextures;
|
||||
import com.simibubi.create.foundation.renderState.RenderTypes;
|
||||
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.ColorHelper;
|
||||
import com.simibubi.create.foundation.utility.MatrixStacker;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.client.renderer.Matrix3f;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public abstract class Outline {
|
||||
|
@ -30,6 +33,20 @@ public abstract class Outline {
|
|||
|
||||
public abstract void render(MatrixStack ms, SuperRenderTypeBuffer buffer);
|
||||
|
||||
public void renderCuboidLine(MatrixStack ms, SuperRenderTypeBuffer buffer, Vec3d start, Vec3d end) {
|
||||
Vec3d diff = end.subtract(start);
|
||||
float hAngle = AngleHelper.deg(MathHelper.atan2(diff.x, diff.z));
|
||||
float hDistance = (float) diff.mul(1, 0, 1)
|
||||
.length();
|
||||
float vAngle = AngleHelper.deg(MathHelper.atan2(hDistance, diff.y)) - 90;
|
||||
ms.push();
|
||||
MatrixStacker.of(ms)
|
||||
.translate(start)
|
||||
.rotateY(hAngle).rotateX(vAngle);
|
||||
renderAACuboidLine(ms, buffer, Vec3d.ZERO, new Vec3d(0, 0, diff.length()));
|
||||
ms.pop();
|
||||
}
|
||||
|
||||
public void renderAACuboidLine(MatrixStack ms, SuperRenderTypeBuffer buffer, Vec3d start, Vec3d end) {
|
||||
IVertexBuilder builder = buffer.getBuffer(RenderTypes.getOutlineSolid());
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"credit": "Made with Blockbench",
|
||||
"textures": {
|
||||
"0": "create:entity/coupling",
|
||||
"particle": "create:entity/coupling"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [-2.5, -2.5, -2.5],
|
||||
"to": [2.5, -1.5, 2.5],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [2.5, -2.5, 0]},
|
||||
"faces": {
|
||||
"north": {"uv": [1, 5, 0, 10], "texture": "#0"},
|
||||
"east": {"uv": [5, 5, 0, 6], "texture": "#0"},
|
||||
"south": {"uv": [5, 5, 4, 10], "texture": "#0"},
|
||||
"west": {"uv": [5, 5, 0, 6], "texture": "#0"},
|
||||
"up": {"uv": [0, 10, 5, 5], "rotation": 90, "texture": "#0"},
|
||||
"down": {"uv": [0, 10, 5, 5], "rotation": 90, "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [-3.5, -2.5, 0.5],
|
||||
"to": [2.5, -1.5, 1.5],
|
||||
"rotation": {"angle": 22.5, "axis": "z", "origin": [2.5, -2.5, 1.5]},
|
||||
"faces": {
|
||||
"north": {"uv": [2, 5, 1, 10], "texture": "#0"},
|
||||
"south": {"uv": [2, 5, 1, 10], "texture": "#0"},
|
||||
"up": {"uv": [2, 5, 1, 10], "texture": "#0"},
|
||||
"down": {"uv": [2, 5, 1, 10], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [-3.5, -2.5, -1.5],
|
||||
"to": [2.5, -1.5, -0.5],
|
||||
"rotation": {"angle": 22.5, "axis": "z", "origin": [2.5, -2.5, 1.5]},
|
||||
"faces": {
|
||||
"north": {"uv": [2, 5, 1, 10], "texture": "#0"},
|
||||
"south": {"uv": [2, 5, 1, 10], "texture": "#0"},
|
||||
"up": {"uv": [2, 5, 1, 10], "texture": "#0"},
|
||||
"down": {"uv": [2, 5, 1, 10], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [-1, -1.5, -1],
|
||||
"to": [1, 2.5, 1],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [0.5, 0, -0.5]},
|
||||
"faces": {
|
||||
"north": {"uv": [1, 5, 0, 9], "texture": "#0"},
|
||||
"east": {"uv": [1, 5, 0, 9], "texture": "#0"},
|
||||
"south": {"uv": [1, 5, 0, 9], "texture": "#0"},
|
||||
"west": {"uv": [1, 5, 0, 9], "texture": "#0"},
|
||||
"up": {"uv": [1, 5, 0, 6], "texture": "#0"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
{"meta":{"format_version":"3.2","model_format":"java_block","box_uv":false},"name":"","ambientocclusion":true,"front_gui_light":false,"resolution":{"width":16,"height":16},"elements":[{"name":"cube","from":[-2.5,-2.5,-2.5],"to":[2.5,-1.5,2.5],"autouv":0,"color":1,"locked":false,"origin":[2.5,-2.5,0],"faces":{"north":{"uv":[1,5,0,10],"texture":0},"east":{"uv":[5,5,0,6],"texture":0},"south":{"uv":[5,5,4,10],"texture":0},"west":{"uv":[5,5,0,6],"texture":0},"up":{"uv":[0,10,5,5],"rotation":90,"texture":0},"down":{"uv":[0,10,5,5],"rotation":90,"texture":0}},"uuid":"2ab28291-d8a0-1c59-0932-fd688d885b36"},{"name":"cube","from":[-3.5,-2.5,0.5],"to":[2.5,-1.5,1.5],"autouv":0,"color":1,"locked":false,"rotation":[0,0,22.5],"origin":[2.5,-2.5,1.5],"faces":{"north":{"uv":[2,5,1,10],"texture":0},"east":{"uv":[0,0,0,0],"texture":null},"south":{"uv":[2,5,1,10],"texture":0},"west":{"uv":[0,0,0,0],"texture":null},"up":{"uv":[2,5,1,10],"texture":0},"down":{"uv":[2,5,1,10],"texture":0}},"uuid":"161c9d0c-ea0d-7643-ea35-2a2b60015c66"},{"name":"cube","from":[-1,-1.5,-1],"to":[1,2.5,1],"autouv":0,"color":0,"locked":false,"origin":[0.5,0,-0.5],"faces":{"north":{"uv":[1,5,0,9],"texture":0},"east":{"uv":[1,5,0,9],"texture":0},"south":{"uv":[1,5,0,9],"texture":0},"west":{"uv":[1,5,0,9],"texture":0},"up":{"uv":[1,5,0,6],"texture":0},"down":{"uv":[0,0,0,0],"texture":null}},"uuid":"df623d06-f1ee-4e7a-d324-cca888af8748"},{"name":"cube","from":[-3.5,-2.5,-1.5],"to":[2.5,-1.5,-0.5],"autouv":0,"color":1,"locked":false,"rotation":[0,0,22.5],"origin":[2.5,-2.5,1.5],"faces":{"north":{"uv":[2,5,1,10],"texture":0},"east":{"uv":[0,0,0,0],"texture":null},"south":{"uv":[2,5,1,10],"texture":0},"west":{"uv":[0,0,0,0],"texture":null},"up":{"uv":[2,5,1,10],"texture":0},"down":{"uv":[2,5,1,10],"texture":0}},"uuid":"3cc3b4bd-1a33-b861-6e08-b88cb413b6a3"},{"name":"cube","from":[-2.5,-1,-2.5],"to":[2.5,1,2.5],"autouv":0,"color":2,"locked":false,"origin":[-5.5,7,5.5],"faces":{"north":{"uv":[10,0,5,2],"texture":0},"east":{"uv":[10,0,5,2],"texture":0},"south":{"uv":[10,0,5,2],"texture":0},"west":{"uv":[10,0,5,2],"texture":0},"up":{"uv":[5,0,0,5],"texture":0},"down":{"uv":[5,0,0,5],"texture":0}},"uuid":"1d3fae57-f8fb-8ae5-6b58-a9545e59439a"}],"outliner":["2ab28291-d8a0-1c59-0932-fd688d885b36","161c9d0c-ea0d-7643-ea35-2a2b60015c66","3cc3b4bd-1a33-b861-6e08-b88cb413b6a3","df623d06-f1ee-4e7a-d324-cca888af8748","1d3fae57-f8fb-8ae5-6b58-a9545e59439a"],"textures":[{"path":"C:\\Users\\simon\\Desktop\\Forgespace 1.15\\Create\\src\\main\\resources\\assets\\create\\textures\\entity\\coupling.png","name":"coupling.png","folder":"entity","namespace":"create","id":"0","particle":true,"mode":"bitmap","saved":true,"uuid":"b6862380-7179-b672-5fd5-f1caa05b56cf","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAm0lEQVQ4T2PMK638Ly4ixAADL9+8AzPRxSZ1tzPCFSExGFs7u/+DND15cJdBRkEZrPHsmdMM/KIScGUfX79gWLd6FW4DQBrevn3LICwszGBlbcPw8+dPhuryUqwa0F2B1QV3Hj5mmD9tEnEGwMKAnZ0dbDPIO7j8izUMgkLD/oP8C/InjMbl31EDsIUAAwNRUYVdK0R01AAqhAEAGbtwESadp4gAAAAASUVORK5CYII="}]}
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"credit": "Made with Blockbench",
|
||||
"textures": {
|
||||
"0": "create:entity/coupling",
|
||||
"particle": "create:entity/coupling"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, -0.75, -1],
|
||||
"to": [16, 0.75, 1],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [21, 7, 7]},
|
||||
"faces": {
|
||||
"north": {"uv": [5, 2, 6, 4], "texture": "#0"},
|
||||
"east": {"uv": [5, 2, 6, 4], "texture": "#0"},
|
||||
"south": {"uv": [5, 2, 6, 4], "texture": "#0"},
|
||||
"west": {"uv": [5, 2, 6, 4], "texture": "#0"},
|
||||
"up": {"uv": [5, 2, 6, 3], "texture": "#0"},
|
||||
"down": {"uv": [5, 3, 6, 4], "texture": "#0"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"credit": "Made with Blockbench",
|
||||
"textures": {
|
||||
"0": "create:entity/coupling",
|
||||
"particle": "create:entity/coupling"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [-2.5, -1, -2.5],
|
||||
"to": [2.5, 1, 2.5],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [-5.5, 7, 5.5]},
|
||||
"faces": {
|
||||
"north": {"uv": [10, 0, 5, 2], "texture": "#0"},
|
||||
"east": {"uv": [10, 0, 5, 2], "texture": "#0"},
|
||||
"south": {"uv": [10, 0, 5, 2], "texture": "#0"},
|
||||
"west": {"uv": [10, 0, 5, 2], "texture": "#0"},
|
||||
"up": {"uv": [5, 0, 0, 5], "texture": "#0"},
|
||||
"down": {"uv": [5, 0, 0, 5], "texture": "#0"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
BIN
src/main/resources/assets/create/textures/entity/coupling.png
Normal file
BIN
src/main/resources/assets/create/textures/entity/coupling.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 471 B |
Binary file not shown.
After Width: | Height: | Size: 341 B |
Loading…
Reference in a new issue