mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-10-14 21:22:49 +00:00
Added Slab handling
Added Slab handling
This commit is contained in:
commit
a4fb677566
5 changed files with 683 additions and 239 deletions
|
|
@ -6,10 +6,9 @@ namespace MinecraftClient.Commands
|
|||
{
|
||||
public class Sneak : Command
|
||||
{
|
||||
private bool sneaking = false;
|
||||
public override string CmdName { get { return "sneak"; } }
|
||||
public override string CmdUsage { get { return "sneak"; } }
|
||||
public override string CmdDesc { get { return Translations.cmd_sneak_desc; } }
|
||||
public override string CmdName => "sneak";
|
||||
public override string CmdUsage => "sneak";
|
||||
public override string CmdDesc => Translations.cmd_sneak_desc;
|
||||
|
||||
public override void RegisterCommand(CommandDispatcher<CmdResult> dispatcher)
|
||||
{
|
||||
|
|
@ -39,27 +38,22 @@ namespace MinecraftClient.Commands
|
|||
|
||||
private int DoSneak(CmdResult r)
|
||||
{
|
||||
McClient handler = CmdResult.currentHandler!;
|
||||
if (sneaking)
|
||||
var handler = CmdResult.currentHandler!;
|
||||
|
||||
if (handler.IsSneaking)
|
||||
{
|
||||
var result = handler.SendEntityAction(Protocol.EntityActionType.StopSneaking);
|
||||
if (result)
|
||||
sneaking = false;
|
||||
if (result)
|
||||
if (!handler.SendEntityAction(Protocol.EntityActionType.StopSneaking))
|
||||
return r.SetAndReturn(CmdResult.Status.Fail);
|
||||
|
||||
handler.IsSneaking = false;
|
||||
return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_sneak_off);
|
||||
else
|
||||
return r.SetAndReturn(CmdResult.Status.Fail);
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = handler.SendEntityAction(Protocol.EntityActionType.StartSneaking);
|
||||
if (result)
|
||||
sneaking = true;
|
||||
if (result)
|
||||
|
||||
if (!handler.SendEntityAction(Protocol.EntityActionType.StartSneaking))
|
||||
return r.SetAndReturn(CmdResult.Status.Fail);
|
||||
|
||||
handler.IsSneaking = true;
|
||||
return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_sneak_on);
|
||||
else
|
||||
return r.SetAndReturn(CmdResult.Status.Fail);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
382
MinecraftClient/Mapping/BlockExtension.cs
Normal file
382
MinecraftClient/Mapping/BlockExtension.cs
Normal file
|
|
@ -0,0 +1,382 @@
|
|||
using MinecraftClient.Protocol.Handlers;
|
||||
|
||||
namespace MinecraftClient.Mapping;
|
||||
|
||||
public static class BlockExtension
|
||||
{
|
||||
public static bool IsTopSlab(this Block block, int protocolVersion)
|
||||
{
|
||||
if (protocolVersion >= Protocol18Handler.MC_1_19_4_Version)
|
||||
{
|
||||
switch (block.BlockId)
|
||||
{
|
||||
case 11018: // OakSlab
|
||||
case 11024: // SpruceSlab
|
||||
case 11030: // BirchSlab
|
||||
case 11036: // JungleSlab
|
||||
case 11042: // AcaciaSlab
|
||||
case 11054: // DarkOakSlab
|
||||
case 11060: // MangroveSlab
|
||||
case 18510: // CrimsonSlab
|
||||
case 18516: // WarpedSlab
|
||||
case 11078: // StoneSlab
|
||||
case 11108: // CobblestoneSlab
|
||||
case 13948: // MossyCobblestoneSlab
|
||||
case 11084: // SmoothStoneSlab
|
||||
case 11120: // StoneBrickSlab
|
||||
case 13936: // MossyStoneBrickSlab
|
||||
case 13972: // GraniteSlab
|
||||
case 13924: // PolishedGraniteSlab
|
||||
case 13996: // DioriteSlab
|
||||
case 13942: // PolishedDioriteSlab
|
||||
case 13978: // AndesiteSlab
|
||||
case 13990: // PolishedAndesiteSlab
|
||||
case 22132: // CobbledDeepslateSlab
|
||||
case 22543: // PolishedDeepslateSlab
|
||||
case 23365: // DeepslateBrickSlab
|
||||
case 22954: // DeepslateTileSlab
|
||||
case 11114: // BrickSlab
|
||||
case 11126: // MudBrickSlab
|
||||
case 11090: // SandstoneSlab
|
||||
case 13960: // SmoothSandstoneSlab
|
||||
case 11096: // CutSandstoneSlab
|
||||
case 11144: // RedSandstoneSlab
|
||||
case 13930: // SmoothRedSandstoneSlab
|
||||
case 11150: // CutRedSandstoneSlab
|
||||
case 10562: // PrismarineSlab
|
||||
case 10568: // PrismarineBrickSlab
|
||||
case 10574: // DarkPrismarineSlab
|
||||
case 11132: // NetherBrickSlab
|
||||
case 13984: // RedNetherBrickSlab
|
||||
case 19707: // BlackstoneSlab
|
||||
case 20208: // PolishedBlackstoneSlab
|
||||
case 19717: // PolishedBlackstoneBrickSlab
|
||||
case 13954: // EndStoneBrickSlab
|
||||
case 11156: // PurpurSlab
|
||||
case 11138: // QuartzSlab
|
||||
case 13966: // SmoothQuartzSlab
|
||||
case 21510: // CutCopperSlab
|
||||
case 21504: // ExposedCutCopperSlab
|
||||
case 21498: // WeatheredCutCopperSlab
|
||||
case 21492: // OxidizedCutCopperSlab
|
||||
case 21862: // WaxedCutCopperSlab
|
||||
case 21856: // WaxedExposedCutCopperSlab
|
||||
case 21850: // WaxedWeatheredCutCopperSlab
|
||||
case 21844: // WaxedOxidizedCutCopperSlab
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (protocolVersion == Protocol18Handler.MC_1_19_3_Version)
|
||||
{
|
||||
switch (block.BlockId)
|
||||
{
|
||||
case 10686: // OakSlab
|
||||
case 10692: // SpruceSlab
|
||||
case 10698: // BirchSlab
|
||||
case 10704: // JungleSlab
|
||||
case 10710: // AcaciaSlab
|
||||
case 10716: // DarkOakSlab
|
||||
case 10722: // MangroveSlab
|
||||
case 18041: // CrimsonSlab
|
||||
case 18047: // WarpedSlab
|
||||
case 10740: // StoneSlab
|
||||
case 10770: // CobblestoneSlab
|
||||
case 13479: // MossyCobblestoneSlab
|
||||
case 10746: // SmoothStoneSlab
|
||||
case 10782: // StoneBrickSlab
|
||||
case 13467: // MossyStoneBrickSlab
|
||||
case 13503: // GraniteSlab
|
||||
case 13455: // PolishedGraniteSlab
|
||||
case 13527: // DioriteSlab
|
||||
case 13473: // PolishedDioriteSlab
|
||||
case 13509: // AndesiteSlab
|
||||
case 13521: // PolishedAndesiteSlab
|
||||
case 21647: // CobbledDeepslateSlab
|
||||
case 22058: // PolishedDeepslateSlab
|
||||
case 22880: // DeepslateBrickSlab
|
||||
case 22469: // DeepslateTileSlab
|
||||
case 10776: // BrickSlab
|
||||
case 10788: // MudBrickSlab
|
||||
case 10752: // SandstoneSlab
|
||||
case 13491: // SmoothSandstoneSlab
|
||||
case 10758: // CutSandstoneSlab
|
||||
case 10806: // RedSandstoneSlab
|
||||
case 13461: // SmoothRedSandstoneSlab
|
||||
case 10812: // CutRedSandstoneSlab
|
||||
case 10230: // PrismarineSlab
|
||||
case 10236: // PrismarineBrickSlab
|
||||
case 10242: // DarkPrismarineSlab
|
||||
case 10794: // NetherBrickSlab
|
||||
case 13515: // RedNetherBrickSlab
|
||||
case 19238: // BlackstoneSlab
|
||||
case 19739: // PolishedBlackstoneSlab
|
||||
case 19248: // PolishedBlackstoneBrickSlab
|
||||
case 13485: // EndStoneBrickSlab
|
||||
case 10818: // PurpurSlab
|
||||
case 10800: // QuartzSlab
|
||||
case 13497: // SmoothQuartzSlab
|
||||
case 21041: // CutCopperSlab
|
||||
case 21035: // ExposedCutCopperSlab
|
||||
case 21029: // WeatheredCutCopperSlab
|
||||
case 21023: // OxidizedCutCopperSlab
|
||||
case 21393: // WaxedCutCopperSlab
|
||||
case 21387: // WaxedExposedCutCopperSlab
|
||||
case 21381: // WaxedWeatheredCutCopperSlab
|
||||
case 21375: // WaxedOxidizedCutCopperSlab
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (protocolVersion >= Protocol18Handler.MC_1_19_Version)
|
||||
{
|
||||
switch (block.BlockId)
|
||||
{
|
||||
case 19257: // CutCopperSlab
|
||||
case 19251: // ExposedCutCopperSlab
|
||||
case 19245: // WeatheredCutCopperSlab
|
||||
case 19239: // OxidizedCutCopperSlab
|
||||
case 19609: // WaxedCutCopperSlab
|
||||
case 19603: // WaxedExposedCutCopperSlab
|
||||
case 19597: // WaxedWeatheredCutCopperSlab
|
||||
case 19591: // WaxedOxidizedCutCopperSlab
|
||||
case 9042: // OakSlab
|
||||
case 9048: // SpruceSlab
|
||||
case 9054: // BirchSlab
|
||||
case 9060: // JungleSlab
|
||||
case 9066: // AcaciaSlab
|
||||
case 9072: // DarkOakSlab
|
||||
case 9078: // MangroveSlab
|
||||
case 16257: // CrimsonSlab
|
||||
case 16263: // WarpedSlab
|
||||
case 9084: // StoneSlab
|
||||
case 9090: // SmoothStoneSlab
|
||||
case 9096: // SandstoneSlab
|
||||
case 9102: // CutSandstoneSlab
|
||||
case 9108: // PetrifiedOakSlab
|
||||
case 9114: // CobblestoneSlab
|
||||
case 9120: // BrickSlab
|
||||
case 9126: // StoneBrickSlab
|
||||
case 9132: // MudBrickSlab
|
||||
case 9138: // NetherBrickSlab
|
||||
case 9144: // QuartzSlab
|
||||
case 9150: // RedSandstoneSlab
|
||||
case 9156: // CutRedSandstoneSlab
|
||||
case 9162: // PurpurSlab
|
||||
case 8586: // PrismarineSlab
|
||||
case 8592: // PrismarineBrickSlab
|
||||
case 8598: // DarkPrismarineSlab
|
||||
case 11671: // PolishedGraniteSlab
|
||||
case 11677: // SmoothRedSandstoneSlab
|
||||
case 11683: // MossyStoneBrickSlab
|
||||
case 11689: // PolishedDioriteSlab
|
||||
case 11695: // MossyCobblestoneSlab
|
||||
case 11701: // EndStoneBrickSlab
|
||||
case 11707: // SmoothSandstoneSlab
|
||||
case 11713: // SmoothQuartzSlab
|
||||
case 11719: // GraniteSlab
|
||||
case 11725: // AndesiteSlab
|
||||
case 11731: // RedNetherBrickSlab
|
||||
case 11737: // PolishedAndesiteSlab
|
||||
case 11743: // DioriteSlab
|
||||
case 19863: // CobbledDeepslateSlab
|
||||
case 20274: // PolishedDeepslateSlab
|
||||
case 21096: // DeepslateBrickSlab
|
||||
case 20685: // DeepslateTileSlab
|
||||
case 17454: // BlackstoneSlab
|
||||
case 17955: // PolishedBlackstoneSlab
|
||||
case 17464: // PolishedBlackstoneBrickSlab
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (protocolVersion >= Protocol18Handler.MC_1_17_Version)
|
||||
{
|
||||
switch (block.BlockId)
|
||||
{
|
||||
case 18163: // CutCopperSlab
|
||||
case 18157: // ExposedCutCopperSlab
|
||||
case 18151: // WeatheredCutCopperSlab
|
||||
case 18145: // OxidizedCutCopperSlab
|
||||
case 18515: // WaxedCutCopperSlab
|
||||
case 18509: // WaxedExposedCutCopperSlab
|
||||
case 18503: // WaxedWeatheredCutCopperSlab
|
||||
case 18497: // WaxedOxidizedCutCopperSlab
|
||||
case 8551: // OakSlab
|
||||
case 8557: // SpruceSlab
|
||||
case 8563: // BirchSlab
|
||||
case 8569: // JungleSlab
|
||||
case 8575: // AcaciaSlab
|
||||
case 8581: // DarkOakSlab
|
||||
case 15302: // CrimsonSlab
|
||||
case 15308: // WarpedSlab
|
||||
case 8587: // StoneSlab
|
||||
case 8593: // SmoothStoneSlab
|
||||
case 8599: // SandstoneSlab
|
||||
case 8605: // CutSandstoneSlab
|
||||
case 8611: // PetrifiedOakSlab
|
||||
case 8617: // CobblestoneSlab
|
||||
case 8623: // BrickSlab
|
||||
case 8629: // StoneBrickSlab
|
||||
case 8635: // NetherBrickSlab
|
||||
case 8641: // QuartzSlab
|
||||
case 8647: // RedSandstoneSlab
|
||||
case 8653: // CutRedSandstoneSlab
|
||||
case 8659: // PurpurSlab
|
||||
case 8095: // PrismarineSlab
|
||||
case 8101: // PrismarineBrickSlab
|
||||
case 8107: // DarkPrismarineSlab
|
||||
case 11040: // PolishedGraniteSlab
|
||||
case 11046: // SmoothRedSandstoneSlab
|
||||
case 11052: // MossyStoneBrickSlab
|
||||
case 11058: // PolishedDioriteSlab
|
||||
case 11064: // MossyCobblestoneSlab
|
||||
case 11070: // EndStoneBrickSlab
|
||||
case 11076: // SmoothSandstoneSlab
|
||||
case 11082: // SmoothQuartzSlab
|
||||
case 11088: // GraniteSlab
|
||||
case 11094: // AndesiteSlab
|
||||
case 11100: // RedNetherBrickSlab
|
||||
case 11106: // PolishedAndesiteSlab
|
||||
case 11112: // DioriteSlab
|
||||
case 18768: // CobbledDeepslateSlab
|
||||
case 19179: // PolishedDeepslateSlab
|
||||
case 20001: // DeepslateBrickSlab
|
||||
case 19590: // DeepslateTileSlab
|
||||
case 16499: // BlackstoneSlab
|
||||
case 17000: // PolishedBlackstoneSlab
|
||||
case 16509: // PolishedBlackstoneBrickSlab
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (protocolVersion >= Protocol18Handler.MC_1_16_Version)
|
||||
{
|
||||
switch (block.BlockId)
|
||||
{
|
||||
case 8305: // OakSlab
|
||||
case 8311: // SpruceSlab
|
||||
case 8317: // BirchSlab
|
||||
case 8323: // JungleSlab
|
||||
case 8329: // AcaciaSlab
|
||||
case 8335: // DarkOakSlab
|
||||
case 15056: // CrimsonSlab
|
||||
case 15062: // WarpedSlab
|
||||
case 8341: // StoneSlab
|
||||
case 8347: // SmoothStoneSlab
|
||||
case 8353: // SandstoneSlab
|
||||
case 8359: // CutSandstoneSlab
|
||||
case 8365: // PetrifiedOakSlab
|
||||
case 8371: // CobblestoneSlab
|
||||
case 8377: // BrickSlab
|
||||
case 8383: // StoneBrickSlab
|
||||
case 8389: // NetherBrickSlab
|
||||
case 8395: // QuartzSlab
|
||||
case 8401: // RedSandstoneSlab
|
||||
case 8407: // CutRedSandstoneSlab
|
||||
case 8413: // PurpurSlab
|
||||
case 7849: // PrismarineSlab
|
||||
case 7855: // PrismarineBrickSlab
|
||||
case 7861: // DarkPrismarineSlab
|
||||
case 10794: // PolishedGraniteSlab
|
||||
case 10800: // SmoothRedSandstoneSlab
|
||||
case 10806: // MossyStoneBrickSlab
|
||||
case 10812: // PolishedDioriteSlab
|
||||
case 10818: // MossyCobblestoneSlab
|
||||
case 10824: // EndStoneBrickSlab
|
||||
case 10830: // SmoothSandstoneSlab
|
||||
case 10836: // SmoothQuartzSlab
|
||||
case 10842: // GraniteSlab
|
||||
case 10848: // AndesiteSlab
|
||||
case 10854: // RedNetherBrickSlab
|
||||
case 10860: // PolishedAndesiteSlab
|
||||
case 10866: // DioriteSlab
|
||||
case 16253: // BlackstoneSlab
|
||||
case 16754: // PolishedBlackstoneSlab
|
||||
case 16263: // PolishedBlackstoneBrickSlab
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (protocolVersion >= Protocol18Handler.MC_1_15_Version)
|
||||
{
|
||||
switch (block.BlockId)
|
||||
{
|
||||
case 7765: // OakSlab
|
||||
case 7771: // SpruceSlab
|
||||
case 7777: // BirchSlab
|
||||
case 7783: // JungleSlab
|
||||
case 7789: // AcaciaSlab
|
||||
case 7795: // DarkOakSlab
|
||||
case 7801: // StoneSlab
|
||||
case 7807: // SmoothStoneSlab
|
||||
case 7813: // SandstoneSlab
|
||||
case 7819: // CutSandstoneSlab
|
||||
case 7825: // PetrifiedOakSlab
|
||||
case 7831: // CobblestoneSlab
|
||||
case 7837: // BrickSlab
|
||||
case 7843: // StoneBrickSlab
|
||||
case 7849: // NetherBrickSlab
|
||||
case 7855: // QuartzSlab
|
||||
case 7861: // RedSandstoneSlab
|
||||
case 7867: // CutRedSandstoneSlab
|
||||
case 7873: // PurpurSlab
|
||||
case 7309: // PrismarineSlab
|
||||
case 7321: // DarkPrismarineSlab
|
||||
case 10254: // PolishedGraniteSlab
|
||||
case 10260: // SmoothRedSandstoneSlab
|
||||
case 10266: // MossyStoneBrickSlab
|
||||
case 10272: // PolishedDioriteSlab
|
||||
case 10278: // MossyCobblestoneSlab
|
||||
case 10284: // EndStoneBrickSlab
|
||||
case 10290: // SmoothSandstoneSlab
|
||||
case 10296: // SmoothQuartzSlab
|
||||
case 10302: // GraniteSlab
|
||||
case 10308: // AndesiteSlab
|
||||
case 10314: // RedNetherBrickSlab
|
||||
case 10320: // PolishedAndesiteSlab
|
||||
case 10326: // DioriteSlab
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (protocolVersion >= Protocol18Handler.MC_1_14_Version)
|
||||
{
|
||||
switch (block.BlockId)
|
||||
{
|
||||
case 7765: // OakSlab
|
||||
case 7771: // SpruceSlab
|
||||
case 7777: // BirchSlab
|
||||
case 7783: // JungleSlab
|
||||
case 7789: // AcaciaSlab
|
||||
case 7795: // DarkOakSlab
|
||||
case 7801: // StoneSlab
|
||||
case 7807: // SmoothStoneSlab
|
||||
case 7813: // SandstoneSlab
|
||||
case 7819: // CutSandstoneSlab
|
||||
case 7825: // PetrifiedOakSlab
|
||||
case 7831: // CobblestoneSlab
|
||||
case 7837: // BrickSlab
|
||||
case 7843: // StoneBrickSlab
|
||||
case 7849: // NetherBrickSlab
|
||||
case 7855: // QuartzSlab
|
||||
case 7861: // RedSandstoneSlab
|
||||
case 7867: // CutRedSandstoneSlab
|
||||
case 7873: // PurpurSlab
|
||||
case 7309: // PrismarineSlab
|
||||
case 7315: // PrismarineBrickSlab
|
||||
case 7321: // DarkPrismarineSlab
|
||||
case 10254: // PolishedGraniteSlab
|
||||
case 10260: // SmoothRedSandstoneSlab
|
||||
case 10266: // MossyStoneBrickSlab
|
||||
case 10272: // PolishedDioriteSlab
|
||||
case 10278: // MossyCobblestoneSlab
|
||||
case 10284: // EndStoneBrickSlab
|
||||
case 10290: // SmoothSandstoneSlab
|
||||
case 10296: // SmoothQuartzSlab
|
||||
case 10302: // GraniteSlab
|
||||
case 10308: // AndesiteSlab
|
||||
case 10314: // RedNetherBrickSlab
|
||||
case 10320: // PolishedAndesiteSlab
|
||||
case 10326: // DioriteSlab
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -728,6 +728,7 @@
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if contact with the provided material can harm players
|
||||
/// </summary>
|
||||
|
|
@ -817,5 +818,74 @@
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the provided material is a slab
|
||||
/// </summary>
|
||||
/// <param name="m">Material to test</param>
|
||||
/// <returns>True if the material is a slab</returns>
|
||||
public static bool IsSlab(this Material m)
|
||||
{
|
||||
switch (m)
|
||||
{
|
||||
case Material.AcaciaSlab:
|
||||
case Material.AndesiteSlab:
|
||||
case Material.BirchSlab:
|
||||
case Material.BlackstoneSlab:
|
||||
case Material.BrickSlab:
|
||||
case Material.CobbledDeepslateSlab:
|
||||
case Material.CobblestoneSlab:
|
||||
case Material.CrimsonSlab:
|
||||
case Material.CutCopperSlab:
|
||||
case Material.CutRedSandstoneSlab:
|
||||
case Material.CutSandstoneSlab:
|
||||
case Material.DarkOakSlab:
|
||||
case Material.DarkPrismarineSlab:
|
||||
case Material.DeepslateBrickSlab:
|
||||
case Material.DeepslateTileSlab:
|
||||
case Material.DioriteSlab:
|
||||
case Material.EndStoneBrickSlab:
|
||||
case Material.ExposedCutCopperSlab:
|
||||
case Material.GraniteSlab:
|
||||
case Material.JungleSlab:
|
||||
case Material.MangroveSlab:
|
||||
case Material.MossyCobblestoneSlab:
|
||||
case Material.MossyStoneBrickSlab:
|
||||
case Material.MudBrickSlab:
|
||||
case Material.NetherBrickSlab:
|
||||
case Material.OakSlab:
|
||||
case Material.OxidizedCutCopperSlab:
|
||||
case Material.PetrifiedOakSlab:
|
||||
case Material.PolishedAndesiteSlab:
|
||||
case Material.PolishedBlackstoneBrickSlab:
|
||||
case Material.PolishedBlackstoneSlab:
|
||||
case Material.PolishedDeepslateSlab:
|
||||
case Material.PolishedDioriteSlab:
|
||||
case Material.PolishedGraniteSlab:
|
||||
case Material.PrismarineBrickSlab:
|
||||
case Material.PrismarineSlab:
|
||||
case Material.PurpurSlab:
|
||||
case Material.QuartzSlab:
|
||||
case Material.RedNetherBrickSlab:
|
||||
case Material.RedSandstoneSlab:
|
||||
case Material.SandstoneSlab:
|
||||
case Material.SmoothQuartzSlab:
|
||||
case Material.SmoothRedSandstoneSlab:
|
||||
case Material.SmoothSandstoneSlab:
|
||||
case Material.SmoothStoneSlab:
|
||||
case Material.SpruceSlab:
|
||||
case Material.StoneBrickSlab:
|
||||
case Material.StoneSlab:
|
||||
case Material.WarpedSlab:
|
||||
case Material.WaxedCutCopperSlab:
|
||||
case Material.WaxedExposedCutCopperSlab:
|
||||
case Material.WaxedOxidizedCutCopperSlab:
|
||||
case Material.WaxedWeatheredCutCopperSlab:
|
||||
case Material.WeatheredCutCopperSlab:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -30,15 +30,17 @@ namespace MinecraftClient.Mapping
|
|||
belowFoots = location;
|
||||
belowFoots.Y = Math.Truncate(location.Y);
|
||||
}
|
||||
|
||||
if (!IsOnGround(world, location) && !IsSwimming(world, location))
|
||||
{
|
||||
while (!IsOnGround(world, belowFoots) && belowFoots.Y >= 1 + World.GetDimension().minY)
|
||||
belowFoots = Move(belowFoots, Direction.Down);
|
||||
location = Move2Steps(location, belowFoots, ref motionY, true).Dequeue();
|
||||
}
|
||||
else if (!(world.GetBlock(onFoots).Type.IsSolid()))
|
||||
else if (!world.GetBlock(onFoots).Type.IsSolid())
|
||||
location = Move2Steps(location, onFoots, ref motionY, true).Dequeue();
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
|
|
@ -46,10 +48,11 @@ namespace MinecraftClient.Mapping
|
|||
/// Return a list of possible moves for the player
|
||||
/// </summary>
|
||||
/// <param name="world">World the player is currently located in</param>
|
||||
/// <param name="location">Location the player is currently at</param>
|
||||
/// <param name="originLocation">Location the player is currently at</param>
|
||||
/// <param name="allowUnsafe">Allow possible but unsafe locations</param>
|
||||
/// <returns>A list of new locations the player can move to</returns>
|
||||
public static IEnumerable<Location> GetAvailableMoves(World world, Location originLocation, bool allowUnsafe = false)
|
||||
public static IEnumerable<Location> GetAvailableMoves(World world, Location originLocation,
|
||||
bool allowUnsafe = false)
|
||||
{
|
||||
Location location = originLocation.ToCenter();
|
||||
List<Location> availableMoves = new();
|
||||
|
|
@ -65,10 +68,12 @@ namespace MinecraftClient.Mapping
|
|||
else
|
||||
{
|
||||
foreach (Direction dir in new[] { Direction.East, Direction.West, Direction.North, Direction.South })
|
||||
if (CanMove(world, location, dir) && IsOnGround(world, Move(location, dir)) && (allowUnsafe || IsSafe(world, Move(location, dir))))
|
||||
if (CanMove(world, location, dir) && IsOnGround(world, Move(location, dir)) &&
|
||||
(allowUnsafe || IsSafe(world, Move(location, dir))))
|
||||
availableMoves.Add(Move(location, dir));
|
||||
availableMoves.Add(Move(location, Direction.Down));
|
||||
}
|
||||
|
||||
return availableMoves;
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +90,8 @@ namespace MinecraftClient.Mapping
|
|||
/// <param name="falling">Specify if performing falling steps</param>
|
||||
/// <param name="stepsByBlock">Amount of steps by block</param>
|
||||
/// <returns>A list of locations corresponding to the requested steps</returns>
|
||||
public static Queue<Location> Move2Steps(Location start, Location goal, ref double motionY, bool falling = false, int stepsByBlock = 8)
|
||||
public static Queue<Location> Move2Steps(Location start, Location goal, ref double motionY,
|
||||
bool falling = false, int stepsByBlock = 8)
|
||||
{
|
||||
if (stepsByBlock <= 0)
|
||||
stepsByBlock = 1;
|
||||
|
|
@ -93,17 +99,17 @@ namespace MinecraftClient.Mapping
|
|||
if (falling)
|
||||
{
|
||||
//Use MC-Like falling algorithm
|
||||
double Y = start.Y;
|
||||
double y = start.Y;
|
||||
Queue<Location> fallSteps = new();
|
||||
fallSteps.Enqueue(start);
|
||||
double motionPrev = motionY;
|
||||
motionY -= 0.08D;
|
||||
motionY *= 0.9800000190734863D;
|
||||
Y += motionY;
|
||||
if (Y < goal.Y)
|
||||
y += motionY;
|
||||
|
||||
if (y < goal.Y)
|
||||
return new Queue<Location>(new[] { goal });
|
||||
else
|
||||
return new Queue<Location>(new[] { new Location(start.X, Y, start.Z) });
|
||||
|
||||
return new Queue<Location>(new[] { new Location(start.X, y, start.Z) });
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -132,6 +138,7 @@ namespace MinecraftClient.Mapping
|
|||
/// Based on the A* pathfinding algorithm described on Wikipedia
|
||||
/// </remarks>
|
||||
/// <see href="https://en.wikipedia.org/wiki/A*_search_algorithm#Pseudocode"/>
|
||||
/// <param name="world">World</param>
|
||||
/// <param name="start">Start location</param>
|
||||
/// <param name="goal">Destination location</param>
|
||||
/// <param name="allowUnsafe">Allow possible but unsafe locations</param>
|
||||
|
|
@ -140,16 +147,19 @@ namespace MinecraftClient.Mapping
|
|||
/// <param name="timeout">How long to wait before stopping computation</param>
|
||||
/// <remarks>When location is unreachable, computation will reach timeout, then optionally fallback to a close location within maxOffset</remarks>
|
||||
/// <returns>A list of locations, or null if calculation failed</returns>
|
||||
public static Queue<Location>? CalculatePath(World world, Location start, Location goal, bool allowUnsafe, int maxOffset, int minOffset, TimeSpan timeout)
|
||||
public static Queue<Location>? CalculatePath(World world, Location start, Location goal, bool allowUnsafe,
|
||||
int maxOffset, int minOffset, TimeSpan timeout)
|
||||
{
|
||||
CancellationTokenSource cts = new();
|
||||
Task<Queue<Location>?> pathfindingTask = Task.Factory.StartNew(() => Movement.CalculatePath(world, start, goal, allowUnsafe, maxOffset, minOffset, cts.Token));
|
||||
Task<Queue<Location>?> pathfindingTask = Task.Factory.StartNew(() =>
|
||||
CalculatePath(world, start, goal, allowUnsafe, maxOffset, minOffset, cts.Token));
|
||||
pathfindingTask.Wait(timeout);
|
||||
if (!pathfindingTask.IsCompleted)
|
||||
{
|
||||
cts.Cancel();
|
||||
pathfindingTask.Wait();
|
||||
}
|
||||
|
||||
return pathfindingTask.Result;
|
||||
}
|
||||
|
||||
|
|
@ -160,6 +170,7 @@ namespace MinecraftClient.Mapping
|
|||
/// Based on the A* pathfinding algorithm described on Wikipedia
|
||||
/// </remarks>
|
||||
/// <see href="https://en.wikipedia.org/wiki/A*_search_algorithm#Pseudocode"/>
|
||||
/// <param name="world">World</param>
|
||||
/// <param name="start">Start location</param>
|
||||
/// <param name="goal">Destination location</param>
|
||||
/// <param name="allowUnsafe">Allow possible but unsafe locations</param>
|
||||
|
|
@ -167,7 +178,8 @@ namespace MinecraftClient.Mapping
|
|||
/// <param name="minOffset">Do not get closer of destination than specified distance</param>
|
||||
/// <param name="ct">Token for stopping computation after a certain time</param>
|
||||
/// <returns>A list of locations, or null if calculation failed</returns>
|
||||
public static Queue<Location>? CalculatePath(World world, Location start, Location goal, bool allowUnsafe, int maxOffset, int minOffset, CancellationToken ct)
|
||||
public static Queue<Location>? CalculatePath(World world, Location start, Location goal, bool allowUnsafe,
|
||||
int maxOffset, int minOffset, CancellationToken ct)
|
||||
{
|
||||
// This is a bad configuration
|
||||
if (minOffset > maxOffset)
|
||||
|
|
@ -181,12 +193,10 @@ namespace MinecraftClient.Mapping
|
|||
minOffset *= minOffset;
|
||||
maxOffset *= maxOffset;
|
||||
|
||||
///---///
|
||||
// Prepare variables and datastructures for A*
|
||||
///---///
|
||||
|
||||
// Dictionary that contains the relation between all coordinates and resolves the final path
|
||||
Dictionary<Location, Location> CameFrom = new();
|
||||
Dictionary<Location, Location> cameFrom = new();
|
||||
// Create a Binary Heap for all open positions => Allows fast access to Nodes with lowest scores
|
||||
BinaryHeap openSet = new();
|
||||
// Dictionary to keep track of the G-Score of every location
|
||||
|
|
@ -197,9 +207,7 @@ namespace MinecraftClient.Mapping
|
|||
gScoreDict[startLower] = 0;
|
||||
BinaryHeap.Node? current = null;
|
||||
|
||||
///---///
|
||||
// Start of A*
|
||||
///---///
|
||||
|
||||
// Execute while we have nodes to process and we are not cancelled
|
||||
while (openSet.Count() > 0 && !ct.IsCancellationRequested)
|
||||
|
|
@ -209,10 +217,9 @@ namespace MinecraftClient.Mapping
|
|||
current = openSet.GetRootLocation();
|
||||
|
||||
// Return if goal found and no maxOffset was given OR current node is between minOffset and maxOffset
|
||||
if ((current.Location == goalLower && maxOffset <= 0) || (maxOffset > 0 && current.H_score >= minOffset && current.H_score <= maxOffset))
|
||||
{
|
||||
return ReconstructPath(CameFrom, current.Location, start, goal);
|
||||
}
|
||||
if ((current.Location == goalLower && maxOffset <= 0) ||
|
||||
(maxOffset > 0 && current.HScore >= minOffset && current.HScore <= maxOffset))
|
||||
return ReconstructPath(cameFrom, current.Location, start, goal);
|
||||
|
||||
// Discover neighbored blocks
|
||||
foreach (Location neighbor in GetAvailableMoves(world, current.Location, allowUnsafe))
|
||||
|
|
@ -221,14 +228,15 @@ namespace MinecraftClient.Mapping
|
|||
if (ct.IsCancellationRequested)
|
||||
break;
|
||||
|
||||
// tentative_gScore is the distance from start to the neighbor through current
|
||||
int tentativeGScore = current.G_score + (int)current.Location.DistanceSquared(neighbor);
|
||||
// tentative_GScore is the distance from start to the neighbor through current
|
||||
int tentativeGScore = current.GScore + (int)current.Location.DistanceSquared(neighbor);
|
||||
|
||||
// If the neighbor is not in the gScoreDict OR its current tentativeGScore is lower than the previously saved one:
|
||||
if (!gScoreDict.ContainsKey(neighbor) || (gScoreDict.ContainsKey(neighbor) && tentativeGScore < gScoreDict[neighbor]))
|
||||
// If the neighbor is not in the GScoreDict OR its current tentativeGScore is lower than the previously saved one:
|
||||
if (!gScoreDict.ContainsKey(neighbor) ||
|
||||
(gScoreDict.ContainsKey(neighbor) && tentativeGScore < gScoreDict[neighbor]))
|
||||
{
|
||||
// Save the new relation between the neighbored block and the current one
|
||||
CameFrom[neighbor] = current.Location;
|
||||
cameFrom[neighbor] = current.Location;
|
||||
gScoreDict[neighbor] = tentativeGScore;
|
||||
|
||||
// If this location is not already included in the Binary Heap: save it
|
||||
|
|
@ -238,47 +246,51 @@ namespace MinecraftClient.Mapping
|
|||
}
|
||||
}
|
||||
|
||||
//// Goal could not be reached. Set the path to the closest location if close enough
|
||||
if (current != null && openSet.MinH_ScoreNode != null && (maxOffset == int.MaxValue || openSet.MinH_ScoreNode.H_score <= maxOffset))
|
||||
return ReconstructPath(CameFrom, openSet.MinH_ScoreNode.Location, start, goal);
|
||||
else
|
||||
// Goal could not be reached. Set the path to the closest location if close enough
|
||||
if (current != null && openSet.MinHScoreNode != null &&
|
||||
(maxOffset == int.MaxValue || openSet.MinHScoreNode.HScore <= maxOffset))
|
||||
return ReconstructPath(cameFrom, openSet.MinHScoreNode.Location, start, goal);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function for CalculatePath(). Backtrack from goal to start to reconstruct a step-by-step path.
|
||||
/// </summary>
|
||||
/// <param name="Came_From">The collection of Locations that leads back to the start</param>
|
||||
/// <param name="cameFrom">The collection of Locations that leads back to the start</param>
|
||||
/// <param name="current">Endpoint of our later walk</param>
|
||||
/// <param name="start">Start location</param>
|
||||
/// <param name="end">End location</param>
|
||||
/// <returns>the path that leads to current from the start position</returns>
|
||||
private static Queue<Location> ReconstructPath(Dictionary<Location, Location> Came_From, Location current, Location start, Location end)
|
||||
private static Queue<Location> ReconstructPath(Dictionary<Location, Location> cameFrom, Location current,
|
||||
Location start, Location end)
|
||||
{
|
||||
int midPathCnt = 0;
|
||||
List<Location> total_path = new();
|
||||
List<Location> totalPath = new();
|
||||
|
||||
// Move from the center of the block to the final position
|
||||
if (current != end && current == end.ToFloor())
|
||||
total_path.Add(end);
|
||||
totalPath.Add(end);
|
||||
|
||||
// Generate intermediate paths
|
||||
total_path.Add(current.ToCenter());
|
||||
while (Came_From.ContainsKey(current))
|
||||
totalPath.Add(current.ToCenter());
|
||||
while (cameFrom.ContainsKey(current))
|
||||
{
|
||||
++midPathCnt;
|
||||
current = Came_From[current];
|
||||
total_path.Add(current.ToCenter());
|
||||
current = cameFrom[current];
|
||||
totalPath.Add(current.ToCenter());
|
||||
}
|
||||
|
||||
if (midPathCnt <= 2 && start.DistanceSquared(end) < 2.0)
|
||||
return new Queue<Location>(new Location[] { end });
|
||||
return new Queue<Location>(new[] { end });
|
||||
else
|
||||
{
|
||||
// Move to the center of the block first
|
||||
if (current != start && current == start.ToFloor())
|
||||
total_path.Add(start.ToCenter());
|
||||
totalPath.Add(start.ToCenter());
|
||||
|
||||
total_path.Reverse();
|
||||
return new Queue<Location>(total_path);
|
||||
totalPath.Reverse();
|
||||
return new Queue<Location>(totalPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -297,62 +309,70 @@ namespace MinecraftClient.Mapping
|
|||
public class Node
|
||||
{
|
||||
// Distance to start
|
||||
public int G_score;
|
||||
public int GScore;
|
||||
|
||||
// Distance to Goal
|
||||
public int H_score;
|
||||
public int F_score { get { return H_score + G_score; } }
|
||||
public int HScore;
|
||||
|
||||
public int FScore
|
||||
{
|
||||
get { return HScore + GScore; }
|
||||
}
|
||||
|
||||
public Location Location;
|
||||
|
||||
public Node(int g_score, int h_score, Location loc)
|
||||
public Node(int gScore, int hScore, Location loc)
|
||||
{
|
||||
G_score = g_score;
|
||||
H_score = h_score;
|
||||
this.GScore = gScore;
|
||||
this.HScore = hScore;
|
||||
Location = loc;
|
||||
}
|
||||
}
|
||||
|
||||
// List which contains all nodes in form of a Binary Heap
|
||||
private readonly List<Node> heapList;
|
||||
|
||||
// Hashset for quick checks of locations included in the heap
|
||||
private readonly HashSet<Location> locationList;
|
||||
public Node? MinH_ScoreNode;
|
||||
public Node? MinHScoreNode;
|
||||
|
||||
public BinaryHeap()
|
||||
{
|
||||
heapList = new List<Node>();
|
||||
locationList = new HashSet<Location>();
|
||||
MinH_ScoreNode = null;
|
||||
MinHScoreNode = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert a new location in the heap
|
||||
/// </summary>
|
||||
/// <param name="newG_Score">G-Score of the location</param>
|
||||
/// <param name="newH_Score">H-Score of the location</param>
|
||||
/// <param name="newGScore">G-Score of the location</param>
|
||||
/// <param name="newHScore">H-Score of the location</param>
|
||||
/// <param name="loc">The location</param>
|
||||
public void Insert(int newG_Score, int newH_Score, Location loc)
|
||||
public void Insert(int newGScore, int newHScore, Location loc)
|
||||
{
|
||||
// Begin at the end of the list
|
||||
int i = heapList.Count;
|
||||
|
||||
// Temporarily save the node created with the parameters to allow comparisons
|
||||
Node newNode = new(newG_Score, newH_Score, loc);
|
||||
Node newNode = new(newGScore, newHScore, loc);
|
||||
|
||||
// Add new note to the end of the list
|
||||
heapList.Add(newNode);
|
||||
locationList.Add(loc);
|
||||
|
||||
// Save node with the smallest H-Score => Distance to goal
|
||||
if (MinH_ScoreNode == null || newNode.H_score < MinH_ScoreNode.H_score)
|
||||
MinH_ScoreNode = newNode;
|
||||
if (MinHScoreNode == null || newNode.HScore < MinHScoreNode.HScore)
|
||||
MinHScoreNode = newNode;
|
||||
|
||||
if (i == 0)
|
||||
return;
|
||||
|
||||
// There is no need of sorting for one node.
|
||||
if (i > 0)
|
||||
{
|
||||
/// Go up the heap from child to parent and move parent down...
|
||||
// Go up the heap from child to parent and move parent down...
|
||||
// while we are not looking at the root node AND the new node has better attributes than the parent node ((i - 1) / 2)
|
||||
while (i > 0 && FirstNodeBetter(newNode /* Current Child */, heapList[(i - 1) / 2] /* Coresponding Parent */))
|
||||
while (i > 0 && FirstNodeBetter(newNode /* Current Child */,
|
||||
heapList[(i - 1) / 2] /* Corresponding Parent */))
|
||||
{
|
||||
// Move parent down and replace current child -> New free space is created
|
||||
heapList[i] = heapList[(i - 1) / 2];
|
||||
|
|
@ -360,11 +380,10 @@ namespace MinecraftClient.Mapping
|
|||
i = (i - 1) / 2;
|
||||
}
|
||||
|
||||
/// Nodes were moved down at position I there is now a free space at the correct position for our new node:
|
||||
// Nodes were moved down at position I there is now a free space at the correct position for our new node:
|
||||
// Insert new node in position
|
||||
heapList[i] = newNode;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtain the root which represents the node the the best attributes currently
|
||||
|
|
@ -375,16 +394,14 @@ namespace MinecraftClient.Mapping
|
|||
{
|
||||
// The heap is empty. There is nothing to return.
|
||||
if (heapList.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("The heap is empty.");
|
||||
}
|
||||
|
||||
// Save the root node
|
||||
Node rootNode = heapList[0];
|
||||
var rootNode = heapList[0];
|
||||
locationList.Remove(rootNode.Location);
|
||||
|
||||
// Temporarirly store the last item's value.
|
||||
Node lastNode = heapList[^1];
|
||||
var lastNode = heapList[^1];
|
||||
|
||||
// Remove the last value.
|
||||
heapList.RemoveAt(heapList.Count - 1);
|
||||
|
|
@ -392,17 +409,18 @@ namespace MinecraftClient.Mapping
|
|||
if (heapList.Count > 0)
|
||||
{
|
||||
// Start at the first index.
|
||||
int currentParentPos = 0;
|
||||
var currentParentPos = 0;
|
||||
|
||||
/// Go through the heap from root to bottom...
|
||||
// Go through the heap from root to bottom...
|
||||
// Continue until the halfway point of the heap.
|
||||
while (currentParentPos < heapList.Count / 2)
|
||||
{
|
||||
// Select the left child of the current parent
|
||||
int currentChildPos = (2 * currentParentPos) + 1;
|
||||
var currentChildPos = (2 * currentParentPos) + 1;
|
||||
|
||||
// If the currently selected child is not the last entry of the list AND right child has better attributes
|
||||
if ((currentChildPos < heapList.Count - 1) && FirstNodeBetter(heapList[currentChildPos + 1], heapList[currentChildPos]))
|
||||
if ((currentChildPos < heapList.Count - 1) && FirstNodeBetter(heapList[currentChildPos + 1],
|
||||
heapList[currentChildPos]))
|
||||
{
|
||||
// Select the right child
|
||||
currentChildPos++;
|
||||
|
|
@ -411,15 +429,14 @@ namespace MinecraftClient.Mapping
|
|||
// If the last item is smaller than both siblings at the
|
||||
// current height, break.
|
||||
if (FirstNodeBetter(lastNode, heapList[currentChildPos]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Move the item at index j up one level.
|
||||
heapList[currentParentPos] = heapList[currentChildPos];
|
||||
// Move index i to the appropriate branch.
|
||||
currentParentPos = currentChildPos;
|
||||
}
|
||||
|
||||
// Insert the last node into the currently free position
|
||||
heapList[currentParentPos] = lastNode;
|
||||
}
|
||||
|
|
@ -432,13 +449,13 @@ namespace MinecraftClient.Mapping
|
|||
/// </summary>
|
||||
/// <param name="firstNode">First node to compare</param>
|
||||
/// <param name="secondNode">Second node to compare</param>
|
||||
/// <returns>True if the first node has a more promissing position to the goal than the second</returns>
|
||||
/// <returns>True if the first node has a more promising position to the goal than the second</returns>
|
||||
private static bool FirstNodeBetter(Node firstNode, Node secondNode)
|
||||
{
|
||||
// Is the F_score smaller?
|
||||
return (firstNode.F_score < secondNode.F_score) ||
|
||||
// If F_score is equal, evaluate the h-score
|
||||
(firstNode.F_score == secondNode.F_score && firstNode.H_score < secondNode.H_score);
|
||||
// Is the FScore smaller?
|
||||
return (firstNode.FScore < secondNode.FScore) ||
|
||||
// If FScore is equal, evaluate the h-score
|
||||
(firstNode.FScore == secondNode.FScore && firstNode.HScore < secondNode.HScore);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -478,120 +495,63 @@ namespace MinecraftClient.Mapping
|
|||
return true; // avoid moving downward in a not loaded chunk
|
||||
|
||||
Location down = Move(location, Direction.Down);
|
||||
|
||||
Material currentMaterial = world.GetBlock(down).Type;
|
||||
|
||||
bool result = currentMaterial.IsSolid()
|
||||
var result = currentMaterial.IsSolid()
|
||||
|| currentMaterial == Material.TwistingVines || currentMaterial == Material.TwistingVinesPlant
|
||||
|| currentMaterial == Material.WeepingVines || currentMaterial == Material.WeepingVinesPlant
|
||||
|| currentMaterial == Material.Vine;
|
||||
|
||||
bool northCheck = 1 + Math.Floor(down.Z) - down.Z > 0.7;
|
||||
bool eastCheck = down.X - Math.Floor(down.X) > 0.7;
|
||||
bool southCheck = down.Z - Math.Floor(down.Z) > 0.7;
|
||||
bool westCheck = 1 + Math.Floor(down.X) - down.X > 0.7;
|
||||
var northCheck = 1 + Math.Floor(down.Z) - down.Z > 0.7;
|
||||
var eastCheck = down.X - Math.Floor(down.X) > 0.7;
|
||||
var southCheck = down.Z - Math.Floor(down.Z) > 0.7;
|
||||
var westCheck = 1 + Math.Floor(down.X) - down.X > 0.7;
|
||||
|
||||
if (!result && northCheck)
|
||||
{
|
||||
Location locationDownNorth = Move(down, Direction.North);
|
||||
result |= world.GetBlock(locationDownNorth).Type.IsSolid()
|
||||
|| world.GetBlock(locationDownNorth).Type == Material.TwistingVines
|
||||
|| world.GetBlock(locationDownNorth).Type == Material.TwistingVinesPlant
|
||||
|| world.GetBlock(locationDownNorth).Type == Material.WeepingVines
|
||||
|| world.GetBlock(locationDownNorth).Type == Material.WeepingVinesPlant
|
||||
|| world.GetBlock(locationDownNorth).Type == Material.Vine;
|
||||
}
|
||||
result |= IsSolidOrVine(world, Move(down, Direction.North));
|
||||
|
||||
if (!result && northCheck && eastCheck)
|
||||
{
|
||||
Location locationDownNorthEast = Move(down, Direction.NorthEast);
|
||||
result |= world.GetBlock(locationDownNorthEast).Type.IsSolid()
|
||||
|| world.GetBlock(locationDownNorthEast).Type == Material.TwistingVines
|
||||
|| world.GetBlock(locationDownNorthEast).Type == Material.TwistingVinesPlant
|
||||
|| world.GetBlock(locationDownNorthEast).Type == Material.WeepingVines
|
||||
|| world.GetBlock(locationDownNorthEast).Type == Material.WeepingVinesPlant
|
||||
|| world.GetBlock(locationDownNorthEast).Type == Material.Vine;
|
||||
}
|
||||
result |= IsSolidOrVine(world, Move(down, Direction.NorthEast));
|
||||
|
||||
if (!result && eastCheck)
|
||||
{
|
||||
Location locationDownEast = Move(down, Direction.East);
|
||||
result |= world.GetBlock(locationDownEast).Type.IsSolid()
|
||||
|| world.GetBlock(locationDownEast).Type == Material.TwistingVines
|
||||
|| world.GetBlock(locationDownEast).Type == Material.TwistingVinesPlant
|
||||
|| world.GetBlock(locationDownEast).Type == Material.WeepingVines
|
||||
|| world.GetBlock(locationDownEast).Type == Material.WeepingVinesPlant
|
||||
|| world.GetBlock(locationDownEast).Type == Material.Vine;
|
||||
}
|
||||
result |= IsSolidOrVine(world, Move(down, Direction.East));
|
||||
|
||||
if (!result && eastCheck && southCheck)
|
||||
{
|
||||
Location locationDownSouthEast = Move(down, Direction.SouthEast);
|
||||
result |= world.GetBlock(locationDownSouthEast).Type.IsSolid()
|
||||
|| world.GetBlock(locationDownSouthEast).Type == Material.TwistingVines
|
||||
|| world.GetBlock(locationDownSouthEast).Type == Material.TwistingVinesPlant
|
||||
|| world.GetBlock(locationDownSouthEast).Type == Material.WeepingVines
|
||||
|| world.GetBlock(locationDownSouthEast).Type == Material.WeepingVinesPlant
|
||||
|| world.GetBlock(locationDownSouthEast).Type == Material.Vine;
|
||||
}
|
||||
result |= IsSolidOrVine(world, Move(down, Direction.SouthEast));
|
||||
|
||||
if (!result && southCheck)
|
||||
{
|
||||
Location locationDownSouth = Move(down, Direction.South);
|
||||
result |= world.GetBlock(locationDownSouth).Type.IsSolid()
|
||||
|| world.GetBlock(locationDownSouth).Type == Material.TwistingVines
|
||||
|| world.GetBlock(locationDownSouth).Type == Material.TwistingVinesPlant
|
||||
|| world.GetBlock(locationDownSouth).Type == Material.WeepingVines
|
||||
|| world.GetBlock(locationDownSouth).Type == Material.WeepingVinesPlant
|
||||
|| world.GetBlock(locationDownSouth).Type == Material.Vine;
|
||||
}
|
||||
result |= IsSolidOrVine(world, Move(down, Direction.South));
|
||||
|
||||
if (!result && southCheck && westCheck)
|
||||
{
|
||||
Location locationDownSouthWest = Move(down, Direction.SouthWest);
|
||||
result |= world.GetBlock(locationDownSouthWest).Type.IsSolid()
|
||||
|| world.GetBlock(locationDownSouthWest).Type == Material.TwistingVines
|
||||
|| world.GetBlock(locationDownSouthWest).Type == Material.TwistingVinesPlant
|
||||
|| world.GetBlock(locationDownSouthWest).Type == Material.WeepingVines
|
||||
|| world.GetBlock(locationDownSouthWest).Type == Material.WeepingVinesPlant
|
||||
|| world.GetBlock(locationDownSouthWest).Type == Material.Vine;
|
||||
}
|
||||
|
||||
result |= IsSolidOrVine(world, Move(down, Direction.SouthWest));
|
||||
|
||||
if (!result && westCheck)
|
||||
{
|
||||
Location locationDownWest = Move(down, Direction.West);
|
||||
result |= world.GetBlock(locationDownWest).Type.IsSolid()
|
||||
|| world.GetBlock(locationDownWest).Type == Material.TwistingVines
|
||||
|| world.GetBlock(locationDownWest).Type == Material.TwistingVinesPlant
|
||||
|| world.GetBlock(locationDownWest).Type == Material.WeepingVines
|
||||
|| world.GetBlock(locationDownWest).Type == Material.WeepingVinesPlant
|
||||
|| world.GetBlock(locationDownWest).Type == Material.Vine;
|
||||
}
|
||||
|
||||
result |= IsSolidOrVine(world, Move(down, Direction.West));
|
||||
|
||||
if (!result && westCheck && northCheck)
|
||||
{
|
||||
Location locationDownNorthWest = Move(down, Direction.NorthWest);
|
||||
result |= world.GetBlock(locationDownNorthWest).Type.IsSolid()
|
||||
|| world.GetBlock(locationDownNorthWest).Type == Material.TwistingVines
|
||||
|| world.GetBlock(locationDownNorthWest).Type == Material.TwistingVinesPlant
|
||||
|| world.GetBlock(locationDownNorthWest).Type == Material.WeepingVines
|
||||
|| world.GetBlock(locationDownNorthWest).Type == Material.WeepingVinesPlant
|
||||
|| world.GetBlock(locationDownNorthWest).Type == Material.Vine;
|
||||
|
||||
}
|
||||
result |= IsSolidOrVine(world, Move(down, Direction.NorthWest));
|
||||
|
||||
return result && (location.Y <= Math.Truncate(location.Y) + 0.0001);
|
||||
}
|
||||
|
||||
private static bool IsSolidOrVine(World world, Location location)
|
||||
{
|
||||
var block = world.GetBlock(location);
|
||||
return block.Type.IsSolid()
|
||||
|| block.Type == Material.TwistingVines
|
||||
|| block.Type == Material.TwistingVinesPlant
|
||||
|| block.Type == Material.WeepingVines
|
||||
|| block.Type == Material.WeepingVinesPlant
|
||||
|| block.Type == Material.Vine;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the specified location implies swimming
|
||||
/// </summary>
|
||||
/// <param name="world">World for performing check</param>
|
||||
/// <param name="location">Location to check</param>
|
||||
/// <returns>True if the specified location implies swimming</returns>
|
||||
public static bool IsSwimming(World world, Location location)
|
||||
private static bool IsSwimming(World world, Location location)
|
||||
{
|
||||
return world.GetBlock(location).Type.IsLiquid();
|
||||
}
|
||||
|
|
@ -602,7 +562,7 @@ namespace MinecraftClient.Mapping
|
|||
/// <param name="world">World for performing check</param>
|
||||
/// <param name="location">Location to check</param>
|
||||
/// <returns>True if the specified location can be climbed on</returns>
|
||||
public static bool IsClimbing(World world, Location location)
|
||||
private static bool IsClimbing(World world, Location location)
|
||||
{
|
||||
return world.GetBlock(location).Type.CanBeClimbedOn();
|
||||
}
|
||||
|
|
@ -613,7 +573,7 @@ namespace MinecraftClient.Mapping
|
|||
/// <param name="world">World for performing check</param>
|
||||
/// <param name="location">Location to check</param>
|
||||
/// <returns>True if the destination location won't directly harm the player</returns>
|
||||
public static bool IsSafe(World world, Location location)
|
||||
private static bool IsSafe(World world, Location location)
|
||||
{
|
||||
return
|
||||
//No block that can harm the player
|
||||
|
|
@ -622,9 +582,12 @@ namespace MinecraftClient.Mapping
|
|||
&& !world.GetBlock(Move(location, Direction.Down)).Type.CanHarmPlayers()
|
||||
|
||||
//No fall from a too high place
|
||||
&& (world.GetBlock(Move(location, Direction.Down)).Type.IsSolid() || IsClimbing(world, Move(location, Direction.Down))
|
||||
|| world.GetBlock(Move(location, Direction.Down, 2)).Type.IsSolid() || IsClimbing(world, Move(location, Direction.Down, 2))
|
||||
|| world.GetBlock(Move(location, Direction.Down, 3)).Type.IsSolid() || IsClimbing(world, Move(location, Direction.Down, 3)))
|
||||
&& (world.GetBlock(Move(location, Direction.Down)).Type.IsSolid() ||
|
||||
IsClimbing(world, Move(location, Direction.Down))
|
||||
|| world.GetBlock(Move(location, Direction.Down, 2)).Type.IsSolid() ||
|
||||
IsClimbing(world, Move(location, Direction.Down, 2))
|
||||
|| world.GetBlock(Move(location, Direction.Down, 3)).Type.IsSolid() ||
|
||||
IsClimbing(world, Move(location, Direction.Down, 3)))
|
||||
|
||||
//Not an underwater location
|
||||
&& !(world.GetBlock(Move(location, Direction.Up)).Type.IsLiquid());
|
||||
|
|
@ -647,11 +610,12 @@ namespace MinecraftClient.Mapping
|
|||
case Direction.Down:
|
||||
return IsClimbing(world, Move(location, Direction.Down)) || !IsOnGround(world, location);
|
||||
case Direction.Up:
|
||||
bool nextTwoBlocks = !world.GetBlock(Move(Move(location, Direction.Up), Direction.Up)).Type.IsSolid();
|
||||
bool nextTwoBlocks =
|
||||
!world.GetBlock(Move(Move(location, Direction.Up), Direction.Up)).Type.IsSolid();
|
||||
|
||||
// Check if the current block can be climbed on
|
||||
if (IsClimbing(world, location))
|
||||
// Check if next block after the next one can be climbed uppon
|
||||
// Check if next block after the next one can be climbed upon
|
||||
return IsClimbing(world, Move(location, Direction.Up)) || nextTwoBlocks;
|
||||
|
||||
return (IsOnGround(world, location) || IsSwimming(world, location)) && nextTwoBlocks;
|
||||
|
|
@ -665,13 +629,21 @@ namespace MinecraftClient.Mapping
|
|||
|
||||
// Move diagonal
|
||||
case Direction.NorthEast:
|
||||
return PlayerFitsHere(world, Move(location, Direction.North)) && PlayerFitsHere(world, Move(location, Direction.East)) && PlayerFitsHere(world, Move(location, direction));
|
||||
return PlayerFitsHere(world, Move(location, Direction.North)) &&
|
||||
PlayerFitsHere(world, Move(location, Direction.East)) &&
|
||||
PlayerFitsHere(world, Move(location, direction));
|
||||
case Direction.SouthEast:
|
||||
return PlayerFitsHere(world, Move(location, Direction.South)) && PlayerFitsHere(world, Move(location, Direction.East)) && PlayerFitsHere(world, Move(location, direction));
|
||||
return PlayerFitsHere(world, Move(location, Direction.South)) &&
|
||||
PlayerFitsHere(world, Move(location, Direction.East)) &&
|
||||
PlayerFitsHere(world, Move(location, direction));
|
||||
case Direction.SouthWest:
|
||||
return PlayerFitsHere(world, Move(location, Direction.South)) && PlayerFitsHere(world, Move(location, Direction.West)) && PlayerFitsHere(world, Move(location, direction));
|
||||
return PlayerFitsHere(world, Move(location, Direction.South)) &&
|
||||
PlayerFitsHere(world, Move(location, Direction.West)) &&
|
||||
PlayerFitsHere(world, Move(location, direction));
|
||||
case Direction.NorthWest:
|
||||
return PlayerFitsHere(world, Move(location, Direction.North)) && PlayerFitsHere(world, Move(location, Direction.West)) && PlayerFitsHere(world, Move(location, direction));
|
||||
return PlayerFitsHere(world, Move(location, Direction.North)) &&
|
||||
PlayerFitsHere(world, Move(location, Direction.West)) &&
|
||||
PlayerFitsHere(world, Move(location, direction));
|
||||
|
||||
default:
|
||||
throw new ArgumentException("Unknown direction", nameof(direction));
|
||||
|
|
@ -686,8 +658,16 @@ namespace MinecraftClient.Mapping
|
|||
/// <returns>True if a player is able to stand in this location</returns>
|
||||
public static bool PlayerFitsHere(World world, Location location)
|
||||
{
|
||||
return (IsClimbing(world, location) && IsClimbing(world, Move(location, Direction.Up)))
|
||||
|| !world.GetBlock(location).Type.IsSolid() && !world.GetBlock(Move(location, Direction.Up)).Type.IsSolid();
|
||||
var canClimb = IsClimbing(world, location) && IsClimbing(world, Move(location, Direction.Up));
|
||||
var isNotSolid = !world.GetBlock(location).Type.IsSolid() &&
|
||||
!world.GetBlock(Move(location, Direction.Up)).Type.IsSolid();
|
||||
|
||||
// Handle slabs
|
||||
if (!isNotSolid && world.GetBlock(Move(location, Direction.Up))
|
||||
.IsTopSlab(McClient.Instance!.GetProtocolVersion()))
|
||||
isNotSolid = true;
|
||||
|
||||
return canClimb || isNotSolid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -707,39 +687,28 @@ namespace MinecraftClient.Mapping
|
|||
/// </summary>
|
||||
/// <param name="direction">Direction to move to</param>
|
||||
/// <returns>A location delta for moving in that direction</returns>
|
||||
public static Location Move(Direction direction)
|
||||
private static Location Move(Direction direction)
|
||||
{
|
||||
switch (direction)
|
||||
return direction switch
|
||||
{
|
||||
// Move vertical
|
||||
case Direction.Down:
|
||||
return new Location(0, -1, 0);
|
||||
case Direction.Up:
|
||||
return new Location(0, 1, 0);
|
||||
Direction.Down => new Location(0, -1, 0),
|
||||
Direction.Up => new Location(0, 1, 0),
|
||||
|
||||
// Move horizontal straight
|
||||
case Direction.East:
|
||||
return new Location(1, 0, 0);
|
||||
case Direction.West:
|
||||
return new Location(-1, 0, 0);
|
||||
case Direction.South:
|
||||
return new Location(0, 0, 1);
|
||||
case Direction.North:
|
||||
return new Location(0, 0, -1);
|
||||
Direction.East => new Location(1, 0, 0),
|
||||
Direction.West => new Location(-1, 0, 0),
|
||||
Direction.South => new Location(0, 0, 1),
|
||||
Direction.North => new Location(0, 0, -1),
|
||||
|
||||
// Move horizontal diagonal
|
||||
case Direction.NorthEast:
|
||||
return Move(Direction.North) + Move(Direction.East);
|
||||
case Direction.SouthEast:
|
||||
return Move(Direction.South) + Move(Direction.East);
|
||||
case Direction.SouthWest:
|
||||
return Move(Direction.South) + Move(Direction.West);
|
||||
case Direction.NorthWest:
|
||||
return Move(Direction.North) + Move(Direction.West);
|
||||
Direction.NorthEast => Move(Direction.North) + Move(Direction.East),
|
||||
Direction.SouthEast => Move(Direction.South) + Move(Direction.East),
|
||||
Direction.SouthWest => Move(Direction.South) + Move(Direction.West),
|
||||
Direction.NorthWest => Move(Direction.North) + Move(Direction.West),
|
||||
|
||||
default:
|
||||
throw new ArgumentException("Unknown direction", nameof(direction));
|
||||
}
|
||||
_ => throw new ArgumentException("Unknown direction", nameof(direction))
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -751,7 +720,7 @@ namespace MinecraftClient.Mapping
|
|||
/// <returns>Is loading complete</returns>
|
||||
public static bool CheckChunkLoading(World world, Location start, Location dest)
|
||||
{
|
||||
ChunkColumn? chunkColumn = world.GetChunkColumn(dest);
|
||||
var chunkColumn = world.GetChunkColumn(dest);
|
||||
if (chunkColumn == null || chunkColumn.FullyLoaded == false)
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using Brigadier.NET.Exceptions;
|
|||
using MinecraftClient.ChatBots;
|
||||
using MinecraftClient.CommandHandler;
|
||||
using MinecraftClient.CommandHandler.Patch;
|
||||
using MinecraftClient.Commands;
|
||||
using MinecraftClient.Inventory;
|
||||
using MinecraftClient.Logger;
|
||||
using MinecraftClient.Mapping;
|
||||
|
|
@ -98,6 +99,11 @@ namespace MinecraftClient
|
|||
private int playerTotalExperience;
|
||||
private byte CurrentSlot = 0;
|
||||
|
||||
// Sneaking
|
||||
public bool IsSneaking { get; set; } = false;
|
||||
private bool isUnderSlab = false;
|
||||
private DateTime nextSneakingUpdate = DateTime.Now;
|
||||
|
||||
// Entity handling
|
||||
private readonly Dictionary<int, Entity> entities = new();
|
||||
|
||||
|
|
@ -145,6 +151,8 @@ namespace MinecraftClient
|
|||
|
||||
public ILogger Log;
|
||||
|
||||
private static IMinecraftComHandler? instance;
|
||||
public static IMinecraftComHandler? Instance => instance;
|
||||
/// <summary>
|
||||
/// Starts the main chat client, wich will login to the server using the MinecraftCom class.
|
||||
/// </summary>
|
||||
|
|
@ -157,6 +165,8 @@ namespace MinecraftClient
|
|||
public McClient(SessionToken session, PlayerKeyPair? playerKeyPair, string server_ip, ushort port, int protocolversion, ForgeInfo? forgeInfo)
|
||||
{
|
||||
CmdResult.currentHandler = this;
|
||||
instance = this;
|
||||
|
||||
terrainAndMovementsEnabled = Config.Main.Advanced.TerrainAndMovements;
|
||||
inventoryHandlingEnabled = Config.Main.Advanced.InventoryHandling;
|
||||
entityHandlingEnabled = Config.Main.Advanced.EntityHandling;
|
||||
|
|
@ -328,6 +338,25 @@ namespace MinecraftClient
|
|||
}
|
||||
}
|
||||
|
||||
if (nextSneakingUpdate < DateTime.Now)
|
||||
{
|
||||
if (world.GetBlock(new Location(location.X, location.Y + 1, location.Z)).IsTopSlab(protocolversion) && !IsSneaking)
|
||||
{
|
||||
isUnderSlab = true;
|
||||
SendEntityAction(EntityActionType.StartSneaking);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isUnderSlab && !IsSneaking)
|
||||
{
|
||||
isUnderSlab = false;
|
||||
SendEntityAction(EntityActionType.StopSneaking);
|
||||
}
|
||||
}
|
||||
|
||||
nextSneakingUpdate = DateTime.Now.AddMilliseconds(300);
|
||||
}
|
||||
|
||||
lock (chatQueue)
|
||||
{
|
||||
TrySendMessageToServer();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue